[Zope-CVS] CVS: Packages/pypes/pypes - __init__.py:1.2 exceptions.py:1.3 identity.py:1.5 interfaces.py:1.10 serviceconfig.py:1.3 services.py:1.4

Casey Duncan casey at zope.com
Mon Feb 9 16:15:28 EST 2004


Update of /cvs-repository/Packages/pypes/pypes
In directory cvs.zope.org:/tmp/cvs-serv11692/pypes

Modified Files:
	__init__.py exceptions.py identity.py interfaces.py 
	serviceconfig.py services.py 
Log Message:
dos -> unix line endings


=== Packages/pypes/pypes/__init__.py 1.1.1.1 => 1.2 ===
--- Packages/pypes/pypes/__init__.py:1.1.1.1	Mon Aug  4 00:46:03 2003
+++ Packages/pypes/pypes/__init__.py	Mon Feb  9 16:14:57 2004
@@ -1,37 +1,37 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Pypes: Persistence services for python
-
-Services for building object-database applications in Python
-
-$Id$"""
-
-import serviceconfig, identity, event
-
-# XXX These should probably be in a config file
-default_services = {
-    'identity': identity.IdentityService,
-    'event': event.EventService,
-}
-
-def initialize(connection):
-    """Setup default pypes services for connection. Does not affect any existing
-    services there.
-    
-    connection -- an open zodb connection object
-    """
-    serviceconfig.initServices(connection)
-    for name, factory in default_services.items():
-        serviceconfig.addService(connection, name, factory())
-    
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Pypes: Persistence services for python
+
+Services for building object-database applications in Python
+
+$Id$"""
+
+import serviceconfig, identity, event
+
+# XXX These should probably be in a config file
+default_services = {
+    'identity': identity.IdentityService,
+    'event': event.EventService,
+}
+
+def initialize(connection):
+    """Setup default pypes services for connection. Does not affect any existing
+    services there.
+    
+    connection -- an open zodb connection object
+    """
+    serviceconfig.initServices(connection)
+    for name, factory in default_services.items():
+        serviceconfig.addService(connection, name, factory())
+    


=== Packages/pypes/pypes/exceptions.py 1.2 => 1.3 ===
--- Packages/pypes/pypes/exceptions.py:1.2	Sun Aug 10 22:32:15 2003
+++ Packages/pypes/pypes/exceptions.py	Mon Feb  9 16:14:57 2004
@@ -1,48 +1,48 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""pypes exception types
-
-$Id$"""
-
-class PypesError(Exception):
-	"""General pypes error base"""
-
-class PypesLookupError(PypesError, LookupError):
-    """Persistent pypes component lookup failure"""
-
-class IdentityError(PypesError):
-    """General identity service error"""
-    
-class IdentityKeyError(IdentityError, KeyError):
-    """Identity service received invalid identifier"""
-
-class SetLookupError(PypesError, LookupError):
-    """Set lookup failed"""
-    
-class EventRegistrationError(PypesError):
-    """Event registration operation failed"""
-    
-class VetoEvent(Exception):
-    """An exception used when an event listener wishes to signal an
-    event sender to cancel the operation that generated the event.
-    """
-
-class GraphLookupError(PypesError):
-    """Lookup of object from graph failed"""
-    
-class GraphValueError(PypesError):
-    """Value could not be retreived from graph"""
-    
-class GraphCycleError(PypesError):
-    """Cycle detected during operation for acyclic graph"""
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""pypes exception types
+
+$Id$"""
+
+class PypesError(Exception):
+	"""General pypes error base"""
+
+class PypesLookupError(PypesError, LookupError):
+    """Persistent pypes component lookup failure"""
+
+class IdentityError(PypesError):
+    """General identity service error"""
+    
+class IdentityKeyError(IdentityError, KeyError):
+    """Identity service received invalid identifier"""
+
+class SetLookupError(PypesError, LookupError):
+    """Set lookup failed"""
+    
+class EventRegistrationError(PypesError):
+    """Event registration operation failed"""
+    
+class VetoEvent(Exception):
+    """An exception used when an event listener wishes to signal an
+    event sender to cancel the operation that generated the event.
+    """
+
+class GraphLookupError(PypesError):
+    """Lookup of object from graph failed"""
+    
+class GraphValueError(PypesError):
+    """Value could not be retreived from graph"""
+    
+class GraphCycleError(PypesError):
+    """Cycle detected during operation for acyclic graph"""


=== Packages/pypes/pypes/identity.py 1.4 => 1.5 ===
--- Packages/pypes/pypes/identity.py:1.4	Sun Feb  8 22:56:21 2004
+++ Packages/pypes/pypes/identity.py	Mon Feb  9 16:14:57 2004
@@ -1,325 +1,325 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Pypes identity service
-
-Provides unique tokens for identifying persistent objects.
-
-$Id$"""
-
-from __future__ import generators
-from random import randint
-from persistent import Persistent
-from types import IntType
-from zope.interface import implements
-from BTrees.IIBTree \
-    import IITreeSet, multiunion, union, intersection, difference
-from BTrees.IOBTree import IOBTree
-from BTrees.Length import Length
-from pypes import services
-from pypes.event import PypesMessage
-from pypes.interfaces import IIdentityService, IIdentitySet, IIdentityMessage
-from pypes.exceptions import PypesError, PypesLookupError
-from pypes.exceptions import IdentityError, IdentityKeyError, SetLookupError
-
-
-class IdentityService(Persistent):
-    """Identity service providing integer identifiers. Before this service
-    can be used, it must be committed to the database
-    """
-    
-    implements(IIdentityService)
-    
-    _v_nextid = 0
-    
-    def __init__(self):
-        self._objs = IOBTree()
-        self._length = Length()
-        
-    def idType(self):
-        return IntType
-    
-    def register(self, obj):
-        if pypesid(obj) is not None:
-            raise IdentityError, 'Object already registered'
-        if self._p_jar is not None and getattr(obj, '_p_jar', 0) is None:
-            # Make sure the object has a data manager so it can be
-            # used as an access point back to the services
-            obj._p_jar = self._p_jar
-        # Ids are generated in sequence in a single thread to group
-        # related objects in the tree
-        while not self._v_nextid or self._objs.has_key(self._v_nextid):
-            self._v_nextid = randint(-2100000000, 2100000000)
-        identifier = self._v_nextid
-        try:
-            obj._pypes_id_ = identifier
-        except AttributeError:
-            raise IdentityError, ('Cannot register object. Unable to store '
-                                  'persistent id as attribute')
-        self._objs[identifier] = obj
-        self._length.change(1)
-        self._v_nextid += 1
-        if self._p_jar is not None:
-            try:
-                event_svc = services.event(self)
-            except PypesLookupError:
-                pass # No event service
-            else:
-                event_svc.send(IdRegisteredMessage(obj, identifier))
-        return identifier
-    
-    def hasId(self, identifier):
-        return bool(self._objs.has_key(identifier))
-    
-    def __contains__(self, obj):
-        identifier = pypesid(obj)
-        return isinstance(identifier, IntType) and self.hasId(identifier)
-        
-    def __len__(self):
-        return self._length()
-        
-    def removeId(self, identifier):
-        try:
-            obj = self._objs[identifier]
-        except KeyError:
-            raise IdentityKeyError, identifier
-        else:
-            del self._objs[identifier]
-            self._length.change(-1)
-            obj._pypes_id_ = None
-    
-    def remove(self, obj):
-        identifier = pypesid(obj)
-        try:
-            obj = self._objs[identifier]
-        except (KeyError, TypeError):
-            raise IdentityError, 'Object not registered'
-        else:
-            del self._objs[identifier]
-            self._length.change(-1)
-            obj._pypes_id_ = None
-            if self._p_jar is not None:
-                try:
-                    event_svc = services.event(self)
-                except PypesLookupError:
-                    pass # No event service
-                else:
-                    event_svc.send(IdUnregisteredMessage(obj, identifier))
-    
-    def getObject(self, identifier):
-        try:
-            return self._objs[identifier]
-        except KeyError:
-            raise IdentityKeyError, identifier
-    
-    def __iter__(self):
-        return iter(self._objs.values())
-        
-    def iterIds(self):
-        return iter(self._objs.keys())
-        
-    def idSet(self):
-        return IITreeSet(self._objs.keys())
-
-
-class IdentitySet(Persistent):
-    """Efficient persistent sets of id-registered objects"""
-    
-    implements(IIdentitySet)
-    
-    def __init__(self, objs=None):
-        """Identity sets can be constructed empty, or populated by an
-        iterable sequence of id-registered objects
-        
-        objs -- An iterable sequence of id-registered objects.
-        """        
-        self._idset = IITreeSet()
-        if objs:
-            self.update(objs)
-    
-    def fromIdSet(cls, idset, copy=False, dbconn=None):
-        """Alternate constructor to create an identity set from a btree set
-        of identifiers. If copy is true, then the set is copied, otherwise it 
-        used by the IdentitySet directly. If a copy is not made, then the
-        idset should not be mutated outside of the set. dbconn is a ZODB 
-        database connection which allows the set to access services before it 
-        is committed.
-        """
-        set = cls()
-        if copy:
-            set._idset.update(idset)
-        else:
-            set._idset = idset
-        if dbconn is not None:
-            set._p_jar = dbconn
-        return set
-    fromIdSet = classmethod(fromIdSet)
-    
-    def add(self, obj):
-        if self._p_jar is None:
-            # Grab the data manager from the obj passed so
-            # we have access to the services before we are committed
-            self._p_jar = getattr(obj, '_p_jar', None)
-        ident = pypesid(obj)
-        if ident is None:
-            raise IdentityError, obj
-        isnew = self._idset.insert(ident)
-        if isnew and not isinstance(self._idset, IITreeSet):
-            # Set operations may result in _idset being an IISet
-            # For better database efficiency we upgrade it to an IITreeSet
-            # When we are mutated in place
-            self._idset = IITreeSet(self._idset)
-        return bool(isnew)
-    
-    def remove(self, obj):
-        ident = pypesid(obj)
-        if ident is None:
-            raise IdentityError, obj
-        try:
-            self._idset.remove(ident)
-        except KeyError:
-            raise SetLookupError, obj
-        else:
-            if not isinstance(self._idset, IITreeSet):
-                # Upgrade to IITreeSet for storage efficiency when mutated
-                self._idset = IITreeSet(self._idset)
-    
-    def update(self, objs):
-        if self._p_jar is None:
-            # Grab the data manager from one of the objects passed
-            # to give us access to other services before we are commited
-            objs = iter(objs)
-            try:
-                first = objs.next()
-            except StopIteration:
-                return
-            self.add(first)
-        insert = self._idset.insert
-        try:
-            for ob in objs:
-                insert(ob._pypes_id_)
-        except AttributeError:
-            raise IdentityError, 'Set update received unregistered object(s)'
-    
-    def __contains__(self, obj):
-        ident = pypesid(obj)
-        if ident is None:
-            raise IdentityError, obj
-        return bool(self._idset.has_key(ident))
-    
-    def __nonzero__(self):
-        # Efficiently determine if we are empty
-        return bool(self._idset)
-    
-    def __len__(self):
-        return len(self._idset) # XXX keep a length for efficiency?
-    
-    def __iter__(self):
-        # If an object in the set is no longer registered None is substituted
-        # This iterator is lazy and changing the set during iteration
-        # has undefined results
-        identity = services.identity(self)
-        for ident in self._idset.keys():
-            try:
-                yield identity.getObject(ident)
-            except IdentityKeyError:
-                yield None
-    
-    def union(self, other):
-        return self.__class__.fromIdSet(union(self._idset, other._idset))
-    
-    __or__ = union
-    
-    def difference(self, other):
-        return self.__class__.fromIdSet(difference(self._idset, other._idset))
-        
-    __sub__ = difference
-    
-    def intersection(self, other):
-        return self.__class__.fromIdSet(
-            intersection(self._idset, other._idset))  
-    
-    __and__ = intersection
-    
-    def issubset(self, other):
-        return not difference(self._idset, other._idset)
-    
-    def issuperset(self, other):
-        return not difference(other._idset, self._idset)
-        
-    def __eq__(self, other):
-        return self.issubset(other) and self.issuperset(other)
-    
-    def __ne__(self, other):
-        return not self.issubset(other) or not self.issuperset(other)
-
-
-## Id Event Messsage Types ##
-
-
-class IdRegisteredMessage(PypesMessage):
-    """object was registered with the identity service"""
-    
-    implements(IIdentityMessage)
-    
-    def __init__(self, object, id):
-        self.object = object
-        self.id = id
-
-
-class IdUnregisteredMessage(PypesMessage):
-    """object was removed from the identity service"""
-    
-    implements(IIdentityMessage)
-    
-    def __init__(self, object, id):
-        self.object = object
-        self.id = id
-
-
-## Helper Functions ##
-
-
-def pypesid(obj):
-    """Return the identifier for obj if registered with an identity service
-    otherwise return None"""
-    return getattr(obj, '_pypes_id_', None)
-    
-
-def listenForIdEvents(listener, conn=None,
-                      id_registered_method='_notifyIdRegistered',
-                      id_unregistered_method='_notifyIdUnRegistered'):
-    """Register obj with the event service as a listener for identity
-    service registrations/unregistrations.
-
-    listener -- Object to be registered as a listener
-
-    conn -- Open ZODB connection object. If None it will be derived from
-    listener if possible.
-
-    id_registered_method -- Name of the method of listener which will 
-    receive idRegisteredMessages.
-
-    id_registered_method -- Name of the method of listener which will
-    receive idUnRegisteredMessages.
-    """
-    if conn is None:
-        conn = listener
-    event = services.event(conn)
-    if id_registered_method:
-        event.registerListener(
-            listener, id_registered_method, IdRegisteredMessage)
-    if id_unregistered_method:
-        event.registerListener(
-            listener, id_unregistered_method, IdUnregisteredMessage)
-    
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Pypes identity service
+
+Provides unique tokens for identifying persistent objects.
+
+$Id$"""
+
+from __future__ import generators
+from random import randint
+from persistent import Persistent
+from types import IntType
+from zope.interface import implements
+from BTrees.IIBTree \
+    import IITreeSet, multiunion, union, intersection, difference
+from BTrees.IOBTree import IOBTree
+from BTrees.Length import Length
+from pypes import services
+from pypes.event import PypesMessage
+from pypes.interfaces import IIdentityService, IIdentitySet, IIdentityMessage
+from pypes.exceptions import PypesError, PypesLookupError
+from pypes.exceptions import IdentityError, IdentityKeyError, SetLookupError
+
+
+class IdentityService(Persistent):
+    """Identity service providing integer identifiers. Before this service
+    can be used, it must be committed to the database
+    """
+    
+    implements(IIdentityService)
+    
+    _v_nextid = 0
+    
+    def __init__(self):
+        self._objs = IOBTree()
+        self._length = Length()
+        
+    def idType(self):
+        return IntType
+    
+    def register(self, obj):
+        if pypesid(obj) is not None:
+            raise IdentityError, 'Object already registered'
+        if self._p_jar is not None and getattr(obj, '_p_jar', 0) is None:
+            # Make sure the object has a data manager so it can be
+            # used as an access point back to the services
+            obj._p_jar = self._p_jar
+        # Ids are generated in sequence in a single thread to group
+        # related objects in the tree
+        while not self._v_nextid or self._objs.has_key(self._v_nextid):
+            self._v_nextid = randint(-2100000000, 2100000000)
+        identifier = self._v_nextid
+        try:
+            obj._pypes_id_ = identifier
+        except AttributeError:
+            raise IdentityError, ('Cannot register object. Unable to store '
+                                  'persistent id as attribute')
+        self._objs[identifier] = obj
+        self._length.change(1)
+        self._v_nextid += 1
+        if self._p_jar is not None:
+            try:
+                event_svc = services.event(self)
+            except PypesLookupError:
+                pass # No event service
+            else:
+                event_svc.send(IdRegisteredMessage(obj, identifier))
+        return identifier
+    
+    def hasId(self, identifier):
+        return bool(self._objs.has_key(identifier))
+    
+    def __contains__(self, obj):
+        identifier = pypesid(obj)
+        return isinstance(identifier, IntType) and self.hasId(identifier)
+        
+    def __len__(self):
+        return self._length()
+        
+    def removeId(self, identifier):
+        try:
+            obj = self._objs[identifier]
+        except KeyError:
+            raise IdentityKeyError, identifier
+        else:
+            del self._objs[identifier]
+            self._length.change(-1)
+            obj._pypes_id_ = None
+    
+    def remove(self, obj):
+        identifier = pypesid(obj)
+        try:
+            obj = self._objs[identifier]
+        except (KeyError, TypeError):
+            raise IdentityError, 'Object not registered'
+        else:
+            del self._objs[identifier]
+            self._length.change(-1)
+            obj._pypes_id_ = None
+            if self._p_jar is not None:
+                try:
+                    event_svc = services.event(self)
+                except PypesLookupError:
+                    pass # No event service
+                else:
+                    event_svc.send(IdUnregisteredMessage(obj, identifier))
+    
+    def getObject(self, identifier):
+        try:
+            return self._objs[identifier]
+        except KeyError:
+            raise IdentityKeyError, identifier
+    
+    def __iter__(self):
+        return iter(self._objs.values())
+        
+    def iterIds(self):
+        return iter(self._objs.keys())
+        
+    def idSet(self):
+        return IITreeSet(self._objs.keys())
+
+
+class IdentitySet(Persistent):
+    """Efficient persistent sets of id-registered objects"""
+    
+    implements(IIdentitySet)
+    
+    def __init__(self, objs=None):
+        """Identity sets can be constructed empty, or populated by an
+        iterable sequence of id-registered objects
+        
+        objs -- An iterable sequence of id-registered objects.
+        """        
+        self._idset = IITreeSet()
+        if objs:
+            self.update(objs)
+    
+    def fromIdSet(cls, idset, copy=False, dbconn=None):
+        """Alternate constructor to create an identity set from a btree set
+        of identifiers. If copy is true, then the set is copied, otherwise it 
+        used by the IdentitySet directly. If a copy is not made, then the
+        idset should not be mutated outside of the set. dbconn is a ZODB 
+        database connection which allows the set to access services before it 
+        is committed.
+        """
+        set = cls()
+        if copy:
+            set._idset.update(idset)
+        else:
+            set._idset = idset
+        if dbconn is not None:
+            set._p_jar = dbconn
+        return set
+    fromIdSet = classmethod(fromIdSet)
+    
+    def add(self, obj):
+        if self._p_jar is None:
+            # Grab the data manager from the obj passed so
+            # we have access to the services before we are committed
+            self._p_jar = getattr(obj, '_p_jar', None)
+        ident = pypesid(obj)
+        if ident is None:
+            raise IdentityError, obj
+        isnew = self._idset.insert(ident)
+        if isnew and not isinstance(self._idset, IITreeSet):
+            # Set operations may result in _idset being an IISet
+            # For better database efficiency we upgrade it to an IITreeSet
+            # When we are mutated in place
+            self._idset = IITreeSet(self._idset)
+        return bool(isnew)
+    
+    def remove(self, obj):
+        ident = pypesid(obj)
+        if ident is None:
+            raise IdentityError, obj
+        try:
+            self._idset.remove(ident)
+        except KeyError:
+            raise SetLookupError, obj
+        else:
+            if not isinstance(self._idset, IITreeSet):
+                # Upgrade to IITreeSet for storage efficiency when mutated
+                self._idset = IITreeSet(self._idset)
+    
+    def update(self, objs):
+        if self._p_jar is None:
+            # Grab the data manager from one of the objects passed
+            # to give us access to other services before we are commited
+            objs = iter(objs)
+            try:
+                first = objs.next()
+            except StopIteration:
+                return
+            self.add(first)
+        insert = self._idset.insert
+        try:
+            for ob in objs:
+                insert(ob._pypes_id_)
+        except AttributeError:
+            raise IdentityError, 'Set update received unregistered object(s)'
+    
+    def __contains__(self, obj):
+        ident = pypesid(obj)
+        if ident is None:
+            raise IdentityError, obj
+        return bool(self._idset.has_key(ident))
+    
+    def __nonzero__(self):
+        # Efficiently determine if we are empty
+        return bool(self._idset)
+    
+    def __len__(self):
+        return len(self._idset) # XXX keep a length for efficiency?
+    
+    def __iter__(self):
+        # If an object in the set is no longer registered None is substituted
+        # This iterator is lazy and changing the set during iteration
+        # has undefined results
+        identity = services.identity(self)
+        for ident in self._idset.keys():
+            try:
+                yield identity.getObject(ident)
+            except IdentityKeyError:
+                yield None
+    
+    def union(self, other):
+        return self.__class__.fromIdSet(union(self._idset, other._idset))
+    
+    __or__ = union
+    
+    def difference(self, other):
+        return self.__class__.fromIdSet(difference(self._idset, other._idset))
+        
+    __sub__ = difference
+    
+    def intersection(self, other):
+        return self.__class__.fromIdSet(
+            intersection(self._idset, other._idset))  
+    
+    __and__ = intersection
+    
+    def issubset(self, other):
+        return not difference(self._idset, other._idset)
+    
+    def issuperset(self, other):
+        return not difference(other._idset, self._idset)
+        
+    def __eq__(self, other):
+        return self.issubset(other) and self.issuperset(other)
+    
+    def __ne__(self, other):
+        return not self.issubset(other) or not self.issuperset(other)
+
+
+## Id Event Messsage Types ##
+
+
+class IdRegisteredMessage(PypesMessage):
+    """object was registered with the identity service"""
+    
+    implements(IIdentityMessage)
+    
+    def __init__(self, object, id):
+        self.object = object
+        self.id = id
+
+
+class IdUnregisteredMessage(PypesMessage):
+    """object was removed from the identity service"""
+    
+    implements(IIdentityMessage)
+    
+    def __init__(self, object, id):
+        self.object = object
+        self.id = id
+
+
+## Helper Functions ##
+
+
+def pypesid(obj):
+    """Return the identifier for obj if registered with an identity service
+    otherwise return None"""
+    return getattr(obj, '_pypes_id_', None)
+    
+
+def listenForIdEvents(listener, conn=None,
+                      id_registered_method='_notifyIdRegistered',
+                      id_unregistered_method='_notifyIdUnRegistered'):
+    """Register obj with the event service as a listener for identity
+    service registrations/unregistrations.
+
+    listener -- Object to be registered as a listener
+
+    conn -- Open ZODB connection object. If None it will be derived from
+    listener if possible.
+
+    id_registered_method -- Name of the method of listener which will 
+    receive idRegisteredMessages.
+
+    id_registered_method -- Name of the method of listener which will
+    receive idUnRegisteredMessages.
+    """
+    if conn is None:
+        conn = listener
+    event = services.event(conn)
+    if id_registered_method:
+        event.registerListener(
+            listener, id_registered_method, IdRegisteredMessage)
+    if id_unregistered_method:
+        event.registerListener(
+            listener, id_unregistered_method, IdUnregisteredMessage)
+    


=== Packages/pypes/pypes/interfaces.py 1.9 => 1.10 ===
--- Packages/pypes/pypes/interfaces.py:1.9	Mon Feb  9 00:24:51 2004
+++ Packages/pypes/pypes/interfaces.py	Mon Feb  9 16:14:57 2004
@@ -1,512 +1,513 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Pypes interface specifications
-
-$Id$"""
-
-from zope.interface import Interface, Attribute
-
-class IPersistentService(Interface):
-    """Pypes Persistent services are globally accessible,
-    persistent objects in the database which perform functions and store data
-    on behalf of many other persistent objects. Persistent services are stored
-    in a registry in the database and are accessible from any persistent object
-    in the database (or a database connection object) by name.
-    """
-
-class IIdentityService(IPersistentService):
-    """Registry of "identified" objects known to pypes.
-    
-    - Creates unique identifiers for persistent objects in a database.
-
-    - Guarantees access to an object by its identifier as long as it 
-      is registered.
-
-    - Provides a count of registered objects.
-
-    - Provides a set of registered objects
-
-    - Allows iteration of registered objects.
-
-    Identifiers must be:
-        
-    - True values.
-
-    - Independent of the objects they identify.
-    
-    - Arbitrarily selected for any persistent object.
-
-    - The same type for all objects.
-
-    - Small, immutable, hashable and pickleable.
-
-    - Comparible/consistently orderable across application runs.
-    """
-
-    def idType():
-        """Return the type object for the identifiers generated by this
-        service.
-        """
-
-    def register(obj):
-        """Register obj with the identity service. Identity registered objects
-        are considered "identified". Return the persistent unique identifier
-        for obj. The service must guarantee that so long as the object remains
-        registered, it can be retrieved using the identifier returned upon
-        registration.
-
-        If obj is already registered or cannot
-        be registered for any reason, raise an IdentityError.
-        """
-
-    def hasId(identifier):
-        """Return true if identifier refers to an object currently registered.
-        If identifier is not the proper type raise TypeError.
-        """
-
-    def __contains__(obj):
-        """Return true if obj is registered with the service."""
-
-    def removeId(identifier):
-        """Remove (unregister) an object by identifier. Raise IdentityKeyError 
-        if the identifier does not coorespond to any registered object.  If
-        identifier is not the proper type raise TypeError. Once an object is
-        removed it can be registered again, but its identifier may not be the
-        same as the first registration. It is acceptable for identifiers to be
-        reused once its object is removed. 
-        """
-
-    def remove(obj):
-        """Remove (unregister) an object. Raise IdentityError if the object
-        is not registered.
-        """
-
-    def getObject(identifier):
-        """Return the registered object for identifier. Raise IdentityKeyError
-        if the identifier does not coorespond to any registered object. Raise
-        TypeError if identifier is not the proper type.
-        """
-
-    def __len__():
-        """Return the number of objects registered."""
-
-    def __iter__():
-        """Return an iterator of registered objects."""
-
-    def iterIds():
-        """Return an iterator of registered object identifiers."""
-
-    def idSet():
-        """Return an identity set of all registered objects."""
-
-class IIdentitySet(Interface):
-    """A set of unique identified objects. Since the set relies
-    on persistent identity, its members may be mutable. Identity sets 
-    weakly reference their members, so being a member of a set does not
-    guarantee continued persistence. Implementations may use the event
-    service to keep informed of object registrations"""
-    
-    def add(obj):
-        """Add obj to the set. Return true if obj was not a member already,
-        false if so. In the latter case insert does not change the set. Raise
-        IdentityError if obj is not identified
-        """
-    
-    def remove(obj):
-        """Remove obj from set. raise SetLookupError if obj is not in the set"""
-        
-    def update(objs):
-        """Iterate objs and add its members to the set in place"""
-    
-    def __contains__(obj):
-        """Return true if obj is in the set"""
-    
-    def __len__():
-        """Return set member count"""
-    
-    def __iter__():
-        """Return an iterator of the members of the set"""
-    
-    def union(other):
-        """Return a set whos members are the union of self and other"""
-        
-    def __or__(other):
-        """Alias for union in an expression"""
-        
-    def difference(other):
-        """Return a set whos members are in self but not in other"""
-    
-    def __sub__(other):
-        """Alias for difference"""
-        
-    def intersection(other):
-        """Return a set whos members are in both self and other"""
-    
-    def __and__(other):
-        """Compute the intersection between self and other and return the 
-        resulting set
-        """
-    
-    def issubset(other):
-        """Return true if all members of self are also in other"""
-    
-    def issuperset(other):
-        """Return true if all members of other are also in self"""
-        
-    def __eq__(other):
-        """Return true if this set and other contain the same members"""
-        
-    
-class IEventService(IPersistentService):
-    """An event service dispatches messages to listeners. It allows loosely
-    bound objects and services to communicate and notify one another without
-    dependancies or direct knowledge of each other. Events can also be vetoed
-    by listeners to enforce data integrity rules or indirectly alter behavior.
-    
-    Some guidelines for implementations:
-        
-    - The event sending overhead should be as cheap as possible.
-    
-    - Registering/unregistering listeners should also be as inexpensive as
-      possible, but not at the expense of event sending performance.
-    """
-    
-    def registerListener(obj, method_name, message_type):        
-        """Register obj as a listener  via the specified  method name.
-        method_name must specify the name of a callable attribute of obj which
-        accepts a single message argument.  message_type must be a type or
-        class object. May be called multiple times for the same listener."""
-
-    def unregisterListener(obj, method_name, message_type):
-        """Unregister a listener for the message_types specified via
-        the registered method name. If obj was never registered via
-        the method specified raise EventRegistrationError.
-        """
-    
-    def unregisterAllListeners(message_type):
-        """Unregister all listeners for the given message type. Only affects
-        objects directly registered for a given message_type, no 
-        listeners for subtypes are affected. If none are registered, do nothing.
-        """
-    
-    def send(message):
-        """Send message to all registered listeners for this message type or
-        its supertypes. Return true if the message was received by any
-        listeners, false if not. Listeners may raise exceptions, which will be
-        propagated to the sender. If the sender wishes to catch exceptions, it
-        should be careful to handle ConflictErrors properly (i.e. let them
-        propagate). A special exception  class VetoEvent should, at the option
-        of the sender, be processed as a request to cancel the operation which
-        generated the event (i.e. by aborting the current transaction)
-        """
-        
-    def wouldReceive(obj, message_type):
-        """Return true if obj would receive a message of the type specified.
-        This will be true if obj is a registered listener for message_type
-        or any of its supertypes
-        """
-
-    def isListener(obj, message_type):
-        """Return true if obj is registered as a listener for the specified
-        message_type.
-        """
-        
-    def iterListeners(message_type):
-        """Return an iterator of (listener, methodname) pairs for all
-        listeners of the message type specified.
-        """
-        
-    def iterReceivers(message_type):
-        """Return an iterator of (listener, methodname) pairs for all
-        listeners that would receive a message of message_type, including
-        listeners for supertypes.
-        """
-        
-    def iterMessageTypes():
-        """Return an iterator of all message types that have listeners
-        registered
-        """
-
-class IObjectMessage(Interface):
-    """A message concerning a single object"""
-    
-    object = Attribute('object', 'Object that is the subject of the message')
-    
-    
-class IIdentityMessage(IObjectMessage):
-    """A message concerning the identity of an object"""
-    
-    id = Attribute('id', 'The identity of the object in question')
-
-
-class IExtentService(Interface):
-    """Service providing global extent sets of identified objects by class and 
-    interface.
-    
-    Extents are typically used as top-level collections by applications. They
-    are generally analogous to tables in a traditional relational database. A
-    strong difference however, is that extents are not directly modified.
-    Objects are added and removed from extents automatically as they are
-    registered and unregistered from the identity service or modified (in terms
-    of interfaces provided) and signaled through the event service. 
-
-    XXX Once the query service is documented, explain how they work together
-    """
-    
-    def __getitem__(key):
-        """Return the canonical extent for key. For class extents the key is a 
-        class. For interface extents it is an interface object. Raise KeyError
-        if key is not contained in the service. Raise TypeError if key type
-        is not supported.
-        """
-
-    def __contains__(key):
-        """Return true if key is an identifier of an extent, false otherwise.
-        Raise TypeError if key type is not supported.
-        """
-    
-    def __iter__():
-        """Return an iterator of all extents in the service"""
-
-
-class IExtentMap(Interface):
-    """Simple mapping-like container for canonical extents of a single type"""
-       
-    def __getitem__(key):
-        """Return extent for key. Raise KeyError if key is the correct type
-        but is not in the map. Raise TypeError if key is not the correct type
-        for the extent map"""
-
-    def __iter__():
-        """Return an iterator of all extents in the mapping"""
-
-    def update():
-        """Update the extent map from all identified objects"""
-        
-        
-class IExtent(Interface):
-    """Automated set of identified objects.
-    
-    Extents are either provided by the extent service or derived from other
-    extents. Extents behave like read-only sets in most respects. They are
-    updated automatically as objects are manipulated and registered with pypes.
-    
-    Although extents may be arbitrarily large, operations between them  (such
-    as union and intersection) are designed to be efficient, especially between
-    extents of the same type (class or interface). Operations between extents
-    and identity sets are also supported; resulting in a new identity set.
-    """
-    
-    def __contains__(obj):
-        """Return true if obj is in the extent"""
-    
-    def __len__():
-        """Return extent member count"""
-    
-    def __iter__():
-        """Return an iterator of the members of the extent"""
-    
-    def union(other):
-        """Return a derived extent or identity set whos members are the union 
-        of self and other"""
-        
-    def __or__(other):
-        """Alias for union in an expression"""
-        
-    def difference(other):
-        """return a derived extent or identity set whos members are in self 
-        but not in other"""
-    
-    def __sub__(other):
-        """Alias for difference"""
-        
-    def intersection(other):
-        """Return a derived extent or identity set whos members are in both 
-        self and other"""
-    
-    def __and__(other):
-        """Compute the intersection between self and other and return the 
-        resulting derived extent or identity set
-        """
-    
-    def issubset(other):
-        """Return true if all members of self are also in other"""
-    
-    def issuperset(other):
-        """Return true if all members of other are also in self"""
-        
-    def __eq__(other):
-        """Return true if this extent and other contain the same members"""
-
-
-class ICanonicalExtent(IExtent):
-    """An extent of a single interface or class provided directly by the
-    extent service
-    """
-    
-    key = Attribute('key',
-        """Key for this extent in the extent service""")
-    
-    def subExtents():
-        """Return the direct sub-extents of the extent, if any, which are
-        disjoint canonical sets which are subsets of the extent. 
-        """
-
-class IDerivedExtent(IExtent):
-    """An extent derived by combining extents"""
-
-
-class IGraphNodes(Interface):
-    """Collection of nodes in a graph"""
-    
-    def add(obj):
-        """Add obj as a node of the graph. Return true if obj is not already
-        a node. If obj is in the graph, return false and do nothing
-        """
-    
-    def remove(obj):
-        """Remove obj from the graph and any edges connecting to and from the
-        obj. If obj is not a node, then raise GraphLookupError
-        """
-    
-    def __contains__(obj):
-        """Return true if obj is a node of the graph, false if not"""
-    
-    def __len__():
-        """Return the graph node count"""
-    
-    def __iter__():
-        """Return an iterator of the graph node objects"""
-        
-    def iterTopological():
-        """Return an iterator of the nodes in topologically sorted order. 
-        The graph must be directed and acyclic. If a cycle is encountered
-        during iteration, raise GraphCycleError.
-        """
-        
-    def degree(node):
-        """Return the degree of the node, which is the integer count
-        of adjacent target nodes
-        """
-    
-    def sources(node, transitive=False):
-        """Return the set of nodes which are the source of an edge where the
-        specified node is a target. If transitive is true, then the set returns
-        all nodes which can reach the specified node by traversing all graph 
-        edges to node. If node is not in the graph, raise GraphLookupError.
-        """
-    
-    def targets(node, transitive=False):
-        """Return the set of nodes which are the targets of an edge where
-        the specified node is the source. If transitive is true, then the set 
-        returns all nodes reachable from the specified node by traversing 
-        all graph edges from node. If node is not in the graph, raise 
-        GraphLookupError.
-        """
-
-class IGraphEdges(Interface):
-    """Collection of edges in a graph"""
-    
-    def add(source, target, value=None):
-        """Add an edge to the graph from object source to target. If these
-        objects are not already nodes of the graph, they are added. The order
-        of source and target are significant only for directed graphs. If the
-        edge did not already exist, return true. Otherwise return false.
-        
-        value -- Optional object used as the value for the edge between source
-        and target. May be used to store the distance or magnitude of the edge
-        or any desired application data. If the edge already exists value
-        replaces any existing edge value; if value is omitted, the existing
-        value is unchanged.
-        """
-        
-    def remove(source, target):
-        """Remove the edge between source and target from the graph. If no
-        edge exists between source and target, raise GraphLookupError. The
-        source and target nodes are not removed from the graph.
-        """
-
-    def get(source, target, default=None):
-        """Return the value for the edge from node source to node target. If 
-        no value was assigned, raise GraphValueError or return default if
-        supplied. If no edge exists, raise GraphLookupError.
-        """
-   
-    def set(source, target, value):
-        """Set the data for the edge from source to target. If no edge exists
-        between source and target, raise GraphLookupError
-        """
-    
-    def __contains__(pair):
-        """Return true if the graph contains an edge cooresponding to pair, a 
-        sequence of two node objects. The order of these objects is significant
-        only for directed graphs. If either object in the pair are not nodes
-        of the graph, raise GraphLookupError
-        """
-    
-    def __len__():
-        """Return the graph edge count"""
-    
-    def __iter__():
-        """Return an iterator of (source, target) pairs representing each
-        edge in the graph
-        """    
-    
-    def iterValues():
-        """Return an iterator of the values assigned to the edges in the graph
-        """
-    
-    def iterItems():
-        """Return an iterator of ((source, target), value) pairs for each
-        edge with a value in the graph.
-        """
-    
-class IGraph(Interface):
-    """Persistent graph of object nodes"""
-    
-    nodes = Attribute('nodes', 
-        """IGraphNodes object for manipulating the nodes of the graph""")
-        
-    edges = Attribute('edges',
-        """IGraphEdges object for manipulating the edges of the graph""")
-        
-    def transitiveClosure(with_values=False):
-        """Return the transitive closure graph for the current graph. If
-        with_values is true, then the values for each edge in the resulting
-        graph are computed from the exisiting values. This means that all
-        edge values in the graph must be addable
-        """
-        
-    def shortestPath(source, target, use_values=False):        
-        """Return the sequence of node which is the shortest path from source
-        to target. For instance, If source and target are
-        adjacent, return [source, target]; if they connect through a single
-        intermediary return  [source, intermediate, target], etc. If no
-        path connects source and target, return None.
-        
-        If use_values is true, then the edge data is used to calculate the
-        distance between nodes. This implies that all data objects in the graph
-        can be added and compared to one another as distances. By default, the
-        values are not used and the distance between adjacent nodes is assumed
-        to be 1.
-        """
-    
-    def allPaths(source=None, target=None):
-        """Return an iterator of sequences of nodes representing all possible
-        paths between nodes of the graph. If source and target are omitted,
-        all possible paths between all graph nodes are returned. If source
-        is specified, only paths starting from source are returned. If 
-        target is specified, only paths to target are returned. If both are
-        specifed to compute all paths connecting source to target
-        """
\ No newline at end of file
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Pypes interface specifications
+
+$Id$"""
+
+from zope.interface import Interface, Attribute
+
+class IPersistentService(Interface):
+    """Pypes Persistent services are globally accessible,
+    persistent objects in the database which perform functions and store data
+    on behalf of many other persistent objects. Persistent services are stored
+    in a registry in the database and are accessible from any persistent object
+    in the database (or a database connection object) by name.
+    """
+
+class IIdentityService(IPersistentService):
+    """Registry of "identified" objects known to pypes.
+    
+    - Creates unique identifiers for persistent objects in a database.
+
+    - Guarantees access to an object by its identifier as long as it 
+      is registered.
+
+    - Provides a count of registered objects.
+
+    - Provides a set of registered objects
+
+    - Allows iteration of registered objects.
+
+    Identifiers must be:
+        
+    - True values.
+
+    - Independent of the objects they identify.
+    
+    - Arbitrarily selected for any persistent object.
+
+    - The same type for all objects.
+
+    - Small, immutable, hashable and pickleable.
+
+    - Comparible/consistently orderable across application runs.
+    """
+
+    def idType():
+        """Return the type object for the identifiers generated by this
+        service.
+        """
+
+    def register(obj):
+        """Register obj with the identity service. Identity registered objects
+        are considered "identified". Return the persistent unique identifier
+        for obj. The service must guarantee that so long as the object remains
+        registered, it can be retrieved using the identifier returned upon
+        registration.
+
+        If obj is already registered or cannot
+        be registered for any reason, raise an IdentityError.
+        """
+
+    def hasId(identifier):
+        """Return true if identifier refers to an object currently registered.
+        If identifier is not the proper type raise TypeError.
+        """
+
+    def __contains__(obj):
+        """Return true if obj is registered with the service."""
+
+    def removeId(identifier):
+        """Remove (unregister) an object by identifier. Raise IdentityKeyError 
+        if the identifier does not coorespond to any registered object.  If
+        identifier is not the proper type raise TypeError. Once an object is
+        removed it can be registered again, but its identifier may not be the
+        same as the first registration. It is acceptable for identifiers to be
+        reused once its object is removed. 
+        """
+
+    def remove(obj):
+        """Remove (unregister) an object. Raise IdentityError if the object
+        is not registered.
+        """
+
+    def getObject(identifier):
+        """Return the registered object for identifier. Raise IdentityKeyError
+        if the identifier does not coorespond to any registered object. Raise
+        TypeError if identifier is not the proper type.
+        """
+
+    def __len__():
+        """Return the number of objects registered."""
+
+    def __iter__():
+        """Return an iterator of registered objects."""
+
+    def iterIds():
+        """Return an iterator of registered object identifiers."""
+
+    def idSet():
+        """Return an identity set of all registered objects."""
+
+class IIdentitySet(Interface):
+    """A set of unique identified objects. Since the set relies
+    on persistent identity, its members may be mutable. Identity sets 
+    weakly reference their members, so being a member of a set does not
+    guarantee continued persistence. Implementations may use the event
+    service to keep informed of object registrations"""
+    
+    def add(obj):
+        """Add obj to the set. Return true if obj was not a member already,
+        false if so. In the latter case insert does not change the set. Raise
+        IdentityError if obj is not identified
+        """
+    
+    def remove(obj):
+        """Remove obj from set. raise SetLookupError if obj is not in the set"""
+        
+    def update(objs):
+        """Iterate objs and add its members to the set in place"""
+    
+    def __contains__(obj):
+        """Return true if obj is in the set"""
+    
+    def __len__():
+        """Return set member count"""
+    
+    def __iter__():
+        """Return an iterator of the members of the set"""
+    
+    def union(other):
+        """Return a set whos members are the union of self and other"""
+        
+    def __or__(other):
+        """Alias for union in an expression"""
+        
+    def difference(other):
+        """Return a set whos members are in self but not in other"""
+    
+    def __sub__(other):
+        """Alias for difference"""
+        
+    def intersection(other):
+        """Return a set whos members are in both self and other"""
+    
+    def __and__(other):
+        """Compute the intersection between self and other and return the 
+        resulting set
+        """
+    
+    def issubset(other):
+        """Return true if all members of self are also in other"""
+    
+    def issuperset(other):
+        """Return true if all members of other are also in self"""
+        
+    def __eq__(other):
+        """Return true if this set and other contain the same members"""
+        
+    
+class IEventService(IPersistentService):
+    """An event service dispatches messages to listeners. It allows loosely
+    bound objects and services to communicate and notify one another without
+    dependancies or direct knowledge of each other. Events can also be vetoed
+    by listeners to enforce data integrity rules or indirectly alter behavior.
+    
+    Some guidelines for implementations:
+        
+    - The event sending overhead should be as cheap as possible.
+    
+    - Registering/unregistering listeners should also be as inexpensive as
+      possible, but not at the expense of event sending performance.
+    """
+    
+    def registerListener(obj, method_name, message_type):        
+        """Register obj as a listener  via the specified  method name.
+        method_name must specify the name of a callable attribute of obj which
+        accepts a single message argument.  message_type must be a type or
+        class object. May be called multiple times for the same listener."""
+
+    def unregisterListener(obj, method_name, message_type):
+        """Unregister a listener for the message_types specified via
+        the registered method name. If obj was never registered via
+        the method specified raise EventRegistrationError.
+        """
+    
+    def unregisterAllListeners(message_type):
+        """Unregister all listeners for the given message type. Only affects
+        objects directly registered for a given message_type, no 
+        listeners for subtypes are affected. If none are registered, do nothing.
+        """
+    
+    def send(message):
+        """Send message to all registered listeners for this message type or
+        its supertypes. Return true if the message was received by any
+        listeners, false if not. Listeners may raise exceptions, which will be
+        propagated to the sender. If the sender wishes to catch exceptions, it
+        should be careful to handle ConflictErrors properly (i.e. let them
+        propagate). A special exception  class VetoEvent should, at the option
+        of the sender, be processed as a request to cancel the operation which
+        generated the event (i.e. by aborting the current transaction)
+        """
+        
+    def wouldReceive(obj, message_type):
+        """Return true if obj would receive a message of the type specified.
+        This will be true if obj is a registered listener for message_type
+        or any of its supertypes
+        """
+
+    def isListener(obj, message_type):
+        """Return true if obj is registered as a listener for the specified
+        message_type.
+        """
+        
+    def iterListeners(message_type):
+        """Return an iterator of (listener, methodname) pairs for all
+        listeners of the message type specified.
+        """
+        
+    def iterReceivers(message_type):
+        """Return an iterator of (listener, methodname) pairs for all
+        listeners that would receive a message of message_type, including
+        listeners for supertypes.
+        """
+        
+    def iterMessageTypes():
+        """Return an iterator of all message types that have listeners
+        registered
+        """
+
+class IObjectMessage(Interface):
+    """A message concerning a single object"""
+    
+    object = Attribute('object', 'Object that is the subject of the message')
+    
+    
+class IIdentityMessage(IObjectMessage):
+    """A message concerning the identity of an object"""
+    
+    id = Attribute('id', 'The identity of the object in question')
+
+
+class IExtentService(Interface):
+    """Service providing global extent sets of identified objects by class and 
+    interface.
+    
+    Extents are typically used as top-level collections by applications. They
+    are generally analogous to tables in a traditional relational database. A
+    strong difference however, is that extents are not directly modified.
+    Objects are added and removed from extents automatically as they are
+    registered and unregistered from the identity service or modified (in terms
+    of interfaces provided) and signaled through the event service. 
+
+    XXX Once the query service is documented, explain how they work together
+    """
+    
+    def __getitem__(key):
+        """Return the canonical extent for key. For class extents the key is a 
+        class. For interface extents it is an interface object. Raise KeyError
+        if key is not contained in the service. Raise TypeError if key type
+        is not supported.
+        """
+
+    def __contains__(key):
+        """Return true if key is an identifier of an extent, false otherwise.
+        Raise TypeError if key type is not supported.
+        """
+    
+    def __iter__():
+        """Return an iterator of all extents in the service"""
+
+
+class IExtentMap(Interface):
+    """Simple mapping-like container for canonical extents of a single type"""
+       
+    def __getitem__(key):
+        """Return extent for key. Raise KeyError if key is the correct type
+        but is not in the map. Raise TypeError if key is not the correct type
+        for the extent map"""
+
+    def __iter__():
+        """Return an iterator of all extents in the mapping"""
+
+    def update():
+        """Update the extent map from all identified objects"""
+        
+        
+class IExtent(Interface):
+    """Automated set of identified objects.
+    
+    Extents are either provided by the extent service or derived from other
+    extents. Extents behave like read-only sets in most respects. They are
+    updated automatically as objects are manipulated and registered with pypes.
+    
+    Although extents may be arbitrarily large, operations between them  (such
+    as union and intersection) are designed to be efficient, especially between
+    extents of the same type (class or interface). Operations between extents
+    and identity sets are also supported; resulting in a new identity set.
+    """
+    
+    def __contains__(obj):
+        """Return true if obj is in the extent"""
+    
+    def __len__():
+        """Return extent member count"""
+    
+    def __iter__():
+        """Return an iterator of the members of the extent"""
+    
+    def union(other):
+        """Return a derived extent or identity set whos members are the union 
+        of self and other"""
+        
+    def __or__(other):
+        """Alias for union in an expression"""
+        
+    def difference(other):
+        """return a derived extent or identity set whos members are in self 
+        but not in other"""
+    
+    def __sub__(other):
+        """Alias for difference"""
+        
+    def intersection(other):
+        """Return a derived extent or identity set whos members are in both 
+        self and other"""
+    
+    def __and__(other):
+        """Compute the intersection between self and other and return the 
+        resulting derived extent or identity set
+        """
+    
+    def issubset(other):
+        """Return true if all members of self are also in other"""
+    
+    def issuperset(other):
+        """Return true if all members of other are also in self"""
+        
+    def __eq__(other):
+        """Return true if this extent and other contain the same members"""
+
+
+class ICanonicalExtent(IExtent):
+    """An extent of a single interface or class provided directly by the
+    extent service
+    """
+    
+    key = Attribute('key',
+        """Key for this extent in the extent service""")
+    
+    def subExtents():
+        """Return the direct sub-extents of the extent, if any, which are
+        disjoint canonical sets which are subsets of the extent. 
+        """
+
+class IDerivedExtent(IExtent):
+    """An extent derived by combining extents"""
+
+
+class IGraphNodes(Interface):
+    """Collection of nodes in a graph"""
+    
+    def add(obj):
+        """Add obj as a node of the graph. Return true if obj is not already
+        a node. If obj is in the graph, return false and do nothing
+        """
+    
+    def remove(obj):
+        """Remove obj from the graph and any edges connecting to and from the
+        obj. If obj is not a node, then raise GraphLookupError
+        """
+    
+    def __contains__(obj):
+        """Return true if obj is a node of the graph, false if not"""
+    
+    def __len__():
+        """Return the graph node count"""
+    
+    def __iter__():
+        """Return an iterator of the graph node objects"""
+        
+    def iterTopological():
+        """Return an iterator of the nodes in topologically sorted order. 
+        The graph must be directed and acyclic. If a cycle is encountered
+        during iteration, raise GraphCycleError.
+        """
+        
+    def degree(node):
+        """Return the degree of the node, which is the integer count
+        of adjacent target nodes
+        """
+    
+    def sources(node, transitive=False):
+        """Return the set of nodes which are the source of an edge where the
+        specified node is a target. If transitive is true, then the set returns
+        all nodes which can reach the specified node by traversing all graph 
+        edges to node. If node is not in the graph, raise GraphLookupError.
+        """
+    
+    def targets(node, transitive=False):
+        """Return the set of nodes which are the targets of an edge where
+        the specified node is the source. If transitive is true, then the set 
+        returns all nodes reachable from the specified node by traversing 
+        all graph edges from node. If node is not in the graph, raise 
+        GraphLookupError.
+        """
+
+class IGraphEdges(Interface):
+    """Collection of edges in a graph"""
+    
+    def add(source, target, value=None):
+        """Add an edge to the graph from object source to target. If these
+        objects are not already nodes of the graph, they are added. The order
+        of source and target are significant only for directed graphs. If the
+        edge did not already exist, return true. Otherwise return false.
+        
+        value -- Optional object used as the value for the edge between source
+        and target. May be used to store the distance or magnitude of the edge
+        or any desired application data. If the edge already exists value
+        replaces any existing edge value; if value is omitted, the existing
+        value is unchanged.
+        """
+        
+    def remove(source, target):
+        """Remove the edge between source and target from the graph. If no
+        edge exists between source and target, raise GraphLookupError. The
+        source and target nodes are not removed from the graph.
+        """
+
+    def get(source, target, default=None):
+        """Return the value for the edge from node source to node target. If 
+        no value was assigned, raise GraphValueError or return default if
+        supplied. If no edge exists, raise GraphLookupError.
+        """
+   
+    def set(source, target, value):
+        """Set the data for the edge from source to target. If no edge exists
+        between source and target, raise GraphLookupError
+        """
+    
+    def __contains__(pair):
+        """Return true if the graph contains an edge cooresponding to pair, a 
+        sequence of two node objects. The order of these objects is significant
+        only for directed graphs. If either object in the pair are not nodes
+        of the graph, raise GraphLookupError
+        """
+    
+    def __len__():
+        """Return the graph edge count"""
+    
+    def __iter__():
+        """Return an iterator of (source, target) pairs representing each
+        edge in the graph
+        """    
+    
+    def iterValues():
+        """Return an iterator of the values assigned to the edges in the graph
+        """
+    
+    def iterItems():
+        """Return an iterator of ((source, target), value) pairs for each
+        edge with a value in the graph.
+        """
+    
+class IGraph(Interface):
+    """Persistent graph of object nodes"""
+    
+    nodes = Attribute('nodes', 
+        """IGraphNodes object for manipulating the nodes of the graph""")
+        
+    edges = Attribute('edges',
+        """IGraphEdges object for manipulating the edges of the graph""")
+        
+    def transitiveClosure(with_values=False):
+        """Return the transitive closure graph for the current graph. If
+        with_values is true, then the values for each edge in the resulting
+        graph are computed from the exisiting values. This means that all
+        edge values in the graph must be addable
+        """
+        
+    def shortestPath(source, target, use_values=False):        
+        """Return the sequence of node which is the shortest path from source
+        to target. For instance, If source and target are
+        adjacent, return [source, target]; if they connect through a single
+        intermediary return  [source, intermediate, target], etc. If no
+        path connects source and target, return None.
+        
+        If use_values is true, then the edge data is used to calculate the
+        distance between nodes. This implies that all data objects in the graph
+        can be added and compared to one another as distances. By default, the
+        values are not used and the distance between adjacent nodes is assumed
+        to be 1.
+        """
+    
+    def allPaths(source=None, target=None):
+        """Return an iterator of sequences of nodes representing all possible
+        paths between nodes of the graph. If source and target are omitted,
+        all possible paths between all graph nodes are returned. If source
+        is specified, only paths starting from source are returned. If 
+        target is specified, only paths to target are returned. If both are
+        specifed to compute all paths connecting source to target
+        """
+


=== Packages/pypes/pypes/serviceconfig.py 1.2 => 1.3 ===
--- Packages/pypes/pypes/serviceconfig.py:1.2	Fri Jan 30 00:35:38 2004
+++ Packages/pypes/pypes/serviceconfig.py	Mon Feb  9 16:14:57 2004
@@ -1,78 +1,78 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""pypes service configuration module
-
-Persistent service registration and configuration routines.
-
-$Id$"""
-
-import pypes
-from persistent.mapping import PersistentMapping
-from pypes.exceptions import PypesError, PypesLookupError
-
-registry_name = 'pypes_services' # Key to service registry in db root
-
-def initServices(connection, force=False):
-    """Initialize the service registry in the database referred from connection
-    then return it.
-
-    connection -- an open zodb connection
-
-    force -- If False (the default), the function does not replace an existing
-    registry. If True then the registry is replaced if existing. This can
-    lead to data loss, so be sure you really want this!
-    """
-    root = connection.root()
-    if not root.has_key(registry_name) or force:
-        root[registry_name] = PersistentMapping()
-    return root[registry_name]
-
-
-def addService(connection, name, service):
-    """Adds a service to the registry if it does not already exist. This
-    is the safe way to add a service because it never affects existing
-    services. If the service already exists, then a PypesError is raised.
-
-    connection -- an open zodb connection
-
-    name -- Name of the service
-
-    service -- IPersistentService object
-    """
-    registry = connection.root()[registry_name]
-    if registry.has_key(name):
-        raise PypesError, 'Service %s already exists' % name
-    registry[name] = service
-    
-
-def setService(connection, name, service):
-    """Like add service, but will also replace existing services. Use with
-    care, since services can contain user data."""
-    registry = connection.root()[registry_name]
-    registry[name] = service
-
-
-def delService(connection, name):
-    """Remove service from registry and any data contained in it"""
-    registry = connection.root()[registry_name]
-    try:
-        del registry[name]
-    except KeyError:
-        raise PypesLookupError, 'No service named %s' % name
-
-
-def hasService(connection, name):
-    """Return true if service name is available from connection"""
-    registry = connection.root()[registry_name]
-    return registry.has_key(name)
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""pypes service configuration module
+
+Persistent service registration and configuration routines.
+
+$Id$"""
+
+import pypes
+from persistent.mapping import PersistentMapping
+from pypes.exceptions import PypesError, PypesLookupError
+
+registry_name = 'pypes_services' # Key to service registry in db root
+
+def initServices(connection, force=False):
+    """Initialize the service registry in the database referred from connection
+    then return it.
+
+    connection -- an open zodb connection
+
+    force -- If False (the default), the function does not replace an existing
+    registry. If True then the registry is replaced if existing. This can
+    lead to data loss, so be sure you really want this!
+    """
+    root = connection.root()
+    if not root.has_key(registry_name) or force:
+        root[registry_name] = PersistentMapping()
+    return root[registry_name]
+
+
+def addService(connection, name, service):
+    """Adds a service to the registry if it does not already exist. This
+    is the safe way to add a service because it never affects existing
+    services. If the service already exists, then a PypesError is raised.
+
+    connection -- an open zodb connection
+
+    name -- Name of the service
+
+    service -- IPersistentService object
+    """
+    registry = connection.root()[registry_name]
+    if registry.has_key(name):
+        raise PypesError, 'Service %s already exists' % name
+    registry[name] = service
+    
+
+def setService(connection, name, service):
+    """Like add service, but will also replace existing services. Use with
+    care, since services can contain user data."""
+    registry = connection.root()[registry_name]
+    registry[name] = service
+
+
+def delService(connection, name):
+    """Remove service from registry and any data contained in it"""
+    registry = connection.root()[registry_name]
+    try:
+        del registry[name]
+    except KeyError:
+        raise PypesLookupError, 'No service named %s' % name
+
+
+def hasService(connection, name):
+    """Return true if service name is available from connection"""
+    registry = connection.root()[registry_name]
+    return registry.has_key(name)


=== Packages/pypes/pypes/services.py 1.3 => 1.4 ===
--- Packages/pypes/pypes/services.py:1.3	Fri Jan 30 00:35:38 2004
+++ Packages/pypes/pypes/services.py	Mon Feb  9 16:14:57 2004
@@ -1,82 +1,82 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""pypes services module
-
-Access to pypes persistent services
-
-$Id$"""
-
-from exceptions import PypesError, PypesLookupError
-from persistent import Persistent
-from ZODB.Connection import Connection
-from serviceconfig import registry_name
-
-
-def get(accesspoint, name):
-    """Generic service accessor. Loads a service by name from the accesspoint
-    and returns it. Services are global to a database, the same service will
-    be returned for a given name for all objects in the database when used
-    as accesspoints.
-    If the service is not available in the datamanager, PypesLookupError is 
-    raised.
-
-    Usage: services.get(someobj, 'identity')::
-
-      accesspoint -- An IAppConnection or an IPersistent object. The database
-      connection for the object must be open for the call to succeed.
-
-      name -- String name of the service.
-    """
-    if isinstance(accesspoint, Persistent):
-        accesspoint = accesspoint._p_jar
-    root = accesspoint.root()
-    try:
-        return root[registry_name][name]
-    except KeyError:
-        raise PypesLookupError, 'Service %s could not be accessed.' % name
-
-
-def identity(accesspoint):
-    """Convenience function to access the identity service from accesspoint
-    
-    Usage: services.identity(someobj)
-    """
-    return get(accesspoint, 'identity')
-
-def event(accesspoint):
-    """Convenience function to access the event service from accesspoint
-    
-    Usage: services.event(someobj)
-    """
-    return get(accesspoint, 'event')
-
-
-def all(accesspoint):
-    """Return a dictionary containing all services available from accesspoint
-    This dictionary is copied from the persistent registry, therefore
-    it cannot be used to add or remove services from the database.
-
-    Usage: svcs = services.all(someobj)
-    """
-    if isinstance(accesspoint, Persistent):
-        accesspoint = accesspoint._p_jar
-    try:
-        return dict(accesspoint.root()[registry_name])
-    except KeyError:
-        raise PypesLookupError, 'Service registry could not be accessed.'
-    except (AttributeError, TypeError):
-        raise PypesLookupError, 'Invalid connection object.'
-
-
-
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""pypes services module
+
+Access to pypes persistent services
+
+$Id$"""
+
+from exceptions import PypesError, PypesLookupError
+from persistent import Persistent
+from ZODB.Connection import Connection
+from serviceconfig import registry_name
+
+
+def get(accesspoint, name):
+    """Generic service accessor. Loads a service by name from the accesspoint
+    and returns it. Services are global to a database, the same service will
+    be returned for a given name for all objects in the database when used
+    as accesspoints.
+    If the service is not available in the datamanager, PypesLookupError is 
+    raised.
+
+    Usage: services.get(someobj, 'identity')::
+
+      accesspoint -- An IAppConnection or an IPersistent object. The database
+      connection for the object must be open for the call to succeed.
+
+      name -- String name of the service.
+    """
+    if isinstance(accesspoint, Persistent):
+        accesspoint = accesspoint._p_jar
+    root = accesspoint.root()
+    try:
+        return root[registry_name][name]
+    except KeyError:
+        raise PypesLookupError, 'Service %s could not be accessed.' % name
+
+
+def identity(accesspoint):
+    """Convenience function to access the identity service from accesspoint
+    
+    Usage: services.identity(someobj)
+    """
+    return get(accesspoint, 'identity')
+
+def event(accesspoint):
+    """Convenience function to access the event service from accesspoint
+    
+    Usage: services.event(someobj)
+    """
+    return get(accesspoint, 'event')
+
+
+def all(accesspoint):
+    """Return a dictionary containing all services available from accesspoint
+    This dictionary is copied from the persistent registry, therefore
+    it cannot be used to add or remove services from the database.
+
+    Usage: svcs = services.all(someobj)
+    """
+    if isinstance(accesspoint, Persistent):
+        accesspoint = accesspoint._p_jar
+    try:
+        return dict(accesspoint.root()[registry_name])
+    except KeyError:
+        raise PypesLookupError, 'Service registry could not be accessed.'
+    except (AttributeError, TypeError):
+        raise PypesLookupError, 'Invalid connection object.'
+
+
+




More information about the Zope-CVS mailing list