src/pyams_utils/traversing.py
branchdev-tf
changeset 427 63284c98cdc1
parent 329 1482a4b86075
--- a/src/pyams_utils/traversing.py	Sat Nov 23 01:24:11 2019 +0100
+++ b/src/pyams_utils/traversing.py	Sat Nov 23 14:57:24 2019 +0100
@@ -10,7 +10,14 @@
 # FOR A PARTICULAR PURPOSE.
 #
 
-__docformat__ = 'restructuredtext'
+"""PyAMS_utils.traversing module
+
+This module provides a custom Pyramid "namespace" traverser: using "++name++" URLs allows
+to traverse URLs based on custom traversing adapters.
+
+It also provides a "get_parent" function, which returns a parent object of given object providing
+a given interface.
+"""
 
 from pyramid.compat import decode_path_info, is_nonstr_iter
 from pyramid.exceptions import NotFound, URLDecodeError
@@ -28,6 +35,9 @@
 from pyams_utils.registry import query_utility
 
 
+__docformat__ = 'restructuredtext'
+
+
 class NamespaceTraverser(ResourceTreeTraverser):
     """Custom traverser handling views and namespaces
 
@@ -41,7 +51,7 @@
     NAMESPACE_SELECTOR = PLUS_SELECTOR * 2
 
     def __call__(self, request):
-
+        # pylint: disable=too-many-locals,too-many-branches,too-many-statements
         environ = request.environ
         matchdict = request.matchdict
 
@@ -68,8 +78,8 @@
             except KeyError:
                 # if environ['PATH_INFO'] is just not there
                 path = slash
-            except UnicodeDecodeError as e:
-                raise URLDecodeError(e.encoding, e.object, e.start, e.end, e.reason)
+            except UnicodeDecodeError as exc:
+                raise URLDecodeError(exc.encoding, exc.object, exc.start, exc.end, exc.reason)
 
         if VH_ROOT_KEY in environ:
             # HTTP_X_VHM_ROOT
@@ -83,7 +93,7 @@
             vroot_idx = -1
 
         root = self.root
-        ob = vroot = root
+        obj = vroot = root
 
         request.registry.notify(BeforeTraverseEvent(root, request))
 
@@ -104,27 +114,28 @@
             vpath_tuple = split_path_info(vpath)
 
             for segment in vpath_tuple:
-                if ob is not root:
-                    request.registry.notify(BeforeTraverseEvent(ob, request))
+                if obj is not root:
+                    request.registry.notify(BeforeTraverseEvent(obj, request))
 
                 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
+                    # 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, '+')
+                    traverser = registry.queryMultiAdapter((obj, request), ITraversable, '+')
                     if traverser is None:
                         raise NotFound()
                     try:
-                        ob = traverser.traverse(vpath_tuple[vroot_idx + i + 2], vpath_tuple[vroot_idx + i + 3:])
+                        obj = traverser.traverse(vpath_tuple[vroot_idx + i + 2],
+                                                 vpath_tuple[vroot_idx + i + 3:])
                     except IndexError:
-                        # the "+" namespace traverser is waiting for additional elements from input URL
-                        # so a "+" URL not followed by something else is just an error!
+                        # the "+" namespace traverser is waiting for additional elements from
+                        # input URL so a "+" URL not followed by something else is just an error!
                         raise NotFound()
                     else:
                         i += 1
                         return {
-                            'context': ob,
+                            'context': obj,
                             'view_name': ''.join(vpath_tuple[vroot_idx + i + 2:]),
                             'subpath': vpath_tuple[i + 2:],
                             'traversed': vpath_tuple[:vroot_idx + i + 2],
@@ -135,24 +146,25 @@
 
                 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, 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)
+                    # when a namespace is detected, named "ITraversable" multi-adapters are
+                    # searched for 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
+                    nss, name = segment[2:].split(ns_selector, 1)
                     registry = get_current_registry()
-                    traverser = registry.queryMultiAdapter((ob, request), ITraversable, ns)
+                    traverser = registry.queryMultiAdapter((obj, request), ITraversable, nss)
                     if traverser is None:
-                        traverser = registry.queryAdapter(ob, ITraversable, ns)
+                        traverser = registry.queryAdapter(obj, ITraversable, nss)
                     if traverser is None:
                         raise NotFound()
-                    ob = traverser.traverse(name, vpath_tuple[vroot_idx + i + 1:])
+                    obj = 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,
+                        'context': obj,
                         'view_name': segment[2:],
                         'subpath': vpath_tuple[i + 1:],
                         'traversed': vpath_tuple[:vroot_idx + i + 1],
@@ -162,10 +174,10 @@
                     }
 
                 try:
-                    getitem = ob.__getitem__
+                    getitem = obj.__getitem__
                 except AttributeError:
                     return {
-                        'context': ob,
+                        'context': obj,
                         'view_name': segment,
                         'subpath': vpath_tuple[i + 1:],
                         'traversed': vpath_tuple[:vroot_idx + i + 1],
@@ -175,10 +187,10 @@
                     }
 
                 try:
-                    next = getitem(segment)
+                    next_item = getitem(segment)
                 except KeyError:
                     return {
-                        'context': ob,
+                        'context': obj,
                         'view_name': segment,
                         'subpath': vpath_tuple[i + 1:],
                         'traversed': vpath_tuple[:vroot_idx + i + 1],
@@ -187,15 +199,15 @@
                         'root': root
                     }
                 if i == vroot_idx:
-                    vroot = next
-                ob = next
+                    vroot = next_item
+                obj = next_item
                 i += 1
 
-        if ob is not root:
-            request.registry.notify(BeforeTraverseEvent(ob, request))
+        if obj is not root:
+            request.registry.notify(BeforeTraverseEvent(obj, request))
 
         return {
-            'context': ob,
+            'context': obj,
             'view_name': empty,
             'subpath': subpath,
             'traversed': vpath_tuple,
@@ -210,10 +222,10 @@
 
     :param object context: base element
     :param Interface interface: the interface that parend should implement
-    :param boolean allow_context: if 'True' (the default), traversing is done starting with context; otherwise,
-        traversing is done starting from context's parent
-    :param callable condition: an optional function that should return a 'True' result when called with parent
-        as first argument
+    :param boolean allow_context: if 'True' (the default), traversing is done starting with
+        context; otherwise, traversing is done starting from context's parent
+    :param callable condition: an optional function that should return a 'True' result when
+        called with parent as first argument
     """
     if allow_context:
         parent = context
@@ -238,6 +250,7 @@
 
     @property
     def parents(self):
+        """Get list of parents OIDs"""
         intids = query_utility(IIntIds)
         if intids is None:
             return []