- infrasynth.configs: typed multi-tenant config store (registry, service, secrets, cache) + public config_changed/config_reset signals and API - emit the declared-but-dead signals (features flags/overrides, scheduler task_completed/task_failed, tenancy tenant_updated, audit model_changed) and per-model audit field exclusions - security: permission catalog (security_permission), Django-style model-derived AutoPermission, PermissionRegistry, RoleAssignment, global-or-tenant Grant/Revoke, catalog API - consolidate the permission surface: PermissionRegistry only (drop the settings dict), IsAuthenticatedAndPermitted aliases HybridPermission, require_permission replaced by required_permissions + require_all - packaging: add [build-system]; add Forgejo publish workflow (.forgejo)
49 lines
1.4 KiB
Python
49 lines
1.4 KiB
Python
"""Public surface of ``infrasynth.configs``.
|
|
|
|
The exports are resolved lazily (PEP 562) so importing this package never
|
|
triggers Django model imports before the app registry is ready. Import from
|
|
here::
|
|
|
|
from infrasynth.configs import ConfigService, ConfigRegistry, config_changed
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from importlib import import_module
|
|
from typing import Any
|
|
|
|
__all__ = [
|
|
"ConfigDefinition",
|
|
"ConfigRegistry",
|
|
"ConfigService",
|
|
"ConfigType",
|
|
"ConfigValue",
|
|
"config_changed",
|
|
"config_reset",
|
|
]
|
|
|
|
# public name -> module (relative to the ``infrasynth`` package) that defines it
|
|
_EXPORTS: dict[str, str] = {
|
|
"ConfigDefinition": "configs.registry",
|
|
"ConfigRegistry": "configs.registry",
|
|
"ConfigService": "configs.services",
|
|
"ConfigType": "configs.registry",
|
|
"ConfigValue": "configs.models",
|
|
"config_changed": "configs.signals",
|
|
"config_reset": "configs.signals",
|
|
}
|
|
|
|
|
|
def __getattr__(name: str) -> Any:
|
|
module_path = _EXPORTS.get(name)
|
|
if module_path is not None:
|
|
return getattr(import_module(f"infrasynth.{module_path}"), name)
|
|
# Let ``infrasynth.<app>.<submodule>`` resolve as usual.
|
|
try:
|
|
return import_module(f"{__name__}.{name}")
|
|
except ModuleNotFoundError as exc:
|
|
raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from exc
|
|
|
|
|
|
def __dir__() -> list[str]:
|
|
return sorted(set(__all__) | set(globals()))
|