python-ddd-framework 0.7.2__py3-none-any.whl → 0.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -280,6 +280,7 @@ from .settings import (
280
280
  SettingDefinitionContext,
281
281
  SettingDefinitionError,
282
282
  SettingDefinitionProvider,
283
+ SettingManagementAccess,
283
284
  SettingManager,
284
285
  SettingProvider,
285
286
  )
@@ -528,6 +529,7 @@ __all__ = (
528
529
  "SettingDefinitionError",
529
530
  "SettingDefinitionProvider",
530
531
  "SettingHandlers",
532
+ "SettingManagementAccess",
531
533
  "SettingManager",
532
534
  "SettingProvider",
533
535
  "SettingsModule",
@@ -212,4 +212,6 @@ class ConfigurationRoot(Mapping[str, object]):
212
212
  provenance=resolved._provenance,
213
213
  secret_paths=secret_paths,
214
214
  sources=self._sources,
215
+ # Settings 等能力的晚期策略检查仍需看到被覆盖的输入;沿用冻结引用。
216
+ payloads=resolved._payloads,
215
217
  )
@@ -1,7 +1,7 @@
1
1
  """Global Runtime Settings 的 typed contract 与 Application-local catalog。"""
2
2
 
3
3
  from .catalog import SettingCatalog
4
- from .contracts import SettingDefinition
4
+ from .contracts import SettingDefinition, SettingManagementAccess
5
5
  from .definitions import SettingDefinitionContext, SettingDefinitionProvider
6
6
  from .errors import RuntimeSettingError, SettingDefinitionError
7
7
  from .handlers import SettingApplicationStatus, SettingHandler, SettingHandlerDefinition
@@ -21,6 +21,7 @@ __all__ = (
21
21
  "SettingDefinitionProvider",
22
22
  "SettingHandler",
23
23
  "SettingHandlerDefinition",
24
+ "SettingManagementAccess",
24
25
  "SettingManager",
25
26
  "SettingProvider",
26
27
  "SettingSnapshot",
@@ -5,15 +5,19 @@ from __future__ import annotations
5
5
  import json
6
6
  from typing import Any, cast
7
7
 
8
+ from dishka import AsyncContainer
8
9
  from pydantic import JsonValue
9
10
 
10
11
  from ..application_services import ApplicationService, application_service
11
- from ..authorization import authorize
12
+ from ..authorization import PermissionDeniedError, PermissionName, authorize
13
+ from ..authorization.checking import _check_authorization
14
+ from ..authorization.contracts import _AuthorizationRequirement
12
15
  from ..configuration.immutability import _serialization_value
13
16
  from ..errors import BusinessError, BusinessErrorDefinition, BusinessErrorField
14
17
  from ..errors.base import ResourceNotFoundError
18
+ from ..invocation.runtime import _InvocationRuntime
15
19
  from .catalog import SettingCatalog
16
- from .contracts import SettingDefinition
20
+ from .contracts import SettingDefinition, SettingManagementAccess
17
21
  from .management import (
18
22
  SETTINGS_READ,
19
23
  SETTINGS_WRITE,
@@ -32,27 +36,41 @@ _VALUE_FIELD = BusinessErrorField(UpdateSettingCommand, "value")
32
36
 
33
37
  @application_service(provides=SettingsManagementApplicationService)
34
38
  class _SettingsManagementApplicationService(ApplicationService):
35
- def __init__(self, catalog: SettingCatalog, settings: SettingManager) -> None:
39
+ def __init__(
40
+ self,
41
+ catalog: SettingCatalog,
42
+ settings: SettingManager,
43
+ container: AsyncContainer,
44
+ runtime: _InvocationRuntime,
45
+ ) -> None:
36
46
  self._catalog = catalog
37
47
  self._settings = settings
48
+ self._container = container
49
+ self._runtime = runtime
38
50
 
39
51
  @authorize(SETTINGS_READ)
40
52
  async def get_list(self) -> tuple[SettingView, ...]:
41
- return tuple(
42
- [
43
- _view(definition, await self.setting_provider.snapshot(definition))
44
- for definition in self._catalog.definitions
45
- ]
46
- )
53
+ result: list[SettingView] = []
54
+ for definition in self._catalog.definitions:
55
+ if definition.management_access is SettingManagementAccess.HIDDEN:
56
+ continue
57
+ try:
58
+ await self._check_permissions(definition.read_permission)
59
+ except PermissionDeniedError:
60
+ continue
61
+ result.append(_view(definition, await self.setting_provider.snapshot(definition)))
62
+ return tuple(result)
47
63
 
48
64
  @authorize(SETTINGS_READ)
49
65
  async def get(self, name: str) -> SettingView:
50
66
  definition = self._definition(name)
67
+ await self._check_permissions(definition.read_permission)
51
68
  return _view(definition, await self.setting_provider.snapshot(definition))
52
69
 
53
- @authorize(SETTINGS_WRITE)
70
+ @authorize(SETTINGS_READ, SETTINGS_WRITE)
54
71
  async def update(self, name: str, command: UpdateSettingCommand) -> SettingWriteResult:
55
72
  definition = self._definition(name)
73
+ await self._check_write(definition)
56
74
  try:
57
75
  # JSON 数组/日期须由 Pydantic 的 JSON 模式解释,不能误用 strict Python 输入语义。
58
76
  value = definition._validate_json(json.dumps(command.value, allow_nan=False))
@@ -65,9 +83,10 @@ class _SettingsManagementApplicationService(ApplicationService):
65
83
  setting=_view(definition, saved.snapshot), notification=saved.notification
66
84
  )
67
85
 
68
- @authorize(SETTINGS_WRITE)
86
+ @authorize(SETTINGS_READ, SETTINGS_WRITE)
69
87
  async def reset(self, name: str, command: ResetSettingCommand) -> SettingWriteResult:
70
88
  definition = self._definition(name)
89
+ await self._check_write(definition)
71
90
  saved = await self._settings.reset(definition, expected_version=command.expected_version)
72
91
  return SettingWriteResult(
73
92
  setting=_view(definition, saved.snapshot), notification=saved.notification
@@ -75,10 +94,28 @@ class _SettingsManagementApplicationService(ApplicationService):
75
94
 
76
95
  def _definition(self, name: str) -> SettingDefinition[Any]:
77
96
  definition = self._catalog.get(name)
78
- if definition is None:
97
+ if definition is None or definition.management_access is SettingManagementAccess.HIDDEN:
79
98
  raise ResourceNotFoundError("Setting not found")
80
99
  return definition
81
100
 
101
+ async def _check_write(self, definition: SettingDefinition[Any]) -> None:
102
+ if (
103
+ definition.management_access is not SettingManagementAccess.READ_WRITE
104
+ or SettingValueSource.RUNTIME not in definition.allowed_sources
105
+ ):
106
+ raise PermissionDeniedError(permission=str(SETTINGS_WRITE))
107
+ # 写入响应包含完整快照;读权限须在校验设置值及执行保存前成立。
108
+ await self._check_permissions(definition.read_permission, definition.write_permission)
109
+
110
+ async def _check_permissions(self, *permissions: PermissionName | None) -> None:
111
+ required = tuple(dict.fromkeys(item for item in permissions if item is not None))
112
+ if required:
113
+ await _check_authorization(
114
+ self._container,
115
+ self._runtime.current_user,
116
+ _AuthorizationRequirement(True, required, False),
117
+ )
118
+
82
119
 
83
120
  def _view(definition: SettingDefinition[Any], snapshot: SettingSnapshot[Any]) -> SettingView:
84
121
  # HTTP DTO 是独立 JSON 副本;不会把内部不可变快照的容器直接交给调用方。
@@ -6,9 +6,11 @@ from dishka import Provider, Scope
6
6
 
7
7
  from ..configuration import ConfigurationRoot
8
8
  from .catalog import SettingCatalog
9
+ from .errors import SettingDefinitionError
9
10
  from .manager import SettingManager
10
11
  from .provider import SettingProvider
11
12
  from .store import RuntimeSettingStore
13
+ from .values import SettingValueSource
12
14
 
13
15
 
14
16
  def _provide_settings(
@@ -18,6 +20,18 @@ def _provide_settings(
18
20
  *,
19
21
  has_store: bool,
20
22
  ) -> None:
23
+ # 检查冻结的输入层,不能让存储覆盖或后续配置遮住被禁止的配置贡献。
24
+ for definition in catalog.definitions:
25
+ path = f"settings.{definition.name}"
26
+ if (
27
+ SettingValueSource.CONFIGURATION not in definition.allowed_sources
28
+ and configuration._section_inputs(path)
29
+ ):
30
+ raise SettingDefinitionError(
31
+ setting=definition.name,
32
+ reason=f"configuration source is not allowed at {path}",
33
+ source=catalog.sources.get(definition.name),
34
+ )
21
35
  if has_store:
22
36
 
23
37
  def reader(store: RuntimeSettingStore) -> SettingProvider:
@@ -2,10 +2,12 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from enum import Enum
5
6
  from typing import Generic, TypeVar, cast, get_args, get_origin
6
7
 
7
8
  from pydantic import BaseModel, Secret, SecretBytes, SecretStr, TypeAdapter, ValidationError
8
9
 
10
+ from ..authorization import PermissionName
9
11
  from ..configuration.immutability import (
10
12
  _serialization_value,
11
13
  freeze_typed_value,
@@ -13,16 +15,65 @@ from ..configuration.immutability import (
13
15
  )
14
16
  from ..configuration.values import _looks_secret_name, canonical_path
15
17
  from .errors import RuntimeSettingError, SettingDefinitionError
18
+ from .values import SettingValueSource
16
19
 
17
20
  _T = TypeVar("_T")
18
21
  _MISSING = object()
22
+ _ALL_VALUE_SOURCES = frozenset(
23
+ source for source in SettingValueSource if source is not SettingValueSource.UNSET
24
+ )
25
+
26
+
27
+ class SettingManagementAccess(str, Enum):
28
+ """只限制通用管理入口;内部读写仍遵守设置自身的来源与值契约。"""
29
+
30
+ HIDDEN = "hidden"
31
+ READ_ONLY = "read_only"
32
+ READ_WRITE = "read_write"
19
33
 
20
34
 
21
35
  class SettingDefinition(Generic[_T]):
22
- __slots__ = ("_adapter", "_default", "_name", "_value_type")
36
+ __slots__ = (
37
+ "_adapter",
38
+ "_allowed_sources",
39
+ "_default",
40
+ "_management_access",
41
+ "_name",
42
+ "_read_permission",
43
+ "_value_type",
44
+ "_write_permission",
45
+ )
23
46
 
24
- def __init__(self, name: str, value_type: type[_T], *, default: object = _MISSING) -> None:
47
+ def __init__(
48
+ self,
49
+ name: str,
50
+ value_type: type[_T],
51
+ *,
52
+ default: object = _MISSING,
53
+ allowed_sources: frozenset[SettingValueSource] = _ALL_VALUE_SOURCES,
54
+ management_access: SettingManagementAccess = SettingManagementAccess.READ_WRITE,
55
+ read_permission: PermissionName | None = None,
56
+ write_permission: PermissionName | None = None,
57
+ ) -> None:
25
58
  _validate_setting_name(name)
59
+ if (
60
+ not isinstance(allowed_sources, frozenset)
61
+ or not allowed_sources
62
+ or any(
63
+ not isinstance(source, SettingValueSource) or source is SettingValueSource.UNSET
64
+ for source in allowed_sources
65
+ )
66
+ ):
67
+ raise SettingDefinitionError(
68
+ setting=name, reason="allowed_sources must contain value sources, not UNSET"
69
+ )
70
+ if not isinstance(management_access, SettingManagementAccess):
71
+ raise SettingDefinitionError(setting=name, reason="invalid management_access")
72
+ for permission in (read_permission, write_permission):
73
+ if permission is not None and not isinstance(permission, PermissionName):
74
+ raise SettingDefinitionError(
75
+ setting=name, reason="permissions must be PermissionName values"
76
+ )
26
77
  if not isinstance(value_type, type):
27
78
  raise SettingDefinitionError(setting=name, reason="value_type must be a runtime type")
28
79
  if _contains_secret_type(value_type):
@@ -46,6 +97,10 @@ class SettingDefinition(Generic[_T]):
46
97
  self._value_type = value_type
47
98
  self._adapter = adapter
48
99
  self._default = validated_default
100
+ self._allowed_sources = allowed_sources
101
+ self._management_access = management_access
102
+ self._read_permission = read_permission
103
+ self._write_permission = write_permission
49
104
 
50
105
  @property
51
106
  def name(self) -> str:
@@ -59,6 +114,22 @@ class SettingDefinition(Generic[_T]):
59
114
  def has_default(self) -> bool:
60
115
  return self._default is not _MISSING
61
116
 
117
+ @property
118
+ def allowed_sources(self) -> frozenset[SettingValueSource]:
119
+ return self._allowed_sources
120
+
121
+ @property
122
+ def management_access(self) -> SettingManagementAccess:
123
+ return self._management_access
124
+
125
+ @property
126
+ def read_permission(self) -> PermissionName | None:
127
+ return self._read_permission
128
+
129
+ @property
130
+ def write_permission(self) -> PermissionName | None:
131
+ return self._write_permission
132
+
62
133
  def _validate_python(self, value: object) -> _T:
63
134
  return cast(
64
135
  _T, freeze_typed_value(self._adapter.validate_python(value), allow_secrets=False)
@@ -49,7 +49,7 @@ class SettingManager:
49
49
  async def update(
50
50
  self, definition: SettingDefinition[_T], value: _T, *, expected_version: UUID | None
51
51
  ) -> SettingWriteOutcome[_T]:
52
- self._catalog.require_owned(definition)
52
+ self._require_write(definition, operation="set")
53
53
  try:
54
54
  validated, serialized = definition._dump_json(value)
55
55
  except (TypeError, ValidationError, PydanticSerializationError):
@@ -68,13 +68,20 @@ class SettingManager:
68
68
  async def reset(
69
69
  self, definition: SettingDefinition[_T], *, expected_version: UUID | None
70
70
  ) -> SettingWriteOutcome[_T]:
71
- self._catalog.require_owned(definition)
71
+ self._require_write(definition, operation="reset")
72
72
  # 默认值先校验,不能在物理删除已经提交之后再抛出配置校验失败。
73
73
  fallback = self._provider._resolve(definition, StoredSetting(None, expected_version))
74
74
  saved = await self._store.write(definition.name, None, expected_version=expected_version)
75
75
  snapshot = SettingSnapshot(definition.name, fallback.value, fallback.source, saved.version)
76
76
  return SettingWriteOutcome(snapshot, await self._committed(definition.name))
77
77
 
78
+ def _require_write(self, definition: SettingDefinition[Any], *, operation: str) -> None:
79
+ self._catalog.require_owned(definition)
80
+ if SettingValueSource.RUNTIME not in definition.allowed_sources:
81
+ raise RuntimeSettingError(
82
+ setting=definition.name, operation=operation, error_type="SourceNotAllowed"
83
+ )
84
+
78
85
  async def _committed(self, name: str) -> NotificationPublishStatus:
79
86
  # 本地刷新先入队;Redis 降级不会撤销短事务已经提交的结果。
80
87
  if self._refresh is not None:
@@ -2,6 +2,7 @@
2
2
 
3
3
  from dishka import DEFAULT_COMPONENT, DependencyKey, Provider, Scope
4
4
 
5
+ from ..authorization.module import AuthorizationModule
5
6
  from ..lifecycle import ConfigureContext
6
7
  from ..modularity import AppModule, ModuleRef
7
8
  from ..services.composition import (
@@ -12,6 +13,7 @@ from ..services.composition import (
12
13
  from ..services.registration import RegistrationDecision, RegistrationKind
13
14
  from .binding import _provide_settings
14
15
  from .catalog import SettingCatalog, _build_setting_catalog, _contribute_setting_handler_defaults
16
+ from .errors import SettingDefinitionError
15
17
  from .store import RuntimeSettingStore
16
18
 
17
19
 
@@ -57,3 +59,19 @@ class SettingsManagementModule(AppModule):
57
59
  "python_ddd_framework.settings.application",
58
60
  "python_ddd_framework.settings.permissions",
59
61
  )
62
+
63
+ def configure(self, context: ConfigureContext) -> None:
64
+ context.services.add_composition(ServiceComposition(bind=self._bind))
65
+
66
+ def _bind(self, context: ServiceBindingContext) -> None:
67
+ # 全局 discovery 屏障后核对实际权限目录;只读 Settings 无需装配授权服务。
68
+ catalog = context.modules.instance(SettingsModule).catalog
69
+ permissions = context.modules.instance(AuthorizationModule).catalog
70
+ for definition in catalog.definitions:
71
+ for permission in (definition.read_permission, definition.write_permission):
72
+ if permission is not None and permission not in permissions:
73
+ raise SettingDefinitionError(
74
+ setting=definition.name,
75
+ reason=f"permission {permission} is not defined",
76
+ source=catalog.sources.get(definition.name),
77
+ )
@@ -43,7 +43,7 @@ class SettingProvider:
43
43
  self._catalog.require_owned(definition)
44
44
  stored = (
45
45
  await self._store.read(definition.name)
46
- if self._store is not None
46
+ if self._store is not None and SettingValueSource.RUNTIME in definition.allowed_sources
47
47
  else StoredSetting(None, None)
48
48
  )
49
49
  return self._resolve(definition, stored)
@@ -56,11 +56,18 @@ class SettingProvider:
56
56
  value = definition._validate_json(stored.value_json)
57
57
  source = SettingValueSource.RUNTIME
58
58
  else:
59
- configured = self._configuration.get_path(f"settings.{definition.name}", _MISSING)
59
+ configured = (
60
+ self._configuration.get_path(f"settings.{definition.name}", _MISSING)
61
+ if SettingValueSource.CONFIGURATION in definition.allowed_sources
62
+ else _MISSING
63
+ )
60
64
  if configured is not _MISSING:
61
65
  value = definition._validate_python(configured)
62
66
  source = SettingValueSource.CONFIGURATION
63
- elif definition.has_default:
67
+ elif (
68
+ definition.has_default
69
+ and SettingValueSource.DEFINITION in definition.allowed_sources
70
+ ):
64
71
  value = definition._default_value()
65
72
  source = SettingValueSource.DEFINITION
66
73
  else:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-ddd-framework
3
- Version: 0.7.2
3
+ Version: 0.8.0
4
4
  Summary: Modular DDD application framework with project CLI and bundled templates
5
5
  License-Expression: LicenseRef-Proprietary
6
6
  License-File: LICENSE
@@ -169,6 +169,8 @@ Open **http://127.0.0.1:8000/docs**. Use the generated `identity.seed_admin_user
169
169
 
170
170
  The empty `orders` skeleton contributes no business routes. The independent [order-management example](examples/order_management/README.md) supplies `/api/orders`, approval and queued approval, file transfer, and an authenticated WebSocket at `/ws/orders`; use its initializer when you want to explore those capabilities.
171
171
 
172
+ For C++ computation, the independent [native integration example](examples/native_integration/README.md) demonstrates an installed nanobind package, typed application-service consumption, cancellation cleanup, source rebuilds, and artifact delivery. It is outside the runtime wheel and does not change the CLI or default templates. Verified platforms and remaining limits are recorded in [status](docs/status.md#c-原生接入样例).
173
+
172
174
  The default business API prefix is `/api`. Liveness and readiness are exposed at `/health/live` and `/health/ready`; readiness describes application lifecycle state, not continuous database or Redis health.
173
175
 
174
176
  ## CLI reference
@@ -312,12 +314,26 @@ New `ddd` modules contain the full responsibility directories and necessary comp
312
314
 
313
315
  See the [migration guide](docs/development.md#数据库聚合与迁移) and [verification record](docs/status.md#http-回收与迁移来源判定未发布).
314
316
 
317
+ ## Settings policies (0.8.0)
318
+
319
+ `SettingDefinition` now accepts `allowed_sources`, `management_access`, `read_permission`, and `write_permission`. Existing definitions retain their source order and management visibility. Generic update/reset now also require `settings.read`, in addition to `settings.write` and any declared per-setting permissions, because their responses contain the saved setting snapshot. Update roles that previously held only write permission.
320
+
321
+ Before excluding `CONFIGURATION` for a setting, remove its entries from YAML, environment variables, dotenv, CLI, explicit configuration and module configuration defaults: composition rejects forbidden inputs even when another value masks them. `HIDDEN` and `READ_ONLY` restrict generic management; internal readers and dedicated application services can still use the existing Provider/Manager subject to source, type and version rules. Defining a per-setting permission does not grant it to existing users or roles; update grants through the application's authorization system. No database migration or dependency change is required for this extension.
322
+
323
+ Version 0.8.0 includes these policies. Follow [Settings setup and usage](docs/development.md#settings-策略与使用) for definition discovery, permission declarations, internal Provider/Manager calls, and HTTP update/reset with version tokens. The [contract](docs/architecture.md#typed-cache-与-settings) owns the rules; [validation evidence](docs/status.md#settings-最小策略扩展) separates implementation results from the later read-only review.
324
+
315
325
  ## Invocation performance (0.7.2)
316
326
 
317
327
  Function calls avoid regenerating DI wrappers, empty extension chains skip unnecessary work, and completed filter/interceptor chains release execution references sooner. Managed declaration checks continue to detect dynamic method and policy changes.
318
328
 
319
329
  Public APIs, DI scopes, authorization, validation, Unit of Work, exception and cancellation behavior are unchanged. No application-code, configuration or data migration is required. Follow the existing [upgrade procedure](#upgrading); validation evidence and performance limits are recorded in [release status](docs/status.md#当前发布).
320
330
 
331
+ ## Native C++ integration example (0.7.3)
332
+
333
+ The repository's [native integration example](examples/native_integration/README.md) demonstrates a separately installed nanobind package, Eigen computation, typed service/HTTP consumption, cancellation cleanup, and wheel/sdist and Docker delivery. Its development entry rebuilds declared native path dependencies before starting the existing Host. The example and its native binaries are maintained outside the framework runtime wheel.
334
+
335
+ Existing applications need no code, configuration, dependency or data migration. Adopt the example from the source checkout when adding native computation; the CLI, default templates and framework lifecycle contracts are unchanged. Platform evidence and remaining limits are recorded in [release status](docs/status.md#当前发布).
336
+
321
337
  <a id="streaming-and-access-migration-07-unreleased"></a>
322
338
 
323
339
  ## Streaming and access migration (0.7)
@@ -1,4 +1,4 @@
1
- python_ddd_framework/__init__.py,sha256=UUsi5Ye8kGFX3zp7nC7QW87VEhfSCWy3_u_dcZ5qUgI,15416
1
+ python_ddd_framework/__init__.py,sha256=P4vRQIXbhDQk8zp_5_ToXK2lRJdPLUvAZ8iC-t6bg7U,15476
2
2
  python_ddd_framework/application/__init__.py,sha256=RPe_lkegIRim7GcBnXyevOg5KM7bfUIO9YGsqcA0lXk,184
3
3
  python_ddd_framework/application/build_spec.py,sha256=Udj1JIgP2oBMCUezmzWzOdjFYBCEE8OxwHSEaDqrMMo,1030
4
4
  python_ddd_framework/application/builder.py,sha256=d0vc1D5HvG_aJI5lPQydr-ha0OTNviWlplxlyP99qDs,8080
@@ -89,7 +89,7 @@ python_ddd_framework/configuration/environment_source.py,sha256=5DFYpLyOXpCkYT4W
89
89
  python_ddd_framework/configuration/immutability.py,sha256=TRB2caTQtoDUA1bcQt9bPWBl-7u45f5vO30sRJQnKkc,5672
90
90
  python_ddd_framework/configuration/input_shape.py,sha256=T97z95F2PQkvNN0PV5Iz1s19UvX1CZGvyV7Ojo7cRLY,2438
91
91
  python_ddd_framework/configuration/merge.py,sha256=VE6vtvcyQu8rQaqGAQs23JQmhJFneq6cWd1SZCow1Bk,3702
92
- python_ddd_framework/configuration/root.py,sha256=aF2ideF_Hz6N3cY_W1kvZDQRe1JGv8SeIC3-bxpYMrQ,7919
92
+ python_ddd_framework/configuration/root.py,sha256=-xmDLRHJWOpLUVKa7i-QABsrp5kCrTtefunvdhGkgvc,8068
93
93
  python_ddd_framework/configuration/sources.py,sha256=Xd7Sxk0umHS7h5SRq08NSWGhLmJ3lHVP6tyzmh1F7AA,19233
94
94
  python_ddd_framework/configuration/values.py,sha256=4S8Ae2CRRekA9ge0ZxoMJcdJn3XqnF06E6DOaAZZuHc,14591
95
95
  python_ddd_framework/configuration/yaml_source.py,sha256=hZhKftmip6rRQUwqQBfTi_d-UYthUqWPbL5dQUvb89Q,2016
@@ -390,23 +390,23 @@ python_ddd_framework/services/registration.py,sha256=AsvhVv_szq8TcaXdUMvOY6fNNp8
390
390
  python_ddd_framework/services/relocation.py,sha256=oMel_8RPFtPHDE9KrUepzx1nJpiug0EaNK7RWEKZFC0,3763
391
391
  python_ddd_framework/services/repository.py,sha256=jjjCmpcz4deAZmDNSM44WlDmh9msFO53qN116CHdBSM,1686
392
392
  python_ddd_framework/services/runtime.py,sha256=57G5jNjOiexpSqTCogdI18u5xeEK2YglztNqDtFcsZI,9300
393
- python_ddd_framework/settings/__init__.py,sha256=5Ikxnl_nT9l_WDuqW916hsvVlO9t_vCjR9OIvvJR8lI,1034
394
- python_ddd_framework/settings/application.py,sha256=9J7Q74Vr6QXJ2ddWU7-MFpwdjUXW-ZGI1Py_R93mAsM,3775
395
- python_ddd_framework/settings/binding.py,sha256=1a-AzTLwCTU6zQ85rYBJrQE63_b7BwFf9UWbMhOfJrQ,962
393
+ python_ddd_framework/settings/__init__.py,sha256=j9byBRTyegmIEK1KD6Q3UkHurPCnMUYJdnlhXTWL_wo,1090
394
+ python_ddd_framework/settings/application.py,sha256=3hAlheeHcwSIS_1bFQmv7qjsAMIk7JYq9LnQLITfOWk,5666
395
+ python_ddd_framework/settings/binding.py,sha256=_wDIsKe-p6WuKaQB9NvhbxCm9aYbiN95m7erJS35T8Y,1621
396
396
  python_ddd_framework/settings/catalog.py,sha256=fqVeFr3DuJWrNUfIuIwfivVhuCobQpWe32EmRieuUVE,4880
397
397
  python_ddd_framework/settings/changes.py,sha256=zpHhCJY83s-KIs7NkjQAmIxzY7cJfT8FD4A08gF9NfE,367
398
- python_ddd_framework/settings/contracts.py,sha256=E70lLiFC5G7XoEpmf3rsoW5BnPhzajm-eri0vzn0xuY,4428
398
+ python_ddd_framework/settings/contracts.py,sha256=v_Wn7kr3_JQYH-rXeusR_YWvtwR3RT_KxQqnvVD7uZI,6899
399
399
  python_ddd_framework/settings/declarations.py,sha256=FeFrgw6fAdjX6bGaajjnO2tsrfxEvKW6sZrRfTAxCEs,526
400
400
  python_ddd_framework/settings/definition_discovery.py,sha256=zHN3-coqzdEb--mecv00v7ifWzzCfJRZ-BrFcdVx4u4,3002
401
401
  python_ddd_framework/settings/definitions.py,sha256=hkWO0dqOoBmd7pKv-cUsCZaEU0AeUEULVLW1Rl8uwdQ,1687
402
402
  python_ddd_framework/settings/errors.py,sha256=ZcU1nMB44_Rq9Wl5bw83s3Y066LxSLrFqOW_gG6ViS4,836
403
403
  python_ddd_framework/settings/handlers.py,sha256=A0GWDKRXASlCoWm_Wduul0thAv4xW4SG305KXd6wY-4,1369
404
404
  python_ddd_framework/settings/management.py,sha256=dJhyZYfNA5Qsup9yt2dKOrIwGq3OnNkDxskJniBV3BI,1656
405
- python_ddd_framework/settings/manager.py,sha256=wjqhRCmtF_B-ETRZOTl3izRTzVJb7ebk3qLOMqFDdRE,4181
406
- python_ddd_framework/settings/module.py,sha256=8c9c4pIpzn3XB8xkJqW4AhKkuUS-HYxwfS4px7VeP1Q,2314
405
+ python_ddd_framework/settings/manager.py,sha256=5pWLFB7EHMUsqnz-Gy615A2Sxv0HsKIEQtgmm0zl70A,4561
406
+ python_ddd_framework/settings/module.py,sha256=KQydGp507MUlcykRWVUa36r5-_--BRJn88QLirxotAI,3340
407
407
  python_ddd_framework/settings/notifications.py,sha256=tVSXjhhJWhkMcOakSmeOfXT1X02Hcx2xRU8Whr8rSig,1700
408
408
  python_ddd_framework/settings/permissions.py,sha256=2nPyZOZ9G-4mSCIqwNI0C9WUBhP0ZwqNjljP3XZD3PE,553
409
- python_ddd_framework/settings/provider.py,sha256=plT4x6UjBGn9B6-OmZYKswdto3NrE6Ib1lsyc1VUKoA,2871
409
+ python_ddd_framework/settings/provider.py,sha256=AvMrdWML_wbbJEqNb9IH8_OcUUX8QbdEpxw4GDibdA4,3216
410
410
  python_ddd_framework/settings/refresh.py,sha256=jYYqEdTU4cOXyHmdMEdw_94qybp4bzVPRdrM6WF8q6k,5413
411
411
  python_ddd_framework/settings/refresh_module.py,sha256=wDxWau4oZCtBiMO6TDXZFbZRcKTiYaTFGWPjZnaFNug,2225
412
412
  python_ddd_framework/settings/sqlalchemy/__init__.py,sha256=G-S-sSsxwfjZxr0mVAyXUBG0SIxC3ZCMtrdpMsZ14YM,158
@@ -452,9 +452,9 @@ python_ddd_framework/unit_of_work/module.py,sha256=EjsUtCG7w56NmLU_xqBRiwJ65Mw5h
452
452
  python_ddd_framework/unit_of_work/options.py,sha256=AVcEmwwn39qvj8PLQetBeGzdU_eblABGuNLDIQU5tyI,3365
453
453
  python_ddd_framework/validation/__init__.py,sha256=nTN_BgIXMLHeUtMgSj2hpisWc1_sk6UWTapk30oh1us,100
454
454
  python_ddd_framework/validation/models.py,sha256=Ydz5ZYgqYMPZEXi9A3DA6beN5lD9AcMaImnxDf1aRXs,1737
455
- python_ddd_framework-0.7.2.dist-info/licenses/LICENSE,sha256=2sSWLZdtk4EhG2GlwpksXzmyux-G6Qiov0D27lE_bqw,805
456
- python_ddd_framework-0.7.2.dist-info/licenses/src/python_ddd_framework/background_jobs/pgqueuer/UPSTREAM_LICENSE.txt,sha256=0lCGUd5Pke2Up1Kqn1kRnHcwLlBz60E8xvR7WL4k_kE,1066
457
- python_ddd_framework-0.7.2.dist-info/WHEEL,sha256=1dD_GoEqEIxQ7VnrUExgdj_eExY4b4UgfR0iBlGKVac,80
458
- python_ddd_framework-0.7.2.dist-info/entry_points.txt,sha256=CMy4XBD8IKGUfHwe0YBmHmSJtjfnA3yyDHqsMZCLsc8,447
459
- python_ddd_framework-0.7.2.dist-info/METADATA,sha256=HZlFBzL92XgY7oq4rysrnDh7zhe0CWxRTVnz1gUwa6U,66019
460
- python_ddd_framework-0.7.2.dist-info/RECORD,,
455
+ python_ddd_framework-0.8.0.dist-info/licenses/LICENSE,sha256=2sSWLZdtk4EhG2GlwpksXzmyux-G6Qiov0D27lE_bqw,805
456
+ python_ddd_framework-0.8.0.dist-info/licenses/src/python_ddd_framework/background_jobs/pgqueuer/UPSTREAM_LICENSE.txt,sha256=0lCGUd5Pke2Up1Kqn1kRnHcwLlBz60E8xvR7WL4k_kE,1066
457
+ python_ddd_framework-0.8.0.dist-info/WHEEL,sha256=si2p8vW03RnhyBnhWl4tj-ObJa78SpE-c9HsEtblGR0,80
458
+ python_ddd_framework-0.8.0.dist-info/entry_points.txt,sha256=CMy4XBD8IKGUfHwe0YBmHmSJtjfnA3yyDHqsMZCLsc8,447
459
+ python_ddd_framework-0.8.0.dist-info/METADATA,sha256=IbP9K_ypVhMhck9GNfdMSwDRTeyqV_Muvph0XxBUDDY,68850
460
+ python_ddd_framework-0.8.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.13.4
2
+ Generator: uv 0.13.5
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any