[Checkins] SVN: zope.location/trunk/ * Add ``getParents`` method to the ILocationInfo (it's actually used by zope.traversing, but was not added to the interface).
Dan Korostelev
nadako at gmail.com
Mon Feb 2 05:59:26 EST 2009
Log message for revision 95958:
* Add ``getParents`` method to the ILocationInfo (it's actually used by zope.traversing, but was not added to the interface).
* Beautify doctests and add some more doctests to improve coverage.
* Add coverage-test and coverage-report to the buildout.
* Make ``getName`` method of ILocationInfo adapter return u'' for the root object.
Changed:
_U zope.location/trunk/
U zope.location/trunk/CHANGES.txt
U zope.location/trunk/buildout.cfg
U zope.location/trunk/src/zope/location/interfaces.py
U zope.location/trunk/src/zope/location/location.txt
U zope.location/trunk/src/zope/location/pickling.py
U zope.location/trunk/src/zope/location/traversing.py
-=-
Property changes on: zope.location/trunk
___________________________________________________________________
Modified: svn:ignore
- bin
build
dist
lib
develop-eggs
eggs
parts
.installed.cfg
+ bin
build
dist
lib
develop-eggs
eggs
parts
.installed.cfg
coverage
Modified: zope.location/trunk/CHANGES.txt
===================================================================
--- zope.location/trunk/CHANGES.txt 2009-02-02 10:27:09 UTC (rev 95957)
+++ zope.location/trunk/CHANGES.txt 2009-02-02 10:59:25 UTC (rev 95958)
@@ -5,6 +5,18 @@
3.5.1 (unreleased)
------------------
+- Improve test coverage.
+
+- The new ``getParents`` method was extracted from ``zope.traversing``
+ and added to ILocationInfo interface in the previous release. Custom
+ ILocationInfo implementations should make sure they have this method
+ as well. That method is already used in ``zope.traversing.api.getParents``
+ function.
+
+- Make ``getName`` of ILocationInfo always return empty string for
+ the IRoot object, like RootPhysicallyLocatable from zope.traversing
+ did, making the latter one obsolete.
+
- Change package mailing list address to zope-dev at zope.org instead
of retired zope3-dev at zope.org.
Modified: zope.location/trunk/buildout.cfg
===================================================================
--- zope.location/trunk/buildout.cfg 2009-02-02 10:27:09 UTC (rev 95957)
+++ zope.location/trunk/buildout.cfg 2009-02-02 10:59:25 UTC (rev 95958)
@@ -1,15 +1,18 @@
[buildout]
develop = .
-parts = test compat
-versions = versions
+parts = test coverage-test coverage-report
-[compat]
-recipe = z3c.recipe.compattest
-max_jobs = 3
-
[test]
recipe = zc.recipe.testrunner
eggs = zope.location
-[versions]
-ZODB3 = 3.8.1
+[coverage-test]
+recipe = zc.recipe.testrunner
+eggs = zope.location
+defaults = ['--coverage', '../../coverage']
+
+[coverage-report]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coverage=coverage-report
+arguments = ('coverage', 'coverage/report')
Modified: zope.location/trunk/src/zope/location/interfaces.py
===================================================================
--- zope.location/trunk/src/zope/location/interfaces.py 2009-02-02 10:27:09 UTC (rev 95957)
+++ zope.location/trunk/src/zope/location/interfaces.py 2009-02-02 10:59:25 UTC (rev 95958)
@@ -68,6 +68,15 @@
"""
+ def getParents():
+ """Returns a list starting with the object's parent followed by
+ each of its parents.
+
+ Raises a TypeError if the object is not connected to a containment
+ root.
+
+ """
+
def getName():
"""Return the last segment of the physical path."""
Modified: zope.location/trunk/src/zope/location/location.txt
===================================================================
--- zope.location/trunk/src/zope/location/location.txt 2009-02-02 10:27:09 UTC (rev 95957)
+++ zope.location/trunk/src/zope/location/location.txt 2009-02-02 10:59:25 UTC (rev 95958)
@@ -10,144 +10,182 @@
Usage within an Object field:
->>> from zope.interface import implements, Interface
->>> from zope.schema import Object
->>> from zope.schema.fieldproperty import FieldProperty
->>> from zope.location.interfaces import ILocation
->>> from zope.location.location import Location
+ >>> from zope.interface import implements, Interface
+ >>> from zope.schema import Object
+ >>> from zope.schema.fieldproperty import FieldProperty
+ >>> from zope.location.interfaces import ILocation
+ >>> from zope.location.location import Location
+
+ >>> class IA(Interface):
+ ... location = Object(schema=ILocation, required=False, default=None)
+ >>> class A(object):
+ ... implements(IA)
+ ... location = FieldProperty(IA['location'])
+
+ >>> a = A()
+ >>> a.location = Location()
+
+ >>> loc = Location(); loc.__name__ = u'foo'
+ >>> a.location = loc
+
+ >>> loc = Location(); loc.__name__ = None
+ >>> a.location = loc
+
+ >>> loc = Location(); loc.__name__ = 'foo'
+ >>> a.location = loc
+ Traceback (most recent call last):
+ ...
+ WrongContainedType: [WrongType('foo', <type 'unicode'>)]
->>> class IA(Interface):
-... location = Object(schema=ILocation, required=False, default=None)
->>> class A(object):
-... implements(IA)
-... location = FieldProperty(IA['location'])
->>> a = A()
->>> a.location = Location()
-
->>> loc = Location(); loc.__name__ = u'foo'
->>> a.location = loc
-
->>> loc = Location(); loc.__name__ = None
->>> a.location = loc
-
->>> loc = Location(); loc.__name__ = 'foo'
->>> a.location = loc
-Traceback (most recent call last):
-...
-WrongContainedType: [WrongType('foo', <type 'unicode'>)]
-
-
The `inside` Function
---------------------
The `inside` function tells if l1 is inside l2. L1 is inside l2 if l2 is an
ancestor of l1.
->>> o1 = Location()
->>> o2 = Location(); o2.__parent__ = o1
->>> o3 = Location(); o3.__parent__ = o2
->>> o4 = Location(); o4.__parent__ = o3
+ >>> o1 = Location()
+ >>> o2 = Location(); o2.__parent__ = o1
+ >>> o3 = Location(); o3.__parent__ = o2
+ >>> o4 = Location(); o4.__parent__ = o3
+
+ >>> from zope.location.location import inside
->>> from zope.location.location import inside
->>> inside(o1, o1)
-1
->>> inside(o2, o1)
-1
->>> inside(o3, o1)
-1
->>> inside(o4, o1)
-1
+ >>> inside(o1, o1)
+ True
->>> inside(o1, o4)
-0
+ >>> inside(o2, o1)
+ True
->>> inside(o1, None)
-0
+ >>> inside(o3, o1)
+ True
+ >>> inside(o4, o1)
+ True
+
+ >>> inside(o1, o4)
+ False
+
+ >>> inside(o1, None)
+ False
+
LocationProxy
-------------
The LocationProxy is a non-picklable proxy that can be put around
objects that don't implement `ILocation`.
->>> from zope.location.location import LocationProxy
->>> l = [1, 2, 3]
->>> ILocation.providedBy(l)
-False
->>> p = LocationProxy(l, "Dad", "p")
->>> p
-[1, 2, 3]
->>> ILocation.providedBy(p)
-True
->>> p.__parent__
-'Dad'
->>> p.__name__
-'p'
+ >>> from zope.location.location import LocationProxy
+ >>> l = [1, 2, 3]
+ >>> ILocation.providedBy(l)
+ False
+ >>> p = LocationProxy(l, "Dad", "p")
+ >>> p
+ [1, 2, 3]
+ >>> ILocation.providedBy(p)
+ True
+ >>> p.__parent__
+ 'Dad'
+ >>> p.__name__
+ 'p'
+
+ >>> import pickle
+ >>> p2 = pickle.dumps(p)
+ Traceback (most recent call last):
+ ...
+ TypeError: Not picklable
->>> import pickle
->>> p2 = pickle.dumps(p)
-Traceback (most recent call last):
-...
-TypeError: Not picklable
-
Proxies should get their doc strings from the object they proxy:
->>> p.__doc__ == l.__doc__
-True
+ >>> p.__doc__ == l.__doc__
+ True
+If we get a "located class" somehow, its doc string well be available
+through proxy as well:
+ >>> class LocalClass(object):
+ ... """This is class that can be located"""
+
+ >>> p = LocationProxy(LocalClass)
+ >>> p.__doc__ == LocalClass.__doc__
+ True
+
+LocationInterator
+-----------------
+
+This function allows us to iterate over object and all its parents.
+
+ >>> from zope.location.location import LocationIterator
+
+ >>> o1 = Location()
+ >>> o2 = Location()
+ >>> o3 = Location()
+ >>> o3.__parent__ = o2
+ >>> o2.__parent__ = o1
+
+ >>> iter = LocationIterator(o3)
+ >>> iter.next() is o3
+ True
+ >>> iter.next() is o2
+ True
+ >>> iter.next() is o1
+ True
+ >>> iter.next()
+ Traceback (most recent call last):
+ ...
+ StopIteration
+
+
The `located` function
----------------------
`located` locates an object in another and returns it:
->>> from zope.location.location import located
->>> a = Location()
->>> parent = Location()
->>> a_located = located(a, parent, 'a')
->>> a_located is a
-True
->>> a_located.__parent__ is parent
-True
->>> a_located.__name__
-'a'
+ >>> from zope.location.location import located
+ >>> a = Location()
+ >>> parent = Location()
+ >>> a_located = located(a, parent, 'a')
+ >>> a_located is a
+ True
+ >>> a_located.__parent__ is parent
+ True
+ >>> a_located.__name__
+ 'a'
If we locate the object again, nothing special happens:
->>> a_located_2 = located(a_located, parent, 'a')
->>> a_located_2 is a_located
-True
+ >>> a_located_2 = located(a_located, parent, 'a')
+ >>> a_located_2 is a_located
+ True
-
If the object does not provide ILocation an adapter can be provided:
->>> import zope.interface
->>> import zope.component
->>> sm = zope.component.getGlobalSiteManager()
->>> sm.registerAdapter(LocationProxy, required=(zope.interface.Interface,))
+ >>> import zope.interface
+ >>> import zope.component
+ >>> sm = zope.component.getGlobalSiteManager()
+ >>> sm.registerAdapter(LocationProxy, required=(zope.interface.Interface,))
+
+ >>> l = [1, 2, 3]
+ >>> parent = Location()
+ >>> l_located = located(l, parent, 'l')
+ >>> l_located.__parent__ is parent
+ True
+ >>> l_located.__name__
+ 'l'
+ >>> l_located is l
+ False
+ >>> type(l_located)
+ <class 'zope.location.location.LocationProxy'>
+ >>> l_located_2 = located(l_located, parent, 'l')
+ >>> l_located_2 is l_located
+ True
->>> l = [1, 2, 3]
->>> parent = Location()
->>> l_located = located(l, parent, 'l')
->>> l_located.__parent__ is parent
-True
->>> l_located.__name__
-'l'
->>> l_located is l
-False
->>> type(l_located)
-<class 'zope.location.location.LocationProxy'>
->>> l_located_2 = located(l_located, parent, 'l')
->>> l_located_2 is l_located
-True
-
When changing the name, we still do not get a different proxied object:
->>> l_located_3 = located(l_located, parent, 'new-name')
->>> l_located_3 is l_located_2
-True
+ >>> l_located_3 = located(l_located, parent, 'new-name')
+ >>> l_located_3 is l_located_2
+ True
->>> sm.unregisterAdapter(LocationProxy, required=(zope.interface.Interface,))
-True
+ >>> sm.unregisterAdapter(LocationProxy, required=(zope.interface.Interface,))
+ True
Modified: zope.location/trunk/src/zope/location/pickling.py
===================================================================
--- zope.location/trunk/src/zope/location/pickling.py 2009-02-02 10:27:09 UTC (rev 95957)
+++ zope.location/trunk/src/zope/location/pickling.py 2009-02-02 10:59:25 UTC (rev 95958)
@@ -56,15 +56,15 @@
>>> c3 = locationCopy(o1.o3)
>>> c3 is o1.o3
- 0
+ False
>>> c3.__parent__ is o1
- 1
+ True
>>> c3.o5 is o1.o3.o5
- 0
+ False
>>> c3.o5.__parent__ is c3
- 1
+ True
>>> c3.o4 is o1.o2.o4
- 1
+ True
"""
tmp = tempfile.TemporaryFile()
@@ -109,27 +109,27 @@
>>> o3 = Location()
>>> id3 = persistent.id(o3)
>>> id3 is None
- 0
+ False
>>> o4 = Location()
>>> id4 = persistent.id(o4)
>>> id4 is None
- 0
+ False
>>> id4 is id3
- 0
+ False
If we ask for the `id` of an outside location more than once, we
always get the same `id` back:
>> persistent.id(o4) == id4
- 1
+ True
We also provide a load function that returns the objects for which
we were given ids:
>>> persistent.load(id3) is o3
- 1
+ True
>>> persistent.load(id4) is o4
- 1
+ True
"""
@@ -210,16 +210,23 @@
>>> persistent.id(o4)
u'/o3/o4'
- We also provide a load function that returns objects by traversing
+ We also provide a load method that returns objects by traversing
given paths. It has to find the root based on the object given to
the constructor. Therefore, that object must also be rooted:
>>> o1.__parent__ = root
>>> persistent.load(u'/o3') is o3
- 1
+ True
>>> persistent.load(u'/o3/o4') is o4
- 1
+ True
+ We must provide an absolute path for the load method:
+
+ >>> persistent.load(u'o3')
+ Traceback (most recent call last):
+ ...
+ ValueError: ('Persistent paths must be absolute', u'o3')
+
"""
def __init__(self, location):
@@ -232,7 +239,7 @@
return None
def load(self, path):
- if path[:1] != u'/':
- raise ValueError("ZPersistent paths must be absolute", path)
+ if not path.startswith(u'/'):
+ raise ValueError("Persistent paths must be absolute", path)
root = LocationPhysicallyLocatable(self.location).getRoot()
return zope.location.interfaces.ITraverser(root).traverse(path[1:])
Modified: zope.location/trunk/src/zope/location/traversing.py
===================================================================
--- zope.location/trunk/src/zope/location/traversing.py 2009-02-02 10:27:09 UTC (rev 95957)
+++ zope.location/trunk/src/zope/location/traversing.py 2009-02-02 10:59:25 UTC (rev 95958)
@@ -27,6 +27,12 @@
class LocationPhysicallyLocatable(object):
"""Provide location information for location objects
+
+ >>> from zope.interface.verify import verifyObject
+ >>> info = LocationPhysicallyLocatable(Location())
+ >>> verifyObject(ILocationInfo, info)
+ True
+
"""
zope.component.adapts(ILocation)
@@ -46,15 +52,15 @@
>>> root = Location()
>>> zope.interface.directlyProvides(root, IRoot)
>>> LocationPhysicallyLocatable(root).getRoot() is root
- 1
+ True
>>> o1 = Location(); o1.__parent__ = root
>>> LocationPhysicallyLocatable(o1).getRoot() is root
- 1
+ True
>>> o2 = Location(); o2.__parent__ = o1
>>> LocationPhysicallyLocatable(o2).getRoot() is root
- 1
+ True
We'll get a TypeError if we try to get the location fo a
rootless object:
@@ -162,6 +168,27 @@
Raises a TypeError if the object is not connected to a containment
root.
+ >>> root = Location()
+ >>> zope.interface.directlyProvides(root, IRoot)
+ >>> LocationPhysicallyLocatable(root).getParents()
+ []
+
+ >>> o1 = Location()
+ >>> o2 = Location()
+ >>> o1.__parent__ = root
+ >>> o2.__parent__ = o1
+ >>> LocationPhysicallyLocatable(o2).getParents() == [o1, root]
+ True
+
+ If the last parent is not an IRoot object, TypeError will be
+ raised as statet before.
+
+ >>> zope.interface.noLongerProvides(root, IRoot)
+ >>> LocationPhysicallyLocatable(o2).getParents()
+ Traceback (most recent call last):
+ ...
+ TypeError: Not enough context information to get all parents
+
"""
# XXX Merge this implementation with getPath. This was refactored
# from zope.traversing.
@@ -186,11 +213,18 @@
See ILocationInfo
- >>> o1 = Location(); o1.__name__ = 'o1'
+ >>> o1 = Location(); o1.__name__ = u'o1'
>>> LocationPhysicallyLocatable(o1).getName()
- 'o1'
+ u'o1'
+ >>> root = Location()
+ >>> zope.interface.directlyProvides(root, IRoot)
+ >>> LocationPhysicallyLocatable(root).getName()
+ u''
+
"""
+ if IRoot.providedBy(self.context):
+ return u''
return self.context.__name__
def getNearestSite(self):
@@ -209,7 +243,17 @@
>>> o1.__name__ = 'o1'
>>> o1.__parent__ = root
>>> LocationPhysicallyLocatable(o1).getNearestSite() is root
- 1
+ True
+
+ >>> zope.interface.directlyProvides(o1, ISite)
+ >>> LocationPhysicallyLocatable(o1).getNearestSite() is o1
+ True
+
+ >>> o2 = Location()
+ >>> o2.__parent__ = o1
+ >>> LocationPhysicallyLocatable(o2).getNearestSite() is o1
+ True
+
"""
if ISite.providedBy(self.context):
return self.context
More information about the Checkins
mailing list