diff --git a/.travis.yml b/.travis.yml index 8b2423d..6b1f33c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,17 @@ language: python +python: + - 3.5 + env: - TOXENV=py26 - TOXENV=py27 - - TOXENV=py32 - TOXENV=py33 - TOXENV=py34 + - TOXENV=py35 - TOXENV=rhel6 install: - - pip install tox + - pip install -U tox script: - tox diff --git a/mixbox/signals.py b/mixbox/signals.py index 67a79b5..3b81a7b 100644 --- a/mixbox/signals.py +++ b/mixbox/signals.py @@ -18,7 +18,7 @@ try: from weakref import WeakMethod except ImportError: - from weakrefmethod import WeakMethod + from .vendor.weakrefmethod import WeakMethod # Module-level logger diff --git a/mixbox/vendor/weakrefmethod.py b/mixbox/vendor/weakrefmethod.py new file mode 100644 index 0000000..6ccaa3f --- /dev/null +++ b/mixbox/vendor/weakrefmethod.py @@ -0,0 +1,56 @@ +import weakref + +"""NOTE: Remove this class in favor of using weakrefmethod as a dependency +once the PyPI version of the weakrefmethod module has the changes from +https://github.com/twang817/weakrefmethod/pull/4 +""" + +__all__ = ['WeakMethod'] + +class WeakMethod(weakref.ref): + """ + A custom 'weakref.ref' subclass which simulates a weak reference to + a bound method, working around the lifetime problem of bound methods + """ + + __slots__ = '_func_ref', '_meth_type', '_alive', '__weakref__' + + def __new__(cls, meth, callback=None): + try: + obj = meth.__self__ + func = meth.__func__ + except AttributeError: + raise TypeError('argument should be a bound method, not {0}'.format(type(meth))) + + def _cb(arg): + # The self-weakref trick is needed to avoid creating a reference cycle. + self = self_wr() + if self._alive: + self._alive = False + if callback is not None: + callback(self) + self = weakref.ref.__new__(cls, obj, _cb) + self._func_ref = weakref.ref(func, _cb) + self._meth_type = type(meth) + self._alive = True + self_wr = weakref.ref(self) + return self + + def __call__(self): + obj = super(WeakMethod, self).__call__() + func = self._func_ref() + if obj is None or func is None: + return None + return self._meth_type(func, obj) + + def __eq__(self, other): + if isinstance(other, WeakMethod): + if not self._alive or not other._alive: + return self is other + return weakref.ref.__eq__(self, other) and self._func_ref == other._func_ref + return False + + def __ne__(self, other): + return not self.__eq__(other) + + __hash__ = weakref.ref.__hash__ diff --git a/setup.py b/setup.py index 5533415..1ae3c3d 100644 --- a/setup.py +++ b/setup.py @@ -32,13 +32,6 @@ def get_version(): install_requires.append('weakrefset') -# WeakMethod was introduced in Python 3.4 -try: - from weakref import WeakMethod -except ImportError: - install_requires.append('weakrefmethod') - - extras_require = { 'docs': [ 'Sphinx==1.3.1', diff --git a/tox.ini b/tox.ini index 2454215..b2fb670 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py26, py27, py32, py33, py34, rhel6 +envlist = py26, py27, py33, py34, py35, rhel6 [testenv] commands =