[Zope3-checkins] CVS: Zope3/src/zope/app - dependable.py:1.5

Guido van Rossum guido@python.org
Thu, 12 Jun 2003 15:28:38 -0400


Update of /cvs-repository/Zope3/src/zope/app
In directory cvs.zope.org:/tmp/cvs-serv16761

Modified Files:
	dependable.py 
Log Message:
Add relative/absolute path equivalence to the Dependable class, a la
UseConfiguration, and add unit tests for this.

Refactoring: share more code between Dependable and UseConfiguration.
The common base is in zope/app/dependable.py, for want of a better place.



=== Zope3/src/zope/app/dependable.py 1.4 => 1.5 ===
--- Zope3/src/zope/app/dependable.py:1.4	Tue Jun  3 11:33:55 2003
+++ Zope3/src/zope/app/dependable.py	Thu Jun 12 15:28:08 2003
@@ -19,32 +19,83 @@
 
 from zope.app.interfaces.dependable import IDependable
 from zope.app.interfaces.annotation import IAnnotations
+from zope.app.traversing import getParent, canonicalPath, getPath
 from zope.component import getAdapter
 from zope.interface import implements
 
-key = 'zope.app.dependable.Dependents'
 
-class Dependable:
-    __doc__ = IDependable.__doc__
+class PathSetAnnotation:
 
-    implements(IDependable)
+    """Abstract base class for annotations that are sets of paths.
+
+    To make this into a concrete class, a subclass must set the class
+    attribute 'key' to a unique annotation key.  A subclass may also
+    choose to rename the methods.
+    """
 
     def __init__(self, context):
         self.context = context
+        try:
+            pp = getPath(getParent(self.context))
+            if not pp.endswith("/"):
+                pp += "/"
+            self.pp = pp # parentpath
+        except TypeError:
+            self.pp = ""
+        self.pplen = len(self.pp)
 
-    def addDependent(self, location):
-        "See IDependable"
+    def addPath(self, path):
+        path = self._make_relative(path)
         annotations = getAdapter(self.context, IAnnotations)
-        annotations [key] = annotations.get(key, ()) + (location, )
+        old = annotations.get(self.key, ())
+        fixed = map(self._make_relative, old)
+        if path not in fixed:
+            fixed.append(path)
+        new = tuple(fixed)
+        if new != old:
+            annotations[self.key] = new
 
-    def removeDependent(self, location):
-        "See IDependable"
+    def removePath(self, path):
+        path = self._make_relative(path)
         annotations = getAdapter(self.context, IAnnotations)
-        annotations[key] = tuple([loc
-                                  for loc in annotations.get(key, ())
-                                  if loc != location])
+        old = annotations.get(self.key, ())
+        if old:
+            fixed = map(self._make_relative, old)
+            fixed = [loc for loc in fixed if loc != path]
+            new = tuple(fixed)
+            if new != old:
+                if new:
+                    annotations[self.key] = new
+                else:
+                    del annotations[self.key]
 
-    def dependents(self):
-        "See IDependable"
+    def getPaths(self):
         annotations = getAdapter(self.context, IAnnotations)
-        return annotations.get(key, ())
+        locs = annotations.get(self.key, ())
+        return tuple(map(self._make_absolute, locs))
+
+    def _make_relative(self, path):
+        if path.startswith("/") and self.pp:
+            path = canonicalPath(path)
+            if path.startswith(self.pp):
+                path = path[self.pplen:]
+                while path.startswith("/"):
+                    path = path[1:]
+        return path
+
+    def _make_absolute(self, path):
+        if not path.startswith("/") and self.pp:
+            path = self.pp + path
+        return path
+
+
+class Dependable(PathSetAnnotation):
+    """See IDependable."""
+
+    implements(IDependable)
+
+    key = "zope.app.dependable.Dependents"
+
+    addDependent = PathSetAnnotation.addPath
+    removeDependent = PathSetAnnotation.removePath
+    dependents = PathSetAnnotation.getPaths