[Zope-CVS] CVS: Packages/pypes/pypes - extent.py:1.3
Casey Duncan
casey at zope.com
Sun Feb 15 23:45:28 EST 2004
Update of /cvs-repository/Packages/pypes/pypes
In directory cvs.zope.org:/tmp/cvs-serv16072
Modified Files:
extent.py
Log Message:
Implement Extent class.
=== Packages/pypes/pypes/extent.py 1.2 => 1.3 ===
--- Packages/pypes/pypes/extent.py:1.2 Tue Feb 10 01:25:36 2004
+++ Packages/pypes/pypes/extent.py Sun Feb 15 23:44:57 2004
@@ -19,10 +19,10 @@
from types import ClassType
from sets import Set
-from zope.interface import implements
+from zope.interface import implements, directlyProvides
from persistent import Persistent
-from BTrees.OOBTree import OOBTree, OOTreeSet
-from pypes import services
+from BTrees.OOBTree import OOBTree, OOTreeSet, union, difference, intersection
+from pypes import services, identity
from pypes.identity import IdRegisteredMessage, IdUnregisteredMessage
from pypes.identity import IdentitySet, listenForIdEvents
from pypes.interfaces import IExtentService, IExtentMap
@@ -30,9 +30,196 @@
from pypes.exceptions import SetLookupError
-class ClassExtent:
- pass
-
+class Extent:
+ """Dynamic set of identified instances of a specific kind"""
+
+ # Extents are dynamically created upon request from an extent map
+ # and therefore do not need to be persistent. They are essentially
+ # specific views of the extent map object.
+
+ implements(IExtent)
+
+ def __init__(self, qualifiers, instances, key=None):
+ """Create the class extent
+
+ qualifiers -- A set of keys to the instances map which identifies
+ which kinds of objects are contained in the extent.
+
+ instances -- A map of type key -> identity set of instances of that
+ type. These sets must be completely disjoint.
+
+ key -- The canonical identifier that is the key to the extent
+ in the extent service. If provided this becomes the key attribute
+ of the extent, and it provides the ICanonicalClass interface
+ """
+ if key is not None:
+ self.key = key
+ directlyProvides(self, ICanonicalExtent)
+ self._qualifiers = qualifiers
+ self._instances = instances
+
+ def __contains__(self, obj):
+ for key in self._qualifiers:
+ try:
+ instances = self._instances[key]
+ except KeyError:
+ pass # No instances for that type
+ else:
+ if obj in instances:
+ return True
+ return False
+
+ def __len__(self):
+ length = 0
+ for key in self._qualifiers:
+ try:
+ instances = self._instances[key]
+ except KeyError:
+ pass # No instances for that type
+ else:
+ length += len(instances)
+ return length
+
+ def __iter__(self):
+ for key in self._qualifiers:
+ try:
+ instances = self._instances[key]
+ except KeyError:
+ pass # No instances for that type
+ else:
+ for obj in instances:
+ yield obj
+
+ def union(self, other):
+ if isinstance(other, Extent):
+ if self._instances is other._instances:
+ extent = self.__class__(
+ union(self._qualifiers, other._qualifiers),
+ self._instances)
+ directlyProvides(extent, IDerivedExtent)
+ return extent
+ else:
+ return identity.multiunion(self._listSets(self, other))
+ elif isinstance(other, IdentitySet):
+ return identity.multiunion(self._listSets(self) + other)
+ else:
+ # Assume other is a sequence of identified objects
+ set = identity.multiunion(self._listSets(self))
+ set.update(other)
+ return set
+
+ __or__ = union
+
+ def difference(self, other):
+ if isinstance(other, Extent):
+ if self._instances is other._instances:
+ extent = self.__class__(
+ difference(self._qualifiers, other._qualifiers),
+ self._instances)
+ directlyProvides(extent, IDerivedExtent)
+ return extent
+ else:
+ return (identity.multiunion(self._listSets(self))
+ - identity.multiunion(self._listSets(other)))
+ elif isinstance(other, IdentitySet):
+ return identity.multiunion(self._listSets(self)) - other
+ else:
+ # Assume other is a sequence of identified objects
+ return (identity.multiunion(self._listSets(self))
+ - IdentitySet(other))
+
+ __sub__ = difference
+
+ def intersection(self, other):
+ if isinstance(other, Extent):
+ if self._instances is other._instances:
+ extent = self.__class__(
+ intersection(self._qualifiers, other._qualifiers),
+ self._instances)
+ directlyProvides(extent, IDerivedExtent)
+ return extent
+ else:
+ return identity.multiintersection(self._listSets(self, other))
+ elif isinstance(other, IdentitySet):
+ return identity.multiintersection(self._listSets(self) + other)
+ else:
+ # Assume other is a sequence of identified objects
+ sets = self._listSets(self)
+ sets.append(IdentitySet(other))
+ return identity.multiintersection(sets)
+
+ __and__ = intersection
+
+ def __invert__(self):
+ inverse_keys = difference(
+ OOTreeSet(self._instances.keys()), self._qualifiers)
+ extent = self.__class__(inverse_keys, self._instances)
+ directlyProvides(extent, IDerivedExtent)
+ return extent
+
+ def issubset(self, other):
+ if isinstance(other, Extent):
+ if self._instances is other._instances:
+ return not difference(self._qualifiers, other._qualifiers)
+ else:
+ self_set = identity.multiintersection(self._listSets(self))
+ other_set = identity.multiintersection(self._listSets(other))
+ return self_set.issubset(other_set)
+ else:
+ self_set = identity.multiintersection(self._listSets(self))
+ return self_set.issubset(other)
+
+ def issuperset(self, other):
+ if isinstance(other, Extent):
+ if self._instances is other._instances:
+ return not difference(other._qualifiers, self._qualifiers)
+ else:
+ self_set = identity.multiintersection(self._listSets(self))
+ other_set = identity.multiintersection(self._listSets(other))
+ return self_set.issuperset(other_set)
+ else:
+ self_set = identity.multiintersection(self._listSets(self))
+ return self_set.issuperset(other)
+
+ def __eq__(self, other):
+ if isinstance(other, Extent):
+ if self._instances is other._instances:
+ return not (difference(self._qualifiers, other._qualifiers) or
+ difference(other._qualifiers, self._qualifiers))
+ else:
+ self_set = identity.multiintersection(self._listSets(self))
+ other_set = identity.multiintersection(self._listSets(other))
+ return self_set == other_set
+ else:
+ self_set = identity.multiintersection(self._listSets(self))
+ return self_set == other
+
+ def __ne__(self, other):
+ if isinstance(other, Extent):
+ if self._instances is other._instances:
+ return (difference(self._qualifiers, other._qualifiers) or
+ difference(other._qualifiers, self._qualifiers))
+ else:
+ self_set = identity.multiintersection(self._listSets(self))
+ other_set = identity.multiintersection(self._listSets(other))
+ return self_set != other_set
+ else:
+ self_set = identity.multiintersection(self._listSets(self))
+ return self_set != other
+
+ ## Helper Methods ##
+
+ def _listSets(self, *extents):
+ """Return a list of identity sets that comprise extents"""
+ sets = []
+ for extent in extents:
+ for key in extent._qualifiers:
+ try:
+ sets.append(self._instances[key])
+ except KeyError:
+ pass # No instances for that type
+ return sets
+
class ClassExtentMap(Persistent):
"""Object extents by class"""
@@ -40,7 +227,7 @@
implements(IExtentMap)
# Extent factory hook for testing/overriding
- _extent_factory = ClassExtent
+ _extent_factory = Extent
def __init__(self, dbconn):
self._subclasses = OOBTree() # Map class key => set of subclass keys
@@ -55,7 +242,7 @@
except KeyError:
raise KeyError, key
else:
- return self._extent_factory(key, subclass_keys, self._instances)
+ return self._extent_factory(subclass_keys, self._instances, key)
else:
raise TypeError, key
More information about the Zope-CVS
mailing list