--- a/src/pyams_utils/traversing.py Mon Jan 07 11:34:52 2019 +0100
+++ b/src/pyams_utils/traversing.py Wed Jan 09 10:14:54 2019 +0100
@@ -15,22 +15,22 @@
# import standard library
-# import interfaces
-from pyams_utils.interfaces.traversing import IPathElements
+from pyramid.compat import decode_path_info, is_nonstr_iter
+from pyramid.exceptions import NotFound, URLDecodeError
from pyramid.interfaces import VH_ROOT_KEY
+from pyramid.location import lineage
+from pyramid.threadlocal import get_current_registry
+from pyramid.traversal import ResourceTreeTraverser, empty, slash, split_path_info
+from zope.interface import Interface
from zope.intid.interfaces import IIntIds
from zope.location.interfaces import IContained
-from zope.traversing.interfaces import ITraversable, BeforeTraverseEvent
+from zope.traversing.interfaces import BeforeTraverseEvent, ITraversable
# import packages
-from pyams_utils.adapter import adapter_config, ContextAdapter
+from pyams_utils.adapter import ContextAdapter, adapter_config
+# import interfaces
+from pyams_utils.interfaces.traversing import IPathElements
from pyams_utils.registry import query_utility
-from pyramid.compat import decode_path_info, is_nonstr_iter
-from pyramid.exceptions import URLDecodeError, NotFound
-from pyramid.location import lineage
-from pyramid.threadlocal import get_current_registry
-from pyramid.traversal import ResourceTreeTraverser, slash, split_path_info, empty
-from zope.interface import Interface
class NamespaceTraverser(ResourceTreeTraverser):
@@ -42,7 +42,8 @@
- support for namespaces with "++" notation
"""
- NAMESPACE_SELECTOR = '++'
+ PLUS_SELECTOR = '+'
+ NAMESPACE_SELECTOR = PLUS_SELECTOR * 2
def __call__(self, request):
@@ -102,64 +103,88 @@
# pushing and popping temporary lists for speed purposes
# and this hurts readability; apologies
i = 0
+ plus_selector = self.PLUS_SELECTOR
+ ns_selector = self.NAMESPACE_SELECTOR
view_selector = self.VIEW_SELECTOR
- ns_selector = self.NAMESPACE_SELECTOR
vpath_tuple = split_path_info(vpath)
for segment in vpath_tuple:
if ob is not root:
request.registry.notify(BeforeTraverseEvent(ob, request))
- if segment[:2] == view_selector:
- # check for view name prefixed by '@@'
- return {'context': ob,
- 'view_name': segment[2:],
- 'subpath': vpath_tuple[i + 1:],
- 'traversed': vpath_tuple[:vroot_idx + i + 1],
- 'virtual_root': vroot,
- 'virtual_root_path': vroot_tuple,
- 'root': root}
+ if segment == plus_selector:
+ # check for custom namespace called '+'
+ # currently this namespace is used in PyAMS_default_theme package to get direct access to a given
+ # content
+ registry = get_current_registry()
+ traverser = registry.queryMultiAdapter((ob, request), ITraversable, '+')
+ if traverser is None:
+ raise NotFound()
+ ob = traverser.traverse(vpath_tuple[vroot_idx + i + 2], vpath_tuple[vroot_idx + i + 3:])
+ i += 1
+ return {
+ 'context': ob,
+ 'view_name': ''.join(vpath_tuple[vroot_idx + i + 2:]),
+ 'subpath': vpath_tuple[i + 2:],
+ 'traversed': vpath_tuple[:vroot_idx + i + 2],
+ 'virtual_root': vroot,
+ 'virtual_root_path': vroot_tuple,
+ 'root': root
+ }
elif segment[:2] == ns_selector:
# check for namespace prefixed by '++'
# when a namespace is detected, named "ITraversable" multi-adapters are searched for
- # context and request, for context and for request, sequentially; a NotFound exception is
- # raised if traverser can't be found, otherwise it's "traverse" method is called to get new
- # context
+ # context and request, or for context, sequentially; a NotFound exception is raised if traverser
+ # can't be found, otherwise it's "traverse" method is called to get new context
ns, name = segment[2:].split(ns_selector, 1)
registry = get_current_registry()
traverser = registry.queryMultiAdapter((ob, request), ITraversable, ns)
if traverser is None:
traverser = registry.queryAdapter(ob, ITraversable, ns)
if traverser is None:
- traverser = registry.queryAdapter(request, ITraversable, ns)
- if traverser is None:
raise NotFound()
ob = traverser.traverse(name, vpath_tuple[vroot_idx + i + 1:])
i += 1
continue
+ elif segment[:2] == view_selector:
+ # check for view name prefixed by '@@'
+ return {
+ 'context': ob,
+ 'view_name': segment[2:],
+ 'subpath': vpath_tuple[i + 1:],
+ 'traversed': vpath_tuple[:vroot_idx + i + 1],
+ 'virtual_root': vroot,
+ 'virtual_root_path': vroot_tuple,
+ 'root': root
+ }
+
try:
getitem = ob.__getitem__
except AttributeError:
- return {'context': ob,
- 'view_name': segment,
- 'subpath': vpath_tuple[i + 1:],
- 'traversed': vpath_tuple[:vroot_idx + i + 1],
- 'virtual_root': vroot,
- 'virtual_root_path': vroot_tuple,
- 'root': root}
+ return {
+ 'context': ob,
+ 'view_name': segment,
+ 'subpath': vpath_tuple[i + 1:],
+ 'traversed': vpath_tuple[:vroot_idx + i + 1],
+ 'virtual_root': vroot,
+ 'virtual_root_path': vroot_tuple,
+ 'root': root
+ }
try:
next = getitem(segment)
except KeyError:
- return {'context': ob,
- 'view_name': segment,
- 'subpath': vpath_tuple[i + 1:],
- 'traversed': vpath_tuple[:vroot_idx + i + 1],
- 'virtual_root': vroot,
- 'virtual_root_path': vroot_tuple,
- 'root': root}
+ return {
+ 'context': ob,
+ 'view_name': segment,
+ 'subpath': vpath_tuple[i + 1:],
+ 'traversed': vpath_tuple[:vroot_idx + i + 1],
+ 'virtual_root': vroot,
+ 'virtual_root_path': vroot_tuple,
+ 'root': root
+ }
if i == vroot_idx:
vroot = next
ob = next
@@ -168,13 +193,15 @@
if ob is not root:
request.registry.notify(BeforeTraverseEvent(ob, request))
- return {'context': ob,
- 'view_name': empty,
- 'subpath': subpath,
- 'traversed': vpath_tuple,
- 'virtual_root': vroot,
- 'virtual_root_path': vroot_tuple,
- 'root': root}
+ return {
+ 'context': ob,
+ 'view_name': empty,
+ 'subpath': subpath,
+ 'traversed': vpath_tuple,
+ 'virtual_root': vroot,
+ 'virtual_root_path': vroot_tuple,
+ 'root': root
+ }
def get_parent(context, interface=Interface, allow_context=True, condition=None):