Quellcode durchsuchen

refactor(config): restructure, make immutable fields mutable, update example

Librellium vor 2 Tagen
Ursprung
Commit
36450ead21
3 geänderte Dateien mit 73 neuen und 89 gelöschten Zeilen
  1. 8 10
      anonflow/config/config.py
  2. 22 37
      anonflow/config/models.py
  3. 43 42
      config.yml.example

+ 8 - 10
anonflow/config/config.py

@@ -3,21 +3,19 @@ from string import Template
 
 import yaml
 from dotenv import dotenv_values
-from pydantic import BaseModel, SecretStr
+from pydantic import BaseModel, Field, SecretStr
 from sqlalchemy.engine import URL
 
-from .models import Behavior, Bot, Database, Forwarding, Logging, Moderation, OpenAI
+from .models import App, Bot, Database, Logging, Moderation, OpenAI
 
 
 class Config(BaseModel):
-    bot: Bot = Bot()
-    behavior: Behavior = Behavior()
-    database: Database = Database()
-    forwarding: Forwarding = Forwarding()
-    openai: OpenAI = OpenAI()
-    moderation: Moderation = Moderation()
-    logging: Logging = Logging()
-    model_config = {"frozen": True}
+    app: App = Field(default_factory=App)
+    bot: Bot = Field(default_factory=Bot)
+    database: Database = Field(default_factory=Database)
+    openai: OpenAI = Field(default_factory=OpenAI)
+    moderation: Moderation = Field(default_factory=Moderation)
+    logging: Logging = Field(default_factory=Logging)
 
     def get_database_url(self):
         password = None

+ 22 - 37
anonflow/config/models.py

@@ -1,5 +1,5 @@
 from pathlib import Path
-from typing import FrozenSet, Literal, Optional, Tuple, TypeAlias, Union
+from typing import List, Literal, Optional, Set, TypeAlias, Union
 
 from pydantic import BaseModel, Field, HttpUrl, SecretStr
 
@@ -8,63 +8,51 @@ ModerationBackend: TypeAlias = Literal["omni", "gpt"]
 LoggingLevel: TypeAlias = Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
 
 
-class Bot(BaseModel):
-    token: Optional[SecretStr] = None
-    timeout: int = 10
-    model_config = {"frozen": True}
+class App(BaseModel):
+    language: str = "ru"
+    fallback_language: str = "ru"
 
 
-class BehaviorThrottling(BaseModel):
+class BotBehaviorThrottling(BaseModel):
     enabled: bool = True
     delay: float = 120
-    model_config = {"frozen": True}
 
 
-class BehaviorSubscriptionRequirement(BaseModel):
+class BotBehaviorSubscriptionRequirement(BaseModel):
     enabled: bool = True
-    channel_ids: Tuple[int, ...] = Field(default_factory=tuple)
-    model_config = {"frozen": True}
+    channel_ids: List[int] = Field(default_factory=list)
 
 
-class Behavior(BaseModel):
-    throttling: BehaviorThrottling = BehaviorThrottling()
-    subscription_requirement: BehaviorSubscriptionRequirement = BehaviorSubscriptionRequirement()  # fmt: skip
-    model_config = {"frozen": True}
+class BotBehavior(BaseModel):
+    throttling: BotBehaviorThrottling = Field(default_factory=BotBehaviorThrottling)
+    subscription_requirement: BotBehaviorSubscriptionRequirement = Field(default_factory=BotBehaviorSubscriptionRequirement)  # fmt: skip
 
 
-class DatabaseRepositoriesUser(BaseModel):
-    cache_size: int = 1024
-    cache_ttl: int = 60
-    model_config = {"frozen": True}
+class BotForwarding(BaseModel):
+    moderation_chat_id: Optional[int] = None
+    publication_channel_ids: List[int] = Field(default_factory=list)
+    types: Set[ForwardingType] = Field(default_factory=lambda: {"text", "photo", "video"})
 
 
-class DatabaseRepositories(BaseModel):
-    user: DatabaseRepositoriesUser = DatabaseRepositoriesUser()
-    model_config = {"frozen": True}
+class Bot(BaseModel):
+    token: Optional[SecretStr] = None
+    timeout: int = 10
+    behavior: BotBehavior = Field(default_factory=BotBehavior)
+    forwarding: BotForwarding = Field(default_factory=BotForwarding)
 
 
 class DatabaseMigrations(BaseModel):
     backend: str = "sqlite"
-    model_config = {"frozen": True}
 
 
 class Database(BaseModel):
     backend: str = "sqlite+aiosqlite"
-    name_or_path: Optional[Union[str, Path]] = None
+    name_or_path: Optional[Union[str, Path]] = "anonflow.db"
     host: Optional[str] = None
     port: Optional[int] = None
     username: Optional[str] = None
     password: Optional[SecretStr] = None
-    repositories: DatabaseRepositories = DatabaseRepositories()
-    migrations: DatabaseMigrations = DatabaseMigrations()
-    model_config = {"frozen": True}
-
-
-class Forwarding(BaseModel):
-    moderation_chat_ids: Tuple[int, ...] = Field(default_factory=tuple)
-    publication_channel_ids: Tuple[int, ...] = Field(default_factory=tuple)
-    types: FrozenSet[ForwardingType] = frozenset(["text", "photo", "video"])
-    model_config = {"frozen": True}
+    migrations: DatabaseMigrations = Field(default_factory=DatabaseMigrations)
 
 
 class OpenAI(BaseModel):
@@ -73,18 +61,15 @@ class OpenAI(BaseModel):
     proxy: Optional[HttpUrl] = None
     timeout: int = 10
     max_retries: int = 0
-    model_config = {"frozen": True}
 
 
 class Moderation(BaseModel):
     enabled: bool = True
     model: str = "gpt-5-mini"
-    backends: FrozenSet[ModerationBackend] = frozenset(["omni", "gpt"])
-    model_config = {"frozen": True}
+    backends: Set[ModerationBackend] = Field(default_factory=lambda: {"omni", "gpt"})
 
 
 class Logging(BaseModel):
     level: LoggingLevel = "INFO"
     fmt: Optional[str] = "%(asctime)s.%(msecs)03d %(levelname)s [%(name)s] %(message)s"
     date_fmt: Optional[str] = "%Y-%m-%d %H:%M:%S"
-    model_config = {"frozen": True}

+ 43 - 42
config.yml.example

@@ -1,3 +1,12 @@
+app:
+  # Primary bot language.
+  # Used by the bot in moderation chats by default.
+  language: ru
+
+  # Language used when a user is not found in the database
+  # and their preferred language cannot be determined.
+  fallback_language: ru
+
 bot:
   # Telegram bot token, passed via environment variable BOT_TOKEN.
   # Used by aiogram to connect to the Telegram Bot API.
@@ -8,23 +17,40 @@ bot:
   # only defines how long a single HTTP request may take before timing out.
   timeout: 15
 
-behavior:
-  throttling:
-    # Enable/disable throttling for user-submitted posts.
-    # When enabled, each user must wait `delay` seconds between submissions.
-    enabled: true
-
-    # Minimal delay (in seconds) between two post submissions from the same user.
-    # The delay is measured between the moments when the user's requests are processed by the bot.
-    delay: 120
-
-  subscription_requirement:
-    # Require users to be subscribed to specific Telegram channels before they can use the bot.
-    # If enabled, the bot checks subscription status for each user action.
-    enabled: false
-
-    # List of Telegram chat_ids (channels) that the user must be subscribed to.
-    channel_ids: []
+  behavior:
+    throttling:
+      # Enable/disable throttling for user-submitted posts.
+      # When enabled, each user must wait `delay` seconds between submissions.
+      enabled: true
+
+      # Minimal delay (in seconds) between two post submissions from the same user.
+      # The delay is measured between the moments when the user's requests are processed by the bot.
+      delay: 120
+
+    subscription_requirement:
+      # Require users to be subscribed to specific Telegram channels before they can use the bot.
+      # If enabled, the bot checks subscription status for each user action.
+      enabled: false
+
+      # List of Telegram chat_ids (channels) that the user must be subscribed to.
+      channel_ids: []
+
+  forwarding:
+    # Telegram chat_id where decisions of the moderation module are sent.
+    # Typically this is a chat for moderators that receive moderation results.
+    moderation_chat_id: null
+
+    # Telegram chat_ids where approved posts are published.
+    # Once approved, messages are forwarded to all configured publication channels.
+    publication_channel_ids: []
+
+    # List of Telegram message types that are handled and can be forwarded
+    # by the bot: text messages, photos, videos, etc.
+    # Types correspond to Telegram message content types.
+    types:
+      - text
+      - photo
+      - video
 
 database:
   # SQLAlchemy database backend/driver.
@@ -58,31 +84,6 @@ database:
     # Alembic is configured to work with the same SQLAlchemy URL.
     backend: ${DB_MIGRATIONS_BACKEND}
 
-  repositories:
-    user:
-      # Maximum number of user records cached in memory.
-      cache_size: 1024
-
-      # Time-to-live for cached user objects (in seconds).
-      cache_ttl: 60
-
-forwarding:
-  # Telegram chat_ids where decisions of the moderation module are sent.
-  # Typically these are chats for moderators that receive moderation results.
-  moderation_chat_ids: []
-
-  # Telegram chat_ids where approved posts are published.
-  # Once approved, messages are forwarded to all configured publication channels.
-  publication_channel_ids: []
-
-  # List of Telegram message types that are handled and can be forwarded
-  # by the bot: text messages, photos, videos, etc.
-  # Types correspond to Telegram message content types.
-  types:
-    - text
-    - photo
-    - video
-
 openai:
   # OpenAI API key used by the client.
   # Can be provided via OPENAI_API_KEY environment variable.