orionis 0.22.0__tar.gz → 0.24.0__tar.gz

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 (156) hide show
  1. {orionis-0.22.0/orionis.egg-info → orionis-0.24.0}/PKG-INFO +1 -1
  2. {orionis-0.22.0 → orionis-0.24.0}/orionis/framework.py +1 -1
  3. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/cache/app/config.py +6 -0
  4. orionis-0.24.0/orionis/luminate/container/container.py +420 -0
  5. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/container/exception.py +18 -0
  6. orionis-0.24.0/orionis/luminate/contracts/container/container_interface.py +222 -0
  7. {orionis-0.22.0 → orionis-0.24.0/orionis.egg-info}/PKG-INFO +1 -1
  8. orionis-0.22.0/orionis/luminate/container/container.py +0 -385
  9. orionis-0.22.0/orionis/luminate/contracts/container/container_interface.py +0 -152
  10. {orionis-0.22.0 → orionis-0.24.0}/LICENCE +0 -0
  11. {orionis-0.22.0 → orionis-0.24.0}/MANIFEST.in +0 -0
  12. {orionis-0.22.0 → orionis-0.24.0}/README.md +0 -0
  13. {orionis-0.22.0 → orionis-0.24.0}/orionis/__init__.py +0 -0
  14. {orionis-0.22.0 → orionis-0.24.0}/orionis/cli_manager.py +0 -0
  15. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/__init__.py +0 -0
  16. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/app.py +0 -0
  17. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/bootstrap/__init__.py +0 -0
  18. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/bootstrap/config/__init__.py +0 -0
  19. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/bootstrap/config/bootstrapper.py +0 -0
  20. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/bootstrap/config/parser.py +0 -0
  21. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/bootstrap/config/register.py +0 -0
  22. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/cache/__init__.py +0 -0
  23. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/cache/app/__init__.py +0 -0
  24. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/cache/console/__init__.py +0 -0
  25. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/cache/console/commands.py +0 -0
  26. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/config/__init__.py +0 -0
  27. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/config/dataclass/__init__.py +0 -0
  28. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/config/dataclass/app.py +0 -0
  29. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/config/dataclass/auth.py +0 -0
  30. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/config/dataclass/cache.py +0 -0
  31. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/config/dataclass/cors.py +0 -0
  32. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/config/dataclass/database.py +0 -0
  33. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/config/dataclass/filesystems.py +0 -0
  34. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/config/dataclass/logging.py +0 -0
  35. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/config/dataclass/mail.py +0 -0
  36. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/config/dataclass/queue.py +0 -0
  37. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/config/dataclass/session.py +0 -0
  38. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/config/environment.py +0 -0
  39. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/__init__.py +0 -0
  40. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/base/__init__.py +0 -0
  41. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/base/command.py +0 -0
  42. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/cache.py +0 -0
  43. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/command.py +0 -0
  44. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/command_filter.py +0 -0
  45. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/commands/__init__.py +0 -0
  46. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/commands/cache_clear.py +0 -0
  47. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/commands/help.py +0 -0
  48. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/commands/schedule_work.py +0 -0
  49. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/commands/tests.py +0 -0
  50. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/commands/version.py +0 -0
  51. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/exceptions/__init__.py +0 -0
  52. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/exceptions/cli_exception.py +0 -0
  53. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/kernel.py +0 -0
  54. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/output/__init__.py +0 -0
  55. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/output/console.py +0 -0
  56. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/output/executor.py +0 -0
  57. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/output/progress_bar.py +0 -0
  58. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/output/styles.py +0 -0
  59. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/parser.py +0 -0
  60. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/register.py +0 -0
  61. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/runner.py +0 -0
  62. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/scripts/__init__.py +0 -0
  63. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/scripts/management.py +0 -0
  64. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/tasks/__init__.py +0 -0
  65. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/console/tasks/scheduler.py +0 -0
  66. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/container/types.py +0 -0
  67. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/__init__.py +0 -0
  68. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/bootstrap/config/bootstrapper_interface.py +0 -0
  69. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/bootstrap/config/parser_interface.py +0 -0
  70. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/bootstrap/config/register_interface.py +0 -0
  71. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/cache/__init__.py +0 -0
  72. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/cache/cache_commands_interface.py +0 -0
  73. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/config/__init__.py +0 -0
  74. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/config/config_interface.py +0 -0
  75. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/config/environment_interface.py +0 -0
  76. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/console/__init__.py +0 -0
  77. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/console/base_command_interface.py +0 -0
  78. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/console/cli_cache_interface.py +0 -0
  79. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/console/command_filter_interface.py +0 -0
  80. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/console/command_interface.py +0 -0
  81. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/console/console_interface.py +0 -0
  82. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/console/executor_interface.py +0 -0
  83. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/console/kernel_interface.py +0 -0
  84. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/console/management_interface.py +0 -0
  85. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/console/parser_interface.py +0 -0
  86. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/console/progress_bar_interface.py +0 -0
  87. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/console/register_interface.py +0 -0
  88. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/console/runner_interface.py +0 -0
  89. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/console/schedule_interface.py +0 -0
  90. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/console/task_manager_interface.py +0 -0
  91. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/container/types_interface.py +0 -0
  92. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/facades/__init__.py +0 -0
  93. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/facades/env_interface.py +0 -0
  94. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/facades/log_interface.py +0 -0
  95. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/facades/paths_interface.py +0 -0
  96. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/facades/tests_interface.py +0 -0
  97. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/files/__init__.py +0 -0
  98. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/files/paths_interface.py +0 -0
  99. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/installer/__init__.py +0 -0
  100. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/installer/output_interface.py +0 -0
  101. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/installer/setup_interface.py +0 -0
  102. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/installer/upgrade_interface.py +0 -0
  103. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/log/__init__.py +0 -0
  104. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/log/logger_interface.py +0 -0
  105. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/pipelines/cli_pipeline_interface.py +0 -0
  106. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/publisher/__init__.py +0 -0
  107. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/publisher/pypi_publisher_interface.py +0 -0
  108. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/test/__init__.py +0 -0
  109. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/test/unit_test_interface.py +0 -0
  110. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/tools/__init__.py +0 -0
  111. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/tools/reflection_interface.py +0 -0
  112. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/contracts/tools/std_interface.py +0 -0
  113. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/facades/__init__.py +0 -0
  114. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/facades/environment.py +0 -0
  115. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/facades/log.py +0 -0
  116. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/facades/paths.py +0 -0
  117. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/facades/tests.py +0 -0
  118. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/files/__init__.py +0 -0
  119. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/files/paths.py +0 -0
  120. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/installer/__init__.py +0 -0
  121. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/installer/icon.ascii +0 -0
  122. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/installer/info.ascii +0 -0
  123. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/installer/output.py +0 -0
  124. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/installer/setup.py +0 -0
  125. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/installer/upgrade.py +0 -0
  126. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/log/__init__.py +0 -0
  127. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/log/logger.py +0 -0
  128. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/pipelines/__init__.py +0 -0
  129. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/pipelines/cli_pipeline.py +0 -0
  130. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/publisher/__init__.py +0 -0
  131. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/publisher/pypi.py +0 -0
  132. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/static/bg/galaxy.jpg +0 -0
  133. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/static/favicon/OrionisFrameworkFavicon.png +0 -0
  134. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/static/logos/OrionisFramework.jpg +0 -0
  135. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/static/logos/OrionisFramework.png +0 -0
  136. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/static/logos/OrionisFramework.psd +0 -0
  137. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/static/logos/OrionisFramework2.png +0 -0
  138. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/static/logos/OrionisFramework3.png +0 -0
  139. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/test/__init__.py +0 -0
  140. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/test/exception.py +0 -0
  141. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/test/unit_test.py +0 -0
  142. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/tools/__init__.py +0 -0
  143. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/tools/dot_dict.py +0 -0
  144. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/tools/reflection.py +0 -0
  145. {orionis-0.22.0 → orionis-0.24.0}/orionis/luminate/tools/std.py +0 -0
  146. {orionis-0.22.0 → orionis-0.24.0}/orionis.egg-info/SOURCES.txt +0 -0
  147. {orionis-0.22.0 → orionis-0.24.0}/orionis.egg-info/dependency_links.txt +0 -0
  148. {orionis-0.22.0 → orionis-0.24.0}/orionis.egg-info/entry_points.txt +0 -0
  149. {orionis-0.22.0 → orionis-0.24.0}/orionis.egg-info/requires.txt +0 -0
  150. {orionis-0.22.0 → orionis-0.24.0}/orionis.egg-info/top_level.txt +0 -0
  151. {orionis-0.22.0 → orionis-0.24.0}/setup.cfg +0 -0
  152. {orionis-0.22.0 → orionis-0.24.0}/setup.py +0 -0
  153. {orionis-0.22.0 → orionis-0.24.0}/tests/__init__.py +0 -0
  154. {orionis-0.22.0 → orionis-0.24.0}/tests/tools/__init__.py +0 -0
  155. {orionis-0.22.0 → orionis-0.24.0}/tests/tools/class_example.py +0 -0
  156. {orionis-0.22.0 → orionis-0.24.0}/tests/tools/test_reflection.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: orionis
3
- Version: 0.22.0
3
+ Version: 0.24.0
4
4
  Summary: Orionis Framework – Elegant, Fast, and Powerful.
5
5
  Home-page: https://github.com/orionis-framework/framework
6
6
  Author: Raul Mauricio Uñate Castro
@@ -5,7 +5,7 @@
5
5
  NAME = "orionis"
6
6
 
7
7
  # Current version of the framework
8
- VERSION = "0.22.0"
8
+ VERSION = "0.24.0"
9
9
 
10
10
  # Full name of the author or maintainer of the project
11
11
  AUTHOR = "Raul Mauricio Uñate Castro"
@@ -11,6 +11,12 @@ class CacheConfig:
11
11
  A dictionary storing registered configuration sections.
12
12
  """
13
13
  def __init__(self) -> None:
14
+ """
15
+ Initializes a new instance of the class with an empty configuration dictionary.
16
+
17
+ Attributes:
18
+ config (dict): A dictionary to store configuration settings.
19
+ """
14
20
  self.config = {}
15
21
 
16
22
  def register(self, section: str, data: Dict[str, Any]) -> None:
@@ -0,0 +1,420 @@
1
+ import inspect
2
+ from collections import deque
3
+ from threading import Lock
4
+ from typing import Callable, Any, Dict
5
+ from orionis.luminate.container.exception import OrionisContainerException, OrionisContainerValueError, OrionisContainerTypeError
6
+ from orionis.luminate.container.types import Types
7
+ from orionis.luminate.contracts.container.container_interface import IContainer
8
+
9
+ BINDING = 'binding'
10
+ TRANSIENT = 'transient'
11
+ SINGLETON = 'singleton'
12
+ SCOPED = 'scoped'
13
+ INSTANCE = 'instance'
14
+
15
+ class Container(IContainer):
16
+ """
17
+ Service container and dependency injection manager.
18
+
19
+ This class follows the singleton pattern to manage service bindings, instances,
20
+ and different lifecycle types such as transient, singleton, and scoped.
21
+ """
22
+
23
+ _instance = None
24
+ _lock = Lock()
25
+
26
+ def __new__(cls):
27
+ if cls._instance is None:
28
+ with cls._lock:
29
+ if cls._instance is None:
30
+ cls._instance = super().__new__(cls)
31
+ cls._instance._bindings = {}
32
+ cls._instance._transients = {}
33
+ cls._instance._singletons = {}
34
+ cls._instance._scoped_services = {}
35
+ cls._instance._instances = {}
36
+ cls._instance._aliases = {}
37
+ cls._instance._scoped_instances = {}
38
+ cls._instance._validate_types = Types()
39
+ return cls._instance
40
+
41
+ def _newRequest(self) -> None:
42
+ """
43
+ Reset scoped instances at the beginning of a new request.
44
+ """
45
+ self._scoped_instances = {}
46
+
47
+ def _ensureNotMain(self, concrete: Callable[..., Any]) -> str:
48
+ """
49
+ Ensure that a class is not defined in the main script.
50
+
51
+ Parameters
52
+ ----------
53
+ concrete : Callable[..., Any]
54
+ The class or function to check.
55
+
56
+ Returns
57
+ -------
58
+ str
59
+ The fully qualified name of the class.
60
+
61
+ Raises
62
+ ------
63
+ OrionisContainerValueError
64
+ If the class is defined in the main module.
65
+ """
66
+ if concrete.__module__ == "__main__":
67
+ raise OrionisContainerValueError(
68
+ "Cannot register a class from the main module in the container."
69
+ )
70
+ return f"{concrete.__module__}.{concrete.__name__}"
71
+
72
+ def _ensureUniqueService(self, obj: Any) -> None:
73
+ """
74
+ Ensure that a service is not already registered.
75
+
76
+ Parameters
77
+ ----------
78
+ obj : Any
79
+ The service to check.
80
+
81
+ Raises
82
+ ------
83
+ OrionisContainerValueError
84
+ If the service is already registered.
85
+ """
86
+ if self.has(obj):
87
+ raise OrionisContainerValueError("The service is already registered in the container.")
88
+
89
+ def _ensureIsCallable(self, concrete: Callable[..., Any]) -> None:
90
+ """
91
+ Ensure that the given implementation is callable or instantiable.
92
+
93
+ Parameters
94
+ ----------
95
+ concrete : Callable[..., Any]
96
+ The implementation to check.
97
+
98
+ Raises
99
+ ------
100
+ OrionisContainerTypeError
101
+ If the implementation is not callable.
102
+ """
103
+ if not callable(concrete):
104
+ raise OrionisContainerTypeError(
105
+ f"The implementation '{str(concrete)}' must be callable or an instantiable class."
106
+ )
107
+
108
+ def _ensureIsInstance(self, instance: Any) -> None:
109
+ """
110
+ Ensure that the given instance is a valid object.
111
+
112
+ Parameters
113
+ ----------
114
+ instance : Any
115
+ The instance to check.
116
+
117
+ Raises
118
+ ------
119
+ OrionisContainerValueError
120
+ If the instance is not a valid object.
121
+ """
122
+ if not isinstance(instance, object) or instance.__class__.__module__ in ['builtins', 'abc']:
123
+ raise OrionisContainerValueError(
124
+ f"The instance '{str(instance)}' must be a valid object."
125
+ )
126
+
127
+ def bind(self, concrete: Callable[..., Any]) -> str:
128
+ """
129
+ Bind a callable to the container.
130
+ This method ensures that the provided callable is not the main function,
131
+ is unique within the container, and is indeed callable. It then creates
132
+ a unique key for the callable based on its module and name, and stores
133
+ the callable in the container's bindings.
134
+ Args:
135
+ concrete (Callable[..., Any]): The callable to be bound to the container.
136
+ Returns:
137
+ str: The unique key generated for the callable.
138
+ """
139
+ self._ensureNotMain(concrete)
140
+ self._ensureUniqueService(concrete)
141
+ self._ensureIsCallable(concrete)
142
+
143
+ key = f"{concrete.__module__}.{concrete.__name__}"
144
+ self._bindings[key] = {
145
+ 'callback': concrete,
146
+ 'module': concrete.__module__,
147
+ 'name': concrete.__name__,
148
+ 'type': BINDING
149
+ }
150
+
151
+ return key
152
+
153
+ def transient(self, concrete: Callable[..., Any]) -> str:
154
+ """
155
+ Registers a transient service in the container.
156
+ A transient service is created each time it is requested.
157
+ Args:
158
+ concrete (Callable[..., Any]): The callable that defines the service.
159
+ Returns:
160
+ str: The unique key generated for the callable.
161
+ """
162
+ self._ensureNotMain(concrete)
163
+ self._ensureUniqueService(concrete)
164
+ self._ensureIsCallable(concrete)
165
+
166
+ key = f"{concrete.__module__}.{concrete.__name__}"
167
+ self._transients[key] = {
168
+ 'callback': concrete,
169
+ 'module': concrete.__module__,
170
+ 'name': concrete.__name__,
171
+ 'type': TRANSIENT
172
+ }
173
+
174
+ return key
175
+
176
+ def singleton(self, concrete: Callable[..., Any]) -> str:
177
+ """
178
+ Registers a callable as a singleton in the container.
179
+ This method ensures that the provided callable is not the main module,
180
+ is unique within the container, and is indeed callable. It then registers
181
+ the callable as a singleton, storing it in the container's singleton registry.
182
+ Args:
183
+ concrete (Callable[..., Any]): The callable to be registered as a singleton.
184
+ Returns:
185
+ str: The key under which the singleton is registered in the container.
186
+ """
187
+ self._ensureNotMain(concrete)
188
+ self._ensureUniqueService(concrete)
189
+ self._ensureIsCallable(concrete)
190
+
191
+ key = f"{concrete.__module__}.{concrete.__name__}"
192
+ self._singletons[key] = {
193
+ 'callback': concrete,
194
+ 'module': concrete.__module__,
195
+ 'name': concrete.__name__,
196
+ 'type': SINGLETON
197
+ }
198
+
199
+ return key
200
+
201
+ def scoped(self, concrete: Callable[..., Any]) -> str:
202
+ """
203
+ Registers a callable as a scoped service.
204
+ This method ensures that the provided callable is not the main service,
205
+ is unique, and is indeed callable. It then registers the callable in the
206
+ scoped services dictionary with relevant metadata.
207
+ Args:
208
+ concrete (Callable[..., Any]): The callable to be registered as a scoped service.
209
+ Returns:
210
+ str: The key under which the callable is registered in the scoped services dictionary.
211
+ """
212
+ self._ensureNotMain(concrete)
213
+ self._ensureUniqueService(concrete)
214
+ self._ensureIsCallable(concrete)
215
+
216
+ key = f"{concrete.__module__}.{concrete.__name__}"
217
+ self._scoped_services[key] = {
218
+ 'callback': concrete,
219
+ 'module': concrete.__module__,
220
+ 'name': concrete.__name__,
221
+ 'type': SCOPED
222
+ }
223
+
224
+ return key
225
+
226
+ def instance(self, instance: Any) -> str:
227
+ """
228
+ Registers an instance as a singleton in the container.
229
+ Args:
230
+ instance (Any): The instance to be registered as a singleton.
231
+ Returns:
232
+ str: The key under which the instance is registered in the container.
233
+ """
234
+ self._ensureNotMain(instance.__class__)
235
+ self._ensureUniqueService(instance)
236
+ self._ensureIsInstance(instance)
237
+
238
+ concrete = instance.__class__
239
+ key = f"{concrete.__module__}.{concrete.__name__}"
240
+ self._instances[key] = {
241
+ 'instance': instance,
242
+ 'module': concrete.__module__,
243
+ 'name': concrete.__name__,
244
+ 'type': INSTANCE
245
+ }
246
+
247
+ return key
248
+
249
+ def alias(self, alias: str, concrete: Any) -> None:
250
+ """
251
+ Creates an alias for a registered service.
252
+ Args:
253
+ alias (str): The alias name to be used for the service.
254
+ concrete (Any): The actual service instance or callable to be aliased.
255
+ Raises:
256
+ OrionisContainerException: If the concrete instance is not a valid object or if the alias is a primitive type.
257
+ """
258
+ if not callable(concrete) and not isinstance(concrete, object):
259
+ raise OrionisContainerException(f"The instance '{str(concrete)}' must be a valid object.")
260
+
261
+ if self._instance._validate_types.isPrimitive(alias):
262
+ raise OrionisContainerException(f"Cannot use primitive type '{alias}' as an alias.")
263
+
264
+ if isinstance(concrete, object) and concrete.__class__.__module__ not in ['builtins', 'abc']:
265
+ cls_concrete = concrete.__class__
266
+ current_key = f"{cls_concrete.__module__}.{cls_concrete.__name__}"
267
+ elif callable(concrete):
268
+ current_key = f"{concrete.__module__}.{concrete.__name__}"
269
+
270
+ self._aliases[alias] = current_key
271
+
272
+ def has(self, obj: Any) -> bool:
273
+ """
274
+ Checks if a service is registered in the container.
275
+
276
+ Parameters
277
+ ----------
278
+ obj : Any
279
+ The service class, instance, or alias to check.
280
+
281
+ Returns
282
+ -------
283
+ bool
284
+ True if the service is registered, False otherwise.
285
+ """
286
+ if isinstance(obj, str):
287
+ return obj in self._aliases or obj in (
288
+ self._bindings | self._transients | self._singletons | self._scoped_services | self._instances
289
+ )
290
+
291
+ if isinstance(obj, object) and obj.__class__.__module__ not in {'builtins', 'abc'}:
292
+ key = f"{obj.__class__.__module__}.{obj.__class__.__name__}"
293
+ return key in self._instances
294
+
295
+ if callable(obj):
296
+ key = f"{obj.__module__}.{obj.__name__}"
297
+ return key in (
298
+ self._bindings | self._transients | self._singletons | self._scoped_services | self._aliases
299
+ )
300
+
301
+ return False
302
+
303
+ def make(self, abstract: Any) -> Any:
304
+ """
305
+ Create and return an instance of a registered service.
306
+
307
+ Parameters
308
+ ----------
309
+ abstract : Any
310
+ The service class or alias to instantiate.
311
+
312
+ Returns
313
+ -------
314
+ Any
315
+ An instance of the requested service.
316
+
317
+ Raises
318
+ ------
319
+ OrionisContainerException
320
+ If the service is not found in the container.
321
+ """
322
+ key = self._aliases.get(abstract, abstract)
323
+
324
+ if key in self._instances:
325
+ return self._instances[key]['instance']
326
+
327
+ if key in self._singletons:
328
+ self._instances[key] = {'instance': self._resolve(self._singletons[key]['callback'])}
329
+ return self._instances[key]['instance']
330
+
331
+ if key in self._scoped_services:
332
+ if key not in self._scoped_instances:
333
+ self._scoped_instances[key] = self._resolve(self._scoped_services[key]['callback'])
334
+ return self._scoped_instances[key]
335
+
336
+ if key in self._transients:
337
+ return self._resolve(self._transients[key]['callback'])
338
+
339
+ if key in self._bindings:
340
+ return self._resolve(self._bindings[key]['callback'])
341
+
342
+ raise OrionisContainerException(f"Service '{abstract}' is not registered in the container.")
343
+
344
+ def _resolve(self, concrete: Callable[..., Any]) -> Any:
345
+ """
346
+ Resolve and instantiate a given service class or function.
347
+
348
+ This method analyzes the constructor of the given class (or callable),
349
+ retrieves its dependencies, and resolves them recursively, while respecting
350
+ the service lifecycle.
351
+ """
352
+
353
+ # Step 1: Retrieve the constructor signature of the class or callable.
354
+ try:
355
+ signature = inspect.signature(concrete)
356
+ except ValueError as e:
357
+ raise OrionisContainerException(f"Unable to inspect signature of {concrete}: {str(e)}")
358
+
359
+ # Step 2: Prepare a dictionary for resolved dependencies and a queue for unresolved ones.
360
+ resolved_dependencies: Dict[str, Any] = {}
361
+ unresolved_dependencies = deque()
362
+
363
+ # Step 3: Iterate through the parameters of the constructor.
364
+ for param_name, param in signature.parameters.items():
365
+ if param_name == 'self':
366
+ # Skip 'self' in methods
367
+ continue
368
+
369
+ # If parameter has no annotation and no default value, it's unresolved
370
+ if param.annotation is param.empty and param.default is param.empty:
371
+ unresolved_dependencies.append(param_name)
372
+ continue
373
+
374
+ # Resolve dependencies based on annotations (excluding primitive types)
375
+ if param.annotation is not param.empty:
376
+ param_type = param.annotation
377
+ # Check if it's a registered service, if so, resolve it through the container
378
+ if isinstance(param_type, type) and not isinstance(param_type, (int, str, bool, float)) and not issubclass(param_type, (int, str, bool, float)):
379
+ # Check if the service is registered in the container
380
+ if self.has(param_type):
381
+ resolved_dependencies[param_name] = self.make(f"{param_type.__module__}.{param_type.__name__}")
382
+ else:
383
+ resolved_dependencies[param_name] = self._resolve_dependency(param_type)
384
+ else:
385
+ resolved_dependencies[param_name] = param_type # It's a primitive, use as-is
386
+
387
+ # Resolve parameters with default values (without annotations)
388
+ elif param.default is not param.empty:
389
+ resolved_dependencies[param_name] = param.default
390
+
391
+ # Step 4: Resolve any remaining unresolved dependencies.
392
+ while unresolved_dependencies:
393
+ dep_name = unresolved_dependencies.popleft()
394
+ if dep_name not in resolved_dependencies:
395
+ resolved_dependencies[dep_name] = self._resolve_dependency(dep_name)
396
+
397
+ # Step 5: Instantiate the class with resolved dependencies.
398
+ try:
399
+ return concrete(**resolved_dependencies)
400
+ except Exception as e:
401
+ raise OrionisContainerException(f"Failed to instantiate {concrete}: {str(e)}")
402
+
403
+ def _resolve_dependency(self, dep_type: Any) -> Any:
404
+ """
405
+ Resolves a dependency based on the provided type.
406
+
407
+ This method looks for the type in the container and returns the instance,
408
+ respecting the lifecycle of the service (transient, singleton, etc.).
409
+ """
410
+ # Check if the dependency exists in the container or create it if necessary
411
+ # If it's a class type
412
+ if isinstance(dep_type, type):
413
+ if self.has(dep_type):
414
+ # Resolves the service through the container
415
+ return self.make(f"{dep_type.__module__}.{dep_type.__name__}")
416
+ else:
417
+ # Instantiate the class if not found in the container
418
+ return self._resolve(dep_type)
419
+
420
+ raise OrionisContainerException(f"Cannot resolve dependency of type {dep_type}")
@@ -34,3 +34,21 @@ class OrionisContainerValueError(ValueError):
34
34
  def __str__(self) -> str:
35
35
  """Retorna una representación en cadena de la excepción."""
36
36
  return f"[OrionisContainerValueError] {self.args[0]}"
37
+
38
+ class OrionisContainerTypeError(TypeError):
39
+ """
40
+ Custom exception for TypeError related to the Orionis container.
41
+ """
42
+
43
+ def __init__(self, message: str) -> None:
44
+ """
45
+ Initializes the exception with an error message.
46
+
47
+ Args:
48
+ message (str): Descriptive error message.
49
+ """
50
+ super().__init__(message)
51
+
52
+ def __str__(self) -> str:
53
+ """Returns a string representation of the exception."""
54
+ return f"[OrionisContainerTypeError] {self.args[0]}"
@@ -0,0 +1,222 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any, Callable
3
+
4
+ class IContainer(ABC):
5
+
6
+ @abstractmethod
7
+ def _newRequest(self) -> None:
8
+ """
9
+ Reset scoped instances at the beginning of a new request.
10
+ """
11
+ pass
12
+
13
+ @abstractmethod
14
+ def _ensureNotMain(self, concrete: Callable[..., Any]) -> str:
15
+ """
16
+ Ensure that a class is not defined in the main script.
17
+
18
+ Parameters
19
+ ----------
20
+ concrete : Callable[..., Any]
21
+ The class or function to check.
22
+
23
+ Returns
24
+ -------
25
+ str
26
+ The fully qualified name of the class.
27
+
28
+ Raises
29
+ ------
30
+ OrionisContainerValueError
31
+ If the class is defined in the main module.
32
+ """
33
+ pass
34
+
35
+ @abstractmethod
36
+ def _ensureUniqueService(self, obj: Any) -> None:
37
+ """
38
+ Ensure that a service is not already registered.
39
+
40
+ Parameters
41
+ ----------
42
+ obj : Any
43
+ The service to check.
44
+
45
+ Raises
46
+ ------
47
+ OrionisContainerValueError
48
+ If the service is already registered.
49
+ """
50
+ pass
51
+
52
+ @abstractmethod
53
+ def _ensureIsCallable(self, concrete: Callable[..., Any]) -> None:
54
+ """
55
+ Ensure that the given implementation is callable or instantiable.
56
+
57
+ Parameters
58
+ ----------
59
+ concrete : Callable[..., Any]
60
+ The implementation to check.
61
+
62
+ Raises
63
+ ------
64
+ OrionisContainerTypeError
65
+ If the implementation is not callable.
66
+ """
67
+ pass
68
+
69
+ @abstractmethod
70
+ def _ensureIsInstance(self, instance: Any) -> None:
71
+ """
72
+ Ensure that the given instance is a valid object.
73
+
74
+ Parameters
75
+ ----------
76
+ instance : Any
77
+ The instance to check.
78
+
79
+ Raises
80
+ ------
81
+ OrionisContainerValueError
82
+ If the instance is not a valid object.
83
+ """
84
+ pass
85
+
86
+ @abstractmethod
87
+ def bind(self, concrete: Callable[..., Any]) -> str:
88
+ """
89
+ Bind a callable to the container.
90
+ This method ensures that the provided callable is not the main function,
91
+ is unique within the container, and is indeed callable. It then creates
92
+ a unique key for the callable based on its module and name, and stores
93
+ the callable in the container's bindings.
94
+ Args:
95
+ concrete (Callable[..., Any]): The callable to be bound to the container.
96
+ Returns:
97
+ str: The unique key generated for the callable.
98
+ """
99
+ pass
100
+
101
+ @abstractmethod
102
+ def transient(self, concrete: Callable[..., Any]) -> str:
103
+ """
104
+ Registers a transient service in the container.
105
+ A transient service is created each time it is requested.
106
+ Args:
107
+ concrete (Callable[..., Any]): The callable that defines the service.
108
+ Returns:
109
+ str: The unique key generated for the callable.
110
+ """
111
+ pass
112
+
113
+ @abstractmethod
114
+ def singleton(self, concrete: Callable[..., Any]) -> str:
115
+ """
116
+ Registers a callable as a singleton in the container.
117
+ This method ensures that the provided callable is not the main module,
118
+ is unique within the container, and is indeed callable. It then registers
119
+ the callable as a singleton, storing it in the container's singleton registry.
120
+ Args:
121
+ concrete (Callable[..., Any]): The callable to be registered as a singleton.
122
+ Returns:
123
+ str: The key under which the singleton is registered in the container.
124
+ """
125
+ pass
126
+
127
+ @abstractmethod
128
+ def scoped(self, concrete: Callable[..., Any]) -> str:
129
+ """
130
+ Registers a callable as a scoped service.
131
+ This method ensures that the provided callable is not the main service,
132
+ is unique, and is indeed callable. It then registers the callable in the
133
+ scoped services dictionary with relevant metadata.
134
+ Args:
135
+ concrete (Callable[..., Any]): The callable to be registered as a scoped service.
136
+ Returns:
137
+ str: The key under which the callable is registered in the scoped services dictionary.
138
+ """
139
+ pass
140
+
141
+ @abstractmethod
142
+ def instance(self, instance: Any) -> str:
143
+ """
144
+ Registers an instance as a singleton in the container.
145
+ Args:
146
+ instance (Any): The instance to be registered as a singleton.
147
+ Returns:
148
+ str: The key under which the instance is registered in the container.
149
+ """
150
+ pass
151
+
152
+ @abstractmethod
153
+ def alias(self, alias: str, concrete: Any) -> None:
154
+ """
155
+ Creates an alias for a registered service.
156
+ Args:
157
+ alias (str): The alias name to be used for the service.
158
+ concrete (Any): The actual service instance or callable to be aliased.
159
+ Raises:
160
+ OrionisContainerException: If the concrete instance is not a valid object or if the alias is a primitive type.
161
+ """
162
+ pass
163
+
164
+ @abstractmethod
165
+ def has(self, obj: Any) -> bool:
166
+ """
167
+ Checks if a service is registered in the container.
168
+
169
+ Parameters
170
+ ----------
171
+ obj : Any
172
+ The service class, instance, or alias to check.
173
+
174
+ Returns
175
+ -------
176
+ bool
177
+ True if the service is registered, False otherwise.
178
+ """
179
+ pass
180
+
181
+ @abstractmethod
182
+ def make(self, abstract: Any) -> Any:
183
+ """
184
+ Create and return an instance of a registered service.
185
+
186
+ Parameters
187
+ ----------
188
+ abstract : Any
189
+ The service class or alias to instantiate.
190
+
191
+ Returns
192
+ -------
193
+ Any
194
+ An instance of the requested service.
195
+
196
+ Raises
197
+ ------
198
+ OrionisContainerException
199
+ If the service is not found in the container.
200
+ """
201
+ pass
202
+
203
+ @abstractmethod
204
+ def _resolve(self, concrete: Callable[..., Any]) -> Any:
205
+ """
206
+ Resolve and instantiate a given service class or function.
207
+
208
+ This method analyzes the constructor of the given class (or callable),
209
+ retrieves its dependencies, and resolves them recursively, while respecting
210
+ the service lifecycle.
211
+ """
212
+ pass
213
+
214
+ @abstractmethod
215
+ def _resolve_dependency(self, dep_type: Any) -> Any:
216
+ """
217
+ Resolves a dependency based on the provided type.
218
+
219
+ This method looks for the type in the container and returns the instance,
220
+ respecting the lifecycle of the service (transient, singleton, etc.).
221
+ """
222
+ pass