Namespaces

URL Namespace Implementations

URL namespaces are an extensible mechanism to provide additional control over traversal (for example, disambiguating item versus attribute access) or access to an additional set of traversable names (such as registered views or path adapters). This mechanism is used for path segments that look like ++ns++name. (It is also used for segments like @@name, which is a shortcut for ++view++name. See nsParse() for details.)

ns is the name of the namespace (a named, registered adapter that implements ITraversable) and name is the name to traverse to in that namespace.

The function namespaceLookup() handles this process.

If you configure this package by loading its configure.zcml using zope.configuration.xmlconfig, several namespaces are registered. They are registered both as single adapters for any object, and as multi-adapters (views) for any object together with a zope.publisher.interfaces.IRequest. Those namespaces are:

etc
Implemented in etc
attribute
Implemented in attr
adapter
Implemented in adapter
item
Implemented in item
acquire
Implemented in acquire
view
Implemented in view
resource
Implemented in resource
lang
Implemented in lang
skin
Implemented in skin
vh
Implemented in vh
debug
Implemented in debug (only if the ZCML feature devmode is enabled) and only registered as a multi-adapter.
exception zope.traversing.namespace.UnexpectedParameters[source]

Bases: zope.location.interfaces.LocationError

Unexpected namespace parameters were provided.

exception zope.traversing.namespace.ExcessiveDepth[source]

Bases: zope.location.interfaces.LocationError

Too many levels of containment. We don’t believe them.

zope.traversing.namespace.namespaceLookup(ns, name, object, request=None)[source]

Lookup a value from a namespace.

We look up a value by getting an adapter from the object to ITraversable named ns. If the request is passed, we get a multi-adapter on the object and request (sometimes this is called a “view”).

Let’s start with adapter-based traversal:

>>> class I(zope.interface.Interface):
...     'Test interface'
>>> @zope.interface.implementer(I)
... class C(object):
...     pass

We’ll register a simple testing adapter:

>>> class Adapter(object):
...     def __init__(self, context):
...         self.context = context
...     def traverse(self, name, remaining):
...         return name+'42'

>>> zope.component.provideAdapter(Adapter, (I,), ITraversable, 'foo')

Then given an object, we can traverse it with a namespace-qualified name:

>>> namespaceLookup('foo', 'bar', C())
'bar42'

If we give an invalid namespace, we’ll get a not found error:

>>> namespaceLookup('fiz', 'bar', C())    
Traceback (most recent call last):
  ...
LocationError: (<zope.traversing.namespace.C object at 0x...>, '++fiz++bar')

We’ll get the same thing if we provide a request:

>>> from zope.publisher.browser import TestRequest
>>> request = TestRequest()
>>> namespaceLookup('foo', 'bar', C(), request)    
Traceback (most recent call last):
  ...
LocationError: (<zope.traversing.namespace.C object at 0x...>, '++foo++bar')

We need to provide a view:

>>> class View(object):
...     def __init__(self, context, request):
...         pass
...     def traverse(self, name, remaining):
...         return name+'fromview'
>>> from zope.traversing.testing import browserView
>>> browserView(I, 'foo', View, providing=ITraversable)

>>> namespaceLookup('foo', 'bar', C(), request)
'barfromview'

Clean up:

>>> from zope.testing.cleanup import cleanUp
>>> cleanUp()
zope.traversing.namespace.nsParse(name)[source]

Parse a namespace-qualified name into a namespace name and a name. Returns the namespace name and a name.

A namespace-qualified name is usually of the form ++ns++name, as in:

>>> nsParse('++acquire++foo')
('acquire', 'foo')

The part inside the +s must be an identifier, so:

>>> nsParse('++hello world++foo')
('', '++hello world++foo')
>>> nsParse('+++acquire+++foo')
('', '+++acquire+++foo')

But it may also be a @@foo, which implies the view namespace:

>>> nsParse('@@foo')
('view', 'foo')

>>> nsParse('@@@foo')
('view', '@foo')

>>> nsParse('@foo')
('', '@foo')
class zope.traversing.namespace.acquire(context, request=None)[source]

Bases: zope.traversing.namespace.SimpleHandler

Traversal adapter for the acquire namespace.

This namespace tries to traverse to the given name starting with the context object. If it cannot be found, it proceeds to look at each __parent__ all the way up the tree until it is found.

It ignores its second constructor arg and stores the first one in its context attr.

traverse(name, remaining)[source]

Acquire a name

Let’s set up some example data:

>>> @zope.interface.implementer(ITraversable)
... class testcontent(object):
...     def traverse(self, name, remaining):
...         v = getattr(self, name, None)
...         if v is None:
...             raise LocationError(self, name)
...         return v
...     def __repr__(self):
...         return 'splat'

>>> ob = testcontent()
>>> ob.a = 1
>>> ob.__parent__ = testcontent()
>>> ob.__parent__.b = 2
>>> ob.__parent__.__parent__ = testcontent()
>>> ob.__parent__.__parent__.c = 3

And acquire some names:

>>> adapter = acquire(ob)
>>> adapter.traverse('a', ())
1
>>> adapter.traverse('b', ())
2
>>> adapter.traverse('c', ())
3
>>> adapter.traverse('d', ())
Traceback (most recent call last):
...
LocationError: (splat, 'd')
class zope.traversing.namespace.attr(context, request=None)[source]

Bases: zope.traversing.namespace.SimpleHandler

Traversal adapter for the attribute namespace.

This namespace simply looks for an attribute of the given name.

It ignores its second constructor arg and stores the first one in its context attr.

traverse(name, ignored)[source]

Attribute traversal adapter

This adapter just provides traversal to attributes:

>>> ob = {'x': 1}
>>> adapter = attr(ob)
>>> list(adapter.traverse('keys', ())())
['x']
class zope.traversing.namespace.item(context, request=None)[source]

Bases: zope.traversing.namespace.SimpleHandler

Traversal adapter for the item namespace.

This namespace simply uses __getitem__ to find a value of the given name.

It ignores its second constructor arg and stores the first one in its context attr.

traverse(name, ignored)[source]

Item traversal adapter

This adapter just provides traversal to items:

>>> ob = {'x': 42}
>>> adapter = item(ob)
>>> adapter.traverse('x', ())
42
class zope.traversing.namespace.etc(context, request=None)[source]

Bases: zope.traversing.namespace.SimpleHandler

Traversal adapter for the etc namespace.

This namespace provides for a layer of indirection. The given name is used to find a utility of that name that implements zope.traversing.interfaces.IEtcNamespace.

As a special case, if there is no such utility, and the name is “site”, then we will attempt to call a method named getSiteManager on the context object.

It ignores its second constructor arg and stores the first one in its context attr.

class zope.traversing.namespace.view(context, request)[source]

Bases: object

Traversal adapter for the view (@@) namespace.

This looks for the default multi-adapter from the context and request of the given name.

Raises:zope.location.interfaces.LocationError – If no such adapter can be found.
class zope.traversing.namespace.resource(context, request)[source]

Bases: zope.traversing.namespace.view

Traversal adapter for the resource namespace.

Resources are default adapters of the given name for the request (not the context). The returned object will have its __parent__ set to the context and its __name__ will match the name we traversed.

class zope.traversing.namespace.lang(context, request)[source]

Bases: zope.traversing.namespace.view

Traversal adapter for the lang namespace.

Traversing to name means to adapt the request to zope.i18n.interfaces.IModifiableUserPreferredLanguages and set the name as the only preferred language.

This needs the request to support zope.publisher.interfaces.http.IVirtualHostRequest because it shifts the language name to the application.

class zope.traversing.namespace.skin(context, request)[source]

Bases: zope.traversing.namespace.view

Traversal adapter for the skin namespace.

Traversing to name looks for the zope.publisher.interfaces.browser.IBrowserSkinType utility having the given name, and then applies it to the request with applySkin().

This needs the request to support zope.publisher.interfaces.http.IVirtualHostRequest because it shifts the skin name to the application.

class zope.traversing.namespace.vh(context, request)[source]

Bases: zope.traversing.namespace.view

Traversal adapter for the vh namespace.

Traversing to name, which must be of the form protocol:host:port causes a call to zope.publisher.interfaces.http.IVirtualHostRequest.setApplicationServer(). Segments in the request’s traversal stack up to a prior ++ are collected and become the application names given to zope.publisher.interfaces.http.IVirtualHostRequest.setVirtualHostRoot().

class zope.traversing.namespace.adapter(context, request=None)[source]

Bases: zope.traversing.namespace.SimpleHandler

Traversal adapter for the adapter namespace.

This adapter provides traversal to named adapters for the context registered to provide zope.traversing.interfaces.IPathAdapter.

It ignores its second constructor arg and stores the first one in its context attr.

traverse(name, ignored)[source]

To demonstrate this, we need to register some adapters:

>>> def adapter1(ob):
...     return 1
>>> def adapter2(ob):
...     return 2
>>> zope.component.provideAdapter(
...     adapter1, (None,), IPathAdapter, 'a1')
>>> zope.component.provideAdapter(
...     adapter2, (None,), IPathAdapter, 'a2')

Now, with these adapters in place, we can use the traversal adapter:

>>> ob = object()
>>> adapter = adapter(ob)
>>> adapter.traverse('a1', ())
1
>>> adapter.traverse('a2', ())
2
>>> try:
...     adapter.traverse('bob', ())
... except LocationError:
...     print('no adapter')
no adapter

Clean up:

>>> from zope.testing.cleanup import cleanUp
>>> cleanUp()
class zope.traversing.namespace.debug(context, request)[source]

Bases: zope.traversing.namespace.view

Traversal adapter for the debug namespace.

This adapter allows debugging flags to be set in the request.

See also

zope.publisher.interfaces.IDebugFlags

traverse(name, ignored)[source]

Setup for demonstration:

>>> from zope.publisher.browser import TestRequest
>>> request = TestRequest()
>>> ob = object()
>>> adapter = debug(ob, request)

in debug mode, ++debug++source enables source annotations

>>> request.debug.sourceAnnotations
False
>>> adapter.traverse('source', ()) is ob
True
>>> request.debug.sourceAnnotations
True

++debug++tal enables TAL markup in output

>>> request.debug.showTAL
False
>>> adapter.traverse('tal', ()) is ob
True
>>> request.debug.showTAL
True

++debug++errors enables tracebacks (by switching to debug skin)

>>> from zope.publisher.interfaces.browser import IBrowserRequest
>>> from zope.interface import directlyProvides
>>> from zope.interface import Interface
>>> class Debug(IBrowserRequest):
...     pass
>>> directlyProvides(Debug, IBrowserSkinType)
>>> zope.component.provideUtility(
...     Debug, IBrowserSkinType, name='Debug')
>>> Debug.providedBy(request)
False
>>> adapter.traverse('errors', ()) is ob
True
>>> Debug.providedBy(request)
True

Interfaces already directly provided by the request are still provided by it once the debug skin is applied.

>>> request = TestRequest()
>>> class IFoo(Interface):
...    pass
>>> directlyProvides(request, IFoo)
>>> adapter = debug(ob, request)
>>> adapter.traverse('errors', ()) is ob
True
>>> Debug.providedBy(request)
True
>>> IFoo.providedBy(request)
True

You can specify several flags separated by commas

>>> adapter.traverse('source,tal', ()) is ob
True

Unknown flag names cause exceptions

>>> try:
...     adapter.traverse('badflag', ())
... except ValueError:
...     print('unknown debugging flag')
unknown debugging flag

Of course, if Python was started with the -O flag to disable debugging, none of this is allowed (we simulate this with a private setting on the instance):

>>> adapter.enable_debug = False
>>> adapter.traverse('source', ())
Traceback (most recent call last):
...
ValueError: Debug flags only allowed in debug mode