orionis 0.450.0__py3-none-any.whl → 0.452.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.
Files changed (43) hide show
  1. orionis/console/base/contracts/command.py +0 -2
  2. orionis/console/core/__init__.py +0 -0
  3. orionis/console/core/reactor.py +19 -4
  4. orionis/container/container.py +1581 -69
  5. orionis/container/contracts/container.py +184 -33
  6. orionis/foundation/config/database/entities/mysql.py +0 -1
  7. orionis/metadata/framework.py +1 -1
  8. orionis/services/inspirational/contracts/__init__.py +0 -0
  9. orionis/services/introspection/abstract/contracts/reflection.py +5 -6
  10. orionis/services/introspection/abstract/reflection.py +5 -6
  11. orionis/services/introspection/callables/contracts/reflection.py +3 -2
  12. orionis/services/introspection/callables/reflection.py +4 -4
  13. orionis/services/introspection/concretes/contracts/reflection.py +5 -6
  14. orionis/services/introspection/concretes/reflection.py +5 -6
  15. orionis/services/introspection/dependencies/contracts/reflection.py +87 -23
  16. orionis/services/introspection/dependencies/entities/argument.py +95 -0
  17. orionis/services/introspection/dependencies/entities/resolve_argument.py +82 -0
  18. orionis/services/introspection/dependencies/reflection.py +176 -106
  19. orionis/services/introspection/instances/contracts/reflection.py +5 -6
  20. orionis/services/introspection/instances/reflection.py +5 -6
  21. orionis/test/core/unit_test.py +150 -48
  22. {orionis-0.450.0.dist-info → orionis-0.452.0.dist-info}/METADATA +1 -1
  23. {orionis-0.450.0.dist-info → orionis-0.452.0.dist-info}/RECORD +35 -38
  24. tests/container/mocks/mock_auto_resolution.py +192 -0
  25. tests/services/introspection/dependencies/test_reflect_dependencies.py +135 -58
  26. tests/services/introspection/reflection/test_reflection_abstract.py +5 -4
  27. tests/services/introspection/reflection/test_reflection_callable.py +3 -3
  28. tests/services/introspection/reflection/test_reflection_concrete.py +4 -4
  29. tests/services/introspection/reflection/test_reflection_instance.py +5 -5
  30. orionis/console/args/parser.py +0 -40
  31. orionis/container/contracts/resolver.py +0 -115
  32. orionis/container/resolver/resolver.py +0 -602
  33. orionis/services/introspection/dependencies/entities/callable_dependencies.py +0 -54
  34. orionis/services/introspection/dependencies/entities/class_dependencies.py +0 -61
  35. orionis/services/introspection/dependencies/entities/known_dependencies.py +0 -67
  36. orionis/services/introspection/dependencies/entities/method_dependencies.py +0 -61
  37. tests/container/resolver/test_resolver.py +0 -62
  38. /orionis/{container/resolver → console/commands}/__init__.py +0 -0
  39. {tests/container/resolver → orionis/console/contracts}/__init__.py +0 -0
  40. {orionis-0.450.0.dist-info → orionis-0.452.0.dist-info}/WHEEL +0 -0
  41. {orionis-0.450.0.dist-info → orionis-0.452.0.dist-info}/licenses/LICENCE +0 -0
  42. {orionis-0.450.0.dist-info → orionis-0.452.0.dist-info}/top_level.txt +0 -0
  43. {orionis-0.450.0.dist-info → orionis-0.452.0.dist-info}/zip-safe +0 -0
@@ -1,602 +0,0 @@
1
- from typing import Any, Callable
2
- from orionis.container.context.scope import ScopedContext
3
- from orionis.container.contracts.container import IContainer
4
- from orionis.container.contracts.resolver import IResolver
5
- from orionis.container.entities.binding import Binding
6
- from orionis.container.enums.lifetimes import Lifetime
7
- from orionis.container.exceptions import OrionisContainerException
8
- from orionis.services.introspection.callables.reflection import ReflectionCallable
9
- from orionis.services.introspection.concretes.reflection import ReflectionConcrete
10
- from orionis.services.introspection.dependencies.entities.known_dependencies import KnownDependency
11
- from orionis.services.introspection.dependencies.entities.method_dependencies import MethodDependency
12
-
13
- class Resolver(IResolver):
14
-
15
- def __init__(
16
- self,
17
- container: IContainer
18
- ):
19
- """
20
- Parameters
21
- ----------
22
- container : IContainer
23
- The container instance used by the resolver to resolve dependencies.
24
-
25
- Notes
26
- -----
27
- Initializes the Resolver with a reference to the dependency injection container.
28
- This allows the resolver to access registered bindings and resolve dependencies
29
- as required throughout the container's lifecycle.
30
- """
31
- self.container = container
32
-
33
- def resolve(
34
- self,
35
- binding: Binding,
36
- *args,
37
- **kwargs
38
- ):
39
- """
40
- Resolves an instance from a binding according to its lifetime.
41
-
42
- Parameters
43
- ----------
44
- binding : Binding
45
- The binding to resolve.
46
- *args : tuple
47
- Additional positional arguments to pass to the constructor.
48
- **kwargs : dict
49
- Additional keyword arguments to pass to the constructor.
50
-
51
- Returns
52
- -------
53
- Any
54
- The resolved instance.
55
-
56
- Raises
57
- ------
58
- OrionisContainerException
59
- If the binding is not an instance of Binding or if the lifetime is not supported.
60
- """
61
-
62
- # Ensure the binding is an instance of Binding
63
- if not isinstance(binding, Binding):
64
- raise OrionisContainerException(
65
- "The binding must be an instance of Binding."
66
- )
67
-
68
- # Handle based on binding type and lifetime
69
- if binding.lifetime == Lifetime.TRANSIENT:
70
- return self.__resolveTransient(binding, *args, **kwargs)
71
- elif binding.lifetime == Lifetime.SINGLETON:
72
- return self.__resolveSingleton(binding, *args, **kwargs)
73
- elif binding.lifetime == Lifetime.SCOPED:
74
- return self.__resolveScoped(binding, *args, **kwargs)
75
-
76
- def resolveType(
77
- self,
78
- type_: Callable[..., Any],
79
- *args,
80
- **kwargs
81
- ) -> Any:
82
- """
83
- Forces resolution of a type whether it's registered in the container or not.
84
-
85
- Parameters
86
- ----------
87
- type_ : Callable[..., Any]
88
- The type or callable to resolve.
89
- *args : tuple
90
- Positional arguments to pass to the constructor/callable.
91
- **kwargs : dict
92
- Keyword arguments to pass to the constructor/callable.
93
-
94
- Returns
95
- -------
96
- Any
97
- The resolved instance.
98
-
99
- Raises
100
- ------
101
- OrionisContainerException
102
- If the type cannot be resolved.
103
- """
104
-
105
- # Try to resolve the type with the provided arguments
106
- # If the type is already bound in the container, resolve it directly
107
- # or if args or kwargs are provided, instantiate it directly
108
- # If the type is a concrete class, instantiate it with resolved dependencies
109
- try:
110
-
111
- # Check if the type is already bound in the container
112
- if self.container.bound(type_):
113
- binding = self.container.getBinding(type_)
114
- return self.resolve(binding, *args, **kwargs)
115
-
116
- # If args or kwargs are provided, use them directly
117
- if args or kwargs:
118
-
119
- # For classes
120
- if isinstance(type_, type):
121
- return type_(*args, **kwargs)
122
-
123
- # For callables
124
- elif callable(type_):
125
- return type_(*args, **kwargs)
126
-
127
- # Otherwise use reflection to resolve dependencies
128
- # If the type is a concrete class, instantiate it with resolved dependencies
129
- elif ReflectionConcrete.isConcreteClass(type_):
130
- return type_(**self.__resolveDependencies(type_, is_class=True))
131
-
132
- # Try to call directly if it's a callable
133
- elif callable(type_) and not isinstance(type_, type):
134
- return type_(**self.__resolveDependencies(type_, is_class=False))
135
-
136
- # If the type is neither a concrete class nor a callable, raise an exception
137
- raise OrionisContainerException(
138
- f"Cannot force resolve: {getattr(type_, '__name__', str(type_))} is neither a concrete class nor a callable."
139
- )
140
-
141
- except Exception as e:
142
-
143
- # Get the type name safely to avoid AttributeError
144
- type_name = getattr(type_, '__name__', str(type_))
145
- module_name = getattr(type_, '__module__', "unknown module")
146
-
147
- # Provide more detailed error message
148
- error_msg = f"Error while force-resolving '{type_name}' from '{module_name}':\n{str(e)}"
149
-
150
- # If it's already an OrionisContainerException, just re-raise it with the context
151
- if isinstance(e, OrionisContainerException):
152
- raise e from None
153
-
154
- # Raise a new OrionisContainerException with the original exception as context
155
- else:
156
- raise OrionisContainerException(error_msg) from e
157
-
158
- def resolveSignature(
159
- self,
160
- signature: MethodDependency
161
- ) -> dict:
162
- """
163
- Resolves dependencies defined in a method signature.
164
-
165
- Parameters
166
- ----------
167
- signature : MethodDependency
168
- The method dependency information to resolve.
169
-
170
- Returns
171
- -------
172
- dict
173
- A dictionary of resolved parameter values.
174
-
175
- Raises
176
- ------
177
- OrionisContainerException
178
- If any dependencies cannot be resolved.
179
- """
180
- # If no dependencies to resolve, return empty dict
181
- if not signature.resolved and not signature.unresolved:
182
- return {}
183
-
184
- # If there are unresolved dependencies, raise an error
185
- if signature.unresolved:
186
- raise OrionisContainerException(
187
- f"Cannot resolve method dependencies because the following parameters are unresolved: {', '.join(signature.unresolved)}."
188
- )
189
-
190
- # Create a dict of resolved dependencies
191
- params = {}
192
- for param_name, dep in signature.resolved.items():
193
- if isinstance(dep, KnownDependency):
194
- # Try to resolve the dependency using the container
195
- if self.container.bound(dep.type):
196
- params[param_name] = self.resolve(
197
- self.container.getBinding(dep.type)
198
- )
199
- elif self.container.bound(dep.full_class_path):
200
- params[param_name] = self.resolve(
201
- self.container.getBinding(dep.full_class_path)
202
- )
203
- # Try to resolve directly if it's a concrete type
204
- elif ReflectionConcrete.isConcreteClass(dep.type):
205
- params[param_name] = self.resolveType(dep.type)
206
- else:
207
- raise OrionisContainerException(
208
- f"Cannot resolve dependency '{param_name}' of type '{dep.type.__name__}'."
209
- )
210
- else:
211
- # Use default value
212
- params[param_name] = dep
213
-
214
- return params
215
-
216
- def __resolveTransient(self, binding: Binding, *args, **kwargs) -> Any:
217
- """
218
- Resolves a service with transient lifetime.
219
-
220
- Parameters
221
- ----------
222
- binding : Binding
223
- The binding to resolve.
224
- *args : tuple
225
- Positional arguments to pass to the constructor.
226
- **kwargs : dict
227
- Keyword arguments to pass to the constructor.
228
-
229
- Returns
230
- -------
231
- Any
232
- A new instance of the requested service.
233
- """
234
-
235
- # Check if the binding has a concrete class or function defined
236
- if binding.concrete:
237
- if args or kwargs:
238
- return self.__instantiateConcreteWithArgs(binding.concrete, *args, **kwargs)
239
- else:
240
- return self.__instantiateConcreteReflective(binding.concrete)
241
-
242
- # If the binding has a function defined
243
- elif binding.function:
244
- if args or kwargs:
245
- return self.__instantiateCallableWithArgs(binding.function, *args, **kwargs)
246
- else:
247
- return self.__instantiateCallableReflective(binding.function)
248
-
249
- # If neither concrete class nor function is defined
250
- else:
251
- raise OrionisContainerException(
252
- "Cannot resolve transient binding: neither a concrete class nor a function is defined."
253
- )
254
-
255
- def __resolveSingleton(self, binding: Binding, *args, **kwargs) -> Any:
256
- """
257
- Resolves a service with singleton lifetime.
258
-
259
- Parameters
260
- ----------
261
- binding : Binding
262
- The binding to resolve.
263
- *args : tuple
264
- Positional arguments to pass to the constructor (only used if instance doesn't exist yet).
265
- **kwargs : dict
266
- Keyword arguments to pass to the constructor (only used if instance doesn't exist yet).
267
-
268
- Returns
269
- -------
270
- Any
271
- The singleton instance of the requested service.
272
- """
273
- # Return existing instance if available
274
- if binding.instance:
275
- return binding.instance
276
-
277
- # Create instance if needed
278
- if binding.concrete:
279
- if args or kwargs:
280
- binding.instance = self.__instantiateConcreteWithArgs(binding.concrete, *args, **kwargs)
281
- else:
282
- binding.instance = self.__instantiateConcreteReflective(binding.concrete)
283
- return binding.instance
284
-
285
- # If the binding has a function defined
286
- elif binding.function:
287
- if args or kwargs:
288
- result = self.__instantiateCallableWithArgs(binding.function, *args, **kwargs)
289
- else:
290
- result = self.__instantiateCallableReflective(binding.function)
291
-
292
- # Store the result directly as the singleton instance
293
- # We don't automatically invoke factory function results anymore
294
- binding.instance = result
295
- return binding.instance
296
-
297
- # If neither concrete class nor function is defined
298
- else:
299
- raise OrionisContainerException(
300
- "Cannot resolve singleton binding: neither a concrete class, instance, nor function is defined."
301
- )
302
-
303
- def __resolveScoped(self, binding: Binding, *args, **kwargs) -> Any:
304
- """
305
- Resolves a service with scoped lifetime.
306
-
307
- Parameters
308
- ----------
309
- binding : Binding
310
- The binding to resolve.
311
- *args : tuple
312
- Positional arguments to pass to the constructor.
313
- **kwargs : dict
314
- Keyword arguments to pass to the constructor.
315
-
316
- Returns
317
- -------
318
- Any
319
- The scoped instance of the requested service.
320
-
321
- Raises
322
- ------
323
- OrionisContainerException
324
- If no scope is active or service can't be resolved.
325
- """
326
- scope = ScopedContext.getCurrentScope()
327
- if scope is None:
328
- raise OrionisContainerException(
329
- f"No active scope found while resolving scoped service '{binding.alias}'. "
330
- f"Use 'with container.createContext():' to create a scope context."
331
- )
332
-
333
- if binding.alias in scope:
334
- return scope[binding.alias]
335
-
336
- # Create a new instance
337
- if binding.concrete:
338
- if args or kwargs:
339
- instance = self.__instantiateConcreteWithArgs(binding.concrete, *args, **kwargs)
340
- else:
341
- instance = self.__instantiateConcreteReflective(binding.concrete)
342
- elif binding.function:
343
- if args or kwargs:
344
- instance = self.__instantiateCallableWithArgs(binding.function, *args, **kwargs)
345
- else:
346
- instance = self.__instantiateCallableReflective(binding.function)
347
- else:
348
- raise OrionisContainerException(
349
- "Cannot resolve scoped binding: neither a concrete class nor a function is defined."
350
- )
351
-
352
- scope[binding.alias] = instance
353
- return instance
354
-
355
- def __instantiateConcreteWithArgs(self, concrete: Callable[..., Any], *args, **kwargs) -> Any:
356
- """
357
- Instantiates a concrete class with the provided arguments.
358
-
359
- Parameters
360
- ----------
361
- concrete : Callable[..., Any]
362
- Class to instantiate.
363
- *args : tuple
364
- Positional arguments to pass to the constructor.
365
- **kwargs : dict
366
- Keyword arguments to pass to the constructor.
367
-
368
- Returns
369
- -------
370
- object
371
- A new instance of the specified concrete class.
372
- """
373
-
374
- # try to instantiate the concrete class with the provided arguments
375
- try:
376
-
377
- # If the concrete is a class, instantiate it directly
378
- return concrete(*args, **kwargs)
379
-
380
- except TypeError as e:
381
-
382
- # If instantiation fails, use ReflectionConcrete to get class name and constructor signature
383
- rf_concrete = ReflectionConcrete(concrete)
384
- class_name = rf_concrete.getClassName()
385
- signature = rf_concrete.getConstructorSignature()
386
-
387
- # Raise an exception with detailed information about the failure
388
- raise OrionisContainerException(
389
- f"Failed to instantiate [{class_name}] with the provided arguments: {e}\n"
390
- f"Expected constructor signature: [{signature}]"
391
- ) from e
392
-
393
- def __instantiateCallableWithArgs(self, fn: Callable[..., Any], *args, **kwargs) -> Any:
394
- """
395
- Invokes a callable with the provided arguments.
396
-
397
- Parameters
398
- ----------
399
- fn : Callable[..., Any]
400
- The callable to invoke.
401
- *args : tuple
402
- Positional arguments to pass to the callable.
403
- **kwargs : dict
404
- Keyword arguments to pass to the callable.
405
-
406
- Returns
407
- -------
408
- Any
409
- The result of the callable.
410
- """
411
-
412
- # Try to invoke the callable with the provided arguments
413
- try:
414
-
415
- # If the callable is a function, invoke it directly
416
- return fn(*args, **kwargs)
417
-
418
- except TypeError as e:
419
-
420
- # If invocation fails, use ReflectionCallable to get function name and signature
421
- rf_callable = ReflectionCallable(fn)
422
- function_name = rf_callable.getName()
423
- signature = rf_callable.getSignature()
424
-
425
- # Raise an exception with detailed information about the failure
426
- raise OrionisContainerException(
427
- f"Failed to invoke function [{function_name}] with the provided arguments: {e}\n"
428
- f"Expected function signature: [{signature}]"
429
- ) from e
430
-
431
- def __instantiateConcreteReflective(self, concrete: Callable[..., Any]) -> Any:
432
- """
433
- Instantiates a concrete class reflectively, resolving its dependencies from the container.
434
-
435
- Parameters
436
- ----------
437
- concrete : Callable[..., Any]
438
- The concrete class to instantiate.
439
-
440
- Returns
441
- -------
442
- Any
443
- A new instance of the concrete class.
444
- """
445
- # Resolve dependencies for the concrete class
446
- params = self.__resolveDependencies(concrete, is_class=True)
447
-
448
- # Instantiate the concrete class with resolved dependencies
449
- return concrete(**params)
450
-
451
- def __instantiateCallableReflective(self, fn: Callable[..., Any]) -> Any:
452
- """
453
- Invokes a callable reflectively, resolving its dependencies from the container.
454
-
455
- Parameters
456
- ----------
457
- fn : Callable[..., Any]
458
- The callable to invoke.
459
-
460
- Returns
461
- -------
462
- Any
463
- The result of the callable.
464
- """
465
-
466
- # Resolve dependencies for the callable
467
- params = self.__resolveDependencies(fn, is_class=False)
468
-
469
- # Invoke the callable with resolved dependencies
470
- return fn(**params)
471
-
472
- def __resolveDependencies(
473
- self,
474
- target: Callable[..., Any],
475
- *,
476
- is_class: bool = False
477
- ) -> dict:
478
- """
479
- Resolves dependencies for a target callable or class.
480
-
481
- Parameters
482
- ----------
483
- target : Callable[..., Any]
484
- The target callable or class whose dependencies to resolve.
485
- is_class : bool, optional
486
- Whether the target is a class (True) or a callable (False).
487
-
488
- Returns
489
- -------
490
- dict
491
- A dictionary of resolved dependencies.
492
- """
493
- try:
494
-
495
- # Use ReflectionConcrete for classes and ReflectionCallable for callables
496
- if is_class:
497
- reflection = ReflectionConcrete(target)
498
- dependencies = reflection.getConstructorDependencies()
499
- name = reflection.getClassName()
500
-
501
- # If the target is a callable, use ReflectionCallable
502
- else:
503
- reflection = ReflectionCallable(target)
504
- dependencies = reflection.getDependencies()
505
- name = reflection.getName()
506
-
507
- # Check for unresolved dependencies
508
- if dependencies.unresolved:
509
- unresolved_args = ', '.join(dependencies.unresolved)
510
- raise OrionisContainerException(
511
- f"Cannot resolve '{name}' because the following required arguments are missing: [{unresolved_args}]."
512
- )
513
-
514
- # Resolve dependencies
515
- params = {}
516
- for param_name, dep in dependencies.resolved.items():
517
-
518
- # If the dependency is a KnownDependency, resolve it
519
- if isinstance(dep, KnownDependency):
520
-
521
- # If the dependency is a built-in type, raise an exception
522
- if dep.module_name == 'builtins':
523
- raise OrionisContainerException(
524
- f"Cannot resolve '{name}' because parameter '{param_name}' depends on built-in type '{dep.type.__name__}'."
525
- )
526
-
527
- # Try to resolve from container using type (Abstract or Interface)
528
- if self.container.bound(dep.type):
529
- params[param_name] = self.resolve(
530
- self.container.getBinding(dep.type)
531
- )
532
-
533
- # Try to resolve from container using full class path
534
- elif self.container.bound(dep.full_class_path):
535
- params[param_name] = self.resolve(
536
- self.container.getBinding(dep.full_class_path)
537
- )
538
-
539
- # Try to instantiate directly if it's a concrete class
540
- elif ReflectionConcrete.isConcreteClass(dep.type):
541
- params[param_name] = dep.type(**self.__resolveDependencies(dep.type, is_class=True))
542
-
543
- # Try to call directly if it's a callable
544
- elif callable(dep.type) and not isinstance(dep.type, type):
545
- params[param_name] = dep.type(**self.__resolveDependencies(dep.type, is_class=False))
546
-
547
- # If the dependency cannot be resolved, raise an exception
548
- else:
549
- raise OrionisContainerException(
550
- f"Cannot resolve dependency '{param_name}' of type '{dep.type.__name__}' for '{name}'."
551
- )
552
- else:
553
- # Use default value
554
- params[param_name] = dep
555
-
556
- # Return the resolved parameters
557
- return params
558
-
559
- except ImportError as e:
560
-
561
- # Get target name safely
562
- target_name = getattr(target, '__name__', str(target))
563
- module_name = getattr(target, '__module__', "unknown module")
564
-
565
- # Improved circular import detection with more helpful guidance
566
- if "circular import" in str(e).lower() or "cannot import name" in str(e).lower():
567
- raise OrionisContainerException(
568
- f"Circular import detected while resolving dependencies for '{target_name}' in module '{module_name}'.\n"
569
- f"This typically happens when two modules import each other. Consider:\n"
570
- f"1. Restructuring your code to avoid circular dependencies\n"
571
- f"2. Using delayed imports inside methods rather than at module level\n"
572
- f"3. Using dependency injection to break the cycle\n"
573
- f"Original error: {str(e)}"
574
- ) from e
575
- else:
576
- raise OrionisContainerException(
577
- f"Import error while resolving dependencies for '{target_name}' in module '{module_name}':\n"
578
- f"{str(e)}"
579
- ) from e
580
-
581
- except Exception as e:
582
-
583
- # More robust attribute extraction with fallbacks
584
- target_type = "class" if isinstance(target, type) else "function"
585
- target_name = getattr(target, '__name__', str(target))
586
- module_name = getattr(target, '__module__', "unknown module")
587
-
588
- # More detailed error message with context about the failure
589
- error_msg = (
590
- f"Error resolving dependencies for {target_type} '{target_name}' in '{module_name}':\n"
591
- f"{str(e)}\n"
592
- )
593
-
594
- # Add specific guidance based on error type
595
- if isinstance(e, TypeError):
596
- error_msg += "This may be caused by incompatible argument types or missing required parameters."
597
- elif isinstance(e, AttributeError):
598
- error_msg += "This may be caused by accessing undefined attributes in the dependency chain."
599
- error_msg += "\nCheck that all dependencies are properly registered in the container."
600
-
601
- # Raise a more informative exception
602
- raise OrionisContainerException(error_msg) from e
@@ -1,54 +0,0 @@
1
- from dataclasses import dataclass
2
- from typing import Any, Dict, List
3
- from orionis.services.introspection.dependencies.entities.known_dependencies import KnownDependency
4
- from orionis.services.introspection.exceptions import ReflectionTypeError
5
-
6
- @dataclass(frozen=True, kw_only=True)
7
- class CallableDependency:
8
- """
9
- Represents the resolved and unresolved dependencies of a callable.
10
-
11
- Attributes
12
- ----------
13
- resolved : Dict[KnownDependency, Any]
14
- Dictionary mapping KnownDependency instances to their resolved values.
15
- unresolved : List[str]
16
- List of parameter names or dependency identifiers that could not be resolved.
17
-
18
- Raises
19
- ------
20
- ReflectionTypeError
21
- If `resolved` is not a dictionary or `unresolved` is not a list.
22
- ValueError
23
- If `resolved` contains None keys or `unresolved` contains empty strings.
24
- """
25
-
26
- # Resolved dependencies mapped to their values
27
- resolved: Dict[KnownDependency, Any]
28
-
29
- # Unresolved dependencies as a list of parameter names
30
- unresolved: List[str]
31
-
32
- def __post_init__(self):
33
- """
34
- Validates the types and values of the attributes after initialization.
35
-
36
- Raises
37
- ------
38
- ReflectionTypeError
39
- If `resolved` is not a dictionary or `unresolved` is not a list.
40
- ValueError
41
- If `resolved` contains None keys or `unresolved` contains empty strings.
42
- """
43
-
44
- # Validate 'resolved' is a dict with proper key types
45
- if not isinstance(self.resolved, dict):
46
- raise ReflectionTypeError(
47
- f"'resolved' must be a dict, got {type(self.resolved).__name__}"
48
- )
49
-
50
- # Validate 'unresolved' is a list of valid parameter names
51
- if not isinstance(self.unresolved, list):
52
- raise ReflectionTypeError(
53
- f"'unresolved' must be a list, got {type(self.unresolved).__name__}"
54
- )