[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.