Coverage for src / lexigram / contracts / exceptions / provider.py: 0%
59 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
1"""Provider and module exception classes."""
3from __future__ import annotations
5from typing import Any
7from lexigram.contracts.exceptions.base import LexigramError
10class ProviderError(LexigramError):
11 """Provider configuration or lifecycle error."""
13 _code = "LEX_ERR_PROV_001"
15 def __init__(self, message: str = "Provider error", **kwargs: Any) -> None:
16 super().__init__(message=message, **kwargs)
19class ModuleError(LexigramError):
20 """Module configuration or lifecycle error."""
22 _code = "LEX_ERR_MOD_001"
24 def __init__(self, message: str = "Module error", **kwargs: Any) -> None:
25 super().__init__(message=message, **kwargs)
28class ModuleImportError(ModuleError):
29 """A module imports a module that does not exist in the graph.
31 Raised during module compilation when a module's ``imports``
32 references a module class that is not registered in the
33 application's module graph.
34 """
36 _code = "LEX_ERR_MOD_002"
38 def __init__(
39 self,
40 message: str = "Module import not found",
41 *,
42 module_name: str | None = None,
43 missing_import: str | None = None,
44 available_modules: list[str] | None = None,
45 **kwargs: Any,
46 ) -> None:
47 details = kwargs.pop("details", {})
48 if module_name:
49 details["module"] = module_name
50 if missing_import:
51 details["missing_import"] = missing_import
52 if available_modules:
53 details["available_modules"] = available_modules
54 super().__init__(
55 message=message,
56 details=details,
57 **kwargs,
58 )
61class ModuleExportError(ModuleError):
62 """A module exports a type not provided by its providers.
64 Raised during post-registration validation when a module
65 declares an export that no provider in that module actually
66 registered in the container.
67 """
69 _code = "LEX_ERR_MOD_003"
71 def __init__(
72 self,
73 message: str = "Module export not registered",
74 *,
75 module_name: str | None = None,
76 missing_export: str | None = None,
77 registered_types: list[str] | None = None,
78 **kwargs: Any,
79 ) -> None:
80 details = kwargs.pop("details", {})
81 if module_name:
82 details["module"] = module_name
83 if missing_export:
84 details["missing_export"] = missing_export
85 if registered_types:
86 details["registered_types"] = registered_types
87 super().__init__(
88 message=message,
89 details=details,
90 **kwargs,
91 )
94class ModuleCycleError(ModuleError):
95 """Circular dependency detected in the module import graph.
97 Raised during module compilation when a cycle is detected in
98 the module import graph, e.g. ``A → B → C → A``.
99 """
101 _code = "LEX_ERR_MOD_004"
103 def __init__(
104 self,
105 message: str = "Circular module dependency detected",
106 *,
107 cycle: list[str] | None = None,
108 **kwargs: Any,
109 ) -> None:
110 details = kwargs.pop("details", {})
111 if cycle:
112 details["cycle"] = cycle
113 super().__init__(
114 message=message,
115 details=details,
116 **kwargs,
117 )
120class ModuleVisibilityError(ModuleError):
121 """A provider depends on a service not visible to its module.
123 Raised when a provider in module A tries to inject a type that
124 is registered by module B but not exported by B, even though
125 A imports B.
126 """
128 _code = "LEX_ERR_MOD_005"
130 def __init__(
131 self,
132 message: str = "Service not visible to module",
133 *,
134 consumer_module: str | None = None,
135 provider_module: str | None = None,
136 service_type: str | None = None,
137 **kwargs: Any,
138 ) -> None:
139 details = kwargs.pop("details", {})
140 if consumer_module:
141 details["consumer_module"] = consumer_module
142 if provider_module:
143 details["provider_module"] = provider_module
144 if service_type:
145 details["service_type"] = service_type
146 super().__init__(
147 message=message,
148 details=details,
149 **kwargs,
150 )
153class ModuleDuplicateError(ModuleError):
154 """The same module appears twice with conflicting configurations.
156 Raised when two :class:`DynamicModule` entries reference the same
157 module class but with different provider lists, exports, or
158 other configuration.
159 """
161 _code = "LEX_ERR_MOD_006"
163 def __init__(
164 self,
165 message: str = "Duplicate module with conflicting configuration",
166 *,
167 module_name: str | None = None,
168 **kwargs: Any,
169 ) -> None:
170 details = kwargs.pop("details", {})
171 if module_name:
172 details["module"] = module_name
173 super().__init__(
174 message=message,
175 details=details,
176 **kwargs,
177 )
180__all__ = [
181 "ModuleCycleError",
182 "ModuleDuplicateError",
183 "ModuleError",
184 "ModuleExportError",
185 "ModuleImportError",
186 "ModuleVisibilityError",
187 "ProviderError",
188]