# Copyright (C) 2007-2010 Samuel Abels. # # This file is part of SpiffWorkflow. # # SpiffWorkflow is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 3.0 of the License, or (at your option) any later version. # # SpiffWorkflow is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA # # DO NOT EDIT THIS FILE. # THIS CODE IS TAKE FROM Exscript.util: # https://github.com/knipknap/exscript/tree/master/src/Exscript/util # """ Weak references to bound and unbound methods. """ import weakref class DeadMethodCalled(Exception): """ Raised by :class:`WeakMethod` if it is called when the referenced object is already dead. """ pass class WeakMethod(object): """ Do not create this class directly; use :class:`ref()` instead. """ __slots__ = 'name', 'callback' def __init__(self, name, callback): """ Constructor. Do not use directly, use :class:`ref()` instead. """ self.name = name self.callback = callback def _dead(self, ref): if self.callback is not None: self.callback(self) def get_function(self): """ Returns the referenced method/function if it is still alive. Returns None otherwise. :rtype: callable|None :returns: The referenced function if it is still alive. """ raise NotImplementedError() def isalive(self): """ Returns True if the referenced function is still alive, False otherwise. :rtype: bool :returns: Whether the referenced function is still alive. """ return self.get_function() is not None def __call__(self, *args, **kwargs): """ Proxied to the underlying function or method. Raises :class:`DeadMethodCalled` if the referenced function is dead. :rtype: object :returns: Whatever the referenced function returned. """ method = self.get_function() if method is None: raise DeadMethodCalled('method called on dead object ' + self.name) method(*args, **kwargs) class _WeakMethodBound(WeakMethod): __slots__ = 'name', 'callback', 'f', 'c' def __init__(self, f, callback): name = f.__self__.__class__.__name__ + '.' + f.__func__.__name__ WeakMethod.__init__(self, name, callback) self.f = f.__func__ self.c = weakref.ref(f.__self__, self._dead) def get_function(self): cls = self.c() if cls is None: return None return getattr(cls, self.f.__name__) class _WeakMethodFree(WeakMethod): __slots__ = 'name', 'callback', 'f' def __init__(self, f, callback): WeakMethod.__init__(self, f.__class__.__name__, callback) self.f = weakref.ref(f, self._dead) def get_function(self): return self.f() def ref(function, callback=None): """ Returns a weak reference to the given method or function. If the callback argument is not None, it is called as soon as the referenced function is garbage deleted. :type function: callable :param function: The function to reference. :type callback: callable :param callback: Called when the function dies. """ try: function.__func__ except AttributeError: return _WeakMethodFree(function, callback) return _WeakMethodBound(function, callback)