orionis 0.653.0__py3-none-any.whl → 0.655.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.
- orionis/container/container.py +107 -56
- orionis/metadata/framework.py +1 -1
- {orionis-0.653.0.dist-info → orionis-0.655.0.dist-info}/METADATA +1 -1
- {orionis-0.653.0.dist-info → orionis-0.655.0.dist-info}/RECORD +7 -7
- {orionis-0.653.0.dist-info → orionis-0.655.0.dist-info}/WHEEL +0 -0
- {orionis-0.653.0.dist-info → orionis-0.655.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.653.0.dist-info → orionis-0.655.0.dist-info}/top_level.txt +0 -0
orionis/container/container.py
CHANGED
|
@@ -88,37 +88,38 @@ class Container(IContainer):
|
|
|
88
88
|
|
|
89
89
|
def __init__(self) -> None:
|
|
90
90
|
"""
|
|
91
|
-
Initializes
|
|
91
|
+
Initializes the internal state of the container instance.
|
|
92
92
|
|
|
93
|
-
This constructor sets up the internal dictionaries for bindings
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
This constructor sets up the internal dictionaries for service bindings, aliases,
|
|
94
|
+
singleton cache, and resolution cache. Initialization is performed only once per
|
|
95
|
+
instance, even if `__init__` is called multiple times due to inheritance or other
|
|
96
|
+
instantiation patterns. The container also registers itself under the `IContainer`
|
|
97
|
+
interface for dependency injection.
|
|
96
98
|
|
|
97
99
|
Notes
|
|
98
100
|
-----
|
|
99
|
-
- The `__bindings` dictionary
|
|
100
|
-
- The `__aliases` dictionary
|
|
101
|
-
-
|
|
102
|
-
- The
|
|
101
|
+
- The `__bindings` dictionary stores service bindings by abstract type.
|
|
102
|
+
- The `__aliases` dictionary maps aliases to their corresponding bindings.
|
|
103
|
+
- The `__singleton_cache` dictionary caches singleton instances.
|
|
104
|
+
- The `__resolution_cache` dictionary tracks types being resolved to prevent circular dependencies.
|
|
105
|
+
- Initialization is guarded to ensure it only occurs once per instance.
|
|
106
|
+
|
|
107
|
+
Returns
|
|
108
|
+
-------
|
|
109
|
+
None
|
|
110
|
+
This method does not return any value.
|
|
103
111
|
"""
|
|
104
112
|
|
|
105
|
-
#
|
|
113
|
+
# Only initialize if this instance hasn't been initialized before
|
|
106
114
|
if not hasattr(self, '_Container__initialized'):
|
|
107
115
|
|
|
108
|
-
#
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
self.__valid_namespaces = set(('app', 'orionis', 'requests', 'rich', 'apscheduler', 'dotenv', current_project_namespace))
|
|
116
|
+
# Set up the container's internal dictionaries for service management
|
|
117
|
+
self.__bindings = {} # Stores service bindings by abstract type
|
|
118
|
+
self.__aliases = {} # Maps aliases to bindings
|
|
119
|
+
self.__resolution_cache = {} # Tracks types currently being resolved
|
|
120
|
+
self.__singleton_cache = {} # Caches singleton instances
|
|
114
121
|
|
|
115
|
-
#
|
|
116
|
-
self.__bindings = {}
|
|
117
|
-
self.__aliases = {}
|
|
118
|
-
self.__resolution_cache = {}
|
|
119
|
-
self.__singleton_cache = {}
|
|
120
|
-
|
|
121
|
-
# Mark this instance as initialized
|
|
122
|
+
# Mark this instance as initialized to prevent re-initialization
|
|
122
123
|
self.__initialized = True
|
|
123
124
|
|
|
124
125
|
def __handleSyncAsyncResult(
|
|
@@ -867,15 +868,6 @@ class Container(IContainer):
|
|
|
867
868
|
f"Unexpected error registering {Lifetime.SCOPED} service: {e}"
|
|
868
869
|
) from e
|
|
869
870
|
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
871
|
def scopedInstance(
|
|
880
872
|
self,
|
|
881
873
|
abstract: Callable[..., Any],
|
|
@@ -1062,10 +1054,15 @@ class Container(IContainer):
|
|
|
1062
1054
|
"""
|
|
1063
1055
|
|
|
1064
1056
|
try:
|
|
1057
|
+
|
|
1065
1058
|
# Use getBinding which includes validation
|
|
1066
1059
|
binding = self.getBinding(abstract_or_alias)
|
|
1060
|
+
|
|
1061
|
+
# A valid binding must be present
|
|
1067
1062
|
return binding is not None
|
|
1063
|
+
|
|
1068
1064
|
except OrionisContainerException:
|
|
1065
|
+
|
|
1069
1066
|
# If binding validation fails, consider it as not bound
|
|
1070
1067
|
return False
|
|
1071
1068
|
|
|
@@ -1675,6 +1672,7 @@ class Container(IContainer):
|
|
|
1675
1672
|
The singleton instance to store cross-references for.
|
|
1676
1673
|
"""
|
|
1677
1674
|
|
|
1675
|
+
# Determine the primary cache key for this binding
|
|
1678
1676
|
primary_key = self.__getSingletonCacheKey(binding)
|
|
1679
1677
|
|
|
1680
1678
|
# Store cross-reference for contract if it's not the primary key
|
|
@@ -2037,6 +2035,7 @@ class Container(IContainer):
|
|
|
2037
2035
|
"""
|
|
2038
2036
|
|
|
2039
2037
|
try:
|
|
2038
|
+
|
|
2040
2039
|
# If there are no dependencies, return empty dict
|
|
2041
2040
|
if not dependencies:
|
|
2042
2041
|
return {}
|
|
@@ -2053,6 +2052,7 @@ class Container(IContainer):
|
|
|
2053
2052
|
for param_name, dep in dependencies.resolved.items():
|
|
2054
2053
|
params[param_name] = self.__resolveSingleDependency(name, param_name, dep)
|
|
2055
2054
|
|
|
2055
|
+
# Return the dictionary of resolved parameters
|
|
2056
2056
|
return params
|
|
2057
2057
|
|
|
2058
2058
|
except Exception as e:
|
|
@@ -2186,43 +2186,61 @@ class Container(IContainer):
|
|
|
2186
2186
|
**kwargs
|
|
2187
2187
|
) -> Any:
|
|
2188
2188
|
"""
|
|
2189
|
-
|
|
2189
|
+
Resolves and instantiates a type or callable regardless of its registration in the container.
|
|
2190
|
+
|
|
2191
|
+
This method attempts to instantiate or invoke the provided type or callable, even if it is not
|
|
2192
|
+
registered in the container. It first tries direct instantiation/invocation if arguments are provided,
|
|
2193
|
+
then attempts auto-resolution for eligible types, and finally falls back to reflection-based instantiation.
|
|
2194
|
+
If the type cannot be resolved by any means, an exception is raised.
|
|
2190
2195
|
|
|
2191
2196
|
Parameters
|
|
2192
2197
|
----------
|
|
2193
2198
|
type_ : Callable[..., Any]
|
|
2194
|
-
The
|
|
2199
|
+
The class or callable to resolve and instantiate.
|
|
2195
2200
|
*args : tuple
|
|
2196
|
-
Positional arguments to pass to the constructor
|
|
2201
|
+
Positional arguments to pass to the constructor or callable.
|
|
2197
2202
|
**kwargs : dict
|
|
2198
|
-
Keyword arguments to pass to the constructor
|
|
2203
|
+
Keyword arguments to pass to the constructor or callable.
|
|
2199
2204
|
|
|
2200
2205
|
Returns
|
|
2201
2206
|
-------
|
|
2202
2207
|
Any
|
|
2203
|
-
The
|
|
2208
|
+
The instantiated object or the result of the callable. If the type is a class, a new instance is returned.
|
|
2209
|
+
If the type is a callable, the result of its invocation is returned.
|
|
2204
2210
|
|
|
2205
2211
|
Raises
|
|
2206
2212
|
------
|
|
2207
2213
|
OrionisContainerException
|
|
2208
|
-
If the type cannot be resolved.
|
|
2214
|
+
If the type cannot be resolved, is not a concrete class or callable, or if an error occurs during instantiation.
|
|
2215
|
+
|
|
2216
|
+
Notes
|
|
2217
|
+
-----
|
|
2218
|
+
- Direct instantiation/invocation is prioritized when arguments are provided.
|
|
2219
|
+
- Auto-resolution is attempted for types eligible for automatic dependency resolution.
|
|
2220
|
+
- Reflection-based instantiation is used as a fallback for concrete classes or callables.
|
|
2221
|
+
- If none of the resolution strategies succeed, an exception is raised.
|
|
2209
2222
|
"""
|
|
2223
|
+
|
|
2210
2224
|
try:
|
|
2211
|
-
|
|
2225
|
+
|
|
2226
|
+
# If explicit arguments are provided, attempt direct instantiation or invocation
|
|
2212
2227
|
if args or kwargs:
|
|
2213
2228
|
if isinstance(type_, type):
|
|
2229
|
+
# Instantiate the class directly with provided arguments
|
|
2214
2230
|
return type_(*args, **kwargs)
|
|
2215
2231
|
elif callable(type_):
|
|
2232
|
+
# Invoke the callable directly with provided arguments
|
|
2216
2233
|
return type_(*args, **kwargs)
|
|
2217
2234
|
|
|
2218
|
-
#
|
|
2235
|
+
# Attempt auto-resolution for eligible types
|
|
2219
2236
|
if self.__canAutoResolve(type_):
|
|
2220
2237
|
return self.__autoResolve(type_)
|
|
2221
2238
|
|
|
2222
|
-
# Use
|
|
2239
|
+
# Use reflection-based instantiation for concrete classes
|
|
2223
2240
|
if ReflectionConcrete.isConcreteClass(type_):
|
|
2224
2241
|
return self.__instantiateWithReflection(type_, is_class=True)
|
|
2225
2242
|
|
|
2243
|
+
# Use reflection-based invocation for callables that are not classes
|
|
2226
2244
|
if callable(type_) and not isinstance(type_, type):
|
|
2227
2245
|
return self.__instantiateWithReflection(type_, is_class=False)
|
|
2228
2246
|
|
|
@@ -2232,9 +2250,12 @@ class Container(IContainer):
|
|
|
2232
2250
|
)
|
|
2233
2251
|
|
|
2234
2252
|
except Exception as e:
|
|
2253
|
+
|
|
2254
|
+
# Re-raise container exceptions directly
|
|
2235
2255
|
if isinstance(e, OrionisContainerException):
|
|
2236
2256
|
raise e from None
|
|
2237
2257
|
|
|
2258
|
+
# Wrap other exceptions in an OrionisContainerException with context
|
|
2238
2259
|
raise OrionisContainerException(
|
|
2239
2260
|
f"Error resolving '{getattr(type_, '__name__', str(type_))}': {str(e)}"
|
|
2240
2261
|
) from e
|
|
@@ -2299,26 +2320,34 @@ class Container(IContainer):
|
|
|
2299
2320
|
|
|
2300
2321
|
def __isValidNamespace(self, type_: type) -> bool:
|
|
2301
2322
|
"""
|
|
2302
|
-
|
|
2323
|
+
Determines if a type belongs to a valid namespace for auto-resolution.
|
|
2324
|
+
|
|
2325
|
+
This method checks whether the provided type is defined within one of the namespaces
|
|
2326
|
+
considered valid for automatic dependency resolution by the container. Valid namespaces
|
|
2327
|
+
are typically application-specific modules or packages that are explicitly allowed
|
|
2328
|
+
for auto-resolution. Built-in types and types from external libraries are excluded.
|
|
2303
2329
|
|
|
2304
2330
|
Parameters
|
|
2305
2331
|
----------
|
|
2306
2332
|
type_ : type
|
|
2307
|
-
The type to check for valid namespace.
|
|
2333
|
+
The type to check for valid namespace membership.
|
|
2308
2334
|
|
|
2309
2335
|
Returns
|
|
2310
2336
|
-------
|
|
2311
2337
|
bool
|
|
2312
|
-
True if the type belongs to a valid namespace
|
|
2313
|
-
|
|
2338
|
+
True if the type belongs to a valid namespace (i.e., its `__module__` attribute
|
|
2339
|
+
matches one of the namespaces in `self.__valid_namespaces`), otherwise False.
|
|
2314
2340
|
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2341
|
+
Notes
|
|
2342
|
+
-----
|
|
2343
|
+
- The method relies on the presence of the `__module__` attribute on the type.
|
|
2344
|
+
- If the type does not have a `__module__` attribute, it cannot be considered valid.
|
|
2345
|
+
- The set of valid namespaces is initialized in the container and may include
|
|
2346
|
+
application modules, framework modules, and the current project namespace.
|
|
2347
|
+
"""
|
|
2319
2348
|
|
|
2320
|
-
#
|
|
2321
|
-
return
|
|
2349
|
+
# Ensure the type has a __module__ attribute before checking namespace validity
|
|
2350
|
+
return hasattr(type_, '__module__')
|
|
2322
2351
|
|
|
2323
2352
|
def __isInstantiable(self, type_: type) -> bool:
|
|
2324
2353
|
"""
|
|
@@ -2370,6 +2399,7 @@ class Container(IContainer):
|
|
|
2370
2399
|
return self.__canQuickInstantiate(type_)
|
|
2371
2400
|
|
|
2372
2401
|
except Exception:
|
|
2402
|
+
|
|
2373
2403
|
# If any check fails with an exception, consider it non-instantiable
|
|
2374
2404
|
return False
|
|
2375
2405
|
|
|
@@ -2394,22 +2424,31 @@ class Container(IContainer):
|
|
|
2394
2424
|
|
|
2395
2425
|
# Check if it inherits from ABC (safely)
|
|
2396
2426
|
try:
|
|
2427
|
+
|
|
2428
|
+
# Check if it inherits from abc.ABC
|
|
2397
2429
|
if issubclass(type_, abc.ABC):
|
|
2398
2430
|
return True
|
|
2431
|
+
|
|
2432
|
+
# type_ is not a class, so it can't be abstract
|
|
2399
2433
|
except TypeError:
|
|
2400
|
-
# type_ is not a class, so it can't be abstract
|
|
2401
2434
|
pass
|
|
2402
2435
|
|
|
2403
2436
|
# Check if it has abstract methods
|
|
2404
2437
|
try:
|
|
2405
2438
|
# Try to get abstract methods using reflection
|
|
2406
2439
|
for attr_name in dir(type_):
|
|
2440
|
+
|
|
2441
|
+
# Get the attribute
|
|
2407
2442
|
attr = getattr(type_, attr_name)
|
|
2443
|
+
|
|
2444
|
+
# Check if the attribute is marked as an abstract method
|
|
2408
2445
|
if hasattr(attr, '__isabstractmethod__') and attr.__isabstractmethod__:
|
|
2409
2446
|
return True
|
|
2447
|
+
|
|
2410
2448
|
except Exception:
|
|
2411
2449
|
pass
|
|
2412
2450
|
|
|
2451
|
+
# If none of the checks matched, it's not abstract
|
|
2413
2452
|
return False
|
|
2414
2453
|
|
|
2415
2454
|
def __isGenericType(self, type_: type) -> bool:
|
|
@@ -2443,6 +2482,7 @@ class Container(IContainer):
|
|
|
2443
2482
|
if hasattr(typing, 'TypeVar') and isinstance(type_, typing.TypeVar):
|
|
2444
2483
|
return True
|
|
2445
2484
|
|
|
2485
|
+
# If none of the checks matched, it's not a generic type
|
|
2446
2486
|
return False
|
|
2447
2487
|
|
|
2448
2488
|
def __isProtocolOrTyping(self, type_: type) -> bool:
|
|
@@ -2475,9 +2515,12 @@ class Container(IContainer):
|
|
|
2475
2515
|
|
|
2476
2516
|
# Check for common typing constructs that shouldn't be instantiated
|
|
2477
2517
|
typing_constructs = ['Union', 'Optional', 'Any', 'Callable', 'Type']
|
|
2518
|
+
|
|
2519
|
+
# If the type's name matches a known typing construct, it's not instantiable
|
|
2478
2520
|
if hasattr(type_, '__name__') and type_.__name__ in typing_constructs:
|
|
2479
2521
|
return True
|
|
2480
2522
|
|
|
2523
|
+
# If none of the checks matched, it's not a protocol or typing construct
|
|
2481
2524
|
return False
|
|
2482
2525
|
|
|
2483
2526
|
def __hasRequiredConstructorParams(self, type_: type) -> bool:
|
|
@@ -2539,6 +2582,7 @@ class Container(IContainer):
|
|
|
2539
2582
|
"""
|
|
2540
2583
|
|
|
2541
2584
|
try:
|
|
2585
|
+
|
|
2542
2586
|
# For safety, first check if the constructor signature suggests it's safe to instantiate
|
|
2543
2587
|
try:
|
|
2544
2588
|
|
|
@@ -2563,8 +2607,10 @@ class Container(IContainer):
|
|
|
2563
2607
|
# Attempt to create an instance only if it seems safe
|
|
2564
2608
|
instance = type_()
|
|
2565
2609
|
|
|
2566
|
-
# If successful, clean up
|
|
2610
|
+
# If successful, clean up
|
|
2567
2611
|
del instance
|
|
2612
|
+
|
|
2613
|
+
# Return True if instantiation succeeded
|
|
2568
2614
|
return True
|
|
2569
2615
|
|
|
2570
2616
|
except Exception:
|
|
@@ -2609,6 +2655,7 @@ class Container(IContainer):
|
|
|
2609
2655
|
)
|
|
2610
2656
|
|
|
2611
2657
|
try:
|
|
2658
|
+
|
|
2612
2659
|
# Mark this type as being resolved to prevent circular dependencies
|
|
2613
2660
|
self.__resolution_cache[type_key] = True
|
|
2614
2661
|
|
|
@@ -2634,17 +2681,21 @@ class Container(IContainer):
|
|
|
2634
2681
|
)
|
|
2635
2682
|
|
|
2636
2683
|
except Exception as e:
|
|
2684
|
+
|
|
2637
2685
|
# Remove the type from the resolution cache on error
|
|
2638
2686
|
self.__resolution_cache.pop(type_key, None)
|
|
2639
2687
|
|
|
2688
|
+
# If the exception is already an OrionisContainerException, re-raise it
|
|
2640
2689
|
if isinstance(e, OrionisContainerException):
|
|
2641
2690
|
raise
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2691
|
+
|
|
2692
|
+
# Otherwise, raise a new OrionisContainerException with additional context
|
|
2693
|
+
raise OrionisContainerException(
|
|
2694
|
+
f"Failed to auto-resolve '{type_.__name__}': {str(e)}"
|
|
2695
|
+
) from e
|
|
2646
2696
|
|
|
2647
2697
|
finally:
|
|
2698
|
+
|
|
2648
2699
|
# Always clean up the resolution cache after resolution attempt
|
|
2649
2700
|
self.__resolution_cache.pop(type_key, None)
|
|
2650
2701
|
|
orionis/metadata/framework.py
CHANGED
|
@@ -67,7 +67,7 @@ orionis/console/stubs/listener.stub,sha256=DbX-ghx2-vb73kzQ6L20lyg5vSKn58jSLTwFu
|
|
|
67
67
|
orionis/console/tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
68
68
|
orionis/console/tasks/schedule.py,sha256=ZeeuQ9Tbu5KNowKC5oIk7yWeJXzlDQiQ278mWEgoCXc,87989
|
|
69
69
|
orionis/container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
70
|
-
orionis/container/container.py,sha256=
|
|
70
|
+
orionis/container/container.py,sha256=wykXRHbXuj5uR_dLWSGV2dP6HJhat9O22xhZ1qrJ710,112458
|
|
71
71
|
orionis/container/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
72
72
|
orionis/container/context/manager.py,sha256=I08K_jKXSKmrq18Pv33qYyMKIlAovVOwIgmfiVm-J7c,2971
|
|
73
73
|
orionis/container/context/scope.py,sha256=p_oCzR7dDz-5ZAd16ab4vfLc3gBf34CaN0f4iR9D0bQ,1155
|
|
@@ -217,7 +217,7 @@ orionis/foundation/providers/scheduler_provider.py,sha256=IrPQJwvQVLRm5Qnz0Cxon4
|
|
|
217
217
|
orionis/foundation/providers/testing_provider.py,sha256=eI1p2lUlxl25b5Z487O4nmqLE31CTDb4c3Q21xFadkE,1615
|
|
218
218
|
orionis/foundation/providers/workers_provider.py,sha256=GdHENYV_yGyqmHJHn0DCyWmWId5xWjD48e6Zq2PGCWY,1674
|
|
219
219
|
orionis/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
220
|
-
orionis/metadata/framework.py,sha256=
|
|
220
|
+
orionis/metadata/framework.py,sha256=fCnJNnu6flu1dXdRyr3BiuEpSCKb5vSVvYYbZ4DsghA,4089
|
|
221
221
|
orionis/metadata/package.py,sha256=k7Yriyp5aUcR-iR8SK2ec_lf0_Cyc-C7JczgXa-I67w,16039
|
|
222
222
|
orionis/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
223
223
|
orionis/services/asynchrony/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -404,8 +404,8 @@ orionis/test/validators/workers.py,sha256=rWcdRexINNEmGaO7mnc1MKUxkHKxrTsVuHgbnI
|
|
|
404
404
|
orionis/test/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
405
405
|
orionis/test/view/render.py,sha256=R55ykeRs0wDKcdTf4O1YZ8GDHTFmJ0IK6VQkbJkYUvo,5571
|
|
406
406
|
orionis/test/view/report.stub,sha256=QLqqCdRoENr3ECiritRB3DO_MOjRQvgBh5jxZ3Hs1r0,28189
|
|
407
|
-
orionis-0.
|
|
408
|
-
orionis-0.
|
|
409
|
-
orionis-0.
|
|
410
|
-
orionis-0.
|
|
411
|
-
orionis-0.
|
|
407
|
+
orionis-0.655.0.dist-info/licenses/LICENCE,sha256=JhC-z_9mbpUrCfPjcl3DhDA8trNDMzb57cvRSam1avc,1463
|
|
408
|
+
orionis-0.655.0.dist-info/METADATA,sha256=aPpUeCj0hOqdFHu448hacU_JrJNuv41S-Kp0km98Uwc,4772
|
|
409
|
+
orionis-0.655.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
410
|
+
orionis-0.655.0.dist-info/top_level.txt,sha256=lyXi6jArpqJ-0zzNqd_uwsH-z9TCEBVBL-pC3Ekv7hU,8
|
|
411
|
+
orionis-0.655.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|