[Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Traversing - AcquireNamespace.py:1.1.2.1 AttrItemNamespaces.py:1.1.2.1 CreateNamespace.py:1.1.2.1 EtcNamespace.py:1.1.2.1 Exceptions.py:1.1.2.1 INamespaceHandler.py:1.1.2.1 Namespaces.py:1.1.2.1 ParameterParsing.py:1.1.2.1 PresentationNamespaces.py:1.1.2.1 DefaultTraversable.py:1.1.2.6 ITraversable.py:1.1.2.3 Traverser.py:1.1.2.11

Jim Fulton jim@zope.com
Thu, 23 May 2002 14:01:48 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/App/Traversing
In directory cvs.zope.org:/tmp/cvs-serv26429/lib/python/Zope/App/Traversing

Modified Files:
      Tag: Zope-3x-branch
	DefaultTraversable.py ITraversable.py Traverser.py 
Added Files:
      Tag: Zope-3x-branch
	AcquireNamespace.py AttrItemNamespaces.py CreateNamespace.py 
	EtcNamespace.py Exceptions.py INamespaceHandler.py 
	Namespaces.py ParameterParsing.py PresentationNamespaces.py 
Log Message:
This all started with wanting to be able to use url;view in a ZPT path. :)

That lead me to:

- Massive traversal refactoring.

  Namespace handling is now centralized in Zope.App.Traversing. 

- ZPT refactoring, including some renaming that touches pretty much everything. :)

  - The application specific ZPT support was moved into
    Zope.App.PageTemplate. 

  - To get page template files (for use in views):

    from Zope.App.PageTemplate import ViewPageTemplateFile

  - Fixed up security so that ZPT expressions only have access to 
    safe builtins and so that modules namespace does imports safely.

  - Got ZPTPage working!

- renaming url to absolute_url and got absolute_url to work in paths.

- Cleaned up the (as yet unused) RestrictedInterpreter module in
  Zope.Security. In particular, changed to use a separate
  RestrictedBuiltins module.



=== Added File Zope3/lib/python/Zope/App/Traversing/AcquireNamespace.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: AcquireNamespace.py,v 1.1.2.1 2002/05/23 18:01:17 jim Exp $
"""

from Namespaces import provideNamespaceHandler
from Exceptions import UnexpectedParameters
from Zope.Exceptions import NotFoundError
from Zope.ComponentArchitecture import getAdapter
from Zope.Proxy.ContextWrapper import ContextWrapper, getWrapperContext
from ITraversable import ITraversable

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

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

    i = 0
    origOb = ob
    while i < 200:
        i += 1
        traversable = getAdapter(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)

provideNamespaceHandler('acquire', acquire)



=== Added File Zope3/lib/python/Zope/App/Traversing/AttrItemNamespaces.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: AttrItemNamespaces.py,v 1.1.2.1 2002/05/23 18:01:17 jim Exp $
"""

from Zope.ComponentArchitecture import getRequestView, getRequestResource
from Namespaces import provideNamespaceHandler
from Exceptions import UnexpectedParameters

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

provideNamespaceHandler('attribute', attr)

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

provideNamespaceHandler('item', item)


# YAGNI
# 
# def accessor(name, parameters, ob, request):
#     if parameters:
#         raise UnexpectedParameters(parameters)
# 
#     method = getattr(ob, name, None)
#     if method is None: 
#         raise NotFound(ob, name, request)
# 
#     return method()
# 
# provideNamespaceHandler('accessor', accessor)


=== Added File Zope3/lib/python/Zope/App/Traversing/CreateNamespace.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: CreateNamespace.py,v 1.1.2.1 2002/05/23 18:01:17 jim Exp $
"""

from Zope.ComponentArchitecture import getService
from Namespaces import provideNamespaceHandler
from Exceptions import UnexpectedParameters
from Zope.Exceptions import NotFoundError
from Zope.Proxy.ContextWrapper import ContextWrapper

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

    for addable in getService(ob, 'AddableContent').getAddables(ob):
        if addable.id == name:
            return ContextWrapper(addable, ob, name=name)
        
    raise NotFoundError(ob, pname)

provideNamespaceHandler('create', create)


=== Added File Zope3/lib/python/Zope/App/Traversing/EtcNamespace.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: EtcNamespace.py,v 1.1.2.1 2002/05/23 18:01:17 jim Exp $
"""
from Zope.App.OFS.ApplicationControl.ApplicationControl \
     import ApplicationController
from Namespaces import provideNamespaceHandler
from Exceptions import UnexpectedParameters
from Zope.Exceptions import NotFoundError

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 is None:
        return ApplicationController

    if name != 'Services':
        
        raise NotFoundError(ob, pname, request)

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

    return method()

provideNamespaceHandler('etc', etc)


=== Added File Zope3/lib/python/Zope/App/Traversing/Exceptions.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: Exceptions.py,v 1.1.2.1 2002/05/23 18:01:17 jim Exp $
"""
from Zope.Exceptions import NotFoundError

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


=== Added File Zope3/lib/python/Zope/App/Traversing/INamespaceHandler.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: INamespaceHandler.py,v 1.1.2.1 2002/05/23 18:01:17 jim Exp $
"""

from Interface import Interface

class INamespaceHandler(Interface):

    def __call__(name, parameters, pname, object, request):
        """Access a name in a namespace

        The name lookup usually depends on an object and/or a
        request. If an object or request is unavailable, None will be passed.

        The parameters provided, are passed as a sequence of
        name, value items.  The 'pname' argument has the original name
        before parameters were removed. 

        It is not the respoonsibility of the handler to wrap the return value.
        """


=== Added File Zope3/lib/python/Zope/App/Traversing/Namespaces.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: Namespaces.py,v 1.1.2.1 2002/05/23 18:01:17 jim Exp $
"""

from Zope.Exceptions import NotFoundError
from Zope.Proxy.ContextWrapper import ContextWrapper

_namespace_handlers = {}

def provideNamespaceHandler(ns, handler):
    _namespace_handlers[ns] = 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
    """
    
    handler = _namespace_handlers.get(ns)
    if handler is None:
        raise NotFoundError(name)
    new = ContextWrapper(handler(qname, parameters, name, object, request),
                         object, name=name)
    return new

# Register the etc, view, and resource namespaces
import EtcNamespace, PresentationNamespaces, AttrItemNamespaces


=== Added File Zope3/lib/python/Zope/App/Traversing/ParameterParsing.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
# 
##############################################################################
"""

Revision information:
$Id: ParameterParsing.py,v 1.1.2.1 2002/05/23 18:01:17 jim Exp $
"""

class DuplicateNamespaces(Exception):
    """More than one namespace was specified in a request"""

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 = ''
    parts = name.split(';')
    nm = parts[:1][0]
    parms = ()
    for param in parts[1:]:
        l = param.find('=')
        if l >= 0:
            pname = param[:l]
            pval = param[l+1:]
            if pname == 'ns':
                if ns:
                    raise DuplicateNamespaces(name)
                ns = pval
            else:
                parms += ((pname, pval),)
        else:
            if ns:
                raise DuplicateNamespaces(name)
            ns = param

    return ns, nm, parms


=== Added File Zope3/lib/python/Zope/App/Traversing/PresentationNamespaces.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: PresentationNamespaces.py,v 1.1.2.1 2002/05/23 18:01:17 jim Exp $
"""

from Zope.ComponentArchitecture import getRequestView, getRequestResource
from Namespaces import provideNamespaceHandler
from Exceptions import UnexpectedParameters
from Zope.Exceptions import NotFoundError

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

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

provideNamespaceHandler('view', view)

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

provideNamespaceHandler('resource', resource)



=== Zope3/lib/python/Zope/App/Traversing/DefaultTraversable.py 1.1.2.5 => 1.1.2.6 ===
 from ITraversable import ITraversable
 from Zope.Exceptions import NotFoundError
+from Exceptions import UnexpectedParameters
 
 class DefaultTraversable:
     """Traverses objects via attribute and item lookup"""
@@ -22,7 +23,9 @@
     def __init__(self, subject):
         self._subject = subject
 
-    def traverse(self, name, furtherPath):
+    def traverse(self, name, parameters, pname, furtherPath):
+        if parameters:
+            raise UnexpectedParameters(parameters)
         subject = self._subject
         r = getattr(subject, name, self) # self used as marker
         if r is not self:
@@ -32,5 +35,5 @@
             # Let exceptions propagate.
             return self._subject[name]
         else:
-            raise NotFoundError, name
+            raise NotFoundError(self._subject, name)
 


=== Zope3/lib/python/Zope/App/Traversing/ITraversable.py 1.1.2.2 => 1.1.2.3 ===
     """To traverse an object, this interface must be provided"""
 
-    def traverse(name, furtherPath):
+    def traverse(name, parameters, pname, furtherPath):
         """Get the next item on the path
 
-        furtherPath is a list of names still to be traversed. This method is
-        allowed to change the contents of furtherPath.
-
         Should return the item corresponding to 'name' or raise
         Zope.Exceptions.NotFoundError where appropriate.
+
+        The parameters provided, are passed as a sequence of
+        name, value items.  The 'pname' argument has the original name
+        before parameters were removed. 
+
+        furtherPath is a list of names still to be traversed. This method is
+        allowed to change the contents of furtherPath.
         
         """


=== Zope3/lib/python/Zope/App/Traversing/Traverser.py 1.1.2.10 => 1.1.2.11 ===
 from Zope.ComponentArchitecture import getAdapter
 from Zope.Exceptions import NotFoundError, Unauthorized
+from Namespaces import namespaceLookup
+from ParameterParsing import parameterizedNameParse
 from Zope.Security.SecurityManagement import getSecurityManager
 
 from types import StringTypes
@@ -42,9 +44,7 @@
 
     __implements__ = ITraverser
 
-    # XXX: This is wishful thinking, as it doesn't work like this yet
-    #      Arguably this feature should work for unwrapped objects as well.
-    # __used_for__ = IWrapper
+    # This adapter can be used for any object.
 
     def __init__(self, wrapper):
         self._wrapper = wrapper
@@ -65,7 +65,7 @@
 
         return tuple(path)
     
-    def traverse(self, path, default=_marker):
+    def traverse(self, path, default=_marker, request=None):
         if not path:
             return self._wrapper
 
@@ -96,11 +96,22 @@
                     curr = getWrapperContext(curr) or curr
                     continue
 
+
+                if name.find(';') >= 0:
+                    ns, nm, parms = parameterizedNameParse(name)
+                    if ns:
+                        curr = namespaceLookup(name, ns, nm, parms,
+                                               curr, request)
+                        continue
+                else:
+                    parms = ()
+                    nm = name
+
                 traversable = getAdapter(curr, ITraversable, None)
                 if traversable is None:
                     raise NotFoundError, 'No traversable adapter found'
 
-                next = traversable.traverse(name, path)
+                next = traversable.traverse(nm, parms, name, path)
                 curr = ContextWrapper(next, curr, name=name)
 
             return curr
@@ -109,4 +120,5 @@
             if default == _marker:
                 raise
             return default
+