Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 28fd2d7

Browse files
committed
Require calling a _BoundMethodProxy to get the underlying callable.
Code that used to call `_proxy(...)` now needs to call `_proxy()(...)`. Instead of catching a ReferenceError, that could be either raised by a failure to dereference the proxy, or by the underlying callable, one can now check that `_proxy()` does not return None (to distinguish between the two cases). This is the same design as the stdlib's WeakMethod.
1 parent 7673002 commit 28fd2d7

File tree

1 file changed

+20
-125
lines changed

1 file changed

+20
-125
lines changed

lib/matplotlib/cbook/__init__.py

Lines changed: 20 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
import traceback
3131
import types
3232
import warnings
33-
from weakref import ref, WeakKeyDictionary
33+
import weakref
34+
from weakref import WeakKeyDictionary, WeakMethod
3435

3536
import numpy as np
3637

@@ -145,111 +146,6 @@ def __call__(self, s):
145146
return int(s)
146147

147148

148-
class _BoundMethodProxy(object):
149-
"""
150-
Our own proxy object which enables weak references to bound and unbound
151-
methods and arbitrary callables. Pulls information about the function,
152-
class, and instance out of a bound method. Stores a weak reference to the
153-
instance to support garbage collection.
154-
155-
@organization: IBM Corporation
156-
@copyright: Copyright (c) 2005, 2006 IBM Corporation
157-
@license: The BSD License
158-
159-
Minor bugfixes by Michael Droettboom
160-
"""
161-
def __init__(self, cb):
162-
self._hash = hash(cb)
163-
self._destroy_callbacks = []
164-
try:
165-
try:
166-
if six.PY3:
167-
self.inst = ref(cb.__self__, self._destroy)
168-
else:
169-
self.inst = ref(cb.im_self, self._destroy)
170-
except TypeError:
171-
self.inst = None
172-
if six.PY3:
173-
self.func = cb.__func__
174-
self.klass = cb.__self__.__class__
175-
else:
176-
self.func = cb.im_func
177-
self.klass = cb.im_class
178-
except AttributeError:
179-
self.inst = None
180-
self.func = cb
181-
self.klass = None
182-
183-
def add_destroy_callback(self, callback):
184-
self._destroy_callbacks.append(_BoundMethodProxy(callback))
185-
186-
def _destroy(self, wk):
187-
for callback in self._destroy_callbacks:
188-
try:
189-
callback(self)
190-
except ReferenceError:
191-
pass
192-
193-
def __getstate__(self):
194-
d = self.__dict__.copy()
195-
# de-weak reference inst
196-
inst = d['inst']
197-
if inst is not None:
198-
d['inst'] = inst()
199-
return d
200-
201-
def __setstate__(self, statedict):
202-
self.__dict__ = statedict
203-
inst = statedict['inst']
204-
# turn inst back into a weakref
205-
if inst is not None:
206-
self.inst = ref(inst)
207-
208-
def __call__(self, *args, **kwargs):
209-
"""
210-
Proxy for a call to the weak referenced object. Take
211-
arbitrary params to pass to the callable.
212-
213-
Raises `ReferenceError`: When the weak reference refers to
214-
a dead object
215-
"""
216-
if self.inst is not None and self.inst() is None:
217-
raise ReferenceError
218-
elif self.inst is not None:
219-
# build a new instance method with a strong reference to the
220-
# instance
221-
222-
mtd = types.MethodType(self.func, self.inst())
223-
224-
else:
225-
# not a bound method, just return the func
226-
mtd = self.func
227-
# invoke the callable and return the result
228-
return mtd(*args, **kwargs)
229-
230-
def __eq__(self, other):
231-
"""
232-
Compare the held function and instance with that held by
233-
another proxy.
234-
"""
235-
try:
236-
if self.inst is None:
237-
return self.func == other.func and other.inst is None
238-
else:
239-
return self.func == other.func and self.inst() == other.inst()
240-
except Exception:
241-
return False
242-
243-
def __ne__(self, other):
244-
"""
245-
Inverse of __eq__.
246-
"""
247-
return not self.__eq__(other)
248-
249-
def __hash__(self):
250-
return self._hash
251-
252-
253149
def _exception_printer(exc):
254150
traceback.print_exc()
255151

@@ -334,13 +230,11 @@ def connect(self, s, func):
334230
"""Register *func* to be called when signal *s* is generated.
335231
"""
336232
self._func_cid_map.setdefault(s, WeakKeyDictionary())
337-
# Note proxy not needed in python 3.
338-
# TODO rewrite this when support for python2.x gets dropped.
339-
proxy = _BoundMethodProxy(func)
233+
proxy = WeakMethod(func)
340234
if proxy in self._func_cid_map[s]:
341235
return self._func_cid_map[s][proxy]
342236

343-
proxy.add_destroy_callback(self._remove_proxy)
237+
weakref.finalize(proxy, self._remove_proxy)
344238
self._cid += 1
345239
cid = self._cid
346240
self._func_cid_map[s][proxy] = cid
@@ -382,12 +276,13 @@ def process(self, s, *args, **kwargs):
382276
All of the functions registered to receive callbacks on *s* will be
383277
called with ``*args`` and ``**kwargs``.
384278
"""
385-
if s in self.callbacks:
386-
for cid, proxy in list(six.iteritems(self.callbacks[s])):
279+
for ref in list(self.callbacks.get(s, {}).values()):
280+
func = ref()
281+
if func is None:
282+
self._remove_proxy(ref)
283+
else:
387284
try:
388-
proxy(*args, **kwargs)
389-
except ReferenceError:
390-
self._remove_proxy(proxy)
285+
func(*args, **kwargs)
391286
# this does not capture KeyboardInterrupt, SystemExit,
392287
# and GeneratorExit
393288
except Exception as exc:
@@ -1483,10 +1378,10 @@ class Grouper(object):
14831378
def __init__(self, init=()):
14841379
mapping = self._mapping = {}
14851380
for x in init:
1486-
mapping[ref(x)] = [ref(x)]
1381+
mapping[weakref.ref(x)] = [weakref.ref(x)]
14871382

14881383
def __contains__(self, item):
1489-
return ref(item) in self._mapping
1384+
return weakref.ref(item) in self._mapping
14901385

14911386
def clean(self):
14921387
"""
@@ -1504,13 +1399,13 @@ def join(self, a, *args):
15041399
arguments.
15051400
"""
15061401
mapping = self._mapping
1507-
set_a = mapping.setdefault(ref(a), [ref(a)])
1402+
set_a = mapping.setdefault(weakref.ref(a), [weakref.ref(a)])
15081403

15091404
for arg in args:
1510-
set_b = mapping.get(ref(arg))
1405+
set_b = mapping.get(weakref.ref(arg))
15111406
if set_b is None:
1512-
set_a.append(ref(arg))
1513-
mapping[ref(arg)] = set_a
1407+
set_a.append(weakref.ref(arg))
1408+
mapping[weakref.ref(arg)] = set_a
15141409
elif set_b is not set_a:
15151410
if len(set_b) > len(set_a):
15161411
set_a, set_b = set_b, set_a
@@ -1528,17 +1423,17 @@ def joined(self, a, b):
15281423

15291424
mapping = self._mapping
15301425
try:
1531-
return mapping[ref(a)] is mapping[ref(b)]
1426+
return mapping[weakref.ref(a)] is mapping[weakref.ref(b)]
15321427
except KeyError:
15331428
return False
15341429

15351430
def remove(self, a):
15361431
self.clean()
15371432

15381433
mapping = self._mapping
1539-
seta = mapping.pop(ref(a), None)
1434+
seta = mapping.pop(weakref.ref(a), None)
15401435
if seta is not None:
1541-
seta.remove(ref(a))
1436+
seta.remove(weakref.ref(a))
15421437

15431438
def __iter__(self):
15441439
"""
@@ -1567,7 +1462,7 @@ def get_siblings(self, a):
15671462
"""
15681463
self.clean()
15691464

1570-
siblings = self._mapping.get(ref(a), [ref(a)])
1465+
siblings = self._mapping.get(weakref.ref(a), [weakref.ref(a)])
15711466
return [x() for x in siblings]
15721467

15731468

0 commit comments

Comments
 (0)