11from importlib .metadata import metadata
2- from typing import Any , ClassVar , List , Optional , Type
2+ from typing import Any , List , Optional , Type , cast
33
44from dotenv import load_dotenv
55from kajson .class_registry import ClassRegistry
66from kajson .class_registry_abstract import ClassRegistryAbstract
77from kajson .kajson_manager import KajsonManager
8+ from kajson .singleton import MetaSingleton
89from pydantic import ValidationError
910from rich import print
1011from typing_extensions import Self
5556PACKAGE_VERSION = metadata (PACKAGE_NAME )["Version" ]
5657
5758
58- class Pipelex :
59- _pipelex_instance : ClassVar [Optional [Self ]] = None
60-
61- def __new__ (
62- cls ,
63- pipelex_cls : Optional [Type [Self ]] = None ,
64- pipelex_hub : Optional [PipelexHub ] = None ,
65- config_cls : Optional [Type [ConfigRoot ]] = None ,
66- ready_made_config : Optional [ConfigRoot ] = None ,
67- class_registry : Optional [ClassRegistryAbstract ] = None ,
68- template_provider : Optional [TemplateLibrary ] = None ,
69- llm_model_provider : Optional [LLMModelLibrary ] = None ,
70- inference_manager : Optional [InferenceManager ] = None ,
71- pipeline_manager : Optional [PipelineManager ] = None ,
72- pipeline_tracker : Optional [PipelineTracker ] = None ,
73- activity_manager : Optional [ActivityManagerProtocol ] = None ,
74- reporting_delegate : Optional [ReportingProtocol ] = None ,
75- ) -> Self :
76- if cls ._pipelex_instance is not None :
77- raise RuntimeError (
78- "Pipelex is a singleton, it is instantiated only once. Its instance is private. All you need is accesible through the hub."
79- )
80- if pipelex_cls is None :
81- pipelex_cls = cls
82-
83- if not issubclass (pipelex_cls , cls ):
84- raise TypeError (f"{ pipelex_cls !r} is not a subclass of { cls .__name__ } " )
85-
86- return super ().__new__ (pipelex_cls )
87-
59+ class Pipelex (metaclass = MetaSingleton ):
8860 def __init__ (
8961 self ,
90- pipelex_cls : Optional [Type [Self ]] = None ,
9162 pipelex_hub : Optional [PipelexHub ] = None ,
9263 config_cls : Optional [Type [ConfigRoot ]] = None ,
9364 ready_made_config : Optional [ConfigRoot ] = None ,
@@ -153,7 +124,11 @@ def __init__(
153124 self .pipelex_hub .set_domain_provider (domain_provider = domain_library )
154125 self .pipelex_hub .set_concept_provider (concept_provider = concept_library )
155126 self .pipelex_hub .set_pipe_provider (pipe_provider = pipe_library )
156- self .library_manager = LibraryManager (domain_library = domain_library , concept_library = concept_library , pipe_library = pipe_library )
127+ self .library_manager = LibraryManager (
128+ domain_library = domain_library ,
129+ concept_library = concept_library ,
130+ pipe_library = pipe_library ,
131+ )
157132 self .library_manager .setup ()
158133 self .pipelex_hub .set_library_manager (library_manager = self .library_manager )
159134
@@ -178,7 +153,6 @@ def __init__(
178153 self .activity_manager = ActivityManagerNoOp ()
179154 self .pipelex_hub .set_activity_manager (activity_manager = self .activity_manager )
180155
181- Pipelex ._pipelex_instance = self
182156 log .debug (f"{ PACKAGE_NAME } version { PACKAGE_VERSION } init done" )
183157
184158 def setup (
@@ -257,10 +231,12 @@ def teardown(self):
257231 self .class_registry .teardown ()
258232 func_registry .teardown ()
259233
260- Pipelex ._pipelex_instance = None
261234 project_name = get_config ().project_name
262235 log .debug (f"{ PACKAGE_NAME } version { PACKAGE_VERSION } teardown done for { get_config ().project_name } (except config & logs)" )
263236 self .pipelex_hub .reset_config ()
237+ # Clear the singleton instance from metaclass
238+ if self .__class__ in MetaSingleton .instances :
239+ del MetaSingleton .instances [self .__class__ ]
264240 print (f"{ PACKAGE_NAME } version { PACKAGE_VERSION } config reset done for { project_name } " )
265241
266242 # TODO: add kwargs to make() so that subclasses can employ specific parameters
@@ -274,10 +250,12 @@ def make(cls, structure_classes: Optional[List[Type[Any]]] = None) -> Self:
274250
275251 @classmethod
276252 def get_optional_instance (cls ) -> Optional [Self ]:
277- return cls ._pipelex_instance
253+ instance = MetaSingleton .instances .get (cls )
254+ return cast (Optional [Self ], instance )
278255
279256 @classmethod
280257 def get_instance (cls ) -> Self :
281- if cls ._pipelex_instance is None :
258+ instance = MetaSingleton .instances .get (cls )
259+ if instance is None :
282260 raise RuntimeError ("Pipelex is not initialized" )
283- return cls . _pipelex_instance
261+ return cast ( Self , instance )
0 commit comments