[Zope-CVS] CVS: Products/Ape/lib/apelib/core - events.py:1.5 gateways.py:1.7 interfaces.py:1.8 io.py:1.5

Shane Hathaway shane@zope.com
Wed, 30 Jul 2003 17:33:35 -0400


Update of /cvs-repository/Products/Ape/lib/apelib/core
In directory cvs.zope.org:/tmp/cvs-serv5368/lib/apelib/core

Modified Files:
	events.py gateways.py interfaces.py io.py 
Log Message:
Merged ape-scan-branch, sneaking in interface updates and minor reformatting.

Ape now watches the filesystem for changes to objects that Zope has in its
cache.


=== Products/Ape/lib/apelib/core/events.py 1.4 => 1.5 ===
--- Products/Ape/lib/apelib/core/events.py:1.4	Mon May 26 15:33:15 2003
+++ Products/Ape/lib/apelib/core/events.py	Wed Jul 30 17:32:59 2003
@@ -90,8 +90,6 @@
 
     __implements__ = interfaces.ILoadEvent
 
-    hash_only = 0
-
 
 class StoreEvent (GatewayEvent):
     """Object storing event."""


=== Products/Ape/lib/apelib/core/gateways.py 1.6 => 1.7 ===
--- Products/Ape/lib/apelib/core/gateways.py:1.6	Wed Jul  9 11:39:59 2003
+++ Products/Ape/lib/apelib/core/gateways.py	Wed Jul 30 17:32:59 2003
@@ -91,6 +91,16 @@
         serials.sort()
         return tuple(serials)
 
+    def getSources(self, event):
+        """Returns data source information.  See IGateway.
+        """
+        res = {}
+        for gw in self._gws.values():
+            sources = gw.getSources(event)
+            if sources is not None:
+                res.update(sources)
+        return res
+
 
 class MappingGateway:
     """Gateway to a simple dictionary (primarily for testing).
@@ -117,4 +127,7 @@
         h = time.time()
         self.data[event.getKeychain()] = (data, h)
         return h
+
+    def getSources(self, event):
+        return None
 


=== Products/Ape/lib/apelib/core/interfaces.py 1.7 => 1.8 ===
--- Products/Ape/lib/apelib/core/interfaces.py:1.7	Mon May 26 15:33:15 2003
+++ Products/Ape/lib/apelib/core/interfaces.py	Wed Jul 30 17:32:59 2003
@@ -147,15 +147,6 @@
 class ILoadEvent (IGatewayEvent):
     """Interface for events involved in loading objects."""
 
-    hash_only = Attribute(
-        'hash_only', """Set when only the hash is needed.
-
-        Sometimes the system only needs the hash value for an object
-        and not the full state.  When this attribute is set, the
-        gateway's load() method can choose to return None as the
-        state.  This is a read-only attribute.
-        """)
-
 
 class IStoreEvent (IGatewayEvent):
     """Interface for events involved in storing objects."""
@@ -352,10 +343,6 @@
         The hash value is either an integer or an object that is
         hashable using the Python hash() function.  The hashable
         object is used to detect storage conflicts.
-
-        If the hash_only attribute of the event is true, the system
-        only needs the hash value and the load() method can return
-        None as the state.
         """
 
     def store(event, data):
@@ -366,6 +353,20 @@
         Returns a new hash value.
         """
 
+    def getSources(event):
+        """Returns source information for a keychain.
+
+        The source information allows the system to poll for changes
+        to keep caches in sync with the data.  Where polling is not
+        necessary, gateways are free to return None.
+
+        The source information is a dictionary in the format:
+        {(repository, source): state}.  The repository must be an
+        ISourceRepository.  The source and state must be in a form
+        recognized by the repository.  Both the repository and source
+        must be hashable.
+        """
+
 
 class IClassifier(Interface):
     """Object classifier
@@ -400,6 +401,24 @@
         """
 
 
+class IConfigurableClassifier (IClassifier):
+    """Classifier that accepts registrations.
+    """
+
+    def register(condition, value, mapper_name):
+        """Registers a sub-mapper to be used when a condition is met.
+
+        The kinds of conditions available depend on the classifier,
+        but the following conditions are expected to be common:
+
+        'class'     - matches a fully-qualified class name
+        'extension' - matches a filename extension
+        'key'       - matched the end of the keychain
+        'fallback'  - matches when no other condition is met.  The
+                      fallback values depend on the classifier.
+        """
+
+
 class IKeychainGenerator (Interface):
     """A utility for generating keychains.
 
@@ -529,4 +548,21 @@
     def close():
         """Closes resources.  Called only once."""
 
+
+class ISourceRepository(Interface):
+    """Represents a collection of object sources.
+
+    Designed to helps keep a cache in sync with its sources.
+    """
+
+    def freshen(sources):
+        """Returns changed source information.
+
+        The source information is a mapping that maps
+        (source_repository, path) to a state object.  The
+        source_repository will always be this object (the redundancy
+        keeps things simpler for scanners).  This method returns a
+        mapping containing only the items of the input dictionary
+        whose state has changed.
+        """
 


=== Products/Ape/lib/apelib/core/io.py 1.4 => 1.5 ===
--- Products/Ape/lib/apelib/core/io.py:1.4	Mon Jun 23 22:50:05 2003
+++ Products/Ape/lib/apelib/core/io.py	Wed Jul 30 17:32:59 2003
@@ -99,7 +99,7 @@
             initializer.init(event)
 
 
-    def load(self, keychain, hash_only=0):
+    def classifyState(self, keychain):
         mapper = self._root_mapper
         mapper_names = []
         # Follow the keychain to find the right mapper.
@@ -112,12 +112,15 @@
             classification, sub_mapper_name = cfr.classifyState(event)
             mapper_names.append(sub_mapper_name)
             mapper = mapper.getSubMapper(sub_mapper_name)
+        return classification, mapper_names, mapper
+
+
+    def load(self, keychain):
+        classification, mapper_names, mapper = self.classifyState(keychain)
         event = LoadEvent(mapper, keychain, self._conn_map)
-        if hash_only:
-            event.hash_only = 1
         state, hash_value = mapper.getGateway().load(event)
         cs = ClassifiedState(state, classification, mapper_names)
-        return cs, hash_value
+        return event, cs, hash_value
 
 
     def store(self, keychain, classified_state):
@@ -132,7 +135,13 @@
         new_hash = mapper.getGateway().store(event, classified_state.state)
         if cfr is not None:
             cfr.store(event, classified_state.classification)
-        return new_hash
+        return event, new_hash
+
+
+    def getSources(self, keychain):
+        classification, mapper_names, mapper = self.classifyState(keychain)
+        event = LoadEvent(mapper, keychain, self._conn_map)
+        return mapper.getGateway().getSources(event)
 
 
     def newKeychain(self):
@@ -150,7 +159,7 @@
         self._kos = kos
 
 
-    def serialize(self, keychain, obj):
+    def classifyObject(self, obj, keychain):
         mapper = self._root_mapper
         mapper_names = []
         classification = None
@@ -169,6 +178,12 @@
             classification, sub_mapper_name = cfr.classifyObject(obj, keychain)
             mapper_names.append(sub_mapper_name)
             mapper = mapper.getSubMapper(sub_mapper_name)
+        return classification, mapper_names, mapper
+
+
+    def serialize(self, keychain, obj):
+        classification, mapper_names, mapper = self.classifyObject(
+            obj, keychain)
         # Now serialize.
         ser = mapper.getSerializer()
         event = SerializationEvent(self._kos, mapper, keychain, obj)
@@ -240,12 +255,12 @@
         return is_new
 
 
-    def exportObject(self, obj, keychain=None, deactivate_func=None):
+    def exportObject(self, src_obj, dest_keychain=None, deactivate_func=None):
         count = 0
-        if keychain is None:
-            keychain = (self.newKey(),)
-        self._register(keychain, obj)
-        todo = [(keychain, obj)]
+        if dest_keychain is None:
+            dest_keychain = (self.newKey(),)
+        self._register(dest_keychain, src_obj)
+        todo = [(dest_keychain, src_obj)]
         while todo:
             keychain, obj = todo.pop()
             event, classified_state = self.obj_io.serialize(keychain, obj)
@@ -260,16 +275,16 @@
                         todo.append((ext_keychain, ext_obj))
 
 
-    def importObject(self, keychain, obj=None, commit_func=None):
+    def importObject(self, src_keychain, dest_obj=None, commit_func=None):
         count = 0
-        if obj is None:
-            obj = self.getObject(keychain)
-        root_obj = obj
-        self._register(keychain, obj)
-        todo = [(keychain, obj)]
+        if dest_obj is None:
+            dest_obj = self.getObject(src_keychain)
+        root_obj = dest_obj
+        self._register(src_keychain, dest_obj)
+        todo = [(src_keychain, dest_obj)]
         while todo:
             keychain, obj = todo.pop()
-            classified_state, hash_value = self.gw_io.load(keychain)
+            e, classified_state, hash_value = self.gw_io.load(keychain)
             event = self.obj_io.deserialize(keychain, obj, classified_state)
             if self._incomplete.has_key(keychain):
                 del self._incomplete[keychain]
@@ -301,7 +316,7 @@
             return self._objects[keychain]
         except KeyError:
             # This object has not been loaded yet.  Make a stub.
-            classified_state, hash_value = self.gw_io.load(keychain)
+            e, classified_state, hash_value = self.gw_io.load(keychain)
             obj = self.obj_io.newObject(classified_state)
             # Don't fill in the state yet, to avoid infinite
             # recursion.  Just register it.