zope.browsermenu-4.0.0/ 0000775 0001750 0001750 00000000000 11775031516 014753 5 ustar tseaver tseaver zope.browsermenu-4.0.0/src/ 0000775 0001750 0001750 00000000000 11775031516 015542 5 ustar tseaver tseaver zope.browsermenu-4.0.0/src/zope.browsermenu.egg-info/ 0000775 0001750 0001750 00000000000 11775031516 022560 5 ustar tseaver tseaver zope.browsermenu-4.0.0/src/zope.browsermenu.egg-info/namespace_packages.txt 0000664 0001750 0001750 00000000005 11775031516 027106 0 ustar tseaver tseaver zope
zope.browsermenu-4.0.0/src/zope.browsermenu.egg-info/PKG-INFO 0000664 0001750 0001750 00000003733 11775031516 023663 0 ustar tseaver tseaver Metadata-Version: 1.0
Name: zope.browsermenu
Version: 4.0.0
Summary: Browser menu implementation for Zope.
Home-page: http://pypi.python.org/pypi/zope.browsermenu/
Author: Zope Foundation and Contributors
Author-email: zope-dev@zope.org
License: ZPL 2.1
Description: ========
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 `_.
This package provides an implementation of browser menus and ZCML directives
for configuring them.
=======
CHANGES
=======
4.0.0 (2012-07-04)
==================
- Strip noise from context actions in doctests.
The output is now more meaningful, and hides irrelevant details.
(forward-compatibility with ``zope.component`` 4.0.0).
- Replaced deprecated ``zope.interface.implements`` usage with equivalent
``zope.interface.implementer`` decorator.
- Dropped support for Python 2.4 and 2.5.
3.9.1 (2010-04-30)
==================
- Removed use of 'zope.testing.doctestunit' in favor of stdlib's 'doctest.
3.9.0 (2009-08-27)
==================
Initial release. This package was splitted off zope.app.publisher.
Platform: UNKNOWN
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Zope Public License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Operating System :: OS Independent
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Framework :: Zope3
zope.browsermenu-4.0.0/src/zope.browsermenu.egg-info/not-zip-safe 0000664 0001750 0001750 00000000001 11775031422 025002 0 ustar tseaver tseaver
zope.browsermenu-4.0.0/src/zope.browsermenu.egg-info/requires.txt 0000664 0001750 0001750 00000000332 11775031516 025156 0 ustar tseaver tseaver setuptools
zope.browser
zope.component>=3.7
zope.configuration
zope.i18nmessageid
zope.interface
zope.pagetemplate>=3.5
zope.publisher
zope.schema
zope.security[untrustedpython]
zope.traversing>3.7
[test]
zope.testing zope.browsermenu-4.0.0/src/zope.browsermenu.egg-info/SOURCES.txt 0000664 0001750 0001750 00000002137 11775031516 024447 0 ustar tseaver tseaver CHANGES.txt
COPYRIGHT.txt
LICENSE.txt
README.txt
bootstrap.py
buildout.cfg
setup.py
src/zope/__init__.py
src/zope.browsermenu.egg-info/PKG-INFO
src/zope.browsermenu.egg-info/SOURCES.txt
src/zope.browsermenu.egg-info/dependency_links.txt
src/zope.browsermenu.egg-info/namespace_packages.txt
src/zope.browsermenu.egg-info/not-zip-safe
src/zope.browsermenu.egg-info/requires.txt
src/zope.browsermenu.egg-info/top_level.txt
src/zope/browsermenu/README.txt
src/zope/browsermenu/__init__.py
src/zope/browsermenu/configure.zcml
src/zope/browsermenu/field.py
src/zope/browsermenu/interfaces.py
src/zope/browsermenu/menu.py
src/zope/browsermenu/meta.zcml
src/zope/browsermenu/metaconfigure.py
src/zope/browsermenu/metadirectives.py
src/zope/browsermenu/tests/__init__.py
src/zope/browsermenu/tests/addmenuitems.zcml
src/zope/browsermenu/tests/menus-permissions.zcml
src/zope/browsermenu/tests/menus.zcml
src/zope/browsermenu/tests/test_addMenuItem.py
src/zope/browsermenu/tests/test_directives.py
src/zope/browsermenu/tests/test_fields.py
src/zope/browsermenu/tests/test_menu.py
src/zope/browsermenu/tests/test_menudirectives.py zope.browsermenu-4.0.0/src/zope.browsermenu.egg-info/top_level.txt 0000664 0001750 0001750 00000000005 11775031516 025305 0 ustar tseaver tseaver zope
zope.browsermenu-4.0.0/src/zope.browsermenu.egg-info/dependency_links.txt 0000664 0001750 0001750 00000000001 11775031516 026626 0 ustar tseaver tseaver
zope.browsermenu-4.0.0/src/zope/ 0000775 0001750 0001750 00000000000 11775031516 016517 5 ustar tseaver tseaver zope.browsermenu-4.0.0/src/zope/__init__.py 0000664 0001750 0001750 00000000070 11775031415 020623 0 ustar tseaver tseaver __import__('pkg_resources').declare_namespace(__name__)
zope.browsermenu-4.0.0/src/zope/browsermenu/ 0000775 0001750 0001750 00000000000 11775031516 021067 5 ustar tseaver tseaver zope.browsermenu-4.0.0/src/zope/browsermenu/menu.py 0000664 0001750 0001750 00000014655 11775031415 022416 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2004 Zope Foundation 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.
#
##############################################################################
"""Menu implementation code
"""
__docformat__ = "reStructuredText"
import sys
from zope.component import getAdapters, getUtility
from zope.interface import Interface, implementer, providedBy
from zope.interface.interfaces import IInterface
from zope.pagetemplate.engine import Engine
from zope.publisher.browser import BrowserView
from zope.security import canAccess, checkPermission
from zope.security.interfaces import Forbidden, Unauthorized
from zope.security.proxy import removeSecurityProxy
from zope.traversing.publicationtraverse import PublicationTraverser
from zope.browsermenu.interfaces import IBrowserMenu, IMenuItemType
from zope.browsermenu.interfaces import IBrowserMenuItem, IBrowserSubMenuItem
from zope.browsermenu.interfaces import IMenuAccessView
@implementer(IBrowserMenu)
class BrowserMenu(object):
"""Browser Menu"""
def __init__(self, id, title=u'', description=u''):
self.id = id
self.title = title
self.description = description
def getMenuItemType(self):
return getUtility(IMenuItemType, self.id)
def getMenuItems(self, object, request):
"""Return menu item entries in a TAL-friendly form."""
result = []
for name, item in getAdapters((object, request),
self.getMenuItemType()):
if item.available():
result.append(item)
# Now order the result. This is not as easy as it seems.
#
# (1) Look at the interfaces and put the more specific menu entries
# to the front.
# (2) Sort unambigious entries by order and then by title.
ifaces = list(providedBy(removeSecurityProxy(object)).__iro__)
max_key = len(ifaces)
def iface_index(item):
iface = item._for
if not iface:
iface = Interface
if IInterface.providedBy(iface):
return ifaces.index(iface)
if isinstance(removeSecurityProxy(object), item._for):
# directly specified for class, this goes first.
return -1
# no idea. This goes last.
return max_key
result = [(iface_index(item), item.order, item.title, item)
for item in result]
result.sort()
result = [
{'title': title,
'description': item.description,
'action': item.action,
'selected': (item.selected() and u'selected') or u'',
'icon': item.icon,
'extra': item.extra,
'submenu': (IBrowserSubMenuItem.providedBy(item) and
getMenu(item.submenuId, object, request)) or None}
for index, order, title, item in result]
return result
@implementer(IBrowserMenuItem)
class BrowserMenuItem(BrowserView):
"""Browser Menu Item Class"""
title = u''
description = u''
action = u''
extra = None
order = 0
permission = None
filter = None
icon = None
_for = Interface
def available(self):
# Make sure we have the permission needed to access the menu's action
if self.permission is not None:
# If we have an explicit permission, check that we
# can access it.
if not checkPermission(self.permission, self.context):
return False
elif self.action != u'':
# Otherwise, test access by attempting access
path = self.action
l = self.action.find('?')
if l >= 0:
path = self.action[:l]
traverser = PublicationTraverser()
try:
view = traverser.traverseRelativeURL(
self.request, self.context, path)
except (Unauthorized, Forbidden, LookupError):
return False
else:
# we're assuming that view pages are callable
# this is a pretty sound assumption
if not canAccess(view, '__call__'):
return False
# Make sure that we really want to see this menu item
if self.filter is not None:
try:
include = self.filter(Engine.getContext(
context = self.context,
nothing = None,
request = self.request,
modules = sys.modules,
))
except Unauthorized:
return False
else:
if not include:
return False
return True
def selected(self):
request_url = self.request.getURL()
normalized_action = self.action
if self.action.startswith('@@'):
normalized_action = self.action[2:]
if request_url.endswith('/'+normalized_action):
return True
if request_url.endswith('/++view++'+normalized_action):
return True
if request_url.endswith('/@@'+normalized_action):
return True
return False
@implementer(IBrowserSubMenuItem)
class BrowserSubMenuItem(BrowserMenuItem):
"""Browser Menu Item Base Class"""
submenuId = None
def selected(self):
if self.action is u'':
return False
return super(BrowserSubMenuItem, self).selected()
def getMenu(id, object, request):
"""Return menu item entries in a TAL-friendly form."""
menu = getUtility(IBrowserMenu, id)
return menu.getMenuItems(object, request)
def getFirstMenuItem(id, object, request):
"""Get the first item of a menu."""
items = getMenu(id, object, request)
if items:
return items[0]
return None
@implementer(IMenuAccessView)
class MenuAccessView(BrowserView):
"""A view allowing easy access to menus."""
def __getitem__(self, menuId):
return getMenu(menuId, self.context, self.request)
zope.browsermenu-4.0.0/src/zope/browsermenu/README.txt 0000664 0001750 0001750 00000046505 11775031415 022575 0 ustar tseaver tseaver =============
Browser Menus
=============
Browser menus are used to categorize browser actions, such as the views of a
content component or the addable components of a container. In essence they
provide the same functionality as menu bars in desktop application.
>>> from zope.browsermenu import menu, metaconfigure
Menus are simple components that have an id, title and description. They also
must provide a method called ``getMenuItems(object, request)`` that returns a
TAL-friendly list of information dictionaries. We will see this in detail
later. The default menu implementation, however, makes the menu be very
transparent by identifying the menu through an interface. So let's define and
register a simple edit menu:
>>> import zope.interface
>>> class EditMenu(zope.interface.Interface):
... """This is an edit menu."""
>>> from zope.browsermenu.interfaces import IMenuItemType
>>> zope.interface.directlyProvides(EditMenu, IMenuItemType)
>>> from zope.component import provideUtility
>>> provideUtility(EditMenu, IMenuItemType, 'edit')
Now we have to create and register the menu itself:
>>> from zope.browsermenu.interfaces import IBrowserMenu
>>> provideUtility(
... menu.BrowserMenu('edit', u'Edit', u'Edit Menu'), IBrowserMenu, 'edit')
Note that these steps seem like a lot of boilerplate, but all this work is
commonly done for you via ZCML. An item in a menu is simply an adapter that
provides. In the following section we will have a closer look at the browser
menu item:
``BrowserMenuItem`` class
-------------------------
The browser menu item represents an entry in the menu. Essentially, the menu
item is a browser view of a content component. Thus we have to create a
content component first:
>>> class IContent(zope.interface.Interface):
... pass
>>> from zope.publisher.interfaces.browser import IBrowserPublisher
>>> from zope.security.interfaces import Unauthorized, Forbidden
>>> @zope.interface.implementer(IContent, IBrowserPublisher)
... class Content(object):
...
... def foo(self):
... pass
...
... def browserDefault(self, r):
... return self, ()
...
... def publishTraverse(self, request, name):
... if name.startswith('fb'):
... raise Forbidden, name
... if name.startswith('ua'):
... raise Unauthorized, name
... if name.startswith('le'):
... raise LookupError, name
... return self.foo
We also implemented the ``IBrowserPublisher`` interface, because we want to
make the object traversable, so that we can make availability checks later.
Since the ``BrowserMenuItem`` is just a view, we can initiate it with an
object and a request.
>>> from zope.publisher.browser import TestRequest
>>> item = menu.BrowserMenuItem(Content(), TestRequest())
Note that the menu item knows *nothing* about the menu itself. It purely
depends on the adapter registration to determine in which menu it will
appear. The advantage is that a menu item can be reused in several menus.
Now we add a title, description, order and icon and see whether we can then
access the value. Note that these assignments are always automatically done by
the framework.
>>> item.title = u'Item 1'
>>> item.title
u'Item 1'
>>> item.description = u'This is Item 1.'
>>> item.description
u'This is Item 1.'
>>> item.order
0
>>> item.order = 1
>>> item.order
1
>>> item.icon is None
True
>>> item.icon = u'/@@/icon.png'
>>> item.icon
u'/@@/icon.png'
Since there is no permission or view specified yet, the menu item should
be available and not selected.
>>> item.available()
True
>>> item.selected()
False
There are two ways to deny availability of a menu item: (1) the current
user does not have the correct permission to access the action or the menu
item itself, or (2) the filter returns ``False``, in which case the menu
item should also not be shown.
>>> from zope.security.interfaces import IPermission
>>> from zope.security.permission import Permission
>>> perm = Permission('perm', 'Permission')
>>> provideUtility(perm, IPermission, 'perm')
>>> class ParticipationStub(object):
... principal = 'principal'
... interaction = None
In the first case, the permission of the menu item was explicitely
specified. Make sure that the user needs this permission to make the menu
item available.
>>> item.permission = perm
Now, we are not setting any user. This means that the menu item should be
available.
>>> from zope.security.management import newInteraction, endInteraction
>>> endInteraction()
>>> newInteraction()
>>> item.available()
True
Now we specify a principal that does not have the specified permission.
>>> endInteraction()
>>> newInteraction(ParticipationStub())
>>> item.available()
False
In the second case, the permission is not explicitely defined and the
availability is determined by the permission required to access the
action.
>>> item.permission = None
All views starting with 'fb' are forbidden, the ones with 'ua' are
unauthorized and all others are allowed.
>>> item.action = u'fb'
>>> item.available()
False
>>> item.action = u'ua'
>>> item.available()
False
>>> item.action = u'a'
>>> item.available()
True
Also, sometimes a menu item might be registered for a view that does not
exist. In those cases the traversal mechanism raises a `TraversalError`, which
is a special type of `LookupError`. All actions starting with `le` should
raise this error:
>>> item.action = u'le'
>>> item.available()
False
Now let's test filtering. If the filter is specified, it is assumed to be
a TALES obejct.
>>> from zope.pagetemplate.engine import Engine
>>> item.action = u'a'
>>> item.filter = Engine.compile('not:context')
>>> item.available()
False
>>> item.filter = Engine.compile('context')
>>> item.available()
True
Finally, make sure that the menu item can be selected.
>>> item.request = TestRequest(SERVER_URL='http://127.0.0.1/@@view.html',
... PATH_INFO='/@@view.html')
>>> item.selected()
False
>>> item.action = u'view.html'
>>> item.selected()
True
>>> item.action = u'@@view.html'
>>> item.selected()
True
>>> item.request = TestRequest(
... SERVER_URL='http://127.0.0.1/++view++view.html',
... PATH_INFO='/++view++view.html')
>>> item.selected()
True
>>> item.action = u'otherview.html'
>>> item.selected()
False
``BrowserSubMenuItem`` class
----------------------------
The menu framework also allows for submenus. Submenus can be inserted by
creating a special menu item that simply points to another menu to be
inserted:
>>> item = menu.BrowserSubMenuItem(Content(), TestRequest())
The framework will always set the sub-menu automatically (we do it
manually here):
>>> class SaveOptions(zope.interface.Interface):
... "A sub-menu that describes available save options for the content."
>>> zope.interface.directlyProvides(SaveOptions, IMenuItemType)
>>> provideUtility(SaveOptions, IMenuItemType, 'save')
>>> provideUtility(menu.BrowserMenu('save', u'Save', u'Save Menu'),
... IBrowserMenu, 'save')
Now we can assign the sub-menu id to the menu item:
>>> item.submenuId = 'save'
Also, the ``action`` attribute for the browser sub-menu item is optional,
because you often do not want the item itself to represent something. The rest
of the class is identical to the ``BrowserMenuItem`` class.
Getting a Menu
--------------
Now that we know how the single menu item works, let's have a look at how menu
items get put together to a menu. But let's first create some menu items and
register them as adapters with the component architecture.
Register the edit menu entries first. We use the menu item factory to create
the items:
>>> from zope.component import provideAdapter
>>> from zope.publisher.interfaces.browser import IBrowserRequest
>>> undo = metaconfigure.MenuItemFactory(menu.BrowserMenuItem, title="Undo",
... action="undo.html")
>>> provideAdapter(undo, (IContent, IBrowserRequest), EditMenu, 'undo')
>>> redo = metaconfigure.MenuItemFactory(menu.BrowserMenuItem, title="Redo",
... action="redo.html", icon="/@@/redo.png")
>>> provideAdapter(redo, (IContent, IBrowserRequest), EditMenu, 'redo')
>>> save = metaconfigure.MenuItemFactory(menu.BrowserSubMenuItem, title="Save",
... submenuId='save', order=2)
>>> provideAdapter(save, (IContent, IBrowserRequest), EditMenu, 'save')
And now the save options:
>>> saveas = metaconfigure.MenuItemFactory(menu.BrowserMenuItem, title="Save as",
... action="saveas.html")
>>> provideAdapter(saveas, (IContent, IBrowserRequest),
... SaveOptions, 'saveas')
>>> saveall = metaconfigure.MenuItemFactory(menu.BrowserMenuItem, title="Save all",
... action="saveall.html")
>>> provideAdapter(saveall, (IContent, IBrowserRequest),
... SaveOptions, 'saveall')
Note that we can also register menu items for classes:
>>> new = metaconfigure.MenuItemFactory(menu.BrowserMenuItem, title="New",
... action="new.html", _for=Content)
>>> provideAdapter(new, (Content, IBrowserRequest), EditMenu, 'new')
The utility that is used to generate the menu into a TAL-friendly
data-structure is ``getMenu()``::
getMenu(menuId, object, request)
where ``menuId`` is the id originally specified for the menu. Let's look up the
menu now:
>>> pprint(menu.getMenu('edit', Content(), TestRequest()))
[{'action': 'new.html',
'description': u'',
'extra': None,
'icon': None,
'selected': u'',
'submenu': None,
'title': 'New'},
{'action': 'redo.html',
'description': u'',
'extra': None,
'icon': '/@@/redo.png',
'selected': u'',
'submenu': None,
'title': 'Redo'},
{'action': 'undo.html',
'description': u'',
'extra': None,
'icon': None,
'selected': u'',
'submenu': None,
'title': 'Undo'},
{'action': u'',
'description': u'',
'extra': None,
'icon': None,
'selected': u'',
'submenu': [{'action': 'saveall.html',
'description': u'',
'extra': None,
'icon': None,
'selected': u'',
'submenu': None,
'title': 'Save all'},
{'action': 'saveas.html',
'description': u'',
'extra': None,
'icon': None,
'selected': u'',
'submenu': None,
'title': 'Save as'}],
'title': 'Save'}]
Custom ``IBrowserMenu`` Implementations
---------------------------------------
Until now we have only seen how to use the default menu implementation. Much
of the above boilerplate was necessary just to support custom menus. But what
could custom menus do? Sometimes menu items are dynamically generated based on
a certain state of the object the menu is for. For example, you might want to
show all items in a folder-like component. So first let's create this
folder-like component:
>>> class Folderish(Content):
... names = ['README.txt', 'logo.png', 'script.py']
Now we create a menu using the names to create a menu:
>>> from zope.browsermenu.interfaces import IBrowserMenu
>>> @zope.interface.implementer(IBrowserMenu)
... class Items(object):
...
... def __init__(self, id, title=u'', description=u''):
... self.id = id
... self.title = title
... self.description = description
...
... def getMenuItems(self, object, request):
... return [{'title': name,
... 'description': None,
... 'action': name + '/manage',
... 'selected': u'',
... 'icon': None,
... 'extra': {},
... 'submenu': None}
... for name in object.names]
and register it:
>>> provideUtility(Items('items', u'Items', u'Items Menu'),
... IBrowserMenu, 'items')
We can now get the menu items using the previously introduced API:
>>> pprint(menu.getMenu('items', Folderish(), TestRequest()))
[{'action': 'README.txt/manage',
'description': None,
'extra': {},
'icon': None,
'selected': u'',
'submenu': None,
'title': 'README.txt'},
{'action': 'logo.png/manage',
'description': None,
'extra': {},
'icon': None,
'selected': u'',
'submenu': None,
'title': 'logo.png'},
{'action': 'script.py/manage',
'description': None,
'extra': {},
'icon': None,
'selected': u'',
'submenu': None,
'title': 'script.py'}]
``MenuItemFactory`` class
-------------------------
As you have seen above already, we have used the menu item factory to generate
adapter factories for menu items. The factory needs a particular
``IBrowserMenuItem`` class to instantiate. Here is an example using a dummy
menu item class:
>>> class DummyBrowserMenuItem(object):
... "a dummy factory for menu items"
... def __init__(self, context, request):
... self.context = context
... self.request = request
To instantiate this class, pass the factory and the other arguments as keyword
arguments (every key in the arguments should map to an attribute of the menu
item class). We use dummy values for this example.
>>> factory = metaconfigure.MenuItemFactory(
... DummyBrowserMenuItem, title='Title', description='Description',
... icon='Icon', action='Action', filter='Filter',
... permission='zope.Public', extra='Extra', order='Order', _for='For')
>>> factory.factory is DummyBrowserMenuItem
True
The "zope.Public" permission needs to be translated to ``CheckerPublic``.
>>> from zope.security.checker import CheckerPublic
>>> factory.kwargs['permission'] is CheckerPublic
True
Call the factory with context and request to return the instance. We continue
to use dummy values.
>>> item = factory('Context', 'Request')
The returned value should be an instance of the ``DummyBrowserMenuItem``, and
have all of the values we initially set on the factory.
>>> isinstance(item, DummyBrowserMenuItem)
True
>>> item.context
'Context'
>>> item.request
'Request'
>>> item.title
'Title'
>>> item.description
'Description'
>>> item.icon
'Icon'
>>> item.action
'Action'
>>> item.filter
'Filter'
>>> item.permission is CheckerPublic
True
>>> item.extra
'Extra'
>>> item.order
'Order'
>>> item._for
'For'
If you pass a permission other than ``zope.Public`` to the
``MenuItemFactory``, it should pass through unmodified.
>>> factory = metaconfigure.MenuItemFactory(
... DummyBrowserMenuItem, title='Title', description='Description',
... icon='Icon', action='Action', filter='Filter',
... permission='another.Permission', extra='Extra', order='Order',
... _for='For_')
>>> factory.kwargs['permission']
'another.Permission'
Directive Handlers
------------------
``menu`` Directive Handler
~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides a new menu (item type).
>>> class Context(object):
... info = u'doc'
... def __init__(self):
... self.actions = []
...
... def action(self, **kw):
... self.actions.append(kw)
Possibility 1: The Old Way
++++++++++++++++++++++++++
>>> context = Context()
>>> metaconfigure.menuDirective(context, u'menu1', title=u'Menu 1')
>>> iface = context.actions[0]['args'][1]
>>> iface.getName()
u'menu1'
>>> import sys
>>> hasattr(sys.modules['zope.app.menus'], 'menu1')
True
>>> del sys.modules['zope.app.menus'].menu1
Possibility 2: Just specify an interface
++++++++++++++++++++++++++++++++++++++++
>>> class menu1(zope.interface.Interface):
... pass
>>> context = Context()
>>> metaconfigure.menuDirective(context, interface=menu1)
>>> context.actions[0]['args'][1] is menu1
True
Possibility 3: Specify an interface and an id
+++++++++++++++++++++++++++++++++++++++++++++
>>> context = Context()
>>> metaconfigure.menuDirective(context, id='menu1', interface=menu1)
>>> pprint([action['discriminator'] for action in context.actions])
[('browser', 'MenuItemType', '__builtin__.menu1'),
('interface', '__builtin__.menu1'),
('browser', 'MenuItemType', 'menu1'),
('utility',
,
'menu1'),
None]
Here are some disallowed configurations.
>>> context = Context()
>>> metaconfigure.menuDirective(context)
Traceback (most recent call last):
...
ConfigurationError: You must specify the 'id' or 'interface' attribute.
>>> metaconfigure.menuDirective(context, title='Menu 1')
Traceback (most recent call last):
...
ConfigurationError: You must specify the 'id' or 'interface' attribute.
``menuItems`` Directive Handler
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Register several menu items for a particular menu.
>>> class TestMenuItemType(zope.interface.Interface):
... pass
>>> class ITest(zope.interface.Interface):
... pass
>>> context = Context()
>>> items = metaconfigure.menuItemsDirective(context, TestMenuItemType, ITest)
>>> context.actions
[]
>>> items.menuItem(context, u'view.html', 'View')
>>> items.subMenuItem(context, SaveOptions, 'Save')
>>> disc = [action['discriminator'] for action in context.actions]
>>> disc.sort()
>>> pprint(disc[-2:])
[('adapter',
(,
),
,
'Save'),
('adapter',
(,
),
,
'View')]
Custom menu item classes
~~~~~~~~~~~~~~~~~~~~~~~~
We can register menu items and sub menu items with custom classes instead
of ones used by default. For that, we need to create an implementation
of IBrowserMenuItem or IBrowserSubMenuItem.
>>> context = Context()
>>> items = metaconfigure.menuItemsDirective(context, TestMenuItemType, ITest)
>>> context.actions
[]
Let's create a custom menu item class that inherits standard BrowserMenuItem:
>>> class MyMenuItem(menu.BrowserMenuItem):
... pass
>>> items.menuItem(context, u'view.html', 'View', item_class=MyMenuItem)
Also create a custom sub menu item class inheriting standard BrowserSubMenuItem:
>>> class MySubMenuItem(menu.BrowserSubMenuItem):
... pass
>>> items.subMenuItem(context, SaveOptions, 'Save', item_class=MySubMenuItem)
>>> actions = sorted(context.actions, key=lambda a:a['discriminator'])
>>> factories = [action['args'][1] for action in actions][-2:]
>>> factories[0].factory is MySubMenuItem
True
>>> factories[1].factory is MyMenuItem
True
These directive will fail if you provide an item_class that does not
implement IBrowserMenuItem/IBrowserSubMenuItem:
>>> items.menuItem(context, u'fail', 'Failed', item_class=object)
Traceback (most recent call last):
...
ValueError: Item class () must implement IBrowserMenuItem
>>> items.subMenuItem(context, SaveOptions, 'Failed', item_class=object)
Traceback (most recent call last):
...
ValueError: Item class () must implement IBrowserSubMenuItem
zope.browsermenu-4.0.0/src/zope/browsermenu/interfaces.py 0000664 0001750 0001750 00000012447 11775031415 023572 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2002 Zope Foundation 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.
#
##############################################################################
"""Menu-specific interfaces
"""
from zope.i18nmessageid import ZopeMessageFactory as _
from zope.interface import Interface, directlyProvides
from zope.interface.interfaces import IInterface
from zope.schema import TextLine, Text, URI, Int
class IMenuItemType(IInterface):
"""Menu item type
Menu item types are interfaces that define classes of
menu items.
"""
class AddMenu(Interface):
"""Special menu for providing a list of addable objects."""
directlyProvides(AddMenu, IMenuItemType)
class IBrowserMenu(Interface):
"""Menu
Menus are objects that can return a list of menu items they contain. How
they generate this list is up to them. Commonly, however, they will look
up adapters that provide the ``IBrowserMenuItem`` interface.
"""
id = TextLine(
title=_("Menu Id"),
description=_("The id uniquely identifies this menu."),
required=True
)
title = TextLine(
title=_("Menu title"),
description=_("The title provides the basic label for the menu."),
required=False
)
description = Text(
title=_("Menu description"),
description=_("A description of the menu. This might be shown "
"on menu pages or in pop-up help for menus."),
required=False
)
def getMenuItems(object, request):
"""Return a TAL-friendly list of menu items.
The object (acts like the context) and request can be used to select
the items that are available.
"""
class IBrowserMenuItem(Interface):
"""Menu type
An interface that defines a menu.
"""
title = TextLine(
title=_("Menu item title"),
description=_("The title provides the basic label for the menu item."),
required=True
)
description = Text(
title=_("Menu item description"),
description=_("A description of the menu item. This might be shown "
"on menu pages or in pop-up help for menu items."),
required=False
)
action = TextLine(
title=_("The URL to display if the item is selected"),
description=_("When a user selects a browser menu item, the URL"
"given in the action is displayed. The action is "
"usually given as a relative URL, relative to the "
"object the menu item is for."),
required=True
)
order = Int(
title=_("Menu item ordering hint"),
description=_("This attribute provides a hint for menu item ordering."
"Menu items will generally be sorted by the `for_`"
"attribute and then by the order.")
)
filter_string = TextLine(
title=_("A condition for displaying the menu item"),
description=_("The condition is given as a TALES expression. The "
"expression has access to the variables:\n"
"\n"
"context -- The object the menu is being displayed "
"for\n"
"\n"
"request -- The browser request\n"
"\n"
"nothing -- None\n"
"\n"
"The menu item will not be displayed if there is a \n"
"filter and the filter evaluates to a false value."),
required=False)
icon = URI(
title=_("Icon URI"),
description=_("URI of the icon representing this menu item"))
def available():
"""Test whether the menu item should be displayed
A menu item might not be available for an object, for example
due to security limitations or constraints.
"""
class IBrowserSubMenuItem(IBrowserMenuItem):
"""A menu item that points to a sub-menu."""
submenuId = TextLine(
title=_("Sub-Menu Id"),
description=_("The menu id of the menu that describes the "
"sub-menu below this item."),
required=True)
action = TextLine(
title=_("The URL to display if the item is selected"),
description=_("When a user selects a browser menu item, the URL "
"given in the action is displayed. The action is "
"usually given as a relative URL, relative to the "
"object the menu item is for."),
required=False
)
class IMenuAccessView(Interface):
"""View that provides access to menus"""
def __getitem__(menu_id):
"""Get menu information
Return a sequence of dictionaries with labels and
actions, where actions are relative URLs.
"""
zope.browsermenu-4.0.0/src/zope/browsermenu/meta.zcml 0000664 0001750 0001750 00000002332 11775031415 022702 0 ustar tseaver tseaver
zope.browsermenu-4.0.0/src/zope/browsermenu/metadirectives.py 0000664 0001750 0001750 00000016165 11775031415 024460 0 ustar tseaver tseaver #############################################################################
#
# Copyright (c) 2001, 2002 Zope Foundation 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.
#
##############################################################################
"""Menu ZCML directives
"""
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
from zope.browsermenu.field import MenuField
class IMenuDirective(Interface):
"""Define a browser menu"""
id = TextLine(
title=u"The name of the menu.",
description=u"This is, effectively, an id.",
required=False
)
title = MessageID(
title=u"Title",
description=u"A descriptive title for documentation purposes",
required=False
)
description = MessageID(
title=u"Description",
description=u"A description title of the menu.",
required=False
)
class_ = GlobalObject(
title=u"Menu Class",
description=u"The menu class used to generate the menu.",
required=False
)
interface = GlobalInterface(
title=u"The menu's interface.",
required=False
)
class IMenuItemsDirective(Interface):
"""
Define a group of browser menu items
This directive is useful when many menu items are defined for the
same interface and menu.
"""
menu = MenuField(
title=u"Menu name",
description=u"The (name of the) menu the items are defined for",
required=True,
)
for_ = GlobalObject(
title=u"Interface",
description=u"The interface the menu items are defined for",
required=True
)
layer = GlobalInterface(
title=u"Layer",
description=u"The Layer for which the item is declared.",
required=False
)
permission = Permission(
title=u"The permission needed access the item",
description=u"""
This can usually be inferred by the system, however, doing so
may be expensive. When displaying a menu, the system tries to
traverse to the URLs given in each action to determine whether
the url is accessible to the current user. This can be
avoided if the permission is given explicitly.""",
required=False
)
class IMenuItem(Interface):
"""Common menu item configuration
"""
title = MessageID(
title=u"Title",
description=u"The text to be displayed for the menu item",
required=True
)
description = MessageID(
title=u"A longer explanation of the menu item",
description=u"""
A UI may display this with the item or display it when the
user requests more assistance.""",
required=False
)
icon = TextLine(
title=u"Icon Path",
description=u"Path to the icon resource representing this menu item.",
required=False
)
permission = Permission(
title=u"The permission needed access the item",
description=u"""
This can usually be inferred by the system, however, doing so
may be expensive. When displaying a menu, the system tries to
traverse to the URLs given in each action to determine whether
the url is accessible to the current user. This can be
avoided if the permission is given explicitly.""",
required=False
)
filter = TextLine(
title=u"A condition for displaying the menu item",
description=u"""
The condition is given as a TALES expression. The expression
has access to the variables:
context -- The object the menu is being displayed for
request -- The browser request
nothing -- None
The menu item will not be displayed if there is a filter and
the filter evaluates to a false value.""",
required=False
)
order = Int(
title=u"Order",
description=u"A relative position of the menu item in the menu.",
required=False,
default=0
)
item_class = GlobalObject(
title=u"Menu item class",
description=u"""
A class to be used as a factory for creating menu item""",
required=False
)
class IMenuItemSubdirective(IMenuItem):
"""Define a menu item within a group of menu items"""
action = TextLine(
title=u"The relative url to use if the item is selected",
description=u"""
The url is relative to the object the menu is being displayed
for.""",
required=True
)
class IMenuItemDirective(IMenuItemsDirective, IMenuItemSubdirective):
"""Define one menu item"""
class ISubMenuItemSubdirective(IMenuItem):
"""Define a menu item that represents a a sub menu.
For a sub-menu menu item, the action is optional, this the item itself
might not represent a destination, but just an entry point to the sub menu.
"""
action = TextLine(
title=u"The relative url to use if the item is selected",
description=u"""
The url is relative to the object the menu is being displayed
for.""",
required=False
)
submenu = TextLine(
title=u"Sub-Menu Id",
description=u"The menu that will be used to provide the sub-entries.",
required=True,
)
class ISubMenuItemDirective(IMenuItemsDirective, ISubMenuItemSubdirective):
"""Define one menu item"""
class IAddMenuItemDirective(IMenuItem):
"""Define an add-menu item"""
for_ = GlobalInterface(
title=u"Interface",
description=u"The interface the menu items are defined for",
required=False
)
class_ = GlobalObject(
title=u"Class",
description=u"""
A class to be used as a factory for creating new objects""",
required=False
)
factory = Id(
title=u"Factory",
description=u"A factory id for creating new objects",
required = False,
)
view = TextLine(
title=u"Custom view name",
description=u"The name of a custom add view",
required = False,
)
menu = MenuField(
title=u"Menu name",
description=u"The (name of the) menu the items are defined for",
required=False,
)
layer = GlobalInterface(
title=u"The layer the custom view is declared for",
description=u"The default layer for which the custom view is "
u"applicable. By default it is applied to all layers.",
required=False
)
zope.browsermenu-4.0.0/src/zope/browsermenu/tests/ 0000775 0001750 0001750 00000000000 11775031516 022231 5 ustar tseaver tseaver zope.browsermenu-4.0.0/src/zope/browsermenu/tests/menus-permissions.zcml 0000664 0001750 0001750 00000000710 11775031414 026613 0 ustar tseaver tseaver
zope.browsermenu-4.0.0/src/zope/browsermenu/tests/test_addMenuItem.py 0000664 0001750 0001750 00000023200 11775031414 026030 0 ustar tseaver tseaver #############################################################################
#
# Copyright (c) 2003 Zope Foundation 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.
#
##############################################################################
"""Test the addMenuItem directive
>>> context = Context()
>>> addMenuItem(context, class_=X, title="Add an X",
... permission="zope.ManageContent")
>>> context
[('utility',
,
'BrowserAdd__zope.browsermenu.tests.test_addMenuItem.X'),
(,
),
('adapter',
(,
),
,
'Add an X'),
(,
),
(,
),
(,
)]
"""
import unittest
from doctest import DocTestSuite
import re
import pprint
import cStringIO
from zope.interface import Interface
from zope.publisher.interfaces.browser import IBrowserRequest
from zope.component.interface import provideInterface
from zope.browsermenu.metaconfigure import addMenuItem
from zope.browsermenu.metaconfigure import _checkViewFor
atre = re.compile(' at [0-9a-fA-Fx]+')
class IX(Interface):
pass
class X(object):
pass
class ILayerStub(IBrowserRequest):
pass
class MenuStub(object):
pass
class Context(object):
info = ''
def __init__(self):
self.actions = []
def action(self, discriminator, callable, args=(), kw={}, order=0):
if discriminator is None:
if callable is provideInterface:
self.actions.append((callable, args[1])) #name is args[0]
elif callable is _checkViewFor:
self.actions.append((callable, args[2]))
else:
self.actions.append(discriminator)
def __repr__(self):
stream = cStringIO.StringIO()
pprinter = pprint.PrettyPrinter(stream=stream, width=60)
pprinter.pprint(self.actions)
r = stream.getvalue()
return (''.join(atre.split(r))).strip()
def test_w_factory():
"""
>>> context = Context()
>>> addMenuItem(context, factory="x.y.z", title="Add an X",
... permission="zope.ManageContent", description="blah blah",
... filter="context/foo")
>>> context
[('adapter',
(,
),
,
'Add an X'),
(,
),
(,
),
(,
)]
"""
def test_w_factory_and_view():
"""
>>> context = Context()
>>> addMenuItem(context, factory="x.y.z", title="Add an X",
... permission="zope.ManageContent", description="blah blah",
... filter="context/foo", view="AddX")
>>> context
[(, 'AddX'),
('adapter',
(,
),
,
'Add an X'),
(,
),
(,
),
(,
)]
"""
def test_w_factory_class_view():
"""
>>> context = Context()
>>> addMenuItem(context, class_=X, title="Add an X",
... permission="zope.ManageContent", description="blah blah",
... filter="context/foo", view="AddX")
>>> import pprint
>>> context
[('utility',
,
'BrowserAdd__zope.browsermenu.tests.test_addMenuItem.X'),
(,
),
(, 'AddX'),
('adapter',
(,
),
,
'Add an X'),
(,
),
(,
),
(,
)]
"""
def test_w_for_factory():
"""
>>> context = Context()
>>> addMenuItem(context, for_=IX, factory="x.y.z", title="Add an X",
... permission="zope.ManageContent", description="blah blah",
... filter="context/foo")
>>> context
[(,
),
('adapter',
(,
),
,
'Add an X'),
(,
),
(,
),
(,
)]
"""
def test_w_factory_layer():
"""
>>> context = Context()
>>> addMenuItem(context, factory="x.y.z", title="Add an X", layer=ILayerStub,
... permission="zope.ManageContent", description="blah blah",
... filter="context/foo")
>>> context
[('adapter',
(,
),
,
'Add an X'),
(,
),
(,
),
(,
)]
"""
def test_w_for_menu_factory():
"""
>>> context = Context()
>>> addMenuItem(context, for_=IX, menu=MenuStub,
... factory="x.y.z", title="Add an X",
... permission="zope.ManageContent", description="blah blah",
... filter="context/foo")
>>> context
[(,
),
('adapter',
(,
),
,
'Add an X'),
(,
),
(,
),
(,
)]
"""
def test_w_factory_icon_extra_order():
"""
>>> context = Context()
>>> addMenuItem(context, factory="x.y.z", title="Add an X",
... permission="zope.ManageContent", description="blah blah",
... filter="context/foo", icon=u'/@@/icon.png', extra='Extra',
... order=99)
>>> context
[('adapter',
(,
),
,
'Add an X'),
(,
),
(,
),
(,
)]
"""
from zope.configuration.xmlconfig import XMLConfig
import zope.browsermenu
import zope.component
from zope.testing import cleanup
class TestAddMenuItem(cleanup.CleanUp, unittest.TestCase):
def setUp(self):
super(TestAddMenuItem, self).setUp()
XMLConfig('meta.zcml', zope.component)()
XMLConfig('meta.zcml', zope.browsermenu)()
def test_addMenuItemDirectives(self):
XMLConfig('tests/addmenuitems.zcml', zope.browsermenu)()
def test_suite():
return unittest.TestSuite((
DocTestSuite(),
unittest.makeSuite(TestAddMenuItem),
))
if __name__ == '__main__':
unittest.main()
zope.browsermenu-4.0.0/src/zope/browsermenu/tests/menus.zcml 0000664 0001750 0001750 00000003420 11775031414 024243 0 ustar tseaver tseaver
zope.browsermenu-4.0.0/src/zope/browsermenu/tests/test_menudirectives.py 0000664 0001750 0001750 00000011340 11775031414 026664 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2002 Zope Foundation 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 Menu Directives Tests
"""
import unittest
from zope.configuration.xmlconfig import XMLConfig
from zope.interface import Interface, implementer
from zope.publisher.browser import TestRequest
from zope.publisher.interfaces.browser import IBrowserPublisher
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
from zope.browsermenu.interfaces import IBrowserMenu
from zope.security.interfaces import Unauthorized, Forbidden
import zope.component
import zope.security
from zope.testing import cleanup
import zope.browsermenu
template = """
%s
"""
class I1(Interface): pass
class I11(I1): pass
class I12(I1): pass
class I111(I11): pass
@implementer(I1)
class C1(object):
pass
class I2(Interface): pass
@implementer(I2)
class C2(object):
pass
@implementer(IBrowserPublisher, I111)
class TestObject(object):
def f(self):
pass
def browserDefault(self, r):
return self, ()
def publishTraverse(self, request, name):
if name[:1] == 'f':
raise Forbidden(name)
if name[:1] == 'u':
raise Unauthorized(name)
return self.f
class IMyLayer(Interface):
pass
class IMySkin(IMyLayer, IDefaultBrowserLayer):
pass
class TestPermissions(cleanup.CleanUp, unittest.TestCase):
def setUp(self):
super(TestPermissions, self).setUp()
XMLConfig('meta.zcml', zope.browsermenu)()
XMLConfig('meta.zcml', zope.security)()
def testMenuItemsPermission(self):
XMLConfig('tests/menus-permissions.zcml', zope.browsermenu)()
menu = zope.component.getUtility(IBrowserMenu, 'test_id')
# This is a bit icky, but the menu hides too much stuff from us.
items = zope.component.getAdapters((C2(), TestRequest()),
menu.getMenuItemType())
item = list(items)[0][1]
self.assertEquals("zope.View", item.permission)
class Test(cleanup.CleanUp, unittest.TestCase):
def setUp(self):
super(Test, self).setUp()
XMLConfig('meta.zcml', zope.browsermenu)()
def testMenusAndMenuItems(self):
XMLConfig('tests/menus.zcml', zope.browsermenu)()
menu = zope.browsermenu.menu.getMenu(
'test_id', TestObject(), TestRequest())
def d(n):
return {'action': "a%s" % n,
'title': "t%s" % n,
'description': u'',
'selected': '',
'submenu': None,
'icon': None,
'extra': None}
self.assertEqual(menu[:-1], [d(5), d(6), d(3), d(2), d(1)])
self.assertEqual(
menu[-1],
{'submenu': [{'submenu': None,
'description': u'',
'extra': None,
'selected': u'',
'action': u'a10',
'title': u't10',
'icon': None}],
'description': u'',
'extra': None,
'selected': u'',
'action': u'',
'title': u's1',
'icon': None})
first = zope.browsermenu.menu.getFirstMenuItem(
'test_id', TestObject(), TestRequest())
self.assertEqual(first, d(5))
def testMenuItemWithLayer(self):
XMLConfig('tests/menus.zcml', zope.browsermenu)()
menu = zope.browsermenu.menu.getMenu(
'test_id', TestObject(), TestRequest())
self.assertEqual(len(menu), 6)
menu = zope.browsermenu.menu.getMenu(
'test_id', TestObject(), TestRequest(skin=IMyLayer))
self.assertEqual(len(menu), 2)
menu = zope.browsermenu.menu.getMenu(
'test_id', TestObject(), TestRequest(skin=IMySkin))
self.assertEqual(len(menu), 8)
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(Test),
unittest.makeSuite(TestPermissions),
))
if __name__=='__main__':
unittest.main(defaultTest='test_suite')
zope.browsermenu-4.0.0/src/zope/browsermenu/tests/test_directives.py 0000664 0001750 0001750 00000012706 11775031414 026006 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2001, 2002 Zope Foundation 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
"""
import sys
import os
import unittest
from cStringIO import StringIO
from doctest import DocTestSuite
from zope import component
from zope.interface import Interface, implementer, 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.browser import IBrowserPublisher
from zope.publisher.interfaces.browser import IBrowserRequest
from zope.publisher.interfaces.browser import IBrowserSkinType
from zope.security.proxy import removeSecurityProxy, ProxyFactory
from zope.security.permission import Permission
from zope.security.interfaces import IPermission
from zope.traversing.adapters import DefaultTraversable
from zope.traversing.interfaces import ITraversable
import zope.browsermenu
from zope.component.testfiles.views import IC, V1, VZMI, R1, IV
from zope.browsermenu.menu import getFirstMenuItem, BrowserMenu
from zope.browsermenu.interfaces import IMenuItemType, IBrowserMenu
from zope.testing import cleanup
tests_path = os.path.join(
os.path.dirname(zope.browsermenu.__file__),
'tests')
template = """
%s
"""
request = TestRequest()
class M1(BrowserMenu):
pass
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)
@implementer(IC)
class Ob(object):
pass
ob = Ob()
class NCV(object):
"non callable view"
def __init__(self, context, request):
pass
class CV(NCV):
"callable view"
def __call__(self):
pass
@implementer(Interface)
class C_w_implements(NCV):
def index(self):
return self
class ITestMenu(Interface):
"""Test menu."""
directlyProvides(ITestMenu, IMenuItemType)
class ITestLayer(IBrowserRequest):
"""Test Layer."""
class ITestSkin(ITestLayer):
"""Test Skin."""
class MyResource(object):
def __init__(self, request):
self.request = request
class Test(cleanup.CleanUp, unittest.TestCase):
def setUp(self):
super(Test, self).setUp()
XMLConfig('meta.zcml', zope.browsermenu)()
component.provideAdapter(DefaultTraversable, (None,), ITraversable)
def tearDown(self):
if 'test_menu' in dir(sys.modules['zope.app.menus']):
delattr(sys.modules['zope.app.menus'], 'test_menu')
super(Test, self).tearDown()
def testMenuOverride(self):
self.assertEqual(
component.queryMultiAdapter((ob, request), name='test'),
None)
xmlconfig(StringIO(template % (
'''
'''
)))
menu1 = component.getUtility(IBrowserMenu, 'test_menu')
menuItem1 = getFirstMenuItem('test_menu', ob, TestRequest())
xmlconfig(StringIO(template % (
'''
'''
)))
menu2 = component.getUtility(IBrowserMenu, 'test_menu')
menuItem2 = getFirstMenuItem('test_menu', ob, TestRequest())
self.assertNotEqual(menu1, menu2)
self.assertEqual(menuItem1, menuItem2)
def testMenuItemNeedsFor(self):
# directive fails if no 'for' argument was provided
from zope.configuration.exceptions import ConfigurationError
self.assertRaises(ConfigurationError, xmlconfig, StringIO(template %
'''
'''
))
# it works, when the argument is there and a valid interface
xmlconfig(StringIO(template %
'''
'''
))
def test_suite():
return unittest.makeSuite(Test)
zope.browsermenu-4.0.0/src/zope/browsermenu/tests/test_menu.py 0000664 0001750 0001750 00000002141 11775031414 024601 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2004 Zope Foundation 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 Menu Item Tests
"""
import unittest
import doctest
import pprint
from zope.testing import cleanup
def test_suite():
return unittest.TestSuite((
doctest.DocFileSuite('../README.txt',
setUp=lambda test:cleanup.setUp(),
tearDown=lambda test:cleanup.tearDown(),
globs={'pprint': pprint.pprint},
optionflags=doctest.NORMALIZE_WHITESPACE),
))
zope.browsermenu-4.0.0/src/zope/browsermenu/tests/__init__.py 0000664 0001750 0001750 00000000000 11775031414 024325 0 ustar tseaver tseaver zope.browsermenu-4.0.0/src/zope/browsermenu/tests/addmenuitems.zcml 0000664 0001750 0001750 00000001245 11775031414 025576 0 ustar tseaver tseaver
zope.browsermenu-4.0.0/src/zope/browsermenu/tests/test_fields.py 0000664 0001750 0001750 00000001674 11775031414 025115 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2004 Zope Foundation 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.
#
##############################################################################
"""Test fields.
"""
import unittest
import doctest
from zope.testing import cleanup
def test_suite():
return unittest.TestSuite((
doctest.DocTestSuite('zope.browsermenu.field',
setUp=lambda test:cleanup.setUp(),
tearDown=lambda test:cleanup.tearDown()),
))
zope.browsermenu-4.0.0/src/zope/browsermenu/metaconfigure.py 0000664 0001750 0001750 00000026111 11775031415 024270 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2004 Zope Foundation 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.
#
##############################################################################
"""Menu Directives Configuration Handlers
"""
from zope.browser.interfaces import IAdding
from zope.component import getGlobalSiteManager, getUtility
from zope.component.interface import provideInterface
from zope.component.zcml import adapter, proxify, utility
from zope.configuration.exceptions import ConfigurationError
from zope.interface import Interface
from zope.interface.interface import InterfaceClass
from zope.pagetemplate.engine import Engine
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
from zope.security.checker import InterfaceChecker, CheckerPublic
from zope.security.metaconfigure import ClassDirective
from zope.browsermenu.menu import BrowserMenu, BrowserMenuItem, BrowserSubMenuItem
from zope.browsermenu.interfaces import IBrowserMenu, IMenuItemType
from zope.browsermenu.interfaces import IBrowserMenuItem, IBrowserSubMenuItem
from zope.browsermenu.interfaces import AddMenu
# Create special modules that contain all menu item types
from types import ModuleType as module
import sys
try:
import zope.app
except ImportError: # we doesn't always have zope.app now
sys.modules['zope.app'] = module('app')
menus = module('menus')
sys.modules['zope.app.menus'] = menus
_order_counter = {}
def menuDirective(_context, id=None, class_=BrowserMenu, interface=None,
title=u'', description=u''):
"""Registers a new browser menu."""
if id is None and interface is None:
raise ConfigurationError(
"You must specify the 'id' or 'interface' attribute.")
if interface is None:
if id in dir(menus):
# reuse existing interfaces for the id, without this we are not
# able to override menus.
interface = getattr(menus, id)
else:
interface = InterfaceClass(id, (),
__doc__='Menu Item Type: %s' %id,
__module__='zope.app.menus')
# Add the menu item type to the `menus` module.
# Note: We have to do this immediately, so that directives using the
# MenuField can find the menu item type.
setattr(menus, id, interface)
path = 'zope.app.menus.' + id
else:
path = interface.__module__ + '.' + interface.getName()
# If an id was specified, make this menu available under this id.
# Note that the menu will be still available under its path, since it
# is an adapter, and the `MenuField` can resolve paths as well.
if id is None:
id = path
else:
# Make the interface available in the `zope.app.menus` module, so
# that other directives can find the interface under the name
# before the CA is setup.
_context.action(
discriminator = ('browser', 'MenuItemType', path),
callable = provideInterface,
args = (path, interface, IMenuItemType, _context.info)
)
setattr(menus, id, interface)
# Register the layer interface as an interface
_context.action(
discriminator = ('interface', path),
callable = provideInterface,
args = (path, interface),
kw = {'info': _context.info}
)
# Register the menu item type interface as an IMenuItemType
_context.action(
discriminator = ('browser', 'MenuItemType', id),
callable = provideInterface,
args = (id, interface, IMenuItemType, _context.info)
)
# Register the menu as a utility
utility(_context, IBrowserMenu, class_(id, title, description), name=id)
def menuItemDirective(_context, menu, for_,
action, title, description=u'', icon=None, filter=None,
permission=None, layer=IDefaultBrowserLayer, extra=None,
order=0, item_class=None):
"""Register a single menu item."""
return menuItemsDirective(_context, menu, for_, layer).menuItem(
_context, action, title, description, icon, filter,
permission, extra, order, item_class)
def subMenuItemDirective(_context, menu, for_, title, submenu,
action=u'', description=u'', icon=None, filter=None,
permission=None, layer=IDefaultBrowserLayer,
extra=None, order=0, item_class=None):
"""Register a single sub-menu menu item."""
return menuItemsDirective(_context, menu, for_, layer).subMenuItem(
_context, submenu, title, description, action, icon, filter,
permission, extra, order, item_class)
class MenuItemFactory(object):
"""generic factory for menu items."""
def __init__(self, factory, **kwargs):
self.factory = factory
if 'permission' in kwargs and kwargs['permission'] == 'zope.Public':
kwargs['permission'] = CheckerPublic
self.kwargs = kwargs
def __call__(self, context, request):
item = self.factory(context, request)
for key, value in self.kwargs.items():
setattr(item, key, value)
if item.permission is not None:
checker = InterfaceChecker(IBrowserMenuItem, item.permission)
item = proxify(item, checker)
return item
class menuItemsDirective(object):
"""Register several menu items for a particular menu."""
menuItemClass = BrowserMenuItem
subMenuItemClass = BrowserSubMenuItem
def __init__(self, _context, menu, for_, layer=IDefaultBrowserLayer,
permission=None):
self.for_ = for_
self.menuItemType = menu
self.layer = layer
self.permission = permission
def menuItem(self, _context, action, title, description=u'',
icon=None, filter=None, permission=None, extra=None,
order=0, item_class=None):
if filter is not None:
filter = Engine.compile(filter)
if permission is None:
permission = self.permission
if order == 0:
order = _order_counter.get(self.for_, 1)
_order_counter[self.for_] = order + 1
if item_class is None:
item_class = self.menuItemClass
if not IBrowserMenuItem.implementedBy(item_class):
raise ValueError("Item class (%s) must implement IBrowserMenuItem" % item_class)
factory = MenuItemFactory(
item_class,
title=title, description=description, icon=icon, action=action,
filter=filter, permission=permission, extra=extra, order=order,
_for=self.for_)
adapter(_context, (factory,), self.menuItemType,
(self.for_, self.layer), name=title)
def subMenuItem(self, _context, submenu, title, description=u'',
action=u'', icon=None, filter=None, permission=None,
extra=None, order=0, item_class=None):
if filter is not None:
filter = Engine.compile(filter)
if permission is None:
permission = self.permission
if order == 0:
order = _order_counter.get(self.for_, 1)
_order_counter[self.for_] = order + 1
if item_class is None:
item_class = self.subMenuItemClass
if not IBrowserSubMenuItem.implementedBy(item_class):
raise ValueError("Item class (%s) must implement IBrowserSubMenuItem" % item_class)
factory = MenuItemFactory(
item_class,
title=title, description=description, icon=icon, action=action,
filter=filter, permission=permission, extra=extra, order=order,
_for=self.for_, submenuId=submenu)
adapter(_context, (factory,), self.menuItemType,
(self.for_, self.layer), name=title)
def __call__(self, _context):
# Nothing to do.
pass
def _checkViewFor(for_=None, layer=None, view_name=None):
"""Check if there is a view of that name registered for IAdding
and IBrowserRequest. If not raise a ConfigurationError
It will raise a ConfigurationError if :
o view=""
o if view_name is not registred
"""
if view_name is None:
raise ConfigurationError(
"Within a addMenuItem directive the view attribut"
" is optional but can\'t be empty"
)
gsm = getGlobalSiteManager()
if gsm.adapters.lookup((for_, layer),
Interface, view_name) is None:
raise ConfigurationError(
"view name %s not found " %view_name
)
def addMenuItem(_context, title, description='', menu=None, for_=None,
class_=None, factory=None, view=None, icon=None, filter=None,
permission=None, layer=IDefaultBrowserLayer, extra=None,
order=0, item_class=None):
"""Create an add menu item for a given class or factory
As a convenience, a class can be provided, in which case, a
factory is automatically defined based on the class. In this
case, the factory id is based on the class name.
"""
if for_ is not None:
_context.action(
discriminator = None,
callable = provideInterface,
args = ('', for_)
)
forname = 'For' + for_.getName()
else:
for_ = IAdding
forname = ''
if menu is not None:
if isinstance(menu, (str, unicode)):
menu = getUtility(IMenuItemType, menu)
if menu is None:
raise ValueError("Missing menu id '%s'" % menu)
if class_ is None:
if factory is None:
raise ValueError("Must specify either class or factory")
else:
if factory is not None:
raise ValueError("Can't specify both class and factory")
if permission is None:
raise ValueError(
"A permission must be specified when a class is used")
factory = "BrowserAdd%s__%s.%s" % (
forname, class_.__module__, class_.__name__)
ClassDirective(_context, class_).factory(_context, id=factory)
extra = {'factory': factory}
if view:
action = view
# This action will check if the view exists
_context.action(
discriminator = None,
callable = _checkViewFor,
args = (for_, layer, view),
order=999999
)
else:
action = factory
if menu == None:
menu = AddMenu
return menuItemsDirective(_context, menu, for_, layer=layer).menuItem(
_context, action, title, description, icon, filter,
permission, extra, order, item_class)
zope.browsermenu-4.0.0/src/zope/browsermenu/configure.zcml 0000664 0001750 0001750 00000000701 11775031415 023733 0 ustar tseaver tseaver
zope.browsermenu-4.0.0/src/zope/browsermenu/__init__.py 0000664 0001750 0001750 00000000000 11775031415 023164 0 ustar tseaver tseaver zope.browsermenu-4.0.0/src/zope/browsermenu/field.py 0000664 0001750 0001750 00000006743 11775031415 022534 0 ustar tseaver tseaver #############################################################################
#
# Copyright (c) 2001, 2002 Zope Foundation 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.
#
##############################################################################
"""Menu field
"""
__docformat__ = 'restructuredtext'
from zope.component import queryUtility
from zope.component.interfaces import ComponentLookupError
from zope.configuration.exceptions import ConfigurationError
from zope.configuration.fields import GlobalObject
from zope.schema import ValidationError
from zope.browsermenu.interfaces import IMenuItemType
class MenuField(GlobalObject):
r"""This fields represents a menu (item type).
Besides being able to look up the menu by importing it, we also try
to look up the name in the site manager.
>>> from zope.interface import directlyProvides
>>> from zope.interface.interface import InterfaceClass
>>> menu1 = InterfaceClass('menu1', (),
... __doc__='Menu Item Type: menu1',
... __module__='zope.app.menus')
>>> directlyProvides(menu1, IMenuItemType)
>>> menus = None
>>> class Resolver(object):
... def resolve(self, path):
... if path.startswith('zope.app.menus') and \
... hasattr(menus, 'menu1') or \
... path == 'zope.browsermenu.menus.menu1':
... return menu1
... raise ConfigurationError('menu1')
>>> field = MenuField()
>>> field = field.bind(Resolver())
Test 1: Import the menu
-----------------------
>>> field.fromUnicode('zope.browsermenu.menus.menu1') is menu1
True
Test 2: We have a shortcut name. Import the menu from `zope.app.menus1`.
------------------------------------------------------------------------
>>> from types import ModuleType as module
>>> import sys
>>> menus = module('menus')
>>> old = sys.modules.get('zope.app.menus', None)
>>> sys.modules['zope.app.menus'] = menus
>>> setattr(menus, 'menu1', menu1)
>>> field.fromUnicode('menu1') is menu1
True
>>> if old is not None:
... sys.modules['zope.app.menus'] = old
Test 3: Get the menu from the Site Manager
------------------------------------------
>>> from zope.component import provideUtility
>>> provideUtility(menu1, IMenuItemType, 'menu1')
>>> field.fromUnicode('menu1') is menu1
True
"""
def fromUnicode(self, u):
name = str(u.strip())
try:
value = queryUtility(IMenuItemType, name)
except ComponentLookupError:
# The component architecture is not up and running.
pass
else:
if value is not None:
self.validate(value)
return value
try:
value = self.context.resolve('zope.app.menus.'+name)
except ConfigurationError, v:
try:
value = self.context.resolve(name)
except ConfigurationError, v:
raise ValidationError(v)
self.validate(value)
return value
zope.browsermenu-4.0.0/README.txt 0000664 0001750 0001750 00000000513 11775031415 016446 0 ustar tseaver tseaver ========
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 `_.
This package provides an implementation of browser menus and ZCML directives
for configuring them.
zope.browsermenu-4.0.0/setup.cfg 0000664 0001750 0001750 00000000073 11775031516 016574 0 ustar tseaver tseaver [egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0
zope.browsermenu-4.0.0/COPYRIGHT.txt 0000664 0001750 0001750 00000000040 11775031415 017054 0 ustar tseaver tseaver Zope Foundation and Contributors zope.browsermenu-4.0.0/PKG-INFO 0000664 0001750 0001750 00000003733 11775031516 016056 0 ustar tseaver tseaver Metadata-Version: 1.0
Name: zope.browsermenu
Version: 4.0.0
Summary: Browser menu implementation for Zope.
Home-page: http://pypi.python.org/pypi/zope.browsermenu/
Author: Zope Foundation and Contributors
Author-email: zope-dev@zope.org
License: ZPL 2.1
Description: ========
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 `_.
This package provides an implementation of browser menus and ZCML directives
for configuring them.
=======
CHANGES
=======
4.0.0 (2012-07-04)
==================
- Strip noise from context actions in doctests.
The output is now more meaningful, and hides irrelevant details.
(forward-compatibility with ``zope.component`` 4.0.0).
- Replaced deprecated ``zope.interface.implements`` usage with equivalent
``zope.interface.implementer`` decorator.
- Dropped support for Python 2.4 and 2.5.
3.9.1 (2010-04-30)
==================
- Removed use of 'zope.testing.doctestunit' in favor of stdlib's 'doctest.
3.9.0 (2009-08-27)
==================
Initial release. This package was splitted off zope.app.publisher.
Platform: UNKNOWN
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Zope Public License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Operating System :: OS Independent
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Framework :: Zope3
zope.browsermenu-4.0.0/bootstrap.py 0000664 0001750 0001750 00000007330 11775031415 017343 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2006 Zope Foundation 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.
"""
import os, shutil, sys, tempfile, urllib2
from optparse import OptionParser
tmpeggs = tempfile.mkdtemp()
is_jython = sys.platform.startswith('java')
# parsing arguments
parser = OptionParser()
parser.add_option("-v", "--version", dest="version",
help="use a specific zc.buildout version")
parser.add_option("-d", "--distribute",
action="store_true", dest="distribute", default=False,
help="Use Disribute rather than Setuptools.")
parser.add_option("-c", None, action="store", dest="config_file",
help=("Specify the path to the buildout configuration "
"file to be used."))
options, args = parser.parse_args()
# if -c was provided, we push it back into args for buildout' main function
if options.config_file is not None:
args += ['-c', options.config_file]
if options.version is not None:
VERSION = '==%s' % options.version
else:
VERSION = ''
USE_DISTRIBUTE = options.distribute
args = args + ['bootstrap']
to_reload = False
try:
import pkg_resources
if not hasattr(pkg_resources, '_distribute'):
to_reload = True
raise ImportError
except ImportError:
ez = {}
if USE_DISTRIBUTE:
exec urllib2.urlopen('http://python-distribute.org/distribute_setup.py'
).read() in ez
ez['use_setuptools'](to_dir=tmpeggs, download_delay=0, no_fake=True)
else:
exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
).read() in ez
ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
if to_reload:
reload(pkg_resources)
else:
import pkg_resources
if sys.platform == 'win32':
def quote(c):
if ' ' in c:
return '"%s"' % c # work around spawn lamosity on windows
else:
return c
else:
def quote (c):
return c
cmd = 'from setuptools.command.easy_install import main; main()'
ws = pkg_resources.working_set
if USE_DISTRIBUTE:
requirement = 'distribute'
else:
requirement = 'setuptools'
if is_jython:
import subprocess
assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd',
quote(tmpeggs), 'zc.buildout' + VERSION],
env=dict(os.environ,
PYTHONPATH=
ws.find(pkg_resources.Requirement.parse(requirement)).location
),
).wait() == 0
else:
assert os.spawnle(
os.P_WAIT, sys.executable, quote (sys.executable),
'-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout' + VERSION,
dict(os.environ,
PYTHONPATH=
ws.find(pkg_resources.Requirement.parse(requirement)).location
),
) == 0
ws.add_entry(tmpeggs)
ws.require('zc.buildout' + VERSION)
import zc.buildout.buildout
zc.buildout.buildout.main(args)
shutil.rmtree(tmpeggs)
zope.browsermenu-4.0.0/LICENSE.txt 0000664 0001750 0001750 00000004026 11775031415 016576 0 ustar tseaver tseaver Zope Public License (ZPL) Version 2.1
A copyright notice accompanies this license document that identifies the
copyright holders.
This license has been certified as open source. It has also been designated as
GPL compatible by the Free Software Foundation (FSF).
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions in source code must retain the accompanying copyright
notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the accompanying copyright
notice, this list of conditions, and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Names of the copyright holders must not be used to endorse or promote
products derived from this software without prior written permission from the
copyright holders.
4. The right to distribute this software or to use it for any purpose does not
give you the right to use Servicemarks (sm) or Trademarks (tm) of the
copyright
holders. Use of them is covered by separate agreement with the copyright
holders.
5. If any files are modified, you must cause the modified files to carry
prominent notices stating that you changed the files and the date of any
change.
Disclaimer
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
zope.browsermenu-4.0.0/setup.py 0000664 0001750 0001750 00000004720 11775031415 016466 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2007 Zope Foundation 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.browsermenu setup
"""
from setuptools import setup, find_packages
long_description = (open('README.txt').read() + '\n\n' +
open('CHANGES.txt').read())
setup(name='zope.browsermenu',
version = '4.0.0',
url='http://pypi.python.org/pypi/zope.browsermenu/',
author='Zope Foundation and Contributors',
author_email='zope-dev@zope.org',
classifiers = ['Environment :: Web Environment',
'Intended Audience :: Developers',
'License :: OSI Approved :: Zope Public License',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Operating System :: OS Independent',
'Topic :: Internet :: WWW/HTTP',
'Framework :: Zope3',
],
description='Browser menu implementation for Zope.',
long_description=long_description,
license='ZPL 2.1',
packages=find_packages('src'),
package_dir={'': 'src'},
namespace_packages=['zope'],
include_package_data=True,
install_requires=['setuptools',
'zope.browser',
'zope.component>=3.7',
'zope.configuration',
'zope.i18nmessageid',
'zope.interface',
'zope.pagetemplate>=3.5',
'zope.publisher',
'zope.schema',
'zope.security[untrustedpython]',
'zope.traversing>3.7',
],
extras_require={
'test': ['zope.testing'],
},
zip_safe = False,
)
zope.browsermenu-4.0.0/buildout.cfg 0000664 0001750 0001750 00000000717 11775031415 017266 0 ustar tseaver tseaver [buildout]
develop = .
parts = test coverage-test coverage-report pydev
[test]
recipe = zc.recipe.testrunner
eggs = zope.browsermenu [test]
[coverage-test]
recipe = zc.recipe.testrunner
eggs = zope.browsermenu [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.browsermenu
zope.browsermenu-4.0.0/CHANGES.txt 0000664 0001750 0001750 00000001157 11775031451 016566 0 ustar tseaver tseaver =======
CHANGES
=======
4.0.0 (2012-07-04)
==================
- Strip noise from context actions in doctests.
The output is now more meaningful, and hides irrelevant details.
(forward-compatibility with ``zope.component`` 4.0.0).
- Replaced deprecated ``zope.interface.implements`` usage with equivalent
``zope.interface.implementer`` decorator.
- Dropped support for Python 2.4 and 2.5.
3.9.1 (2010-04-30)
==================
- Removed use of 'zope.testing.doctestunit' in favor of stdlib's 'doctest.
3.9.0 (2009-08-27)
==================
Initial release. This package was splitted off zope.app.publisher.