Using zope.location

Location

The Location base class is a mix-in that defines __parent__ and __name__ attributes.

Usage within an Object field:

>>> from zope.interface import implementer, 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)
>>> @implementer(IA)
... class A(object):
...     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__ = b'foo'
>>> a.location = loc
Traceback (most recent call last):
...
SchemaNotCorrectlyImplemented: ([WrongType('foo', <type 'unicode'>, '__name__')], 'location')

inside()

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

>>> from zope.location.location import inside

>>> inside(o1, o1)
True

>>> inside(o2, o1)
True

>>> inside(o3, o1)
True

>>> inside(o4, o1)
True

>>> inside(o1, o4)
False

>>> inside(o1, None)
False

LocationProxy

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'

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

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)
>>> next(iter) is o3
True
>>> next(iter) is o2
True
>>> next(iter) is o1
True
>>> next(iter)
Traceback (most recent call last):
...
StopIteration

located()

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'

If we locate the object again, nothing special happens:

>>> 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,))

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

>>> sm.unregisterAdapter(LocationProxy, required=(zope.interface.Interface,))
True