1818 proxy ,
1919 CallableProxyType ,
2020 ProxyType ,
21- ReferenceType )
21+ ReferenceType ,
22+ _remove_dead_weakref )
2223
2324from _weakrefset import WeakSet , _IterationGuard
2425
@@ -58,7 +59,9 @@ def remove(wr, selfref=ref(self)):
5859 if self ._iterating :
5960 self ._pending_removals .append (wr .key )
6061 else :
61- del self .data [wr .key ]
62+ # Atomic removal is necessary since this function
63+ # can be called asynchronously by the GC
64+ _remove_dead_weakref (self .data , wr .key )
6265 self ._remove = remove
6366 # A list of keys to be removed
6467 self ._pending_removals = []
@@ -71,9 +74,12 @@ def _commit_removals(self):
7174 # We shouldn't encounter any KeyError, because this method should
7275 # always be called *before* mutating the dict.
7376 while l :
74- del d [l .pop ()]
77+ key = l .pop ()
78+ _remove_dead_weakref (d , key )
7579
7680 def __getitem__ (self , key ):
81+ if self ._pending_removals :
82+ self ._commit_removals ()
7783 o = self .data [key ]()
7884 if o is None :
7985 raise KeyError , key
@@ -86,13 +92,17 @@ def __delitem__(self, key):
8692 del self .data [key ]
8793
8894 def __contains__ (self , key ):
95+ if self ._pending_removals :
96+ self ._commit_removals ()
8997 try :
9098 o = self .data [key ]()
9199 except KeyError :
92100 return False
93101 return o is not None
94102
95103 def has_key (self , key ):
104+ if self ._pending_removals :
105+ self ._commit_removals ()
96106 try :
97107 o = self .data [key ]()
98108 except KeyError :
@@ -113,6 +123,8 @@ def clear(self):
113123 self .data .clear ()
114124
115125 def copy (self ):
126+ if self ._pending_removals :
127+ self ._commit_removals ()
116128 new = WeakValueDictionary ()
117129 for key , wr in self .data .items ():
118130 o = wr ()
@@ -124,6 +136,8 @@ def copy(self):
124136
125137 def __deepcopy__ (self , memo ):
126138 from copy import deepcopy
139+ if self ._pending_removals :
140+ self ._commit_removals ()
127141 new = self .__class__ ()
128142 for key , wr in self .data .items ():
129143 o = wr ()
@@ -132,6 +146,8 @@ def __deepcopy__(self, memo):
132146 return new
133147
134148 def get (self , key , default = None ):
149+ if self ._pending_removals :
150+ self ._commit_removals ()
135151 try :
136152 wr = self .data [key ]
137153 except KeyError :
@@ -145,6 +161,8 @@ def get(self, key, default=None):
145161 return o
146162
147163 def items (self ):
164+ if self ._pending_removals :
165+ self ._commit_removals ()
148166 L = []
149167 for key , wr in self .data .items ():
150168 o = wr ()
@@ -153,13 +171,17 @@ def items(self):
153171 return L
154172
155173 def iteritems (self ):
174+ if self ._pending_removals :
175+ self ._commit_removals ()
156176 with _IterationGuard (self ):
157177 for wr in self .data .itervalues ():
158178 value = wr ()
159179 if value is not None :
160180 yield wr .key , value
161181
162182 def iterkeys (self ):
183+ if self ._pending_removals :
184+ self ._commit_removals ()
163185 with _IterationGuard (self ):
164186 for k in self .data .iterkeys ():
165187 yield k
@@ -176,11 +198,15 @@ def itervaluerefs(self):
176198 keep the values around longer than needed.
177199
178200 """
201+ if self ._pending_removals :
202+ self ._commit_removals ()
179203 with _IterationGuard (self ):
180204 for wr in self .data .itervalues ():
181205 yield wr
182206
183207 def itervalues (self ):
208+ if self ._pending_removals :
209+ self ._commit_removals ()
184210 with _IterationGuard (self ):
185211 for wr in self .data .itervalues ():
186212 obj = wr ()
@@ -212,13 +238,13 @@ def pop(self, key, *args):
212238 return o
213239
214240 def setdefault (self , key , default = None ):
241+ if self ._pending_removals :
242+ self ._commit_removals ()
215243 try :
216244 o = self .data [key ]()
217245 except KeyError :
218246 o = None
219247 if o is None :
220- if self ._pending_removals :
221- self ._commit_removals ()
222248 self .data [key ] = KeyedRef (default , self ._remove , key )
223249 return default
224250 else :
@@ -254,9 +280,13 @@ def valuerefs(self):
254280 keep the values around longer than needed.
255281
256282 """
283+ if self ._pending_removals :
284+ self ._commit_removals ()
257285 return self .data .values ()
258286
259287 def values (self ):
288+ if self ._pending_removals :
289+ self ._commit_removals ()
260290 L = []
261291 for wr in self .data .values ():
262292 o = wr ()
0 commit comments