[Checkins] SVN: zope.browserpage/trunk/ Initial import.

Dan Korostelev nadako at gmail.com
Mon Aug 24 11:54:31 EDT 2009


Log message for revision 103161:
  Initial import.

Changed:
  _U  zope.browserpage/trunk/
  A   zope.browserpage/trunk/CHANGES.txt
  A   zope.browserpage/trunk/README.txt
  A   zope.browserpage/trunk/bootstrap.py
  A   zope.browserpage/trunk/buildout.cfg
  A   zope.browserpage/trunk/setup.py
  A   zope.browserpage/trunk/src/
  A   zope.browserpage/trunk/src/zope/
  A   zope.browserpage/trunk/src/zope/__init__.py
  A   zope.browserpage/trunk/src/zope/browserpage/
  A   zope.browserpage/trunk/src/zope/browserpage/__init__.py
  A   zope.browserpage/trunk/src/zope/browserpage/meta.zcml
  A   zope.browserpage/trunk/src/zope/browserpage/metaconfigure.py
  A   zope.browserpage/trunk/src/zope/browserpage/metadirectives.py
  A   zope.browserpage/trunk/src/zope/browserpage/testfiles/
  A   zope.browserpage/trunk/src/zope/browserpage/testfiles/test.pt
  A   zope.browserpage/trunk/src/zope/browserpage/testfiles/test2.pt
  A   zope.browserpage/trunk/src/zope/browserpage/testfiles/test3.pt
  A   zope.browserpage/trunk/src/zope/browserpage/tests.py

-=-

Property changes on: zope.browserpage/trunk
___________________________________________________________________
Added: svn:ignore
   + bin
develop-eggs
parts
.installed.cfg
coverage


Added: zope.browserpage/trunk/CHANGES.txt
===================================================================
--- zope.browserpage/trunk/CHANGES.txt	                        (rev 0)
+++ zope.browserpage/trunk/CHANGES.txt	2009-08-24 15:54:31 UTC (rev 103161)
@@ -0,0 +1,8 @@
+=======
+CHANGES
+=======
+
+3.9.0 (unreleased)
+==================
+
+Initial release. This package was splitted off from zope.app.publisher.


Property changes on: zope.browserpage/trunk/CHANGES.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: zope.browserpage/trunk/README.txt
===================================================================
--- zope.browserpage/trunk/README.txt	                        (rev 0)
+++ zope.browserpage/trunk/README.txt	2009-08-24 15:54:31 UTC (rev 103161)
@@ -0,0 +1,102 @@
+========
+Overview
+========
+
+*This package is at present not reusable without depending on a large
+chunk of the Zope Toolkit and its assumptions. It is maintained by the*
+`Zope Toolkit project <http://docs.zope.org/zopetoolkit/>`_.
+
+``zope.publisher`` is a general purpose object publishing framework
+which delegates to a publication object for determining the
+to-be-published object.  With Zope 3's default publication from
+``zope.app.publication``, this is usually a view or a resource.
+
+This package, ``zope.app.publisher``, provides base implementations
+for those.  It also provides ZCML directives for configuring views and
+resources.  More specifically, ``zope.app.publisher`` defines the
+following ZCML directives:
+
+* browser:page
+
+* browser:pages
+
+* browser:view
+
+* browser:menu
+
+* browser:menuItem
+
+* browser:menuItems
+
+* browser:addMenuitem
+
+* browser:resource
+
+* browser:resourceDirectory
+
+* browser:defaultSkin
+
+* browser:icon
+
+* xmlrpc:view
+
+
+Views and Browser pages
+=======================
+
+XXX writeme
+
+
+Resources
+=========
+
+Resources are static files and directories that are served to the browser
+directly from the filesystem. The most common example are images, CSS style
+sheets, or JavaScript files.
+
+Resources are be registered under a symbolic name and can later be referred to
+by that name, so their usage is independent from their physical location.
+
+You can register a single file with the `<browser:resource>` directive, and a
+whole directory with the `<browser:resourceDirectory>` directive, for example
+
+  <browser:resource
+    directory="/path/to/static.file"
+    name="myfile"
+    />
+
+  <browser:resourceDirectory
+    directory="/path/to/images"
+    name="main-images"
+    />
+
+This causes a named adapter to be registered that adapts the request to
+zope.interface.Interface (XXX why do we not use an explicit interface?),
+so to later retrieve a resource, use
+`zope.component.getAdapter(request, name='myfile')`.
+
+There are two ways to traverse to a resource,
+
+1. with the 'empty' view on a site, e. g. `http://localhost/@@/myfile`
+   (This is declared by zope.app.publisher.browser)
+
+2. with the `++resource++` namespace, e. g. `http://localhost/++resource++myfile`
+   (This is declared by zope.traversing.namespace)
+
+In case of resource-directories traversal simply continues through its contents,
+e. g. `http://localhost/@@/main-images/subdir/sample.jpg`
+
+Rather than putting together the URL to a resource manually, you should use
+zope.traversing.browser.interfaces.IAbsoluteURL to get the URL, or for a
+shorthand, call the resource object. This has an additional benefit:
+
+If you want to serve resources from a different URL, for example
+because you want to use a web server specialized in serving static files instead
+of the appserver, you can register an IAbsoluteURL adapter for the site under
+the name 'resource' that will be used to compute the base URLs for resources.
+
+For example, if you register 'http://static.example.com/' as the base 'resource'
+URL, the resources from the above example would yield the following absolute
+URLs: http://static.example.com/myfile and
+http://static.example.com/main-images
+(XXX what about http://static.example.com/main-images/subdir/sample.jpg?)


Property changes on: zope.browserpage/trunk/README.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: zope.browserpage/trunk/bootstrap.py
===================================================================
--- zope.browserpage/trunk/bootstrap.py	                        (rev 0)
+++ zope.browserpage/trunk/bootstrap.py	2009-08-24 15:54:31 UTC (rev 103161)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (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.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id: bootstrap.py 73800 2007-03-27 16:16:42Z dobe $
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+                     ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+    cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+    os.P_WAIT, sys.executable, sys.executable,
+    '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+    dict(os.environ,
+         PYTHONPATH=
+         ws.find(pkg_resources.Requirement.parse('setuptools')).location
+         ),
+    ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)


Property changes on: zope.browserpage/trunk/bootstrap.py
___________________________________________________________________
Added: svn:keywords
   + Id,svn:eol-style=native

Added: zope.browserpage/trunk/buildout.cfg
===================================================================
--- zope.browserpage/trunk/buildout.cfg	                        (rev 0)
+++ zope.browserpage/trunk/buildout.cfg	2009-08-24 15:54:31 UTC (rev 103161)
@@ -0,0 +1,22 @@
+[buildout]
+develop = . ../zope.browsermenu
+parts = test coverage-test coverage-report pydev
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = zope.browserpage [test]
+
+[coverage-test]
+recipe = zc.recipe.testrunner
+eggs = zope.browserpage [test]
+defaults = ['--coverage', '../../coverage']
+
+[coverage-report]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coverage=coverage-report
+arguments = ('coverage', 'coverage/report')
+
+[pydev]
+recipe = pb.recipes.pydev
+eggs = zope.browserpage

Added: zope.browserpage/trunk/setup.py
===================================================================
--- zope.browserpage/trunk/setup.py	                        (rev 0)
+++ zope.browserpage/trunk/setup.py	2009-08-24 15:54:31 UTC (rev 103161)
@@ -0,0 +1,60 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (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.
+#
+##############################################################################
+"""zope.browserpage setup
+"""
+from setuptools import setup, find_packages, Extension
+
+long_description = (open('README.txt').read() + '\n\n' +
+                    open('CHANGES.txt').read())
+
+setup(name='zope.browserpage',
+      version = '3.9.0dev',
+      url='http://pypi.python.org/pypi/zope.browserpage/',
+      author='Zope Corporation and Contributors',
+      author_email='zope-dev at zope.org',
+      classifiers = ['Environment :: Web Environment',
+                     'Intended Audience :: Developers',
+                     'License :: OSI Approved :: Zope Public License',
+                     'Programming Language :: Python',
+                     'Operating System :: OS Independent',
+                     'Topic :: Internet :: WWW/HTTP',
+                     'Framework :: Zope3',
+                     ],
+      description='Implementations and means for configuration of Zope 3-'
+                  'style views.',
+      long_description=long_description,
+
+      packages=find_packages('src'),
+      package_dir={'': 'src'},
+
+      namespace_packages=['zope'],
+      include_package_data=True,
+      install_requires=['setuptools',
+                        'zope.app.pagetemplate',
+                        'zope.browser',
+                        'zope.component>=3.7.0',
+                        'zope.configuration',
+                        'zope.interface',
+                        'zope.publisher>=3.8.0',
+                        'zope.schema',
+                        'zope.security',
+                        'zope.traversing>3.7.0',
+                        ],
+      extras_require={
+          'menu': ['zope.browsermenu'],
+          'test': ['zope.testing', 'zope.browsermenu'],
+          },
+
+      zip_safe = False,
+      )


Property changes on: zope.browserpage/trunk/setup.py
___________________________________________________________________
Added: svn:keywords
   + Id,svn:eol-style=native

Added: zope.browserpage/trunk/src/zope/__init__.py
===================================================================
--- zope.browserpage/trunk/src/zope/__init__.py	                        (rev 0)
+++ zope.browserpage/trunk/src/zope/__init__.py	2009-08-24 15:54:31 UTC (rev 103161)
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+    import pkg_resources
+    pkg_resources.declare_namespace(__name__)
+except ImportError:
+    import pkgutil
+    __path__ = pkgutil.extend_path(__path__, __name__)


Property changes on: zope.browserpage/trunk/src/zope/__init__.py
___________________________________________________________________
Added: svn:keywords
   + Id,svn:eol-style=native


Property changes on: zope.browserpage/trunk/src/zope/browserpage/__init__.py
___________________________________________________________________
Added: svn:keywords
   + Id,svn:eol-style=native

Added: zope.browserpage/trunk/src/zope/browserpage/meta.zcml
===================================================================
--- zope.browserpage/trunk/src/zope/browserpage/meta.zcml	                        (rev 0)
+++ zope.browserpage/trunk/src/zope/browserpage/meta.zcml	2009-08-24 15:54:31 UTC (rev 103161)
@@ -0,0 +1,44 @@
+<configure xmlns:meta="http://namespaces.zope.org/meta">
+
+  <meta:directives namespace="http://namespaces.zope.org/browser">
+
+    <meta:directive
+        name="page"
+        schema=".metadirectives.IPageDirective"
+        handler=".metaconfigure.page"
+        />
+
+    <meta:complexDirective
+        name="pages"
+        schema=".metadirectives.IPagesDirective"
+        handler=".metaconfigure.pages"
+        >
+
+      <meta:subdirective
+          name="page"
+          schema=".metadirectives.IPagesPageSubdirective"
+          />
+
+    </meta:complexDirective>
+
+    <meta:complexDirective
+        name="view"
+        schema=".metadirectives.IViewDirective"
+        handler=".metaconfigure.view"
+        >
+
+      <meta:subdirective
+          name="page"
+          schema=".metadirectives.IViewPageSubdirective"
+          />
+
+      <meta:subdirective
+          name="defaultPage"
+          schema=".metadirectives.IViewDefaultPageSubdirective"
+          />
+
+    </meta:complexDirective>
+
+  </meta:directives>
+
+</configure>


Property changes on: zope.browserpage/trunk/src/zope/browserpage/meta.zcml
___________________________________________________________________
Added: svn:eol-style
   + native

Added: zope.browserpage/trunk/src/zope/browserpage/metaconfigure.py
===================================================================
--- zope.browserpage/trunk/src/zope/browserpage/metaconfigure.py	                        (rev 0)
+++ zope.browserpage/trunk/src/zope/browserpage/metaconfigure.py	2009-08-24 15:54:31 UTC (rev 103161)
@@ -0,0 +1,431 @@
+##############################################################################
+#
+# 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.1 (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.
+#
+##############################################################################
+"""Browser configuration code
+
+$Id: viewmeta.py 103154 2009-08-24 14:45:16Z nadako $
+"""
+import os
+
+from zope.component import queryMultiAdapter
+from zope.component.interface import provideInterface
+from zope.component.zcml import handler
+from zope.interface import implements, classImplements, Interface
+from zope.publisher.interfaces import NotFound
+from zope.security.checker import CheckerPublic, Checker, defineChecker
+from zope.configuration.exceptions import ConfigurationError
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+from zope.publisher.interfaces.browser import IBrowserPublisher
+from zope.publisher.browser import BrowserView
+
+from zope.app.pagetemplate.simpleviewclass import SimpleViewClass
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+
+try:
+    from zope.browsermenu.metaconfigure import menuItemDirective
+except ImportError:
+    menuItemDirective = None
+
+# There are three cases we want to suport:
+#
+# Named view without pages (single-page view)
+#
+#     <browser:page
+#         for=".IContact.IContactInfo."
+#         name="info.html" 
+#         template="info.pt"
+#         class=".ContactInfoView."
+#         permission="zope.View"
+#         />
+#
+# Unnamed view with pages (multi-page view)
+#
+#     <browser:pages
+#         for=".IContact."
+#         class=".ContactEditView."
+#         permission="ZopeProducts.Contact.ManageContacts"
+#         >
+# 
+#       <browser:page name="edit.html"       template="edit.pt" />
+#       <browser:page name="editAction.html" attribute="action" />
+#       </browser:pages>
+#
+# Named view with pages (add view is a special case of this)
+#
+#        <browser:view
+#            name="ZopeProducts.Contact"
+#            for="Zope.App.OFS.Container.IAdding."
+#            class=".ContactAddView."
+#            permission="ZopeProducts.Contact.ManageContacts"
+#            >
+#
+#          <browser:page name="add.html"    template="add.pt" />
+#          <browser:page name="action.html" attribute="action" />
+#          </browser:view>
+
+# We'll also provide a convenience directive for add views:
+#
+#        <browser:add
+#            name="ZopeProducts.Contact"
+#            class=".ContactAddView."
+#            permission="ZopeProducts.Contact.ManageContacts"
+#            >
+#
+#          <browser:page name="add.html"    template="add.pt" />
+#          <browser:page name="action.html" attribute="action" />
+#          </browser:view>
+
+# page
+
+def page(_context, name, permission, for_=Interface,
+         layer=IDefaultBrowserLayer, template=None, class_=None,
+         allowed_interface=None, allowed_attributes=None,
+         attribute='__call__', menu=None, title=None, 
+         ):
+    _handle_menu(_context, menu, title, [for_], name, permission, layer)
+    required = {}
+
+    permission = _handle_permission(_context, permission)
+
+    if not (class_ or template):
+        raise ConfigurationError("Must specify a class or template")
+
+    if attribute != '__call__':
+        if template:
+            raise ConfigurationError(
+                "Attribute and template cannot be used together.")
+
+        if not class_:
+            raise ConfigurationError(
+                "A class must be provided if attribute is used")
+
+    if template:
+        template = os.path.abspath(str(_context.path(template)))
+        if not os.path.isfile(template):
+            raise ConfigurationError("No such file", template)
+        required['__getitem__'] = permission
+
+    # TODO: new __name__ attribute must be tested
+    if class_:
+        if attribute != '__call__':
+            if not hasattr(class_, attribute):
+                raise ConfigurationError(
+                    "The provided class doesn't have the specified attribute "
+                    )
+        if template:
+            # class and template
+            new_class = SimpleViewClass(template, bases=(class_, ), name=name)
+        else:
+            if not hasattr(class_, 'browserDefault'):
+                cdict = {
+                    'browserDefault':
+                    lambda self, request: (getattr(self, attribute), ())
+                    }
+            else:
+                cdict = {}
+
+            cdict['__name__'] = name
+            cdict['__page_attribute__'] = attribute
+            new_class = type(class_.__name__, (class_, simple,), cdict)
+
+        if hasattr(class_, '__implements__'):
+            classImplements(new_class, IBrowserPublisher)
+
+    else:
+        # template
+        new_class = SimpleViewClass(template, name=name)
+
+    for n in (attribute, 'browserDefault', '__call__', 'publishTraverse'):
+        required[n] = permission
+
+    _handle_allowed_interface(_context, allowed_interface, permission,
+                              required)
+    _handle_allowed_attributes(_context, allowed_attributes, permission,
+                               required)
+
+    _handle_for(_context, for_)
+
+    defineChecker(new_class, Checker(required))
+
+    _context.action(
+        discriminator = ('view', for_, name, IBrowserRequest, layer),
+        callable = handler,
+        args = ('registerAdapter',
+                new_class, (for_, layer), Interface, name, _context.info),
+        )
+
+
+# pages, which are just a short-hand for multiple page directives.
+
+# Note that a class might want to access one of the defined
+# templates. If it does though, it should use getMultiAdapter.
+
+class pages(object):
+
+    def __init__(self, _context, for_, permission,
+                 layer=IDefaultBrowserLayer, class_=None,
+                 allowed_interface=None, allowed_attributes=None,
+                 ):
+        self.opts = dict(for_=for_, permission=permission,
+                         layer=layer, class_=class_,
+                         allowed_interface=allowed_interface,
+                         allowed_attributes=allowed_attributes,
+                         )
+
+    def page(self, _context, name, attribute='__call__', template=None,
+             menu=None, title=None):
+        return page(_context,
+                    name=name,
+                    attribute=attribute,
+                    template=template,
+                    menu=menu, title=title,
+                    **(self.opts))
+
+    def __call__(self):
+        return ()
+
+# view (named view with pages)
+
+# This is a different case. We actually build a class with attributes
+# for all of the given pages.
+
+class view(object):
+
+    default = None
+
+    def __init__(self, _context, for_, permission,
+                 name='', layer=IDefaultBrowserLayer, class_=None,
+                 allowed_interface=None, allowed_attributes=None,
+                 menu=None, title=None, provides=Interface,
+                 ):
+
+        _handle_menu(_context, menu, title, [for_], name, permission, layer)
+
+        permission = _handle_permission(_context, permission)
+
+        self.args = (_context, name, for_, permission, layer, class_,
+                     allowed_interface, allowed_attributes)
+
+        self.pages = []
+        self.menu = menu
+        self.provides = provides
+
+    def page(self, _context, name, attribute=None, template=None):
+        if template:
+            template = os.path.abspath(_context.path(template))
+            if not os.path.isfile(template):
+                raise ConfigurationError("No such file", template)
+        else:
+            if not attribute:
+                raise ConfigurationError(
+                    "Must specify either a template or an attribute name")
+
+        self.pages.append((name, attribute, template))
+        return ()
+
+    def defaultPage(self, _context, name):
+        self.default = name
+        return ()
+
+    def __call__(self):
+        (_context, name, for_, permission, layer, class_,
+         allowed_interface, allowed_attributes) = self.args
+
+        required = {}
+
+        cdict = {}
+        pages = {}
+
+        for pname, attribute, template in self.pages:
+
+            if template:
+                cdict[pname] = ViewPageTemplateFile(template)
+                if attribute and attribute != name:
+                    cdict[attribute] = cdict[pname]
+            else:
+                if not hasattr(class_, attribute):
+                    raise ConfigurationError("Undefined attribute",
+                                             attribute)
+
+            attribute = attribute or pname
+            required[pname] = permission
+
+            pages[pname] = attribute
+
+        # This should go away, but noone seems to remember what to do. :-(
+        if hasattr(class_, 'publishTraverse'):
+
+            def publishTraverse(self, request, name,
+                                pages=pages, getattr=getattr):
+
+                if name in pages:
+                    return getattr(self, pages[name])
+                view = queryMultiAdapter((self, request), name=name)
+                if view is not None:
+                    return view
+
+                m = class_.publishTraverse.__get__(self)
+                return m(request, name)
+
+        else:
+            def publishTraverse(self, request, name,
+                                pages=pages, getattr=getattr):
+
+                if name in pages:
+                    return getattr(self, pages[name])
+                view = queryMultiAdapter((self, request), name=name)
+                if view is not None:
+                    return view
+
+                raise NotFound(self, name, request)
+
+        cdict['publishTraverse'] = publishTraverse
+
+        if not hasattr(class_, 'browserDefault'):
+            if self.default or self.pages:
+                default = self.default or self.pages[0][0]
+                cdict['browserDefault'] = (
+                    lambda self, request, default=default:
+                    (self, (default, ))
+                    )
+            elif providesCallable(class_):
+                cdict['browserDefault'] = (
+                    lambda self, request: (self, ())
+                    )
+
+        if class_ is not None:
+            bases = (class_, simple)
+        else:
+            bases = (simple,)
+
+        try:
+            cname = str(name)
+        except:
+            cname = "GeneratedClass"
+
+        cdict['__name__'] = name
+        newclass = type(cname, bases, cdict)
+
+        for n in ('publishTraverse', 'browserDefault', '__call__'):
+            required[n] = permission
+
+        _handle_allowed_interface(_context, allowed_interface, permission,
+                                  required)
+        _handle_allowed_attributes(_context, allowed_attributes, permission,
+                                   required)
+        _handle_for(_context, for_)
+
+        defineChecker(newclass, Checker(required))
+
+        if self.provides is not None:
+            _context.action(
+                discriminator = None,
+                callable = provideInterface,
+                args = ('', self.provides)
+                )
+
+        _context.action(
+            discriminator = ('view', (for_, layer), name, self.provides),
+            callable = handler,
+            args = ('registerAdapter',
+                    newclass, (for_, layer), self.provides, name,
+                    _context.info),
+            )
+
+def _handle_menu(_context, menu, title, for_, name, permission,
+                 layer=IDefaultBrowserLayer):
+
+    if menu or title:
+        if not (menu and title):
+            raise ConfigurationError(
+                "If either menu or title are specified, they must "
+                "both be specified.")
+        if len(for_) != 1:
+            raise ConfigurationError(
+                "Menus can be specified only for single-view, not for "
+                "multi-views.")
+
+        if menuItemDirective is None:
+            import warnings
+            warnings.warn_explicit(
+                'Page directive used with "menu" argument, while "zope.browsermenu" '
+                'package is not installed. Doing nothing.',
+                UserWarning,
+                _context.info.file, _context.info.line)
+            return []
+    
+        return menuItemDirective(
+            _context, menu, for_[0], '@@' + name, title,
+            permission=permission, layer=layer)
+
+    return []
+
+def _handle_permission(_context, permission):
+    if permission == 'zope.Public':
+        permission = CheckerPublic
+
+    return permission
+
+def _handle_allowed_interface(_context, allowed_interface, permission,
+                              required):
+    # Allow access for all names defined by named interfaces
+    if allowed_interface:
+        for i in allowed_interface:
+            _context.action(
+                discriminator = None,
+                callable = provideInterface,
+                args = (None, i)
+                )
+
+            for name in i:
+                required[name] = permission
+
+def _handle_allowed_attributes(_context, allowed_attributes, permission,
+                               required):
+    # Allow access for all named attributes
+    if allowed_attributes:
+        for name in allowed_attributes:
+            required[name] = permission
+
+def _handle_for(_context, for_):
+    if for_ is not None:
+        _context.action(
+            discriminator = None,
+            callable = provideInterface,
+            args = ('', for_)
+            )
+
+class simple(BrowserView):
+    implements(IBrowserPublisher)
+
+    def publishTraverse(self, request, name):
+        raise NotFound(self, name, request)
+
+    def __call__(self, *a, **k):
+        # If a class doesn't provide it's own call, then get the attribute
+        # given by the browser default.
+
+        attr = self.__page_attribute__
+        if attr == '__call__':
+            raise AttributeError("__call__")
+
+        meth = getattr(self, attr)
+        return meth(*a, **k)
+
+def providesCallable(class_):
+    if hasattr(class_, '__call__'):
+        for c in class_.__mro__:
+            if '__call__' in c.__dict__:
+                return True
+    return False


Property changes on: zope.browserpage/trunk/src/zope/browserpage/metaconfigure.py
___________________________________________________________________
Added: svn:keywords
   + Id,svn:eol-style=native

Added: zope.browserpage/trunk/src/zope/browserpage/metadirectives.py
===================================================================
--- zope.browserpage/trunk/src/zope/browserpage/metadirectives.py	                        (rev 0)
+++ zope.browserpage/trunk/src/zope/browserpage/metadirectives.py	2009-08-24 15:54:31 UTC (rev 103161)
@@ -0,0 +1,191 @@
+#############################################################################
+#
+# 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.1 (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.
+#
+##############################################################################
+"""Browser configuration code
+
+This module defines the schemas for browser directives.
+
+$Id: metadirectives.py 103154 2009-08-24 14:45:16Z nadako $
+"""
+from zope.interface import Interface
+from zope.configuration.fields import GlobalObject, GlobalInterface
+from zope.configuration.fields import Tokens, Path, PythonIdentifier, MessageID
+from zope.schema import TextLine, Id, Int, Bool
+from zope.security.zcml import Permission
+
+from zope.component.zcml import IBasicViewInformation
+
+try:
+    from zope.browsermenu.field import MenuField
+except ImportError: # avoid hard dependency on zope.browsermenu
+    MenuField = TextLine
+
+
+class IPagesDirective(IBasicViewInformation):
+    """
+    Define multiple pages without repeating all of the parameters.
+
+    The pages directive allows multiple page views to be defined
+    without repeating the 'for', 'permission', 'class', 'layer',
+    'allowed_attributes', and 'allowed_interface' attributes.
+    """
+
+    for_ = GlobalObject(
+        title=u"The interface or class this view is for.",
+        required=False
+        )
+
+    permission = Permission(
+        title=u"Permission",
+        description=u"The permission needed to use the view.",
+        required=True
+        )
+
+class IViewDirective(IPagesDirective):
+    """
+    The view directive defines a view that has subpages.
+
+    The pages provided by the defined view are accessed by first
+    traversing to the view name and then traversing to the page name.
+    """
+
+    for_ = GlobalInterface(
+        title=u"The interface this view is for.",
+        required=False
+        )
+
+    name = TextLine(
+        title=u"The name of the view.",
+        description=u"The name shows up in URLs/paths. For example 'foo'.",
+        required=False,
+        default=u'',
+        )
+
+    menu = MenuField(
+        title=u"The browser menu to include the page (view) in.",
+        description=u"""
+          Many views are included in menus. It's convenient to name
+          the menu in the page directive, rather than having to give a
+          separate menuItem directive.  'zmi_views' is the menu most often
+          used in the Zope management interface.
+          
+          This attribute will only work if zope.browsermenu is installed.
+          """,
+        required=False
+        )
+
+    title = MessageID(
+        title=u"The browser menu label for the page (view)",
+        description=u"""
+          This attribute must be supplied if a menu attribute is
+          supplied.
+
+          This attribute will only work if zope.browsermenu is installed.
+          """,
+        required=False
+        )
+
+    provides = GlobalInterface(
+        title=u"The interface this view provides.",
+        description=u"""
+        A view can provide an interface.  This would be used for
+        views that support other views.""",
+        required=False,
+        default=Interface,
+        )
+
+class IViewPageSubdirective(Interface):
+    """
+    Subdirective to IViewDirective.
+    """
+
+    name = TextLine(
+        title=u"The name of the page (view)",
+        description=u"""
+        The name shows up in URLs/paths. For example 'foo' or
+        'foo.html'. This attribute is required unless you use the
+        subdirective 'page' to create sub views. If you do not have
+        sub pages, it is common to use an extension for the view name
+        such as '.html'. If you do have sub pages and you want to
+        provide a view name, you shouldn't use extensions.""",
+        required=True
+        )
+
+    attribute = PythonIdentifier(
+        title=u"The name of the view attribute implementing the page.",
+        description=u"""
+        This refers to the attribute (method) on the view that is
+        implementing a specific sub page.""",
+        required=False
+        )
+
+    template = Path(
+        title=u"The name of a template that implements the page.",
+        description=u"""
+        Refers to a file containing a page template (should end in
+        extension '.pt' or '.html').""",
+        required=False
+        )
+
+class IViewDefaultPageSubdirective(Interface):
+    """
+    Subdirective to IViewDirective.
+    """
+
+    name = TextLine(
+        title=u"The name of the page that is the default.",
+        description=u"""
+        The named page will be used as the default if no name is
+        specified explicitly in the path. If no defaultPage directive
+        is supplied, the default page will be the first page
+        listed.""",
+        required=True
+        )
+
+
+class IPagesPageSubdirective(IViewPageSubdirective):
+    """
+    Subdirective to IPagesDirective
+    """
+
+    menu = MenuField(
+        title=u"The browser menu to include the page (view) in.",
+        description=u"""
+        Many views are included in menus. It's convenient to name the
+        menu in the page directive, rather than having to give a
+        separate menuItem directive.
+
+        This attribute will only work if zope.browsermenu is installed.
+        """,
+        required=False
+        )
+
+    title = MessageID(
+        title=u"The browser menu label for the page (view)",
+        description=u"""
+        This attribute must be supplied if a menu attribute is
+        supplied.
+
+        This attribute will only work if zope.browsermenu is installed.
+        """,
+        required=False
+        )
+
+class IPageDirective(IPagesDirective, IPagesPageSubdirective):
+    """
+    The page directive is used to create views that provide a single
+    url or page.
+
+    The page directive creates a new view class from a given template
+    and/or class and registers it.
+    """


Property changes on: zope.browserpage/trunk/src/zope/browserpage/metadirectives.py
___________________________________________________________________
Added: svn:keywords
   + Id,svn:eol-style=native

Added: zope.browserpage/trunk/src/zope/browserpage/testfiles/test.pt
===================================================================
--- zope.browserpage/trunk/src/zope/browserpage/testfiles/test.pt	                        (rev 0)
+++ zope.browserpage/trunk/src/zope/browserpage/testfiles/test.pt	2009-08-24 15:54:31 UTC (rev 103161)
@@ -0,0 +1 @@
+<html><body><p>test</p></body></html>


Property changes on: zope.browserpage/trunk/src/zope/browserpage/testfiles/test.pt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: zope.browserpage/trunk/src/zope/browserpage/testfiles/test2.pt
===================================================================
--- zope.browserpage/trunk/src/zope/browserpage/testfiles/test2.pt	                        (rev 0)
+++ zope.browserpage/trunk/src/zope/browserpage/testfiles/test2.pt	2009-08-24 15:54:31 UTC (rev 103161)
@@ -0,0 +1 @@
+<html><body><p tal:content="view/data">test</p></body></html>


Property changes on: zope.browserpage/trunk/src/zope/browserpage/testfiles/test2.pt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: zope.browserpage/trunk/src/zope/browserpage/testfiles/test3.pt
===================================================================
--- zope.browserpage/trunk/src/zope/browserpage/testfiles/test3.pt	                        (rev 0)
+++ zope.browserpage/trunk/src/zope/browserpage/testfiles/test3.pt	2009-08-24 15:54:31 UTC (rev 103161)
@@ -0,0 +1 @@
+<html><body><p tal:content="view/action">test</p></body></html>


Property changes on: zope.browserpage/trunk/src/zope/browserpage/testfiles/test3.pt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: zope.browserpage/trunk/src/zope/browserpage/tests.py
===================================================================
--- zope.browserpage/trunk/src/zope/browserpage/tests.py	                        (rev 0)
+++ zope.browserpage/trunk/src/zope/browserpage/tests.py	2009-08-24 15:54:31 UTC (rev 103161)
@@ -0,0 +1,961 @@
+##############################################################################
+#
+# 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.1 (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.
+#
+##############################################################################
+"""'browser' namespace directive tests
+
+$Id: test_directives.py 103154 2009-08-24 14:45:16Z nadako $
+"""
+
+import sys
+import os
+import unittest
+from cStringIO import StringIO
+
+from zope import component
+from zope.interface import Interface, implements, directlyProvides, providedBy
+
+import zope.security.management
+from zope.configuration.xmlconfig import xmlconfig, XMLConfig
+from zope.configuration.exceptions import ConfigurationError
+from zope.publisher.browser import TestRequest
+from zope.publisher.interfaces import IDefaultViewName
+from zope.publisher.interfaces.browser import IBrowserPublisher
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.publisher.interfaces.browser import IBrowserSkinType, IDefaultSkin
+from zope.security.proxy import removeSecurityProxy, ProxyFactory
+from zope.security.permission import Permission
+from zope.security.interfaces import IPermission
+from zope.testing.doctestunit import DocTestSuite
+from zope.testing import cleanup
+from zope.traversing.adapters import DefaultTraversable
+from zope.traversing.interfaces import ITraversable
+
+import zope.publisher.defaultview
+import zope.browserpage
+import zope.browsermenu
+from zope.browsermenu.menu import getFirstMenuItem
+from zope.browsermenu.interfaces import IMenuItemType
+from zope.component.testfiles.views import IC, V1, VZMI, R1, IV
+
+tests_path = os.path.dirname(__file__)
+
+template = """<configure
+   xmlns='http://namespaces.zope.org/zope'
+   xmlns:browser='http://namespaces.zope.org/browser'
+   i18n_domain='zope'>
+   %s
+   </configure>"""
+
+class templateclass(object):
+    def data(self): return 42
+
+request = TestRequest()
+
+class V2(V1, object):
+
+    def action(self):
+        return self.action2()
+
+    def action2(self):
+        return "done"
+
+class VT(V1, object):
+    def publishTraverse(self, request, name):
+        try:
+            return int(name)
+        except:
+            return super(VT, self).publishTraverse(request, name)
+
+class Ob(object):
+    implements(IC)
+
+ob = Ob()
+
+class NCV(object):
+    "non callable view"
+
+    def __init__(self, context, request):
+        pass
+
+class CV(NCV):
+    "callable view"
+    def __call__(self):
+        pass
+
+
+class C_w_implements(NCV):
+    implements(Interface)
+
+    def index(self):
+        return self
+
+class ITestLayer(IBrowserRequest):
+    """Test Layer."""
+
+class ITestSkin(ITestLayer):
+    """Test Skin."""
+
+
+class ITestMenu(Interface):
+    """Test menu."""
+
+directlyProvides(ITestMenu, IMenuItemType)
+
+class Test(cleanup.CleanUp, unittest.TestCase):
+
+    def setUp(self):
+        super(Test, self).setUp()
+        XMLConfig('meta.zcml', zope.browserpage)()
+        XMLConfig('meta.zcml', zope.browsermenu)()
+        component.provideAdapter(DefaultTraversable, (None,), ITraversable, )
+        zope.security.management.newInteraction()
+
+    def testPage(self):
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='test'),
+            None)
+
+        xmlconfig(StringIO(template % (
+            '''
+            <browser:page
+                name="test"
+                class="zope.component.testfiles.views.V1"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                attribute="index"
+                />
+            '''
+            )))
+
+        v = component.queryMultiAdapter((ob, request), name='test')
+        self.assert_(issubclass(v.__class__, V1))
+
+
+    def testPageWithClassWithMenu(self):
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='test'),
+            None)
+        testtemplate = os.path.join(tests_path, 'testfiles', 'test.pt')
+
+
+        xmlconfig(StringIO(template % (
+            '''
+            <browser:menu
+                id="test_menu" title="Test menu" />
+            <browser:page
+                name="test"
+                class="zope.component.testfiles.views.V1"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                template="%s"
+                menu="test_menu"
+                title="Test View"
+                />
+            ''' % testtemplate
+            )))
+        menuItem = getFirstMenuItem('test_menu', ob, TestRequest())
+        self.assertEqual(menuItem["title"], "Test View")
+        self.assertEqual(menuItem["action"], "@@test")
+        v = component.queryMultiAdapter((ob, request), name='test')
+        self.assertEqual(v(), "<html><body><p>test</p></body></html>\n")
+
+
+    def testPageWithTemplateWithMenu(self):
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='test'),
+            None)
+        testtemplate = os.path.join(tests_path, 'testfiles', 'test.pt')
+
+        xmlconfig(StringIO(template % (
+            '''
+            <browser:menu
+                id="test_menu" title="Test menu"/>
+            <browser:page
+                name="test"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                template="%s"
+                menu="test_menu"
+                title="Test View"
+                />
+            ''' % testtemplate
+            )))
+
+        menuItem = getFirstMenuItem('test_menu', ob, TestRequest())
+        self.assertEqual(menuItem["title"], "Test View")
+        self.assertEqual(menuItem["action"], "@@test")
+        v = component.queryMultiAdapter((ob, request), name='test')
+        self.assertEqual(v(), "<html><body><p>test</p></body></html>\n")
+
+
+    def testPageInPagesWithTemplateWithMenu(self):
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='test'),
+            None)
+        testtemplate = os.path.join(tests_path, 'testfiles', 'test.pt')
+
+        xmlconfig(StringIO(template % (
+            '''
+            <browser:menu
+                id="test_menu" title="Test menu" />
+            <browser:pages
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public">
+              <browser:page
+                  name="test"
+                  template="%s"
+                  menu="test_menu"
+                  title="Test View"
+                  />
+            </browser:pages>
+            ''' % testtemplate
+            )))
+
+        menuItem = getFirstMenuItem('test_menu', ob, TestRequest())
+        self.assertEqual(menuItem["title"], "Test View")
+        self.assertEqual(menuItem["action"], "@@test")
+        v = component.queryMultiAdapter((ob, request), name='test')
+        self.assertEqual(v(), "<html><body><p>test</p></body></html>\n")
+
+
+    def testPageInPagesWithClassWithMenu(self):
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='test'),
+            None)
+        testtemplate = os.path.join(tests_path, 'testfiles', 'test.pt')
+
+        xmlconfig(StringIO(template % (
+            '''
+            <browser:menu
+                id="test_menu" title="Test menu" />
+            <browser:pages
+                for="zope.component.testfiles.views.IC"
+                class="zope.component.testfiles.views.V1"
+                permission="zope.Public">
+              <browser:page
+                  name="test"
+                  template="%s"
+                  menu="test_menu"
+                  title="Test View"
+                  />
+            </browser:pages>
+            ''' % testtemplate
+            )))
+
+        menuItem = getFirstMenuItem('test_menu', ob, TestRequest())
+        self.assertEqual(menuItem["title"], "Test View")
+        self.assertEqual(menuItem["action"], "@@test")
+        v = component.queryMultiAdapter((ob, request), name='test')
+        self.assertEqual(v(), "<html><body><p>test</p></body></html>\n")
+
+    def testSkinPage(self):
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='test'),
+            None)
+
+        xmlconfig(StringIO(template % (
+            '''
+            <browser:page name="test"
+                class="zope.component.testfiles.views.VZMI"
+                layer="
+                  zope.browserpage.tests.ITestLayer"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                attribute="index"
+                />
+            <browser:page name="test"
+                class="zope.component.testfiles.views.V1"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                attribute="index"
+                />
+            '''
+            )))
+
+        v = component.queryMultiAdapter((ob, request), name='test')
+        self.assert_(issubclass(v.__class__, V1))
+        v = component.queryMultiAdapter(
+            (ob, TestRequest(skin=ITestSkin)), name='test')
+        self.assert_(issubclass(v.__class__, VZMI))
+
+
+    def testInterfaceProtectedPage(self):
+        xmlconfig(StringIO(template %
+            '''
+            <browser:page name="test"
+                class="zope.component.testfiles.views.V1"
+                attribute="index"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                allowed_interface="zope.component.testfiles.views.IV"
+                />
+            '''
+            ))
+
+        v = component.getMultiAdapter((ob, request), name='test')
+        v = ProxyFactory(v)
+        self.assertEqual(v.index(), 'V1 here')
+        self.assertRaises(Exception, getattr, v, 'action')
+
+    def testAttributeProtectedPage(self):
+        xmlconfig(StringIO(template %
+            '''
+            <browser:page name="test"
+                class="zope.browserpage.tests.V2"
+                for="zope.component.testfiles.views.IC"
+                attribute="action"
+                permission="zope.Public"
+                allowed_attributes="action2"
+                />
+            '''
+            ))
+
+        v = component.getMultiAdapter((ob, request), name='test')
+        v = ProxyFactory(v)
+        self.assertEqual(v.action(), 'done')
+        self.assertEqual(v.action2(), 'done')
+        self.assertRaises(Exception, getattr, v, 'index')
+
+    def testAttributeProtectedView(self):
+        xmlconfig(StringIO(template %
+            '''
+            <browser:view name="test"
+                class="zope.browserpage.tests.V2"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                allowed_attributes="action2"
+                >
+              <browser:page name="index.html" attribute="action" />
+           </browser:view>
+            '''
+            ))
+
+        v = component.getMultiAdapter((ob, request), name='test')
+        v = ProxyFactory(v)
+        page = v.publishTraverse(request, 'index.html')
+        self.assertEqual(page(), 'done')
+        self.assertEqual(v.action2(), 'done')
+        self.assertRaises(Exception, getattr, page, 'index')
+
+    def testInterfaceAndAttributeProtectedPage(self):
+        xmlconfig(StringIO(template %
+            '''
+            <browser:page name="test"
+                class="zope.component.testfiles.views.V1"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                attribute="index"
+                allowed_attributes="action"
+                allowed_interface="zope.component.testfiles.views.IV"
+                />
+            '''
+            ))
+
+        v = component.getMultiAdapter((ob, request), name='test')
+        self.assertEqual(v.index(), 'V1 here')
+        self.assertEqual(v.action(), 'done')
+
+    def testDuplicatedInterfaceAndAttributeProtectedPage(self):
+        xmlconfig(StringIO(template %
+            '''
+            <browser:page name="test"
+                class="zope.component.testfiles.views.V1"
+                for="zope.component.testfiles.views.IC"
+                attribute="index"
+                permission="zope.Public"
+                allowed_attributes="action index"
+                allowed_interface="zope.component.testfiles.views.IV"
+                />
+            '''
+            ))
+
+        v = component.getMultiAdapter((ob, request), name='test')
+        self.assertEqual(v.index(), 'V1 here')
+        self.assertEqual(v.action(), 'done')
+
+    def test_class_w_implements(self):
+        xmlconfig(StringIO(template %
+            '''
+            <browser:page
+                name="test"
+                class="
+             zope.browserpage.tests.C_w_implements"
+                for="zope.component.testfiles.views.IC"
+                attribute="index"
+                permission="zope.Public"
+                />
+            '''
+            ))
+
+        v = component.getMultiAdapter((ob, request), name='test')
+        self.assertEqual(v.index(), v)
+        self.assert_(IBrowserPublisher.providedBy(v))
+
+    def testIncompleteProtectedPageNoPermission(self):
+        self.assertRaises(
+            ConfigurationError,
+            xmlconfig,
+            StringIO(template %
+            '''
+            <browser:page name="test"
+                class="zope.component.testfiles.views.V1"
+                for="zope.component.testfiles.views.IC"
+                attribute="index"
+                allowed_attributes="action index"
+                />
+            '''
+            ))
+
+
+    def testPageViews(self):
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='test'),
+            None)
+        test3 = os.path.join(tests_path, 'testfiles', 'test3.pt')
+
+        xmlconfig(StringIO(template %
+            '''
+            <browser:pages
+                class="zope.component.testfiles.views.V1"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                >
+
+              <browser:page name="index.html" attribute="index" />
+              <browser:page name="action.html" attribute="action" />
+              <browser:page name="test.html" template="%s" />
+            </browser:pages>
+            ''' % test3
+            ))
+
+        v = component.getMultiAdapter((ob, request), name='index.html')
+        self.assertEqual(v(), 'V1 here')
+        v = component.getMultiAdapter((ob, request), name='action.html')
+        self.assertEqual(v(), 'done')
+        v = component.getMultiAdapter((ob, request), name='test.html')
+        self.assertEqual(str(v()), '<html><body><p>done</p></body></html>\n')
+
+    def testNamedViewPageViewsCustomTraversr(self):
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='test'),
+            None)
+
+        xmlconfig(StringIO(template %
+            '''
+            <browser:view
+                name="test"
+                class="zope.browserpage.tests.V1"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                >
+
+              <browser:page name="index.html" attribute="index" />
+              <browser:page name="action.html" attribute="action" />
+            </browser:view>
+            '''
+            ))
+
+        view = component.getMultiAdapter((ob, request), name='test')
+        view = removeSecurityProxy(view)
+        self.assertEqual(view.browserDefault(request)[1], (u'index.html', ))
+
+
+        v = view.publishTraverse(request, 'index.html')
+        v = removeSecurityProxy(v)
+        self.assertEqual(v(), 'V1 here')
+        v = view.publishTraverse(request, 'action.html')
+        v = removeSecurityProxy(v)
+        self.assertEqual(v(), 'done')
+
+
+    def testNamedViewNoPagesForCallable(self):
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='test'),
+            None)
+
+        xmlconfig(StringIO(template %
+            '''
+            <browser:view
+                name="test"
+                class="zope.browserpage.tests.CV"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                />
+            '''
+            ))
+
+        view = component.getMultiAdapter((ob, request), name='test')
+        view = removeSecurityProxy(view)
+        self.assertEqual(view.browserDefault(request), (view, ()))
+
+    def testNamedViewNoPagesForNonCallable(self):
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='test'),
+            None)
+
+        xmlconfig(StringIO(template %
+            '''
+            <browser:view
+                name="test"
+                class="zope.browserpage.tests.NCV"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                />
+            '''
+            ))
+
+        view = component.getMultiAdapter((ob, request), name='test')
+        view = removeSecurityProxy(view)
+        self.assertEqual(getattr(view, 'browserDefault', None), None)
+
+    def testNamedViewPageViewsNoDefault(self):
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='test'),
+            None)
+        test3 = os.path.join(tests_path, 'testfiles', 'test3.pt')
+
+        xmlconfig(StringIO(template %
+            '''
+            <browser:view
+                name="test"
+                class="zope.component.testfiles.views.V1"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                >
+
+              <browser:page name="index.html" attribute="index" />
+              <browser:page name="action.html" attribute="action" />
+              <browser:page name="test.html" template="%s" />
+            </browser:view>
+            ''' % test3
+            ))
+
+        view = component.getMultiAdapter((ob, request), name='test')
+        view = removeSecurityProxy(view)
+        self.assertEqual(view.browserDefault(request)[1], (u'index.html', ))
+
+
+        v = view.publishTraverse(request, 'index.html')
+        v = removeSecurityProxy(v)
+        self.assertEqual(v(), 'V1 here')
+        v = view.publishTraverse(request, 'action.html')
+        v = removeSecurityProxy(v)
+        self.assertEqual(v(), 'done')
+        v = view.publishTraverse(request, 'test.html')
+        v = removeSecurityProxy(v)
+        self.assertEqual(str(v()), '<html><body><p>done</p></body></html>\n')
+
+    def testNamedViewPageViewsWithDefault(self):
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='test'),
+            None)
+        test3 = os.path.join(tests_path, 'testfiles', 'test3.pt')
+
+        xmlconfig(StringIO(template %
+            '''
+            <browser:view
+                name="test"
+                class="zope.component.testfiles.views.V1"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                >
+
+              <browser:defaultPage name="test.html" />
+              <browser:page name="index.html" attribute="index" />
+              <browser:page name="action.html" attribute="action" />
+              <browser:page name="test.html" template="%s" />
+            </browser:view>
+            ''' % test3
+            ))
+
+        view = component.getMultiAdapter((ob, request), name='test')
+        view = removeSecurityProxy(view)
+        self.assertEqual(view.browserDefault(request)[1], (u'test.html', ))
+
+
+        v = view.publishTraverse(request, 'index.html')
+        v = removeSecurityProxy(v)
+        self.assertEqual(v(), 'V1 here')
+        v = view.publishTraverse(request, 'action.html')
+        v = removeSecurityProxy(v)
+        self.assertEqual(v(), 'done')
+        v = view.publishTraverse(request, 'test.html')
+        v = removeSecurityProxy(v)
+        self.assertEqual(str(v()), '<html><body><p>done</p></body></html>\n')
+
+    def testTraversalOfPageForView(self):
+        """Tests proper traversal of a page defined for a view."""
+
+        xmlconfig(StringIO(template %
+            '''
+            <browser:view
+                name="test"
+                class="zope.component.testfiles.views.V1"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public" />
+
+            <browser:page name="index.html"
+                for="zope.component.testfiles.views.IV"
+                class="zope.browserpage.tests.CV"
+                permission="zope.Public" />
+            '''
+            ))
+
+        view = component.getMultiAdapter((ob, request), name='test')
+        view = removeSecurityProxy(view)
+        view.publishTraverse(request, 'index.html')
+
+    def testTraversalOfPageForViewWithPublishTraverse(self):
+        """Tests proper traversal of a page defined for a view.
+
+        This test is different from testTraversalOfPageForView in that it
+        tests the behavior on a view that has a publishTraverse method --
+        the implementation of the lookup is slightly different in such a
+        case.
+        """
+        xmlconfig(StringIO(template %
+            '''
+            <browser:view
+                name="test"
+                class="zope.browserpage.tests.VT"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public" />
+
+            <browser:page name="index.html"
+                for="zope.component.testfiles.views.IV"
+                class="zope.browserpage.tests.CV"
+                permission="zope.Public" />
+            '''
+            ))
+
+        view = component.getMultiAdapter((ob, request), name='test')
+        view = removeSecurityProxy(view)
+        view.publishTraverse(request, 'index.html')
+
+    def testProtectedPageViews(self):
+        component.provideUtility(Permission('p', 'P'), IPermission, 'p')
+
+        request = TestRequest()
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='test'),
+            None)
+
+        xmlconfig(StringIO(template %
+            '''
+            <include package="zope.security" file="meta.zcml" />
+
+            <permission id="zope.TestPermission" title="Test permission" />
+
+            <browser:pages
+                class="zope.component.testfiles.views.V1"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.TestPermission"
+                >
+
+              <browser:page name="index.html" attribute="index" />
+              <browser:page name="action.html" attribute="action" />
+            </browser:pages>
+            '''
+            ))
+
+        v = component.getMultiAdapter((ob, request), name='index.html')
+        v = ProxyFactory(v)
+        zope.security.management.getInteraction().add(request)
+        self.assertRaises(Exception, v)
+        v = component.getMultiAdapter((ob, request), name='action.html')
+        v = ProxyFactory(v)
+        self.assertRaises(Exception, v)
+
+    def testProtectedNamedViewPageViews(self):
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='test'),
+            None)
+
+        xmlconfig(StringIO(template %
+            '''
+            <include package="zope.security" file="meta.zcml" />
+
+            <permission id="zope.TestPermission" title="Test permission" />
+
+            <browser:view
+                name="test"
+                class="zope.component.testfiles.views.V1"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                >
+
+              <browser:page name="index.html" attribute="index" />
+              <browser:page name="action.html" attribute="action" />
+            </browser:view>
+            '''
+            ))
+
+        view = component.getMultiAdapter((ob, request), name='test')
+        self.assertEqual(view.browserDefault(request)[1], (u'index.html', ))
+
+        v = view.publishTraverse(request, 'index.html')
+        self.assertEqual(v(), 'V1 here')
+
+    def testSkinnedPageView(self):
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='test'),
+            None)
+
+        xmlconfig(StringIO(template %
+            '''
+            <browser:pages
+                for="*"
+                class="zope.component.testfiles.views.V1"
+                permission="zope.Public"
+                >
+              <browser:page name="index.html" attribute="index" />
+            </browser:pages>
+
+            <browser:pages
+                for="*"
+                class="zope.component.testfiles.views.V1"
+                layer="
+                  zope.browserpage.tests.ITestLayer"
+                permission="zope.Public"
+                >
+              <browser:page name="index.html" attribute="action" />
+            </browser:pages>
+            '''
+            ))
+
+        v = component.getMultiAdapter((ob, request), name='index.html')
+        self.assertEqual(v(), 'V1 here')
+        v = component.getMultiAdapter((ob, TestRequest(skin=ITestSkin)),
+                                 name='index.html')
+        self.assertEqual(v(), 'done')
+
+
+    def test_template_page(self):
+        path = os.path.join(tests_path, 'testfiles', 'test.pt')
+
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='index.html'),
+            None)
+
+        xmlconfig(StringIO(template %
+            '''
+            <browser:page
+                name="index.html"
+                template="%s"
+                permission="zope.Public"
+                for="zope.component.testfiles.views.IC" />
+            ''' % path
+            ))
+
+        v = component.getMultiAdapter((ob, request), name='index.html')
+        self.assertEqual(v().strip(), '<html><body><p>test</p></body></html>')
+
+    def test_page_menu_within_different_layers(self):
+        path = os.path.join(tests_path, 'testfiles', 'test.pt')
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='index.html'),
+            None)
+
+        xmlconfig(StringIO(template %
+            '''
+            <browser:menu
+                id="test_menu"
+                title="Test menu"
+                interface="zope.browserpage.tests.ITestMenu"/>
+
+            <browser:page
+                name="index.html"
+                permission="zope.Public"
+                for="zope.component.testfiles.views.IC"
+                template="%s"
+                menu="test_menu" title="Index"/>
+
+            <browser:page
+                name="index.html"
+                permission="zope.Public"
+                for="zope.component.testfiles.views.IC"
+                menu="test_menu" title="Index"
+                template="%s"
+                layer="zope.browserpage.tests.ITestLayer"/>
+            ''' % (path, path)
+            ))
+
+        v = component.getMultiAdapter((ob, request), name='index.html')
+        self.assertEqual(v().strip(), '<html><body><p>test</p></body></html>')
+
+    def testtemplateWClass(self):
+        path = os.path.join(tests_path, 'testfiles', 'test2.pt')
+
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='index.html'),
+            None)
+
+        xmlconfig(StringIO(template %
+            '''
+            <browser:page
+                name="index.html"
+                template="%s"
+                permission="zope.Public"
+          class="zope.browserpage.tests.templateclass"
+                for="zope.component.testfiles.views.IC" />
+            ''' % path
+            ))
+
+        v = component.getMultiAdapter((ob, request), name='index.html')
+        self.assertEqual(v().strip(), '<html><body><p>42</p></body></html>')
+
+    def testProtectedtemplate(self):
+
+        path = os.path.join(tests_path, 'testfiles', 'test.pt')
+
+        request = TestRequest()
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), name='test'),
+            None)
+
+        xmlconfig(StringIO(template %
+            '''
+            <include package="zope.security" file="meta.zcml" />
+
+            <permission id="zope.TestPermission" title="Test permission" />
+
+            <browser:page
+                name="xxx.html"
+                template="%s"
+                permission="zope.TestPermission"
+                for="zope.component.testfiles.views.IC" />
+            ''' % path
+            ))
+
+        xmlconfig(StringIO(template %
+            '''
+            <browser:page
+                name="index.html"
+                template="%s"
+                permission="zope.Public"
+                for="zope.component.testfiles.views.IC" />
+            ''' % path
+            ))
+
+        v = component.getMultiAdapter((ob, request), name='xxx.html')
+        v = ProxyFactory(v)
+        zope.security.management.getInteraction().add(request)
+        self.assertRaises(Exception, v)
+
+        v = component.getMultiAdapter((ob, request), name='index.html')
+        v = ProxyFactory(v)
+        self.assertEqual(v().strip(), '<html><body><p>test</p></body></html>')
+
+
+    def testtemplateNoName(self):
+        path = os.path.join(tests_path, 'testfiles', 'test.pt')
+        self.assertRaises(
+            ConfigurationError,
+            xmlconfig,
+            StringIO(template %
+            '''
+            <browser:page
+                template="%s"
+                for="zope.component.testfiles.views.IC"
+                />
+            ''' % path
+            ))
+
+    def testtemplateAndPage(self):
+        path = os.path.join(tests_path, 'testfiles', 'test.pt')
+        self.assertRaises(
+            ConfigurationError,
+            xmlconfig,
+            StringIO(template %
+            '''
+            <browser:view
+                name="index.html"
+                template="%s"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                >
+              <browser:page name="foo.html" attribute="index" />
+            </browser:view>
+            ''' % path
+            ))
+
+    def testViewThatProvidesAnInterface(self):
+        request = TestRequest()
+        self.assertEqual(
+            component.queryMultiAdapter((ob, request), IV, name='test'), None)
+
+        xmlconfig(StringIO(template %
+            '''
+            <browser:view
+                name="test"
+                class="zope.component.testfiles.views.V1"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                />
+            '''
+            ))
+
+        v = component.queryMultiAdapter((ob, request), IV, name='test')
+        self.assertEqual(v, None)
+
+        xmlconfig(StringIO(template %
+            '''
+            <browser:view
+                name="test"
+                class="zope.component.testfiles.views.V1"
+                for="zope.component.testfiles.views.IC"
+                provides="zope.component.testfiles.views.IV"
+                permission="zope.Public"
+                />
+            '''
+            ))
+
+        v = component.queryMultiAdapter((ob, request), IV, name='test')
+        self.assert_(isinstance(v, V1))
+
+    def testUnnamedViewThatProvidesAnInterface(self):
+        request = TestRequest()
+        self.assertEqual(component.queryMultiAdapter((ob, request), IV),
+                         None)
+
+        xmlconfig(StringIO(template %
+            '''
+            <browser:view
+                class="zope.component.testfiles.views.V1"
+                for="zope.component.testfiles.views.IC"
+                permission="zope.Public"
+                />
+            '''
+            ))
+
+        v = component.queryMultiAdapter((ob, request), IV)
+        self.assertEqual(v, None)
+
+        xmlconfig(StringIO(template %
+            '''
+            <browser:view
+                class="zope.component.testfiles.views.V1"
+                for="zope.component.testfiles.views.IC"
+                provides="zope.component.testfiles.views.IV"
+                permission="zope.Public"
+                />
+            '''
+            ))
+
+        v = component.queryMultiAdapter((ob, request), IV)
+
+        self.assert_(isinstance(v, V1))
+
+
+def test_suite():
+    return unittest.makeSuite(Test)


Property changes on: zope.browserpage/trunk/src/zope/browserpage/tests.py
___________________________________________________________________
Added: svn:keywords
   + Id,svn:eol-style=native



More information about the Checkins mailing list