orionis 0.651.0__py3-none-any.whl → 0.653.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 +466 -226
- orionis/foundation/application.py +1 -8
- orionis/metadata/framework.py +1 -1
- {orionis-0.651.0.dist-info → orionis-0.653.0.dist-info}/METADATA +1 -1
- {orionis-0.651.0.dist-info → orionis-0.653.0.dist-info}/RECORD +8 -8
- {orionis-0.651.0.dist-info → orionis-0.653.0.dist-info}/WHEEL +0 -0
- {orionis-0.651.0.dist-info → orionis-0.653.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.651.0.dist-info → orionis-0.653.0.dist-info}/top_level.txt +0 -0
orionis/container/container.py
CHANGED
|
@@ -11,6 +11,7 @@ from orionis.container.contracts.container import IContainer
|
|
|
11
11
|
from orionis.container.entities.binding import Binding
|
|
12
12
|
from orionis.container.enums.lifetimes import Lifetime
|
|
13
13
|
from orionis.container.exceptions import OrionisContainerException
|
|
14
|
+
from orionis.container.exceptions.container import OrionisContainerTypeError
|
|
14
15
|
from orionis.container.validators import (
|
|
15
16
|
ImplementsAbstractMethods,
|
|
16
17
|
IsAbstractClass,
|
|
@@ -28,6 +29,8 @@ from orionis.services.introspection.concretes.reflection import ReflectionConcre
|
|
|
28
29
|
from orionis.services.introspection.dependencies.entities.argument import Argument
|
|
29
30
|
from orionis.services.introspection.dependencies.entities.resolve_argument import ResolveArguments
|
|
30
31
|
from orionis.services.introspection.dependencies.reflection import ReflectDependencies
|
|
32
|
+
from orionis.services.introspection.instances.reflection import ReflectionInstance
|
|
33
|
+
from orionis.services.introspection.objects.types import Type
|
|
31
34
|
|
|
32
35
|
class Container(IContainer):
|
|
33
36
|
|
|
@@ -178,6 +181,7 @@ class Container(IContainer):
|
|
|
178
181
|
return future.result()
|
|
179
182
|
|
|
180
183
|
else:
|
|
184
|
+
|
|
181
185
|
# If loop exists but not running, we can run the coroutine
|
|
182
186
|
return loop.run_until_complete(result)
|
|
183
187
|
|
|
@@ -225,12 +229,8 @@ class Container(IContainer):
|
|
|
225
229
|
total_dependencies = len(dependencies.resolved) + len(dependencies.unresolved)
|
|
226
230
|
|
|
227
231
|
# If the callable does not require any dependencies, invoke directly
|
|
228
|
-
if total_dependencies == 0:
|
|
229
|
-
result = fn(*args, **kwargs)
|
|
230
|
-
return self.__handleSyncAsyncResult(result)
|
|
231
|
-
|
|
232
232
|
# If enough arguments are provided, invoke directly
|
|
233
|
-
if total_provided_args >= total_dependencies:
|
|
233
|
+
if (total_dependencies == 0) or (total_provided_args >= total_dependencies):
|
|
234
234
|
result = fn(*args, **kwargs)
|
|
235
235
|
return self.__handleSyncAsyncResult(result)
|
|
236
236
|
|
|
@@ -298,6 +298,184 @@ class Container(IContainer):
|
|
|
298
298
|
f"Expected function signature: {function_name}{signature}"
|
|
299
299
|
) from e
|
|
300
300
|
|
|
301
|
+
def __decouplingCheck(
|
|
302
|
+
self,
|
|
303
|
+
abstract: Callable[..., Any],
|
|
304
|
+
concrete: Callable[..., Any],
|
|
305
|
+
enforce_decoupling: bool
|
|
306
|
+
) -> None:
|
|
307
|
+
"""
|
|
308
|
+
Validates the decoupling relationship between abstract and concrete classes.
|
|
309
|
+
|
|
310
|
+
Parameters
|
|
311
|
+
----------
|
|
312
|
+
abstract : Callable[..., Any]
|
|
313
|
+
The abstract base class.
|
|
314
|
+
concrete : Callable[..., Any]
|
|
315
|
+
The concrete implementation class.
|
|
316
|
+
enforce_decoupling : bool
|
|
317
|
+
Whether to enforce that concrete does NOT inherit from abstract.
|
|
318
|
+
|
|
319
|
+
Raises
|
|
320
|
+
------
|
|
321
|
+
OrionisContainerException
|
|
322
|
+
If the decoupling check fails.
|
|
323
|
+
"""
|
|
324
|
+
|
|
325
|
+
if enforce_decoupling:
|
|
326
|
+
if issubclass(concrete, abstract):
|
|
327
|
+
raise OrionisContainerException(
|
|
328
|
+
"The concrete class must NOT inherit from the provided abstract class. "
|
|
329
|
+
"Please ensure that the concrete class is not a subclass of the specified abstract class."
|
|
330
|
+
)
|
|
331
|
+
else:
|
|
332
|
+
if not issubclass(concrete, abstract):
|
|
333
|
+
raise OrionisContainerException(
|
|
334
|
+
"The concrete class must inherit from the provided abstract class. "
|
|
335
|
+
"Please ensure that the concrete class is a subclass of the specified abstract class."
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
def __implementsAbstractMethods(
|
|
339
|
+
self,
|
|
340
|
+
*,
|
|
341
|
+
abstract: Callable[..., Any] = None,
|
|
342
|
+
concrete: Callable[..., Any] = None,
|
|
343
|
+
instance: Any = None
|
|
344
|
+
) -> None:
|
|
345
|
+
"""
|
|
346
|
+
Validates that a concrete class or instance implements all abstract methods defined in an abstract class.
|
|
347
|
+
|
|
348
|
+
Parameters
|
|
349
|
+
----------
|
|
350
|
+
abstract : Callable[..., Any]
|
|
351
|
+
The abstract base class.
|
|
352
|
+
concrete : Callable[..., Any], optional
|
|
353
|
+
The class expected to implement the abstract methods.
|
|
354
|
+
instance : Any, optional
|
|
355
|
+
The instance expected to implement the abstract methods.
|
|
356
|
+
|
|
357
|
+
Raises
|
|
358
|
+
------
|
|
359
|
+
OrionisContainerException
|
|
360
|
+
If any abstract method is not implemented.
|
|
361
|
+
"""
|
|
362
|
+
|
|
363
|
+
# Validate that the abstract class is provided
|
|
364
|
+
if abstract is None:
|
|
365
|
+
raise OrionisContainerException("Abstract class must be provided for implementation check.")
|
|
366
|
+
|
|
367
|
+
# Instantiation of ReflectionAbstract for potential future use
|
|
368
|
+
rf_abstract = ReflectionAbstract(abstract)
|
|
369
|
+
|
|
370
|
+
# Check if the abstract class has abstract methods
|
|
371
|
+
abstract_methods = rf_abstract.getMethods()
|
|
372
|
+
if not abstract_methods:
|
|
373
|
+
raise OrionisContainerException(
|
|
374
|
+
f"The abstract class '{abstract.__name__}' does not define any abstract methods. "
|
|
375
|
+
"An abstract class must have at least one abstract method."
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
# Determine the target class or instance to check
|
|
379
|
+
target = concrete if concrete is not None else instance
|
|
380
|
+
if target is None:
|
|
381
|
+
raise OrionisContainerException("Either concrete class or instance must be provided for implementation check.")
|
|
382
|
+
|
|
383
|
+
# Validate that the target is a class or instance
|
|
384
|
+
target_class = target if Type(target).isClass() else target.__class__
|
|
385
|
+
|
|
386
|
+
# Instantiation of ReflectionConcrete for potential future use
|
|
387
|
+
rf_class = ReflectionConcrete(target_class)
|
|
388
|
+
|
|
389
|
+
# Extract class names for error messages
|
|
390
|
+
target_name = rf_class.getClassName()
|
|
391
|
+
abstract_name = rf_abstract.getClassName()
|
|
392
|
+
|
|
393
|
+
# Extract methods implemented by the target class
|
|
394
|
+
implemented_methods = rf_class.getMethods()
|
|
395
|
+
|
|
396
|
+
# Check if the target class implements all abstract methods
|
|
397
|
+
not_implemented = []
|
|
398
|
+
for method in abstract_methods:
|
|
399
|
+
if method not in implemented_methods:
|
|
400
|
+
not_implemented.append(method)
|
|
401
|
+
|
|
402
|
+
# If any abstract methods are not implemented, raise an exception
|
|
403
|
+
if not_implemented:
|
|
404
|
+
formatted = "\n • " + "\n • ".join(not_implemented)
|
|
405
|
+
raise OrionisContainerException(
|
|
406
|
+
f"'{target_name}' does not implement the following abstract methods defined in '{abstract_name}':{formatted}\n"
|
|
407
|
+
"Please ensure that all abstract methods are implemented."
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
def __makeAliasKey(
|
|
411
|
+
self,
|
|
412
|
+
abstract: Callable[..., Any],
|
|
413
|
+
alias: str = None
|
|
414
|
+
) -> str:
|
|
415
|
+
"""
|
|
416
|
+
Generates a unique and valid key for an alias based on the abstract class and optional alias.
|
|
417
|
+
|
|
418
|
+
This method ensures that the alias used for service registration is valid and unique.
|
|
419
|
+
If an explicit alias is provided, it validates the alias for type, emptiness, and
|
|
420
|
+
forbidden characters. If no alias is provided, it generates a default alias using
|
|
421
|
+
the abstract class's module and name.
|
|
422
|
+
|
|
423
|
+
Parameters
|
|
424
|
+
----------
|
|
425
|
+
abstract : Callable[..., Any]
|
|
426
|
+
The abstract base class or interface for which the alias is being generated.
|
|
427
|
+
alias : str, optional
|
|
428
|
+
An optional custom alias to use instead of the default generated alias.
|
|
429
|
+
|
|
430
|
+
Returns
|
|
431
|
+
-------
|
|
432
|
+
str
|
|
433
|
+
The validated or generated alias key. If a valid alias is provided, it is returned
|
|
434
|
+
directly. Otherwise, the default alias in the format 'module.ClassName' is returned.
|
|
435
|
+
|
|
436
|
+
Raises
|
|
437
|
+
------
|
|
438
|
+
OrionisContainerTypeError
|
|
439
|
+
If the provided alias is None, empty, whitespace only, not a string, or contains
|
|
440
|
+
invalid characters.
|
|
441
|
+
|
|
442
|
+
Notes
|
|
443
|
+
-----
|
|
444
|
+
- The alias must not contain whitespace or special symbols.
|
|
445
|
+
- If no alias is provided, the default alias is generated using the abstract's module
|
|
446
|
+
and class name.
|
|
447
|
+
"""
|
|
448
|
+
|
|
449
|
+
# Set of characters that are not allowed in aliases
|
|
450
|
+
invalid_chars = set(' \t\n\r\x0b\x0c!@#$%^&*()[]{};:,/<>?\\|`~"\'')
|
|
451
|
+
|
|
452
|
+
# If an alias is provided, validate and use it directly
|
|
453
|
+
if alias:
|
|
454
|
+
# Check for None, empty string, or whitespace-only alias
|
|
455
|
+
if alias is None or alias == "" or str(alias).isspace():
|
|
456
|
+
raise OrionisContainerTypeError(
|
|
457
|
+
"Alias cannot be None, empty, or whitespace only."
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
# Ensure the alias is a string
|
|
461
|
+
if not isinstance(alias, str):
|
|
462
|
+
raise OrionisContainerTypeError(
|
|
463
|
+
f"Expected a string type for alias, but got {type(alias).__name__} instead."
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
# Check for invalid characters in the alias
|
|
467
|
+
if any(char in invalid_chars for char in alias):
|
|
468
|
+
raise OrionisContainerTypeError(
|
|
469
|
+
f"Alias '{alias}' contains invalid characters. "
|
|
470
|
+
"Aliases must not contain whitespace or special symbols."
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
# Return the validated alias
|
|
474
|
+
return alias
|
|
475
|
+
|
|
476
|
+
# If no alias is provided, generate a default alias using module and class name
|
|
477
|
+
return f"{abstract.__module__}.{abstract.__name__}"
|
|
478
|
+
|
|
301
479
|
def transient(
|
|
302
480
|
self,
|
|
303
481
|
abstract: Callable[..., Any],
|
|
@@ -309,79 +487,190 @@ class Container(IContainer):
|
|
|
309
487
|
"""
|
|
310
488
|
Registers a service with a transient lifetime.
|
|
311
489
|
|
|
490
|
+
This method binds a concrete implementation to an abstract base type or interface
|
|
491
|
+
in the container, ensuring that a new instance of the concrete class is created
|
|
492
|
+
each time the service is requested. It validates the abstract and concrete types,
|
|
493
|
+
enforces decoupling rules if specified, checks that all abstract methods are implemented,
|
|
494
|
+
and manages service aliases.
|
|
495
|
+
|
|
312
496
|
Parameters
|
|
313
497
|
----------
|
|
314
498
|
abstract : Callable[..., Any]
|
|
315
|
-
The abstract base type or interface to be bound.
|
|
499
|
+
The abstract base type or interface to be bound. Must be an abstract class or interface.
|
|
316
500
|
concrete : Callable[..., Any]
|
|
317
|
-
The concrete implementation to associate with the abstract type.
|
|
501
|
+
The concrete implementation to associate with the abstract type. Must be a concrete class.
|
|
318
502
|
alias : str, optional
|
|
319
|
-
An alternative name to register the service under. If not provided,
|
|
503
|
+
An alternative name to register the service under. If not provided, a default alias is generated
|
|
504
|
+
using the abstract's module and class name.
|
|
505
|
+
enforce_decoupling : bool, optional
|
|
506
|
+
If True, enforces that the concrete class does NOT inherit from the abstract class.
|
|
507
|
+
If False, requires that the concrete class is a subclass of the abstract.
|
|
320
508
|
|
|
321
509
|
Returns
|
|
322
510
|
-------
|
|
323
|
-
bool
|
|
324
|
-
True if the service was registered successfully.
|
|
511
|
+
bool or None
|
|
512
|
+
Returns True if the service was registered successfully.
|
|
513
|
+
Returns None if registration fails due to an exception.
|
|
325
514
|
|
|
326
515
|
Raises
|
|
327
516
|
------
|
|
328
517
|
OrionisContainerTypeError
|
|
329
|
-
If the abstract or concrete class
|
|
518
|
+
If the abstract or concrete class validation fails.
|
|
330
519
|
OrionisContainerException
|
|
331
|
-
If the
|
|
520
|
+
If the decoupling check fails or if an unexpected error occurs during registration.
|
|
332
521
|
|
|
333
522
|
Notes
|
|
334
523
|
-----
|
|
335
|
-
Registers the given concrete implementation to the abstract type with a transient lifetime,
|
|
336
|
-
|
|
337
|
-
|
|
524
|
+
- Registers the given concrete implementation to the abstract type with a transient lifetime,
|
|
525
|
+
meaning a new instance will be created each time the service is requested.
|
|
526
|
+
- Validates the abstract and concrete types, checks decoupling rules, ensures all abstract methods
|
|
527
|
+
are implemented, and manages service aliases.
|
|
528
|
+
- If a service is already registered under the same abstract or alias, it is removed before registering
|
|
529
|
+
the new binding.
|
|
338
530
|
"""
|
|
339
531
|
|
|
340
|
-
|
|
341
|
-
IsAbstractClass(abstract, Lifetime.TRANSIENT)
|
|
532
|
+
try:
|
|
342
533
|
|
|
343
|
-
|
|
344
|
-
|
|
534
|
+
# Ensure that abstract is an abstract class
|
|
535
|
+
ReflectionAbstract.ensureIsAbstractClass(abstract)
|
|
345
536
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
IsNotSubclass(abstract, concrete)
|
|
537
|
+
# Ensure that concrete is a concrete class
|
|
538
|
+
ReflectionConcrete.ensureIsConcreteClass(concrete)
|
|
349
539
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
IsSubclass(abstract, concrete)
|
|
540
|
+
# Enforce decoupling or subclass relationship as specified
|
|
541
|
+
self.__decouplingCheck(abstract, concrete, enforce_decoupling)
|
|
353
542
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
543
|
+
# Ensure all abstract methods are implemented by the concrete class
|
|
544
|
+
self.__implementsAbstractMethods(
|
|
545
|
+
abstract=abstract,
|
|
546
|
+
concrete=concrete
|
|
547
|
+
)
|
|
359
548
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
IsValidAlias(alias)
|
|
549
|
+
# Validate and generate the alias key (either provided or default)
|
|
550
|
+
alias = self.__makeAliasKey(abstract, alias)
|
|
363
551
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
alias = f"{abstract.__module__}.{abstract.__name__}"
|
|
552
|
+
# If the service is already registered, remove the existing binding
|
|
553
|
+
self.drop(abstract, alias)
|
|
367
554
|
|
|
368
|
-
|
|
369
|
-
|
|
555
|
+
# Register the service with transient lifetime
|
|
556
|
+
self.__bindings[abstract] = Binding(
|
|
557
|
+
contract = abstract,
|
|
558
|
+
concrete = concrete,
|
|
559
|
+
lifetime = Lifetime.TRANSIENT,
|
|
560
|
+
enforce_decoupling = enforce_decoupling,
|
|
561
|
+
alias = alias
|
|
562
|
+
)
|
|
370
563
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
contract = abstract,
|
|
374
|
-
concrete = concrete,
|
|
375
|
-
lifetime = Lifetime.TRANSIENT,
|
|
376
|
-
enforce_decoupling = enforce_decoupling,
|
|
377
|
-
alias = alias
|
|
378
|
-
)
|
|
564
|
+
# Register the alias for lookup
|
|
565
|
+
self.__aliases[alias] = self.__bindings[abstract]
|
|
379
566
|
|
|
380
|
-
|
|
381
|
-
|
|
567
|
+
# Return True to indicate successful registration
|
|
568
|
+
return True
|
|
382
569
|
|
|
383
|
-
|
|
384
|
-
|
|
570
|
+
except Exception as e:
|
|
571
|
+
|
|
572
|
+
# Raise a container exception with details if registration fails
|
|
573
|
+
raise OrionisContainerException(
|
|
574
|
+
f"Unexpected error registering {Lifetime.TRANSIENT} service: {e}"
|
|
575
|
+
) from e
|
|
576
|
+
|
|
577
|
+
def instance(
|
|
578
|
+
self,
|
|
579
|
+
abstract: Callable[..., Any],
|
|
580
|
+
instance: Any,
|
|
581
|
+
*,
|
|
582
|
+
alias: str = None,
|
|
583
|
+
enforce_decoupling: bool = False
|
|
584
|
+
) -> Optional[bool]:
|
|
585
|
+
"""
|
|
586
|
+
Registers an instance of a class or interface in the container with singleton lifetime.
|
|
587
|
+
|
|
588
|
+
This method validates the abstract type, the instance, and the alias (if provided).
|
|
589
|
+
It ensures that the instance is a valid implementation of the abstract class or interface,
|
|
590
|
+
optionally enforces decoupling, and registers the instance in the container under both
|
|
591
|
+
the abstract type and the alias. The registered instance will be shared across all resolutions
|
|
592
|
+
of the abstract type or alias.
|
|
593
|
+
|
|
594
|
+
Parameters
|
|
595
|
+
----------
|
|
596
|
+
abstract : Callable[..., Any]
|
|
597
|
+
The abstract class or interface to associate with the instance.
|
|
598
|
+
instance : Any
|
|
599
|
+
The concrete instance to register.
|
|
600
|
+
alias : str, optional
|
|
601
|
+
An optional alias to register the instance under. If not provided,
|
|
602
|
+
a default alias is generated from the abstract's module and class name.
|
|
603
|
+
enforce_decoupling : bool, optional
|
|
604
|
+
If True, enforces that the instance's class does NOT inherit from the abstract class.
|
|
605
|
+
If False, requires that the instance's class is a subclass of the abstract.
|
|
606
|
+
|
|
607
|
+
Returns
|
|
608
|
+
-------
|
|
609
|
+
bool or None
|
|
610
|
+
Returns True if the instance was successfully registered.
|
|
611
|
+
Returns None if registration fails due to an exception.
|
|
612
|
+
|
|
613
|
+
Raises
|
|
614
|
+
------
|
|
615
|
+
OrionisContainerTypeError
|
|
616
|
+
If `abstract` is not an abstract class or if `alias` is not a valid string.
|
|
617
|
+
OrionisContainerException
|
|
618
|
+
If the instance is not a valid implementation, fails decoupling check,
|
|
619
|
+
or if registration fails for any other reason.
|
|
620
|
+
|
|
621
|
+
Notes
|
|
622
|
+
-----
|
|
623
|
+
- The instance is registered with singleton lifetime, meaning it will be shared
|
|
624
|
+
across all resolutions of the abstract type or alias.
|
|
625
|
+
- All abstract methods must be implemented by the instance.
|
|
626
|
+
- If a service is already registered under the same abstract or alias, it is removed
|
|
627
|
+
before registering the new instance.
|
|
628
|
+
"""
|
|
629
|
+
|
|
630
|
+
try:
|
|
631
|
+
|
|
632
|
+
# Ensure that the abstract is an abstract class
|
|
633
|
+
ReflectionAbstract.ensureIsAbstractClass(abstract)
|
|
634
|
+
|
|
635
|
+
# Ensure that the instance is a valid instance of the abstract
|
|
636
|
+
ReflectionInstance.ensureIsInstance(instance)
|
|
637
|
+
|
|
638
|
+
# Enforce decoupling or subclass relationship as specified
|
|
639
|
+
self.__decouplingCheck(abstract, instance.__class__, enforce_decoupling)
|
|
640
|
+
|
|
641
|
+
# Ensure all abstract methods are implemented by the instance
|
|
642
|
+
self.__implementsAbstractMethods(
|
|
643
|
+
abstract=abstract,
|
|
644
|
+
instance=instance
|
|
645
|
+
)
|
|
646
|
+
|
|
647
|
+
# Validate and generate the alias key (either provided or default)
|
|
648
|
+
alias = self.__makeAliasKey(abstract, alias)
|
|
649
|
+
|
|
650
|
+
# Remove any existing binding for this abstract or alias
|
|
651
|
+
self.drop(abstract, alias)
|
|
652
|
+
|
|
653
|
+
# Register the instance with singleton lifetime
|
|
654
|
+
self.__bindings[abstract] = Binding(
|
|
655
|
+
contract = abstract,
|
|
656
|
+
instance = instance,
|
|
657
|
+
lifetime = Lifetime.SINGLETON,
|
|
658
|
+
enforce_decoupling = enforce_decoupling,
|
|
659
|
+
alias = alias
|
|
660
|
+
)
|
|
661
|
+
|
|
662
|
+
# Register the alias for lookup
|
|
663
|
+
self.__aliases[alias] = self.__bindings[abstract]
|
|
664
|
+
|
|
665
|
+
# Return True to indicate successful registration
|
|
666
|
+
return True
|
|
667
|
+
|
|
668
|
+
except Exception as e:
|
|
669
|
+
|
|
670
|
+
# Raise a container exception with details if registration fails
|
|
671
|
+
raise OrionisContainerException(
|
|
672
|
+
f"Unexpected error registering instance: {e}"
|
|
673
|
+
) from e
|
|
385
674
|
|
|
386
675
|
def singleton(
|
|
387
676
|
self,
|
|
@@ -394,76 +683,91 @@ class Container(IContainer):
|
|
|
394
683
|
"""
|
|
395
684
|
Registers a service with a singleton lifetime.
|
|
396
685
|
|
|
686
|
+
This method binds a concrete implementation to an abstract base type or interface
|
|
687
|
+
in the container, ensuring that only one instance of the concrete class is created
|
|
688
|
+
and shared throughout the application's lifetime. It validates the abstract and
|
|
689
|
+
concrete types, enforces decoupling rules if specified, checks that all abstract
|
|
690
|
+
methods are implemented, and manages service aliases.
|
|
691
|
+
|
|
397
692
|
Parameters
|
|
398
693
|
----------
|
|
399
694
|
abstract : Callable[..., Any]
|
|
400
|
-
The abstract base type or interface to be bound.
|
|
695
|
+
The abstract base type or interface to be bound. Must be an abstract class or interface.
|
|
401
696
|
concrete : Callable[..., Any]
|
|
402
|
-
The concrete implementation to associate with the abstract type.
|
|
697
|
+
The concrete implementation to associate with the abstract type. Must be a concrete class.
|
|
403
698
|
alias : str, optional
|
|
404
|
-
An alternative name to register the service under. If not provided,
|
|
699
|
+
An alternative name to register the service under. If not provided, a default alias is generated
|
|
700
|
+
using the abstract's module and class name.
|
|
701
|
+
enforce_decoupling : bool, optional
|
|
702
|
+
If True, enforces that the concrete class does NOT inherit from the abstract class.
|
|
703
|
+
If False, requires that the concrete class is a subclass of the abstract.
|
|
405
704
|
|
|
406
705
|
Returns
|
|
407
706
|
-------
|
|
408
|
-
bool
|
|
409
|
-
True if the service was registered successfully.
|
|
707
|
+
bool or None
|
|
708
|
+
Returns True if the service was registered successfully.
|
|
709
|
+
Returns None if registration fails due to an exception.
|
|
410
710
|
|
|
411
711
|
Raises
|
|
412
712
|
------
|
|
413
713
|
OrionisContainerTypeError
|
|
414
|
-
If the abstract or concrete class
|
|
714
|
+
If the abstract or concrete class validation fails.
|
|
415
715
|
OrionisContainerException
|
|
416
|
-
If the
|
|
716
|
+
If the decoupling check fails or if an unexpected error occurs during registration.
|
|
417
717
|
|
|
418
718
|
Notes
|
|
419
719
|
-----
|
|
420
|
-
Registers the given concrete implementation to the abstract type with a singleton lifetime,
|
|
421
|
-
|
|
720
|
+
- Registers the given concrete implementation to the abstract type with a singleton lifetime,
|
|
721
|
+
meaning a single instance will be created and shared for all resolutions.
|
|
722
|
+
- If a service is already registered under the same abstract or alias, it is removed before registering the new binding.
|
|
723
|
+
- All abstract methods must be implemented by the concrete class.
|
|
724
|
+
- Aliases are validated and managed for lookup.
|
|
422
725
|
"""
|
|
423
726
|
|
|
424
|
-
|
|
425
|
-
IsAbstractClass(abstract, Lifetime.SINGLETON)
|
|
727
|
+
try:
|
|
426
728
|
|
|
427
|
-
|
|
428
|
-
|
|
729
|
+
# Ensure that abstract is an abstract class
|
|
730
|
+
ReflectionAbstract.ensureIsAbstractClass(abstract)
|
|
429
731
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
IsNotSubclass(abstract, concrete)
|
|
732
|
+
# Ensure that concrete is a concrete class
|
|
733
|
+
ReflectionConcrete.ensureIsConcreteClass(concrete)
|
|
433
734
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
IsSubclass(abstract, concrete)
|
|
735
|
+
# Enforce decoupling or subclass relationship as specified
|
|
736
|
+
self.__decouplingCheck(abstract, concrete, enforce_decoupling)
|
|
437
737
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
738
|
+
# Ensure all abstract methods are implemented by the concrete class
|
|
739
|
+
self.__implementsAbstractMethods(
|
|
740
|
+
abstract=abstract,
|
|
741
|
+
concrete=concrete
|
|
742
|
+
)
|
|
443
743
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
IsValidAlias(alias)
|
|
447
|
-
else:
|
|
448
|
-
alias = f"{abstract.__module__}.{abstract.__name__}"
|
|
744
|
+
# Validate and generate the alias key (either provided or default)
|
|
745
|
+
alias = self.__makeAliasKey(abstract, alias)
|
|
449
746
|
|
|
450
|
-
|
|
451
|
-
|
|
747
|
+
# If the service is already registered, remove the existing binding
|
|
748
|
+
self.drop(abstract, alias)
|
|
452
749
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
750
|
+
# Register the service with singleton lifetime
|
|
751
|
+
self.__bindings[abstract] = Binding(
|
|
752
|
+
contract = abstract,
|
|
753
|
+
concrete = concrete,
|
|
754
|
+
lifetime = Lifetime.SINGLETON,
|
|
755
|
+
enforce_decoupling = enforce_decoupling,
|
|
756
|
+
alias = alias
|
|
757
|
+
)
|
|
461
758
|
|
|
462
|
-
|
|
463
|
-
|
|
759
|
+
# Register the alias for lookup
|
|
760
|
+
self.__aliases[alias] = self.__bindings[abstract]
|
|
464
761
|
|
|
465
|
-
|
|
466
|
-
|
|
762
|
+
# Return True to indicate successful registration
|
|
763
|
+
return True
|
|
764
|
+
|
|
765
|
+
except Exception as e:
|
|
766
|
+
|
|
767
|
+
# Raise a container exception with details if registration fails
|
|
768
|
+
raise OrionisContainerException(
|
|
769
|
+
f"Unexpected error registering {Lifetime.SINGLETON} service: {e}"
|
|
770
|
+
) from e
|
|
467
771
|
|
|
468
772
|
def scoped(
|
|
469
773
|
self,
|
|
@@ -476,76 +780,101 @@ class Container(IContainer):
|
|
|
476
780
|
"""
|
|
477
781
|
Registers a service with a scoped lifetime.
|
|
478
782
|
|
|
783
|
+
This method binds a concrete implementation to an abstract base type or interface
|
|
784
|
+
in the container, ensuring that a new instance of the concrete class is created
|
|
785
|
+
for each scope context. It validates the abstract and concrete types, enforces
|
|
786
|
+
decoupling rules if specified, checks that all abstract methods are implemented,
|
|
787
|
+
and manages service aliases.
|
|
788
|
+
|
|
479
789
|
Parameters
|
|
480
790
|
----------
|
|
481
791
|
abstract : Callable[..., Any]
|
|
482
|
-
The abstract base type or interface to be bound.
|
|
792
|
+
The abstract base type or interface to be bound. Must be an abstract class or interface.
|
|
483
793
|
concrete : Callable[..., Any]
|
|
484
|
-
The concrete implementation to associate with the abstract type.
|
|
794
|
+
The concrete implementation to associate with the abstract type. Must be a concrete class.
|
|
485
795
|
alias : str, optional
|
|
486
|
-
An alternative name to register the service under. If not provided,
|
|
796
|
+
An alternative name to register the service under. If not provided, a default alias is generated
|
|
797
|
+
using the abstract's module and class name.
|
|
798
|
+
enforce_decoupling : bool, optional
|
|
799
|
+
If True, enforces that the concrete class does NOT inherit from the abstract class.
|
|
800
|
+
If False, requires that the concrete class is a subclass of the abstract.
|
|
487
801
|
|
|
488
802
|
Returns
|
|
489
803
|
-------
|
|
490
|
-
bool
|
|
491
|
-
True if the service was registered successfully.
|
|
804
|
+
bool or None
|
|
805
|
+
Returns True if the service was registered successfully.
|
|
806
|
+
Returns None if registration fails due to an exception.
|
|
492
807
|
|
|
493
808
|
Raises
|
|
494
809
|
------
|
|
495
810
|
OrionisContainerTypeError
|
|
496
|
-
If the abstract or concrete class
|
|
811
|
+
If the abstract or concrete class validation fails.
|
|
497
812
|
OrionisContainerException
|
|
498
|
-
If the
|
|
813
|
+
If the decoupling check fails or if an unexpected error occurs during registration.
|
|
499
814
|
|
|
500
815
|
Notes
|
|
501
816
|
-----
|
|
502
|
-
Registers the given concrete implementation to the abstract type with a scoped lifetime,
|
|
503
|
-
|
|
817
|
+
- Registers the given concrete implementation to the abstract type with a scoped lifetime,
|
|
818
|
+
meaning a new instance will be created for each scope context.
|
|
819
|
+
- Validates the abstract and concrete types, checks decoupling rules, ensures all abstract methods
|
|
820
|
+
are implemented, and manages service aliases.
|
|
821
|
+
- If a service is already registered under the same abstract or alias, it is removed before registering
|
|
822
|
+
the new binding.
|
|
504
823
|
"""
|
|
505
824
|
|
|
506
|
-
|
|
507
|
-
|
|
825
|
+
try:
|
|
826
|
+
|
|
827
|
+
# Ensure that abstract is an abstract class
|
|
828
|
+
ReflectionAbstract.ensureIsAbstractClass(abstract)
|
|
829
|
+
|
|
830
|
+
# Ensure that concrete is a concrete class
|
|
831
|
+
ReflectionConcrete.ensureIsConcreteClass(concrete)
|
|
832
|
+
|
|
833
|
+
# Enforce decoupling or subclass relationship as specified
|
|
834
|
+
self.__decouplingCheck(abstract, concrete, enforce_decoupling)
|
|
835
|
+
|
|
836
|
+
# Ensure all abstract methods are implemented by the concrete class
|
|
837
|
+
self.__implementsAbstractMethods(
|
|
838
|
+
abstract=abstract,
|
|
839
|
+
concrete=concrete
|
|
840
|
+
)
|
|
841
|
+
|
|
842
|
+
# Validate and generate the alias key (either provided or default)
|
|
843
|
+
alias = self.__makeAliasKey(abstract, alias)
|
|
844
|
+
|
|
845
|
+
# If the service is already registered, remove the existing binding
|
|
846
|
+
self.drop(abstract, alias)
|
|
847
|
+
|
|
848
|
+
# Register the service with scoped lifetime
|
|
849
|
+
self.__bindings[abstract] = Binding(
|
|
850
|
+
contract = abstract,
|
|
851
|
+
concrete = concrete,
|
|
852
|
+
lifetime = Lifetime.SCOPED,
|
|
853
|
+
enforce_decoupling = enforce_decoupling,
|
|
854
|
+
alias = alias
|
|
855
|
+
)
|
|
856
|
+
|
|
857
|
+
# Register the alias for lookup
|
|
858
|
+
self.__aliases[alias] = self.__bindings[abstract]
|
|
859
|
+
|
|
860
|
+
# Return True to indicate successful registration
|
|
861
|
+
return True
|
|
862
|
+
|
|
863
|
+
except Exception as e:
|
|
864
|
+
|
|
865
|
+
# Raise a container exception with details if registration fails
|
|
866
|
+
raise OrionisContainerException(
|
|
867
|
+
f"Unexpected error registering {Lifetime.SCOPED} service: {e}"
|
|
868
|
+
) from e
|
|
508
869
|
|
|
509
|
-
# Ensure that concrete is a concrete class
|
|
510
|
-
IsConcreteClass(concrete, Lifetime.SCOPED)
|
|
511
870
|
|
|
512
|
-
# Ensure that concrete is NOT a subclass of abstract
|
|
513
|
-
if enforce_decoupling:
|
|
514
|
-
IsNotSubclass(abstract, concrete)
|
|
515
871
|
|
|
516
|
-
# Validate that concrete is a subclass of abstract
|
|
517
|
-
else:
|
|
518
|
-
IsSubclass(abstract, concrete)
|
|
519
872
|
|
|
520
|
-
# Ensure implementation
|
|
521
|
-
ImplementsAbstractMethods(
|
|
522
|
-
abstract=abstract,
|
|
523
|
-
concrete=concrete
|
|
524
|
-
)
|
|
525
873
|
|
|
526
|
-
# Ensure that the alias is a valid string if provided
|
|
527
|
-
if alias:
|
|
528
|
-
IsValidAlias(alias)
|
|
529
|
-
else:
|
|
530
|
-
alias = f"{abstract.__module__}.{abstract.__name__}"
|
|
531
874
|
|
|
532
|
-
# If the service is already registered, drop it
|
|
533
|
-
self.drop(abstract, alias)
|
|
534
875
|
|
|
535
|
-
# Register the service with scoped lifetime
|
|
536
|
-
self.__bindings[abstract] = Binding(
|
|
537
|
-
contract = abstract,
|
|
538
|
-
concrete = concrete,
|
|
539
|
-
lifetime = Lifetime.SCOPED,
|
|
540
|
-
enforce_decoupling = enforce_decoupling,
|
|
541
|
-
alias = alias
|
|
542
|
-
)
|
|
543
876
|
|
|
544
|
-
# Register the alias
|
|
545
|
-
self.__aliases[alias] = self.__bindings[abstract]
|
|
546
877
|
|
|
547
|
-
# Return True to indicate successful registration
|
|
548
|
-
return True
|
|
549
878
|
|
|
550
879
|
def scopedInstance(
|
|
551
880
|
self,
|
|
@@ -641,96 +970,7 @@ class Container(IContainer):
|
|
|
641
970
|
# Return True to indicate successful registration
|
|
642
971
|
return True
|
|
643
972
|
|
|
644
|
-
|
|
645
|
-
self,
|
|
646
|
-
abstract: Callable[..., Any],
|
|
647
|
-
instance: Any,
|
|
648
|
-
*,
|
|
649
|
-
alias: str = None,
|
|
650
|
-
enforce_decoupling: bool = False
|
|
651
|
-
) -> Optional[bool]:
|
|
652
|
-
"""
|
|
653
|
-
Registers an instance of a class or interface in the container.
|
|
654
|
-
Parameters
|
|
655
|
-
----------
|
|
656
|
-
abstract : Callable[..., Any]
|
|
657
|
-
The abstract class or interface to associate with the instance.
|
|
658
|
-
instance : Any
|
|
659
|
-
The concrete instance to register.
|
|
660
|
-
alias : str, optional
|
|
661
|
-
An optional alias to register the instance under. If not provided,
|
|
662
|
-
the abstract's `__name__` attribute will be used as the alias if available.
|
|
663
|
-
Returns
|
|
664
|
-
-------
|
|
665
|
-
bool
|
|
666
|
-
True if the instance was successfully registered.
|
|
667
|
-
Raises
|
|
668
|
-
------
|
|
669
|
-
TypeError
|
|
670
|
-
If `abstract` is not an abstract class or if `alias` is not a valid string.
|
|
671
|
-
ValueError
|
|
672
|
-
If `instance` is not a valid instance of `abstract`.
|
|
673
|
-
Notes
|
|
674
|
-
-----
|
|
675
|
-
This method ensures that the abstract is a valid abstract class, the instance
|
|
676
|
-
is valid, and the alias (if provided) is a valid string. The instance is then
|
|
677
|
-
registered in the container under both the abstract and the alias.
|
|
678
|
-
"""
|
|
679
|
-
|
|
680
|
-
# Validate the enforce_decoupling parameter
|
|
681
|
-
if isinstance(enforce_decoupling, bool):
|
|
682
|
-
|
|
683
|
-
# Ensure that the abstract is an abstract class
|
|
684
|
-
IsAbstractClass(abstract, f"Instance {Lifetime.SINGLETON}")
|
|
685
|
-
|
|
686
|
-
# Ensure that the instance is a valid instance
|
|
687
|
-
IsInstance(instance)
|
|
688
|
-
|
|
689
|
-
# Ensure that instance is NOT a subclass of abstract
|
|
690
|
-
if enforce_decoupling:
|
|
691
|
-
IsNotSubclass(abstract, instance.__class__)
|
|
692
|
-
|
|
693
|
-
# Validate that instance is a subclass of abstract
|
|
694
|
-
else:
|
|
695
|
-
IsSubclass(abstract, instance.__class__)
|
|
696
|
-
|
|
697
|
-
# Ensure implementation
|
|
698
|
-
ImplementsAbstractMethods(
|
|
699
|
-
abstract=abstract,
|
|
700
|
-
instance=instance
|
|
701
|
-
)
|
|
702
|
-
|
|
703
|
-
# Ensure that the alias is a valid string if provided
|
|
704
|
-
if alias:
|
|
705
|
-
IsValidAlias(alias)
|
|
706
|
-
else:
|
|
707
|
-
alias = f"{abstract.__module__}.{abstract.__name__}"
|
|
708
|
-
|
|
709
|
-
# If the service is already registered, drop it
|
|
710
|
-
self.drop(abstract, alias)
|
|
711
|
-
|
|
712
|
-
else:
|
|
713
|
-
|
|
714
|
-
# Drop the existing alias if it exists
|
|
715
|
-
self.drop(alias=alias)
|
|
716
|
-
|
|
717
|
-
# If enforce_decoupling is not a boolean, set it to False
|
|
718
|
-
enforce_decoupling = False
|
|
719
|
-
|
|
720
|
-
# Register the instance with the abstract type
|
|
721
|
-
self.__bindings[abstract] = Binding(
|
|
722
|
-
contract = abstract,
|
|
723
|
-
instance = instance,
|
|
724
|
-
lifetime = Lifetime.SINGLETON,
|
|
725
|
-
enforce_decoupling = enforce_decoupling,
|
|
726
|
-
alias = alias
|
|
727
|
-
)
|
|
728
|
-
|
|
729
|
-
# Register the alias
|
|
730
|
-
self.__aliases[alias] = self.__bindings[abstract]
|
|
731
|
-
|
|
732
|
-
# Return True to indicate successful registration
|
|
733
|
-
return True
|
|
973
|
+
|
|
734
974
|
|
|
735
975
|
def callable(
|
|
736
976
|
self,
|
|
@@ -2198,12 +2198,7 @@ class Application(Container, IApplication):
|
|
|
2198
2198
|
if not self.__booted:
|
|
2199
2199
|
|
|
2200
2200
|
# Register the application instance in the container
|
|
2201
|
-
self.instance(
|
|
2202
|
-
IApplication,
|
|
2203
|
-
self,
|
|
2204
|
-
alias="x-orionis.foundation.contracts.application.IApplication",
|
|
2205
|
-
enforce_decoupling=None
|
|
2206
|
-
)
|
|
2201
|
+
self.instance(IApplication, self, alias="x-orionis.foundation.contracts.application.IApplication")
|
|
2207
2202
|
|
|
2208
2203
|
# Load configuration if not already set
|
|
2209
2204
|
self.__loadConfig()
|
|
@@ -2213,8 +2208,6 @@ class Application(Container, IApplication):
|
|
|
2213
2208
|
self.__loadFrameworkProviders()
|
|
2214
2209
|
self.__registerProviders()
|
|
2215
2210
|
self.__bootProviders()
|
|
2216
|
-
|
|
2217
|
-
# Mark as booted
|
|
2218
2211
|
self.__booted = True
|
|
2219
2212
|
|
|
2220
2213
|
# Load core framework kernels with app booted
|
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=cbwsntr_yRy-W18MipLZ8Gy2d7mCoO51_eq4z53bxVk,109309
|
|
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
|
|
@@ -104,7 +104,7 @@ orionis/failure/contracts/handler.py,sha256=AeJfkJfD3hTkOIYAtADq6GnQfq-qWgDfUc7b
|
|
|
104
104
|
orionis/failure/entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
105
105
|
orionis/failure/entities/throwable.py,sha256=1zD-awcuAyEtlR-L7V7ZIfPSF4GpXkf-neL5sXul7dc,1240
|
|
106
106
|
orionis/foundation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
107
|
-
orionis/foundation/application.py,sha256=
|
|
107
|
+
orionis/foundation/application.py,sha256=5A93XNiYJi1FEu8hIv2UStxZu--ac4KanhcWsSU25hU,94028
|
|
108
108
|
orionis/foundation/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
109
109
|
orionis/foundation/config/startup.py,sha256=btqvryeIf9lLNQ9fBff7bJMrfraEY8qrWi4y_5YAR0Q,9681
|
|
110
110
|
orionis/foundation/config/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -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=otOsCfm3C9Cc9HHO-slNc79h08eMiZuSsG_zqA0F3i4,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.653.0.dist-info/licenses/LICENCE,sha256=JhC-z_9mbpUrCfPjcl3DhDA8trNDMzb57cvRSam1avc,1463
|
|
408
|
+
orionis-0.653.0.dist-info/METADATA,sha256=QjGBZ4J_obp_gOTBFsYVPHTNKkvUTAm8yZMmLT-Tszk,4772
|
|
409
|
+
orionis-0.653.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
410
|
+
orionis-0.653.0.dist-info/top_level.txt,sha256=lyXi6jArpqJ-0zzNqd_uwsH-z9TCEBVBL-pC3Ekv7hU,8
|
|
411
|
+
orionis-0.653.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|