@@ -67,36 +67,41 @@ class JobsProgress:
6767 """Track the state of current jobs in progress using shared memory."""
6868
6969 _instance : Optional ['JobsProgress' ] = None
70- _manager : SyncManager
71- _shared_data : Any
72- _lock : Any
73-
70+ # Singleton
7471 def __new__ (cls ):
7572 if cls ._instance is None :
76- instance = object .__new__ (cls )
77- # Initialize instance variables
78- instance ._manager = Manager ()
79- instance ._shared_data = instance ._manager .dict ()
80- instance ._shared_data ['jobs' ] = instance ._manager .list ()
81- instance ._lock = instance ._manager .Lock ()
82- cls ._instance = instance
73+ cls ._instance = super ().__new__ (cls )
8374 return cls ._instance
8475
8576 def __init__ (self ):
86- # Everything is already initialized in __new__
87- pass
77+ if not hasattr (self , '_initialized' ):
78+ self ._manager : Optional [SyncManager ] = None
79+ self ._shared_data : Optional [Any ] = None
80+ self ._lock : Optional [Any ] = None
81+ self ._initialized = True
82+
83+ def _ensure_initialized (self ):
84+ """Initialize the multiprocessing manager and shared data structures only when needed."""
85+ if self ._manager is None :
86+ self ._manager = Manager ()
87+ self ._shared_data = self ._manager .dict ()
88+ self ._shared_data ['jobs' ] = self ._manager .list ()
89+ self ._lock = self ._manager .Lock ()
8890
8991 def __repr__ (self ) -> str :
9092 return f"<{ self .__class__ .__name__ } >: { self .get_job_list ()} "
9193
9294 def clear (self ) -> None :
95+ self ._ensure_initialized ()
9396 with self ._lock :
9497 self ._shared_data ['jobs' ][:] = []
9598
9699 def add (self , element : Any ):
97100 """
98101 Adds a Job object to the set.
99102 """
103+ self ._ensure_initialized ()
104+
100105 if isinstance (element , str ):
101106 job_dict = {'id' : element }
102107 elif isinstance (element , dict ):
@@ -123,6 +128,8 @@ def get(self, element: Any) -> Optional[Job]:
123128
124129 If the element is a string, searches for Job with that id.
125130 """
131+ self ._ensure_initialized ()
132+
126133 if isinstance (element , str ):
127134 search_id = element
128135 elif isinstance (element , Job ):
@@ -142,6 +149,8 @@ def remove(self, element: Any):
142149 """
143150 Removes a Job object from the set.
144151 """
152+ self ._ensure_initialized ()
153+
145154 if isinstance (element , str ):
146155 job_id = element
147156 elif isinstance (element , dict ):
@@ -153,7 +162,6 @@ def remove(self, element: Any):
153162
154163 with self ._lock :
155164 job_list = self ._shared_data ['jobs' ]
156- # Find and remove the job
157165 for i , job_dict in enumerate (job_list ):
158166 if job_dict ['id' ] == job_id :
159167 del job_list [i ]
@@ -164,6 +172,9 @@ def get_job_list(self) -> Optional[str]:
164172 """
165173 Returns the list of job IDs as comma-separated string.
166174 """
175+ if self ._manager is None :
176+ return None
177+
167178 with self ._lock :
168179 job_list = list (self ._shared_data ['jobs' ])
169180
@@ -177,11 +188,17 @@ def get_job_count(self) -> int:
177188 """
178189 Returns the number of jobs.
179190 """
191+ if self ._manager is None :
192+ return 0
193+
180194 with self ._lock :
181195 return len (self ._shared_data ['jobs' ])
182196
183197 def __iter__ (self ):
184198 """Make the class iterable - returns Job objects"""
199+ if self ._manager is None :
200+ return iter ([])
201+
185202 with self ._lock :
186203 # Create a snapshot of jobs to avoid holding lock during iteration
187204 job_dicts = list (self ._shared_data ['jobs' ])
@@ -195,14 +212,15 @@ def __len__(self):
195212
196213 def __contains__ (self , element : Any ) -> bool :
197214 """Support 'in' operator"""
215+ if self ._manager is None :
216+ return False
217+
198218 if isinstance (element , str ):
199219 search_id = element
200220 elif isinstance (element , Job ):
201221 search_id = element .id
202- elif isinstance (element , dict ):
203- search_id = element .get ('id' )
204222 else :
205- return False
223+ raise TypeError ( "Only Job objects can be checked in JobsProgress." )
206224
207225 with self ._lock :
208226 for job_dict in self ._shared_data ['jobs' ]:
0 commit comments