rpms/sugar-base/F-10 sugar-dispatcher.patch, NONE, 1.1 sugar-base.spec, 1.8, 1.9

Simon Schampijer erikos at fedoraproject.org
Mon Nov 17 16:33:02 UTC 2008


Author: erikos

Update of /cvs/pkgs/rpms/sugar-base/F-10
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv17278

Modified Files:
	sugar-base.spec 
Added Files:
	sugar-dispatcher.patch 
Log Message:
* Mon Nov 17 2008 Simon Schampijer <simon at schampijer.de> - 0.82.2-2
- add sugar dispatcher (needed by NM 0.7 support)



sugar-dispatcher.patch:

--- NEW FILE sugar-dispatcher.patch ---
diff --git a/configure.ac b/configure.ac
index 9400a88..a0f4330 100644
--- a/configure.ac
+++ b/configure.ac
@@ -31,5 +31,6 @@ AC_OUTPUT([
 Makefile
 src/Makefile
 src/sugar/Makefile
+src/sugar/dispatch/Makefile
 po/Makefile.in
 ])
diff --git a/po/.gitignore b/po/.gitignore
new file mode 100644
index 0000000..becd153
--- /dev/null
+++ b/po/.gitignore
@@ -0,0 +1 @@
+*.gmo
diff --git a/src/sugar/Makefile.am b/src/sugar/Makefile.am
index 4da4a1e..e6db230 100644
--- a/src/sugar/Makefile.am
+++ b/src/sugar/Makefile.am
@@ -1,3 +1,5 @@
+SUBDIRS = dispatch
+
 INCLUDES = -DXDG_PREFIX=sugar_mime
 
 sugardir = $(pythondir)/sugar
diff --git a/src/sugar/dispatch/Makefile.am b/src/sugar/dispatch/Makefile.am
new file mode 100644
index 0000000..8b0e9e6
--- /dev/null
+++ b/src/sugar/dispatch/Makefile.am
@@ -0,0 +1,5 @@
+sugardir = $(pythondir)/sugar/dispatch
+sugar_PYTHON =		\
+	__init__.py	\
+	dispatcher.py	\
+	saferef.py
diff --git a/src/sugar/dispatch/__init__.py b/src/sugar/dispatch/__init__.py
new file mode 100644
index 0000000..776b1bc
--- /dev/null
+++ b/src/sugar/dispatch/__init__.py
@@ -0,0 +1,9 @@
+"""Multi-consumer multi-producer dispatching mechanism
+
+Originally based on pydispatch (BSD) http://pypi.python.org/pypi/PyDispatcher/2.0.1
+See license.txt for original license.
+
+Heavily modified for Django's purposes.
+"""
+
+from sugar.dispatch.dispatcher import Signal
diff --git a/src/sugar/dispatch/dispatcher.py b/src/sugar/dispatch/dispatcher.py
new file mode 100644
index 0000000..9e7efc1
--- /dev/null
+++ b/src/sugar/dispatch/dispatcher.py
@@ -0,0 +1,192 @@
+import weakref
+try:
+    set
+except NameError:
+    from sets import Set as set # Python 2.3 fallback
+
+from sugar.dispatch import saferef
+
+WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref)
+
+def _make_id(target):
+    if hasattr(target, 'im_func'):
+        return (id(target.im_self), id(target.im_func))
+    return id(target)
+
+class Signal(object):
+    """Base class for all signals
+    
+    Internal attributes:
+        receivers -- { receriverkey (id) : weakref(receiver) }
+    """
+    
+    def __init__(self, providing_args=None):
+        """providing_args -- A list of the arguments this signal can pass along in
+                       a send() call.
+        """
+        self.receivers = []
+        if providing_args is None:
+            providing_args = []
+        self.providing_args = set(providing_args)
+
+    def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
+        """Connect receiver to sender for signal
+    
+        receiver -- a function or an instance method which is to
+            receive signals.  Receivers must be
+            hashable objects.
+
+            if weak is True, then receiver must be weak-referencable
+            (more precisely saferef.safeRef() must be able to create
+            a reference to the receiver).
+        
+            Receivers must be able to accept keyword arguments.
+
+            If receivers have a dispatch_uid attribute, the receiver will
+              not be added if another receiver already exists with that
+              dispatch_uid.
+
+        sender -- the sender to which the receiver should respond
+            Must either be of type Signal, or None to receive events
+            from any sender.
+
+        weak -- whether to use weak references to the receiver
+            By default, the module will attempt to use weak
+            references to the receiver objects.  If this parameter
+            is false, then strong references will be used.
+        
+        dispatch_uid -- an identifier used to uniquely identify a particular
+            instance of a receiver. This will usually be a string, though it
+            may be anything hashable.
+
+        returns None
+        """
+
+        if dispatch_uid:
+            lookup_key = (dispatch_uid, _make_id(sender))
+        else:
+            lookup_key = (_make_id(receiver), _make_id(sender))
+
+        if weak:
+            receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver)
+
+        for r_key, _ in self.receivers:
+            if r_key == lookup_key:
+                break
+        else:
+            self.receivers.append((lookup_key, receiver))
+
+    def disconnect(self, receiver=None, sender=None, weak=True, dispatch_uid=None):
+        """Disconnect receiver from sender for signal
+    
+        receiver -- the registered receiver to disconnect. May be none if
+            dispatch_uid is specified.
+        sender -- the registered sender to disconnect
+        weak -- the weakref state to disconnect
+        dispatch_uid -- the unique identifier of the receiver to disconnect
+    
+        disconnect reverses the process of connect.
+
+        If weak references are used, disconnect need not be called.
+          The receiver will be remove from dispatch automatically.
+
+        returns None
+        """
+
+        if dispatch_uid:
+            lookup_key = (dispatch_uid, _make_id(sender))
+        else:
+            lookup_key = (_make_id(receiver), _make_id(sender))
+
+        for idx, (r_key, _) in enumerate(self.receivers):
+            if r_key == lookup_key:
+                del self.receivers[idx]
+
+    def send(self, sender, **named):
+        """Send signal from sender to all connected receivers.
+
+        sender -- the sender of the signal
+            Either a specific object or None.
+    
+        named -- named arguments which will be passed to receivers.
+
+        Returns a list of tuple pairs [(receiver, response), ... ].
+
+        If any receiver raises an error, the error propagates back
+        through send, terminating the dispatch loop, so it is quite
+        possible to not have all receivers called if a raises an
+        error.
+        """
+
+        responses = []
+        if not self.receivers:
+            return responses
+
+        for receiver in self._live_receivers(_make_id(sender)):
+            response = receiver(signal=self, sender=sender, **named)
+            responses.append((receiver, response))
+        return responses
+
+    def send_robust(self, sender, **named):
+        """Send signal from sender to all connected receivers catching errors
+
+        sender -- the sender of the signal
+            Can be any python object (normally one registered with
+            a connect if you actually want something to occur).
+
+        named -- named arguments which will be passed to receivers.
+            These arguments must be a subset of the argument names
+            defined in providing_args.
+
+        Return a list of tuple pairs [(receiver, response), ... ],
+        may raise DispatcherKeyError
+
+        if any receiver raises an error (specifically any subclass of Exception),
+        the error instance is returned as the result for that receiver.
+        """
+
+        responses = []
+        if not self.receivers:
+            return responses
+
+        # Call each receiver with whatever arguments it can accept.
+        # Return a list of tuple pairs [(receiver, response), ... ].
+        for receiver in self._live_receivers(_make_id(sender)):
+            try:
+                response = receiver(signal=self, sender=sender, **named)
+            except Exception, err:
+                responses.append((receiver, err))
+            else:
+                responses.append((receiver, response))
+        return responses
+
+    def _live_receivers(self, senderkey):
+        """Filter sequence of receivers to get resolved, live receivers
+
+        This checks for weak references
+        and resolves them, then returning only live
+        receivers.
+        """
+        none_senderkey = _make_id(None)
+
+        for (receiverkey, r_senderkey), receiver in self.receivers:
+            if r_senderkey == none_senderkey or r_senderkey == senderkey:
+                if isinstance(receiver, WEAKREF_TYPES):
+                    # Dereference the weak reference.
+                    receiver = receiver()
+                    if receiver is not None:
+                        yield receiver
+                else:
+                    yield receiver
+
+    def _remove_receiver(self, receiver):
+        """Remove dead receivers from connections."""
+
+        to_remove = []
+        for key, connected_receiver in self.receivers:
+            if connected_receiver == receiver:
+                to_remove.append(key)
+        for key in to_remove:
+            for idx, (r_key, _) in enumerate(self.receivers):
+                if r_key == key:
+                    del self.receivers[idx]
diff --git a/src/sugar/dispatch/license.txt b/src/sugar/dispatch/license.txt
new file mode 100644
index 0000000..0272c28
--- /dev/null
+++ b/src/sugar/dispatch/license.txt
@@ -0,0 +1,66 @@
+sugar.dispatch was originally forked from django.dispatch
+
+Copyright (c) Django Software Foundation and individual contributors.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    1. Redistributions of source code must retain the above copyright notice, 
+       this list of conditions and the following disclaimer.
+    
+    2. Redistributions in binary form must reproduce the above copyright 
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+    3. Neither the name of Django nor the names of its contributors may be used
+       to endorse or promote products derived from this software without
+       specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+django.dispatch was originally forked from PyDispatcher.
+
+PyDispatcher License:
+
+    Copyright (c) 2001-2003, Patrick K. O'Brien and Contributors
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+    
+        Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+    
+        Redistributions in binary form must reproduce the above
+        copyright notice, this list of conditions and the following
+        disclaimer in the documentation and/or other materials
+        provided with the distribution.
+    
+        The name of Patrick K. O'Brien, or the name of any Contributor,
+        may not be used to endorse or promote products derived from this 
+        software without specific prior written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+    COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE. 
+
diff --git a/src/sugar/dispatch/saferef.py b/src/sugar/dispatch/saferef.py
new file mode 100644
index 0000000..8bcfd8a
--- /dev/null
+++ b/src/sugar/dispatch/saferef.py
@@ -0,0 +1,250 @@
+"""
+"Safe weakrefs", originally from pyDispatcher.
+
+Provides a way to safely weakref any function, including bound methods (which
+aren't handled by the core weakref module).
+"""
+
+import weakref, traceback
+
+def safeRef(target, onDelete = None):
+    """Return a *safe* weak reference to a callable target
+
+    target -- the object to be weakly referenced, if it's a
+        bound method reference, will create a BoundMethodWeakref,
+        otherwise creates a simple weakref.
+    onDelete -- if provided, will have a hard reference stored
+        to the callable to be called after the safe reference
+        goes out of scope with the reference object, (either a
+        weakref or a BoundMethodWeakref) as argument.
+    """
+    if hasattr(target, 'im_self'):
+        if target.im_self is not None:
+            # Turn a bound method into a BoundMethodWeakref instance.
+            # Keep track of these instances for lookup by disconnect().
+            assert hasattr(target, 'im_func'), """safeRef target %r has im_self, but no im_func, don't know how to create reference"""%( target,)
+            reference = get_bound_method_weakref(
+                target=target,
+                onDelete=onDelete
+            )
+            return reference
+    if callable(onDelete):
+        return weakref.ref(target, onDelete)
+    else:
+        return weakref.ref( target )
+
+class BoundMethodWeakref(object):
+    """'Safe' and reusable weak references to instance methods
+
+    BoundMethodWeakref objects provide a mechanism for
+    referencing a bound method without requiring that the
+    method object itself (which is normally a transient
+    object) is kept alive.  Instead, the BoundMethodWeakref
+    object keeps weak references to both the object and the
+    function which together define the instance method.
+
+    Attributes:
+        key -- the identity key for the reference, calculated
+            by the class's calculateKey method applied to the
+            target instance method
+        deletionMethods -- sequence of callable objects taking
+            single argument, a reference to this object which
+            will be called when *either* the target object or
+            target function is garbage collected (i.e. when
+            this object becomes invalid).  These are specified
+            as the onDelete parameters of safeRef calls.
+        weakSelf -- weak reference to the target object
+        weakFunc -- weak reference to the target function
+
+    Class Attributes:
+        _allInstances -- class attribute pointing to all live
+            BoundMethodWeakref objects indexed by the class's
+            calculateKey(target) method applied to the target
+            objects.  This weak value dictionary is used to
+            short-circuit creation so that multiple references
+            to the same (object, function) pair produce the
+            same BoundMethodWeakref instance.
+
+    """
+    
+    _allInstances = weakref.WeakValueDictionary()
+    
+    def __new__( cls, target, onDelete=None, *arguments,**named ):
+        """Create new instance or return current instance
+
+        Basically this method of construction allows us to
+        short-circuit creation of references to already-
+        referenced instance methods.  The key corresponding
+        to the target is calculated, and if there is already
+        an existing reference, that is returned, with its
+        deletionMethods attribute updated.  Otherwise the
+        new instance is created and registered in the table
+        of already-referenced methods.
+        """
+        key = cls.calculateKey(target)
+        current =cls._allInstances.get(key)
+        if current is not None:
+            current.deletionMethods.append( onDelete)
+            return current
+        else:
+            base = super( BoundMethodWeakref, cls).__new__( cls )
+            cls._allInstances[key] = base
+            base.__init__( target, onDelete, *arguments,**named)
+            return base
+    
+    def __init__(self, target, onDelete=None):
+        """Return a weak-reference-like instance for a bound method
+
+        target -- the instance-method target for the weak
+            reference, must have im_self and im_func attributes
+            and be reconstructable via:
+                target.im_func.__get__( target.im_self )
+            which is true of built-in instance methods.
+        onDelete -- optional callback which will be called
+            when this weak reference ceases to be valid
+            (i.e. either the object or the function is garbage
+            collected).  Should take a single argument,
+            which will be passed a pointer to this object.
+        """
+        def remove(weak, self=self):
+            """Set self.isDead to true when method or instance is destroyed"""
+            methods = self.deletionMethods[:]
+            del self.deletionMethods[:]
+            try:
+                del self.__class__._allInstances[ self.key ]
+            except KeyError:
+                pass
+            for function in methods:
+                try:
+                    if callable( function ):
+                        function( self )
+                except Exception, e:
+                    try:
+                        traceback.print_exc()
+                    except AttributeError, err:
+                        print '''Exception during saferef %s cleanup function %s: %s'''%(
+                            self, function, e
+                        )
+        self.deletionMethods = [onDelete]
+        self.key = self.calculateKey( target )
+        self.weakSelf = weakref.ref(target.im_self, remove)
+        self.weakFunc = weakref.ref(target.im_func, remove)
+        self.selfName = str(target.im_self)
+        self.funcName = str(target.im_func.__name__)
+    
+    def calculateKey( cls, target ):
+        """Calculate the reference key for this reference
+
+        Currently this is a two-tuple of the id()'s of the
+        target object and the target function respectively.
+        """
+        return (id(target.im_self),id(target.im_func))
+    calculateKey = classmethod( calculateKey )
+    
+    def __str__(self):
+        """Give a friendly representation of the object"""
+        return """%s( %s.%s )"""%(
+            self.__class__.__name__,
+            self.selfName,
+            self.funcName,
+        )
+    
+    __repr__ = __str__
+    
+    def __nonzero__( self ):
+        """Whether we are still a valid reference"""
+        return self() is not None
+    
+    def __cmp__( self, other ):
+        """Compare with another reference"""
+        if not isinstance (other,self.__class__):
+            return cmp( self.__class__, type(other) )
+        return cmp( self.key, other.key)
+    
+    def __call__(self):
+        """Return a strong reference to the bound method
+
+        If the target cannot be retrieved, then will
+        return None, otherwise returns a bound instance
+        method for our object and function.
+
+        Note:
+            You may call this method any number of times,
+            as it does not invalidate the reference.
+        """
+        target = self.weakSelf()
+        if target is not None:
+            function = self.weakFunc()
+            if function is not None:
+                return function.__get__(target)
+        return None
+
+class BoundNonDescriptorMethodWeakref(BoundMethodWeakref):
+    """A specialized BoundMethodWeakref, for platforms where instance methods
+    are not descriptors.
+
+    It assumes that the function name and the target attribute name are the
+    same, instead of assuming that the function is a descriptor. This approach
+    is equally fast, but not 100% reliable because functions can be stored on an
+    attribute named differenty than the function's name such as in:
+
+    class A: pass
+    def foo(self): return "foo"
+    A.bar = foo
+
+    But this shouldn't be a common use case. So, on platforms where methods
+    aren't descriptors (such as Jython) this implementation has the advantage
+    of working in the most cases.
+    """
+    def __init__(self, target, onDelete=None):
+        """Return a weak-reference-like instance for a bound method
+
+        target -- the instance-method target for the weak
+            reference, must have im_self and im_func attributes
+            and be reconstructable via:
+                target.im_func.__get__( target.im_self )
+            which is true of built-in instance methods.
+        onDelete -- optional callback which will be called
+            when this weak reference ceases to be valid
+            (i.e. either the object or the function is garbage
+            collected).  Should take a single argument,
+            which will be passed a pointer to this object.
+        """
+        assert getattr(target.im_self, target.__name__) == target, \
+               ("method %s isn't available as the attribute %s of %s" %
+                (target, target.__name__, target.im_self))
+        super(BoundNonDescriptorMethodWeakref, self).__init__(target, onDelete)
+
+    def __call__(self):
+        """Return a strong reference to the bound method
+
+        If the target cannot be retrieved, then will
+        return None, otherwise returns a bound instance
+        method for our object and function.
+
+        Note:
+            You may call this method any number of times,
+            as it does not invalidate the reference.
+        """
+        target = self.weakSelf()
+        if target is not None:
+            function = self.weakFunc()
+            if function is not None:
+                # Using curry() would be another option, but it erases the
+                # "signature" of the function. That is, after a function is
+                # curried, the inspect module can't be used to determine how
+                # many arguments the function expects, nor what keyword
+                # arguments it supports, and pydispatcher needs this
+                # information.
+                return getattr(target, function.__name__)
+        return None
+
+def get_bound_method_weakref(target, onDelete):
+    """Instantiates the appropiate BoundMethodWeakRef, depending on the details of
+    the underlying class method implementation"""
+    if hasattr(target, '__get__'):
+        # target method is a descriptor, so the default implementation works:
+        return BoundMethodWeakref(target=target, onDelete=onDelete)
+    else:
+        # no luck, use the alternative implementation:
+        return BoundNonDescriptorMethodWeakref(target=target, onDelete=onDelete)


Index: sugar-base.spec
===================================================================
RCS file: /cvs/pkgs/rpms/sugar-base/F-10/sugar-base.spec,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- sugar-base.spec	30 Aug 2008 00:22:55 -0000	1.8
+++ sugar-base.spec	17 Nov 2008 16:32:31 -0000	1.9
@@ -3,13 +3,15 @@
 Summary: Base Sugar library
 Name: sugar-base
 Version: 0.82.2
-Release: 1%{?dist}
+Release: 2%{?dist}
 URL: http://dev.laptop.org/
 Source0: http://dev.laptop.org/pub/sugar/sources/sugar-base/%{name}-%{version}.tar.bz2
 License: LGPLv2
 Group: System Environment/Libraries
 Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
+Patch1: sugar-dispatcher.patch
+
 BuildRequires: python-devel
 BuildRequires: pygobject2-devel
 BuildRequires: pygtk2-codegen
@@ -25,6 +27,8 @@
 %prep
 %setup -q
 
+%patch1 -p1 -b .sugar-dispatcher
+
 %build
 %configure
 make
@@ -43,6 +47,9 @@
 %{python_sitelib}/*
 
 %changelog
+* Mon Nov 17 2008 Simon Schampijer <simon at schampijer.de> - 0.82.2-2
+- add sugar dispatcher (needed by NM 0.7 support)
+
 * Thu Aug 28 2008 Marco Pesenti Gritti <mpg at redhat.com> - 0.82.2-1
 - Translation updates
 




More information about the scm-commits mailing list