1616 proxy ,
1717 CallableProxyType ,
1818 ProxyType ,
19- ReferenceType )
19+ ReferenceType ,
20+ _remove_dead_weakref )
2021
2122from _weakrefset import WeakSet , _IterationGuard
2223
@@ -111,7 +112,9 @@ def remove(wr, selfref=ref(self)):
111112 if self ._iterating :
112113 self ._pending_removals .append (wr .key )
113114 else :
114- del self .data [wr .key ]
115+ # Atomic removal is necessary since this function
116+ # can be called asynchronously by the GC
117+ _remove_dead_weakref (d , wr .key )
115118 self ._remove = remove
116119 # A list of keys to be removed
117120 self ._pending_removals = []
@@ -125,9 +128,12 @@ def _commit_removals(self):
125128 # We shouldn't encounter any KeyError, because this method should
126129 # always be called *before* mutating the dict.
127130 while l :
128- del d [l .pop ()]
131+ key = l .pop ()
132+ _remove_dead_weakref (d , key )
129133
130134 def __getitem__ (self , key ):
135+ if self ._pending_removals :
136+ self ._commit_removals ()
131137 o = self .data [key ]()
132138 if o is None :
133139 raise KeyError (key )
@@ -140,9 +146,13 @@ def __delitem__(self, key):
140146 del self .data [key ]
141147
142148 def __len__ (self ):
143- return len (self .data ) - len (self ._pending_removals )
149+ if self ._pending_removals :
150+ self ._commit_removals ()
151+ return len (self .data )
144152
145153 def __contains__ (self , key ):
154+ if self ._pending_removals :
155+ self ._commit_removals ()
146156 try :
147157 o = self .data [key ]()
148158 except KeyError :
@@ -158,6 +168,8 @@ def __setitem__(self, key, value):
158168 self .data [key ] = KeyedRef (value , self ._remove , key )
159169
160170 def copy (self ):
171+ if self ._pending_removals :
172+ self ._commit_removals ()
161173 new = WeakValueDictionary ()
162174 for key , wr in self .data .items ():
163175 o = wr ()
@@ -169,6 +181,8 @@ def copy(self):
169181
170182 def __deepcopy__ (self , memo ):
171183 from copy import deepcopy
184+ if self ._pending_removals :
185+ self ._commit_removals ()
172186 new = self .__class__ ()
173187 for key , wr in self .data .items ():
174188 o = wr ()
@@ -177,6 +191,8 @@ def __deepcopy__(self, memo):
177191 return new
178192
179193 def get (self , key , default = None ):
194+ if self ._pending_removals :
195+ self ._commit_removals ()
180196 try :
181197 wr = self .data [key ]
182198 except KeyError :
@@ -190,13 +206,17 @@ def get(self, key, default=None):
190206 return o
191207
192208 def items (self ):
209+ if self ._pending_removals :
210+ self ._commit_removals ()
193211 with _IterationGuard (self ):
194212 for k , wr in self .data .items ():
195213 v = wr ()
196214 if v is not None :
197215 yield k , v
198216
199217 def keys (self ):
218+ if self ._pending_removals :
219+ self ._commit_removals ()
200220 with _IterationGuard (self ):
201221 for k , wr in self .data .items ():
202222 if wr () is not None :
@@ -214,10 +234,14 @@ def itervaluerefs(self):
214234 keep the values around longer than needed.
215235
216236 """
237+ if self ._pending_removals :
238+ self ._commit_removals ()
217239 with _IterationGuard (self ):
218240 yield from self .data .values ()
219241
220242 def values (self ):
243+ if self ._pending_removals :
244+ self ._commit_removals ()
221245 with _IterationGuard (self ):
222246 for wr in self .data .values ():
223247 obj = wr ()
@@ -290,6 +314,8 @@ def valuerefs(self):
290314 keep the values around longer than needed.
291315
292316 """
317+ if self ._pending_removals :
318+ self ._commit_removals ()
293319 return list (self .data .values ())
294320
295321
0 commit comments