Source code for codegen_database.config

"""Global codegen_database configuration."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import TYPE_CHECKING

from codegen_database.extension import (
    discover_extensions,
    validate_extension_deps,
)

if TYPE_CHECKING:
    from sqlalchemy import MetaData

    from codegen_database.extension import CodegenDatabaseExtension
    from codegen_database.plugin import Plugin

#: Default schema for codegen_database-managed utility objects -- the
#: ``CodegenDatabaseConfig.utility_schema`` default and the fallback
#: :func:`resolve_utility_schema` uses when no config is present.
DEFAULT_UTILITY_SCHEMA = "codegen_database"


[docs] @dataclass class CodegenDatabaseConfig: """Global plugin and extension registry. Plugins registered here are prepended to every factory's resolved plugin list, so they run before factory-specific plugins. Extensions bundle plugins, metadata hooks, Alembic hooks, and CLI commands into a single unit. Example:: config = CodegenDatabaseConfig() config.register(TimestampPlugin(), TenantPlugin()) CodegenDatabaseSimple( "users", "public", metadata, ..., config=config ) Args: plugins: Global plugins prepended to every factory. extensions: Manually registered extension instances. auto_discover: Whether to discover extensions via entry points. Defaults to ``True``. utility_schema: PostgreSQL schema for codegen_database-managed utility functions (e.g. ``ledger_apply_state``). Defaults to ``"codegen_database"``. Override only if your project already uses a schema named ``"codegen_database"``. """ plugins: list[Plugin] = field(default_factory=list) extensions: list[CodegenDatabaseExtension] = field(default_factory=list) auto_discover: bool = True utility_schema: str = DEFAULT_UTILITY_SCHEMA
[docs] def register(self, *plugins: Plugin) -> CodegenDatabaseConfig: """Register one or more plugins globally. Args: *plugins: Plugin instances to add. Returns: ``self`` for chaining. """ self.plugins.extend(plugins) return self
[docs] def use( self, *extensions: CodegenDatabaseExtension ) -> CodegenDatabaseConfig: """Register one or more extensions. Args: *extensions: Extension instances to add. Returns: ``self`` for chaining. """ self.extensions.extend(extensions) return self
def _resolved_extensions(self) -> list[CodegenDatabaseExtension]: """Return manual + discovered extensions, deduped by name. Manual extensions take precedence over discovered ones with the same name. Returns: Ordered list of extension instances. """ seen: dict[str, CodegenDatabaseExtension] = {} for ext in self.extensions: seen[ext.name] = ext if self.auto_discover: for name, ext_cls in discover_extensions().items(): if name not in seen: seen[name] = ext_cls(name=name) result = list(seen.values()) validate_extension_deps(result) return result @property def all_plugins(self) -> list[Plugin]: """Return extension plugins + direct plugins. Extension plugins are prepended before direct plugins. Returns: Combined plugin list. """ ext_plugins: list[Plugin] = [] for ext in self._resolved_extensions(): ext_plugins.extend(ext.plugins()) return ext_plugins + self.plugins
[docs] def resolve_utility_schema(metadata: MetaData) -> str: """Return the codegen_database utility schema for *metadata*. Reads ``utility_schema`` off the :class:`CodegenDatabaseConfig` registered at ``metadata.info["codegen_database_config"]``, falling back to :data:`DEFAULT_UTILITY_SCHEMA` when no config is present. Any codegen_database-managed object that needs a shared home -- utility functions, the autogenerated-identifier pointer table -- routes through here so a single ``utility_schema`` setting governs them all. Args: metadata: SQLAlchemy ``MetaData`` to inspect. Returns: The schema name for codegen_database-managed utility objects. """ config = metadata.info.get("codegen_database_config") if config is None: return DEFAULT_UTILITY_SCHEMA return getattr(config, "utility_schema", DEFAULT_UTILITY_SCHEMA)