[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