@@ -14,30 +14,54 @@ class ThreadMappingContext(BaseContext):
1414
1515 def __init__ (self ):
1616 self .__local = threading .local ()
17- self .__local .data = {}
17+ self .ensure_data ()
18+
19+ def ensure_data (self ):
20+ """Ensure the current thread has a `data` attribute in its local storage.
21+
22+ The `threading.local()` object provides each thread with its own independent attribute
23+ namespace. Attributes created in one thread are not visible to other threads. This means
24+ that even if `data` was initialized in the thread where this object was constructed,
25+ new threads will not automatically have a `data` attribute since the constructor is not
26+ run again.
27+
28+ Calling this method guarantees that `self.__local.data` exists in the *current* thread,
29+ creating an empty dictionary if needed. It must be invoked on every access path
30+ (e.g., __getitem__, __iter__).
31+ """
32+ if not hasattr (self .__local , 'data' ):
33+ self .__local .data = {}
1834
1935 def __str__ (self ):
36+ self .ensure_data ()
2037 return str (self .__local .data )
2138
2239 def __getitem__ (self , __key ):
40+ self .ensure_data ()
2341 return self .__local .data [__key ]
2442
2543 def __setitem__ (self , __key , __value ):
44+ self .ensure_data ()
2645 self .__local .data [__key ] = __value
2746
2847 def __delitem__ (self , __key ):
48+ self .ensure_data ()
2949 del self .__local .data [__key ]
3050
3151 def __len__ (self ):
52+ self .ensure_data ()
3253 return len (self .__local .data )
3354
3455 def __iter__ (self ):
56+ self .ensure_data ()
3557 return self .__local .data .__iter__ ()
3658
3759 def __contains__ (self , __o ):
60+ self .ensure_data ()
3861 return self .__local .data .__contains__ (__o )
3962
4063 def init (self , data = None ):
64+ self .ensure_data ()
4165 if data is None :
4266 self .__local .data = {}
4367 else :
@@ -46,18 +70,23 @@ def init(self, data=None):
4670 self .__local .data = data
4771
4872 def get (self , key , default = None ):
73+ self .ensure_data ()
4974 return self .__local .data .get (key , default )
5075
5176 def pop (self , key , default = __marker ):
77+ self .ensure_data ()
5278 if default == self .__marker :
5379 return self .__local .data .pop (key )
5480 return self .__local .data .pop (key , default )
5581
5682 def set (self , key , value ):
83+ self .ensure_data ()
5784 self .__local .data [key ] = value
5885
5986 def delete (self , key ):
87+ self .ensure_data ()
6088 del self .__local .data [key ]
6189
6290 def clear (self ):
91+ self .ensure_data ()
6392 self .__local .data = {}
0 commit comments