[Zope3-checkins] CVS: Zope3/src/zope/app/traversing - adapters.py:1.1 namespace.py:1.1 __init__.py:1.5 configure.zcml:1.4 meta.zcml:1.3 acquirenamespace.py:NONE attritemnamespaces.py:NONE defaulttraversable.py:NONE etcnamespace.py:NONE exceptions.py:NONE getresource.py:NONE modulenamespace.py:NONE namespaces.py:NONE objectname.py:NONE parameterparsing.py:NONE physicallocationadapters.py:NONE presentationnamespaces.py:NONE skinnamespace.py:NONE traverser.py:NONE

Steve Alexander steve@cat-box.net
Sat, 28 Dec 2002 12:50:04 -0500


Update of /cvs-repository/Zope3/src/zope/app/traversing
In directory cvs.zope.org:/tmp/cvs-serv912/src/zope/app/traversing

Modified Files:
	__init__.py configure.zcml meta.zcml 
Added Files:
	adapters.py namespace.py 
Removed Files:
	acquirenamespace.py attritemnamespaces.py 
	defaulttraversable.py etcnamespace.py exceptions.py 
	getresource.py modulenamespace.py namespaces.py objectname.py 
	parameterparsing.py physicallocationadapters.py 
	presentationnamespaces.py skinnamespace.py traverser.py 
Log Message:
Compressed various independent modules in zope.app.traversing into 
far fewer modules.
Also, changed the place where the textindex lives to one level higher.


=== Added File Zope3/src/zope/app/traversing/adapters.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id: adapters.py,v 1.1 2002/12/28 17:49:33 stevea Exp $
"""

from zope.exceptions import NotFoundError

from zope.app.interfaces.traversing import IObjectName, IPhysicallyLocatable
from zope.app.interfaces.traversing import IContainmentRoot
from zope.app.interfaces.traversing import ITraverser, ITraversable

from zope.component import getAdapter, queryAdapter
from zope.proxy.context import getInnerWrapperData, getWrapperContainer
from zope.proxy.context import ContextWrapper

from zope.app.traversing.namespace import namespaceLookup
from zope.app.traversing.namespace import UnexpectedParameters
from zope.app.traversing.namespace import parameterizedNameParse

from types import StringTypes

__metaclass__ = type
_marker = object()  # opaque marker that doesn't get security proxied

class DefaultTraversable:
    """Traverses objects via attribute and item lookup"""

    __implements__ = ITraversable

    def __init__(self, subject):
        self._subject = subject

    def traverse(self, name, parameters, pname, furtherPath):
        if parameters:
            raise UnexpectedParameters(parameters)
        subject = self._subject
        r = getattr(subject, name, _marker)
        if r is not _marker:
            return r

        if hasattr(subject, '__getitem__'):
            # Let exceptions propagate.
            return self._subject[name]
        else:
            raise NotFoundError(self._subject, name)

class ObjectName(object):

    __implements__ = IObjectName

    def __init__(self, context):
        self.context = context

    def __str__(self):
        dict = getInnerWrapperData(self.context)
        name = dict and dict.get('name') or None
        if name is None:
            raise TypeError, \
                  'Not enough context information to get an object name'
        return name

    __call__ = __str__


class SiteObjectName(object):

    __implements__ = IObjectName

    def __init__(self, context):
        pass

    def __str__(self):
        return ''

    __call__ = __str__

class WrapperPhysicallyLocatable:
    __doc__ = IPhysicallyLocatable.__doc__

    __implements__ =  IPhysicallyLocatable

    def __init__(self, context):
        self.context = context

    def getPhysicalRoot(self):
        "See IPhysicallyLocatable"
        container = getWrapperContainer(self.context)
        if container is None:
            raise TypeError("Not enough context to determine location root")
        return getAdapter(container, IPhysicallyLocatable).getPhysicalRoot()

    def getPhysicalPath(self):
        "See IPhysicallyLocatable"
        context = self.context
        container = getWrapperContainer(context)
        if container is None:
            raise TypeError("Not enough context to determine location")
        name = getInnerWrapperData(context)['name']

        container = getAdapter(container, IPhysicallyLocatable)
        container_path = container.getPhysicalPath()

        if name == '.':
            # skip
            return container_path

        return container_path + (name, )

class RootPhysicallyLocatable:
    __doc__ = IPhysicallyLocatable.__doc__

    __implements__ =  IPhysicallyLocatable

    __used_for__ = IContainmentRoot

    def __init__(self, context):
        self.context = context

    def getPhysicalPath(self):
        "See IPhysicallyLocatable"
        return ('', )

    def getPhysicalRoot(self):
        "See IPhysicallyLocatable"
        return self.context

class Traverser:
    """Provide traverse features"""

    __implements__ = ITraverser

    # This adapter can be used for any object.

    def __init__(self, wrapper):
        self.context = wrapper

    def traverse(self, path, default=_marker, request=None):
        if not path:
            return self.context

        if isinstance(path, StringTypes):
            path = path.split('/')
            if len(path) > 1 and not path[-1]:
                # Remove trailing slash
                path.pop()
        else:
            path = list(path)

        path.reverse()
        pop = path.pop

        curr = self.context
        if not path[-1]:
            # Start at the root
            pop()
            curr = getAdapter(self.context, IPhysicallyLocatable
                              ).getPhysicalRoot()
        try:
            while path:
                name = pop()

                if name == '.':
                    continue

                if name == '..':
                    # XXX This doesn't look right. Why fall back to curr?
                    curr = getWrapperContainer(curr) or curr
                    continue


                if name and name[:1] in '@+':
                    ns, nm, parms = parameterizedNameParse(name)
                    if ns:
                        curr = namespaceLookup(name, ns, nm, parms,
                                               curr, request)
                        continue
                else:
                    parms = ()
                    nm = name

                traversable = queryAdapter(curr, ITraversable, None)
                if traversable is None:
                    raise NotFoundError(
                        'No traversable adapter found', curr)

                next = traversable.traverse(nm, parms, name, path)
                curr = ContextWrapper(next, curr, name=name)

            return curr
        except NotFoundError:
            if default == _marker:
                raise
            return default


=== Added File Zope3/src/zope/app/traversing/namespace.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: namespace.py,v 1.1 2002/12/28 17:49:33 stevea Exp $
"""

from zope.interface import Interface
from zope.exceptions import NotFoundError
from zope.proxy.context import ContextWrapper, getWrapperObject
from zope.proxy.context import getWrapperContext
from zope.configuration.action import Action
from zope.component import queryAdapter, getAdapter, getServiceManager
from zope.component import queryDefaultViewName, getView, getService

from zope.app.interfaces.traversing import ITraversable
from zope.app.applicationcontrol.applicationcontrol \
    import applicationController
from zope.app.content.folder import RootFolder
from zope.app.interfaces.services.service import INameResolver

import re

class UnexpectedParameters(NotFoundError):
    "Unexpected namespace parameters were provided."

class ExcessiveWrapping(NotFoundError):
    "Too many levels of acquisition wrapping. We don't believe them."

class NoRequest(NotFoundError):
    "Attempt to access a presentation component outside of a request context."


_namespace_handlers = {}

def provideNamespaceHandler(ns, handler):
    _namespace_handlers[ns] = handler

def directive(_context, name, handler):
    handler = _context.resolve(handler)
    return [Action(
               discriminator=("traversalNamespace", name),
               callable=provideNamespaceHandler,
               args=(name, handler),
               )]

def namespaceLookup(name, ns, qname, parameters, object, request=None):
    """Lookup a value from a namespace

    name -- the original name
    ns -- The namespace
    qname -- The name without any parameters

    The resulting object is returned in the context of the original.
    This means that the caller should *not* wrap the result.
    """

    handler = _namespace_handlers.get(ns)
    if handler is None:
        raise NotFoundError(name)

    new = handler(qname, parameters, name, object, request)
    if new is object:
        # The handler had a side effect only and didn't look up a
        # different object.  We want to retain the side-effect name
        # for things like URLs.

        # But wait, there's more. The object may be wrapped. If the
        # object is already wrapped and we return the object in the
        # context of itself, the containment context will be wrong,
        # because the inner wrapper will be the original object, so
        # our added layer with the name we want to preserve will be
        # ignored when searching containment.

        # For this reason, we'll remove a layer of wrapping from new
        # before we put it in context.

        new = getWrapperObject(new)

        new = ContextWrapper(new, object, name='.', side_effect_name=name)

    else:
        new = ContextWrapper(new, object, name=name)

    return new


namespace_pattern = re.compile('[+][+]([a-zA-Z0-9_]+)[+][+]')

def parameterizedNameParse(name):
    """Parse a name with parameters, including namespace parameters.

    Return:

    - namespace, or None if there isn't one.

    - unparameterized name.

    - sequence of parameters, as name-value pairs.
    """

    ns = ''
    if name.startswith('@@'):
        ns = 'view'
        name = name[2:]
    else:
        match = namespace_pattern.match(name)
        if match:
            prefix, ns = match.group(0, 1)
            name = name[len(prefix):]

    return ns, name, ()

def getResourceInContext(ob, name, request):
    resource = queryResourceInContext(ob, name, request)
    if resource is None:
        raise NotFoundError(ob, name)
    return resource

def queryResourceInContext(ob, name, request, default=None):
    resource_service = getService(ob, 'Resources')
    resource = resource_service.queryResource(ob, name, request)
    if resource is None:
        return default
    return ContextWrapper(resource, resource_service, name=name)


# ---- namespace processors below ----

def acquire(name, parameters, pname, ob, request):
    if parameters:
        raise UnexpectedParameters(parameters)

    i = 0
    origOb = ob
    while i < 200:
        i += 1
        traversable = queryAdapter(ob, ITraversable, None)
        if traversable is not None:

            try:
                # XXX what do we do if the path gets bigger?
                path = []
                next = traversable.traverse(name, parameters, pname, path)
                if path: continue
            except NotFoundError:
                pass
            else:
                return ContextWrapper(next, ob, name=name)

        ob = getWrapperContext(ob)
        if ob is None:
            raise NotFoundError(origOb, pname)

    raise ExcessiveWrapping(origOb, pname)

def attr(name, parameters, pname, ob, request):
    if parameters:
        raise UnexpectedParameters(parameters)
    return getattr(ob, name)

def item(name, parameters, pname, ob, request):
    if parameters:
        raise UnexpectedParameters(parameters)
    return ob[name]

def etc(name, parameters, pname, ob, request):
    # XXX

    # This is here now to allow us to get service managers from a
    # separate namespace from the content. We add and etc
    # namespace to allow us to handle misc objects.  We'll apply
    # YAGNI for now and hard code this. We'll want something more
    # general later. We were thinking of just calling "get"
    # methods, but this is probably too magic. In particular, we
    # will treat returned objects as sub-objects wrt security and
    # not all get methods may satisfy this assumption. It might be
    # best to introduce some sort of etc registry.

    if parameters:
        raise UnexpectedParameters(parameters)

    if name == 'ApplicationController' and ob.__class__ == RootFolder:
        return applicationController

    if name != 'Services':

        raise NotFoundError(ob, pname, request)

    method_name = "getServiceManager"
    method = getattr(ob, method_name, None)
    if method is None:
        raise NotFoundError(ob, pname, request)

    return method()

def module(name, parameters, pname, ob, request):
    """Used to traverse to a module (in dot notation)"""
    servicemanager = getServiceManager(ob)
    adapter = getAdapter(servicemanager, INameResolver)
    if adapter is not None:
        ob = adapter.resolve(name)
    if queryDefaultViewName(ob, request) is None:
        return Interface
    return ob

def view(name, parameters, pname, ob, request):
    if parameters:
        raise UnexpectedParameters(parameters)
    if not request:
        raise NoRequest(pname)
    return getView(ob, name, request)

def resource(name, parameters, pname, ob, request):
    if parameters:
        raise UnexpectedParameters(parameters)
    if not request:
        raise NoRequest(pname)

    resource = queryResourceInContext(ob, name, request)
    if resource is None:
        raise NotFoundError(ob, pname)

    return resource

def skin(name, parameters, pname, ob, request):

    if parameters:
        raise UnexpectedParameters(parameters)

    if not request:
        raise NoRequest(pname)

    request.setViewSkin(name)

    return ob


=== Zope3/src/zope/app/traversing/__init__.py 1.4 => 1.5 ===
--- Zope3/src/zope/app/traversing/__init__.py:1.4	Sat Dec 28 10:20:50 2002
+++ Zope3/src/zope/app/traversing/__init__.py	Sat Dec 28 12:49:33 2002
@@ -12,13 +12,15 @@
 #
 ##############################################################################
 """
-Traversing the object tree.
+Convenience functions for traversing the object tree.
 """
 from zope.component import getAdapter
 from zope.app.interfaces.traversing import IObjectName, IContainmentRoot
 from zope.app.interfaces.traversing import ITraverser, IPhysicallyLocatable
-from zope.app.traversing.traverser import WrapperChain, Traverser
+# XXX moved to later on to avoid byzantine circular import
+#from zope.app.traversing.adapters import Traverser
 from zope.proxy.context import getWrapperContext, isWrapper
+from zope.proxy.context import getWrapperContainer
 from types import StringTypes
 
 __all__ = ['traverse', 'traverseName', 'objectName', 'getParent',
@@ -45,6 +47,7 @@
           code unexpectedly.
           Consider using traverseName instead.
     """
+    from zope.app.traversing.adapters import Traverser
     traverser = Traverser(place)
     if default is _marker:
         return traverser.traverse(path, request=request)
@@ -100,9 +103,14 @@
     if IContainmentRoot.isImplementedBy(obj):
         return []
     if isWrapper(obj):
-        iterator = WrapperChain(obj)
-        iterator.next()  # send head of chain (current object) to /dev/null
-        parents = [p for p in iterator]
+        parents = []
+        w = obj
+        while 1:
+            w = getWrapperContainer(w)
+            if w is None:
+                break
+            parents.append(w)
+            
         if parents and IContainmentRoot.isImplementedBy(parents[-1]):
             return parents
     raise TypeError, "Not enough context information to get all parents"


=== Zope3/src/zope/app/traversing/configure.zcml 1.3 => 1.4 ===
--- Zope3/src/zope/app/traversing/configure.zcml:1.3	Sat Dec 28 10:35:27 2002
+++ Zope3/src/zope/app/traversing/configure.zcml	Sat Dec 28 12:49:33 2002
@@ -3,47 +3,70 @@
    xmlns:browser='http://namespaces.zope.org/browser'
 >
 
-<adapter factory="zope.app.traversing.traverser.Traverser"
+<adapter factory="zope.app.traversing.adapters.Traverser"
          provides="zope.app.interfaces.traversing.ITraverser"
          />
     <!-- Ultimately, this should be registered only for IWrapper, but that
          won't work like that just now.
          for="zope.proxy.interfaces.context.IWrapper" /> -->
 
-<adapter factory="zope.app.traversing.defaulttraversable.DefaultTraversable"
+<adapter factory="zope.app.traversing.adapters.DefaultTraversable"
          provides="zope.app.interfaces.traversing.ITraversable" />
 
 <adapter
-    factory="zope.app.traversing.objectname.ObjectName"
-    provides="zope.app.traversing.objectname.IObjectName"
+    factory="zope.app.traversing.adapters.ObjectName"
+    provides="zope.app.interfaces.traversing.IObjectName"
     permission='zope.Public'
     />
 
 <adapter
-    factory="zope.app.traversing.objectname.SiteObjectName"
-    provides="zope.app.traversing.objectname.IObjectName"
+    factory="zope.app.traversing.adapters.SiteObjectName"
+    provides="zope.app.interfaces.traversing.IObjectName"
     for="zope.app.interfaces.content.folder.IRootFolder"
     permission='zope.Public'
     />
 
 <adapter 
     provides="zope.app.interfaces.traversing.IPhysicallyLocatable"
-    factory="zope.app.traversing.physicallocationadapters.WrapperPhysicallyLocatable" 
+    factory="zope.app.traversing.adapters.WrapperPhysicallyLocatable" 
     />
 
 <adapter 
     provides="zope.app.interfaces.traversing.IPhysicallyLocatable"
     for="zope.app.interfaces.traversing.IContainmentRoot"
-    factory="zope.app.traversing.physicallocationadapters.RootPhysicallyLocatable" 
+    factory="zope.app.traversing.adapters.RootPhysicallyLocatable" 
     />
 
-<traversalNamespace name="etc" handler="zope.app.traversing.etcnamespace.etc" />
-<traversalNamespace name="view" handler="zope.app.traversing.presentationnamespaces.view" />
-<traversalNamespace name="resource"
-                    handler="zope.app.traversing.presentationnamespaces.resource" />
-<traversalNamespace name="attribute" handler="zope.app.traversing.attritemnamespaces.attr" />
-<traversalNamespace name="item" handler="zope.app.traversing.attritemnamespaces.item" />
-<traversalNamespace name="acquire" handler="zope.app.traversing.acquirenamespace.acquire" />
-<traversalNamespace name="skin" handler="zope.app.traversing.skinnamespace.skin" />
-<traversalNamespace name="module" handler="zope.app.traversing.modulenamespace.module" />
+<traversalNamespace
+    name="etc"
+    handler="zope.app.traversing.namespace.etc"
+    />
+<traversalNamespace
+    name="view"
+    handler="zope.app.traversing.namespace.view"
+    />
+<traversalNamespace
+    name="resource"
+    handler="zope.app.traversing.namespace.resource"
+    />
+<traversalNamespace
+    name="attribute"
+    handler="zope.app.traversing.namespace.attr"
+    />
+<traversalNamespace
+    name="item"
+    handler="zope.app.traversing.namespace.item"
+    />
+<traversalNamespace
+    name="acquire"
+    handler="zope.app.traversing.namespace.acquire"
+    />
+<traversalNamespace
+    name="skin"
+    handler="zope.app.traversing.namespace.skin"
+    />
+<traversalNamespace
+    name="module"
+    handler="zope.app.traversing.namespace.module"
+    />
 </zopeConfigure>


=== Zope3/src/zope/app/traversing/meta.zcml 1.2 => 1.3 ===
--- Zope3/src/zope/app/traversing/meta.zcml:1.2	Wed Dec 25 09:13:26 2002
+++ Zope3/src/zope/app/traversing/meta.zcml	Sat Dec 28 12:49:33 2002
@@ -3,7 +3,7 @@
   <directives namespace="http://namespaces.zope.org/zope">
 
     <directive name="traversalNamespace" attributes="name handler"
-       handler="zope.app.traversing.namespaces.directive" />
+       handler="zope.app.traversing.namespace.directive" />
 
   </directives>
 

=== Removed File Zope3/src/zope/app/traversing/acquirenamespace.py ===

=== Removed File Zope3/src/zope/app/traversing/attritemnamespaces.py ===

=== Removed File Zope3/src/zope/app/traversing/defaulttraversable.py ===

=== Removed File Zope3/src/zope/app/traversing/etcnamespace.py ===

=== Removed File Zope3/src/zope/app/traversing/exceptions.py ===

=== Removed File Zope3/src/zope/app/traversing/getresource.py ===

=== Removed File Zope3/src/zope/app/traversing/modulenamespace.py ===

=== Removed File Zope3/src/zope/app/traversing/namespaces.py ===

=== Removed File Zope3/src/zope/app/traversing/objectname.py ===

=== Removed File Zope3/src/zope/app/traversing/parameterparsing.py ===

=== Removed File Zope3/src/zope/app/traversing/physicallocationadapters.py ===

=== Removed File Zope3/src/zope/app/traversing/presentationnamespaces.py ===

=== Removed File Zope3/src/zope/app/traversing/skinnamespace.py ===

=== Removed File Zope3/src/zope/app/traversing/traverser.py ===