Commit 83c583ac authored by Godefroid Chapelle's avatar Godefroid Chapelle

importing actual copy of Five zope28-integration branch

parent 493cec6b
Five Changes
============
Five 0.3 (2005-03-11)
---------------------
* Five now uses the Zope 2 page template engine, not the Zope 3
engine. This allows better integration with Zope 2-based page
templates, such as macros.
It uses TrustedExecutables technology (thanks to Dieter Maurer) to
turn off Zope 2 security in page templates, so Five's security
behavior is very similar to what it was before.
* Five now supports the browser:menu, menuItem and menuItems
directives.
* A new Five-specific directive has been added:
five:pagesFromDirectory. This adds one page for each .pt file in a
directory to the specified interface. This is useful for Five
integration with CMF and other systems that have Page Templates
macros that need to be shared between Zope2 and Five.
* Five.security.checkPermission has been changed from a (unused)
method for checking the existence of permissions. Use
zope.app.security.permission.checkPermission if you need that
functionality.
Instead Five.security.checkPermission is now a Five version of
zope.security.checkPermission, which checks if the current user has
a permission on an object.
* Support for browser:editform. You can now use schemas for editing.
* Support for browser:addform; add forms using '+'. You can now browse
to 'container/+/addsomething.html' to get to a schema-driven add
form.
* Fixed a traversal bug which caused Zope to give the wrong error when
a page could not be found (missing docstring instead of not
found). Zope 2.7.4 (or higher) is required for this fix.
Five 0.2b (2004-09-24)
----------------------
* Added utility module, 'bridge', allowing reuse of Zope 2 interfaces
(by introspecting them to create equivalent Zope 3 interfaces).
* five:viewable was renamed to five:traversable, five:viewable still
works but is deprecated; a deprecation warning is emitted when it is
used.
* like in Zope3, an ITraverser adapter is looked up to determine what
happens when traversing into a Five traversable object.
* added five:defaultViewable to make instances of a class directly
viewable using browser:defaultView. This is hookable by the use of a
IBrowserDefault adapter
* deprecated use of Products.Five.api as public API for other products
to use, instead import directly from Products.Five. Retired
Traversable and Viewable from the public API; use ZCML directives
(five:traversable, five:defaultView) instead of mixins to make
instances of classes work with Five.
* classes that Five monkeypatches now have a __five_method__
attribute, making it easier for Five not to stomp on existing methods.
* registered absolute_url view and IAbsoluteURL adapter for *
* zope.app.traversing is registered by default, to make special
namespaces available (eg: @@, ++resource++)
* we now have resources (FileResource, ImageResource,
PageTemplateResource) and directory resources.
* Zope 3 'StandardMacros' now works with Five as well.
* browser:page now correctly handles the allow_attributes and protects
the named attributes on the view with the same permission used for
the view.
* zopeconf.py will try to find etc/zope.conf on INSTANCE_HOME. This
requires Zope 2.7.2, as earlier Zope versions have a bug in this
area which causes them to look in lib/python/Testing.
* Exposed the Zope 3 event system to Five. A class can be made to send
out event notifications using the five:sendEvents directive. Events can
be subscribed to using the subscriber directive.
* Change in findProducts so that non-filesystem products are skipped.
Five 0.1 (2004-07-30)
---------------------
Initial public release (mainly Martijn's work)
Five is distributed under the provisions of the Zope Public License
(ZPL) v2.1. See doc/ZopePublicLicense.txt for the license text.
Copyright (C) 2005 Five Contributors. See CREDITS.txt for a list of
Five contributors.
Five contains source code derived from:
- Zope 3, copyright (C) 2001-2005 by Zope Corporation. Code that
falls under this copyright is prefixed with the following header:
Copyright (c) 2001-2004 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.
- metaclass.py is derived from PEAK, copyright (C) 1996-2004 by
Phillip J. Eby and Tyler C. Sarna. PEAK may be used under the same
terms as Zope.
- TrustedExecutables. Dieter Mauer kindly allow licensing this under the
ZPL 2.1.
\ No newline at end of file
Five contributors
-----------------
- Martijn Faassen (faassen@infrae.com)
- Sidnei da Silva (sidnei@awkly.org)
- Philipp von Weitershausen (philikon@philikon.de)
- Lennart Regebro (regebro@nuxeo.com)
- Tres Seaver (tres@zope.com)
- Andy Adiwidjaja (mail@adiwidjaja.com)
- Stuart Bishop (stuart@stuartbishop.net)
- Simon Eisenmann (simon@struktur.de)
- Dieter Maurer (dieter@handshake.de)
Thank you
---------
Infrae for the initial development and continuing support.
Martijn Faassen would like to thank ETH Zurich for their support and
encouragement during the initial development of Five.
Nuxeo for significant contributions to making Five usable in the real
world.
Dieter Maurer for use of code from TrustedExecutables within Five
under the ZPL.
The Five developers would like to thank the Zope 3 developers, in
particular Jim Fulton, for the mountain to stand on.
How to install Five
-------------------
Requirements for Five 0.3
=========================
* Zope 2.7.4+ with python 2.3.x. Zope versions lower than Zope 2.7.4
may work, but no guarantees.
* Zope X3.0.0, found here: http://zope.org/Products/ZopeX3/3.0.0final/
Installing Five
===============
Installing Five is relatively straightforward.
* Select a Zope 2.7 instance.
* Download and install Zope X3.0.0. You can get it compiled and
installed by:
* Typing ``configure``. When you're experimenting, typically you
want to use the ``--prefix`` directive to install the binaries
to install it somewhere in your homedirectory.
* ``make``
* ``make install``
On windows you can install choose to use the binary release instead.
Alternatively you can check out the latest subversion version of
Zope X3.0 and typing ``make`` to produce it in-place.
* You need to make your Zope 2.7 instance aware of Zope 3 so it can
import the ``zope``, ``persistent`` and ``transaction`` packages from it.
* In non-ZEO setups, you can simply go to the ``etc/zope.conf`` of
your Zope 2.7 instance and add a ``path`` entry. If you used the
released version of Zope X3.0.0, use something like the following::
path /path/to/installed/Zope3/lib/python
If you are instead using the subversion version, use::
path /path/to/Zope3/src
If you have problems however, see the instructions for the ZEO
setup.
* In ZEO setups (or some other circumstances), Zope 3's ZEO packages
will interfere with Zope 2's. In this case you can create a new
directory, symlink the ``zope``, ``persistent`` and ``transaction``
packages in it and use this directory for the ``path`` entry in the
``etc/zope.conf`` of your Zope 2.7 instance.
* Next, install the Five product into your Zope 2.7 instance as a
product and restart Zope. Five should now be installed.
* You can also install various products in the ``demo`` subdirectory
of Five by copying them into your ``Products`` directory. In
addition, you can look at tests/products/FiveTest, which is a
product used for the Five tests, and may contain more recent
examples.
Installing the tests
====================
For information on how to install the automatic Five tests, please see
``tests/README.txt``.
Introduction
------------
"It was the dawn of the third age of Zope. The Five project was a dream
given form. Its goal: to use Zope 3 technologies in Zope 2.7 by
creating a Zope 2 product where Zope 3 and Zope 2 could work out their
differences peacefully." -- Babylon 5, creatively quoted
"The Law of Fives states simply that: ALL THINGS HAPPEN IN FIVES, OR
ARE DIVISIBLE BY OR ARE MULTIPLES OF FIVE, OR ARE SOMEHOW DIRECTLY OR
INDIRECTLY RELATED TO FIVE.
THE LAW OF FIVES IS NEVER WRONG." -- Principia Discordia
What is Five?
-------------
The goal of five is to allow Zope 2 developers to use Zope 3
technology right now, inside of Zope 2. Additionally, this allows a
gradual evolution of Zope 2 code to Zope 3.
Five already makes the following Zope 3 technologies available in Zope
2:
* Zope 3 interfaces
* ZCML (Zope Configuration Markup Language)
* Adapters
* Zope 3 views, even for standard Zope objects
* layers & skins
* schema/forms machinery, including edit and add forms.
* Zope 2 security declarations in ZCML instead of in Python code.
Together with another product, CMFonFive, Five can integrate into CMF.
For more information, see ``doc/features.txt``.
How to install Five
-------------------
See ``INSTALL.txt``.
How to use Five
---------------
Please see ``doc/manual.txt``.
# Copyright (C) 2004 by Dr. Dieter Maurer, Eichendorffstr. 23, D-66386 St. Ingbert, Germany
from new import function
def rebindFunction(f,rebindDir=None,**rebinds):
'''return *f* with some globals rebound.'''
d= {}
if rebindDir : d.update(rebindDir)
if rebinds: d.update(rebinds)
if not d: return f
f= getattr(f,'im_func',f)
fd= f.func_globals.copy()
fd.update(d)
nf= function(f.func_code,fd,f.func_name,f.func_defaults or ())
nf.__doc__= f.__doc__
if f.__dict__ is not None: nf.__dict__= f.__dict__.copy()
return nf
====
TODO
====
- more extensive testing whether event system works with things like Zope 2
folders etc
- ensuring that the event-sending behavior is as close to Zope 3's as
possible. A lot of edge cases with different behavior likely remain,
and things like IObjectModifiedEvents are not sent yet for folders.
- allow the multiple use of five:sendEvents
- allow Zope2 boilerplate context.registerClass be configured through zcml
- Figure out where add-view redirects should go.
- Instructions on using add views.
# Copyright (C) 2004 by Dr. Dieter Maurer, Eichendorffstr. 23, D-66386 St. Ingbert, Germany
from sys import modules
from Products.PageTemplates.PythonExpr import PythonExpr
from Products.PageTemplates.Expressions import \
SubPathExpr, PathExpr, \
StringExpr, \
getEngine, installHandlers
from ReuseUtils import rebindFunction
class _ModuleImporter:
def __getitem__(self, module):
__import__(module)
return modules[module]
ModuleImporter = _ModuleImporter()
def trustedTraverse(ob, path, ignored,):
if not path: return self
get = getattr
has = hasattr
N = None
M = rebindFunction # artifical marker
if isinstance(path, str): path = path.split('/')
else: path=list(path)
REQUEST={'TraversalRequestNameStack': path}
path.reverse()
pop=path.pop
if len(path) > 1 and not path[0]:
# Remove trailing slash
path.pop(0)
if not path[-1]:
# If the path starts with an empty string, go to the root first.
pop()
self=ob.getPhysicalRoot()
object = ob
while path:
name=pop()
__traceback_info__ = path, name
if name == '..':
o=getattr(object, 'aq_parent', M)
if o is not M:
object=o
continue
t=get(object, '__bobo_traverse__', M)
if t is not M: o=t(REQUEST, name)
else:
o = get(object, name, M)
if o is M:
try: o = object[name]
except AttributeError: # better exception
raise AttributeError(name)
object = o
return object
class SubPathExpr(SubPathExpr):
_eval = rebindFunction(SubPathExpr._eval.im_func,
restrictedTraverse=trustedTraverse,
)
class PathExpr(PathExpr):
__init__ = rebindFunction(PathExpr.__init__.im_func,
SubPathExpr=SubPathExpr,
)
class StringExpr(StringExpr):
__init__ = rebindFunction(StringExpr.__init__.im_func,
PathExpr=PathExpr,
)
installHandlers = rebindFunction(installHandlers,
PathExpr=PathExpr,
StringExpr=StringExpr,
PythonExpr=PythonExpr,
)
_engine=None
getEngine = rebindFunction(getEngine,
_engine=_engine,
installHandlers=installHandlers
)
##############################################################################
#
# Copyright (c) 2004 Five Contributors. All rights reserved.
#
# This software is distributed under the terms of the Zope Public
# License (ZPL) v2.1. See COPYING.txt for more information.
#
##############################################################################
"""Initialize the Five product
$Id: __init__.py 9796 2005-03-15 14:58:39Z efge $
"""
import Acquisition
from Globals import INSTANCE_HOME
import zcml
# public API provided by Five
# usage: from Products.Five import <something>
from browser import BrowserView, StandardMacros
def initialize(context):
zcml.load_site()
<html metal:use-macro="here/five_template/macros/master">
<body>
<div metal:fill-slot="main">
<div metal:define-macro="addform">
<form action="." tal:attributes="action request/URL" method="post"
enctype="multipart/form-data">
<div metal:define-macro="formbody">
<h3 tal:condition="view/label"
tal:content="view/label"
metal:define-slot="heading"
>Edit something</h3>
<p tal:define="status view/update"
tal:condition="status"
tal:content="status" />
<p tal:condition="view/errors" i18n:translate="">
There are <strong tal:content="python:len(view.errors)"
i18n:name="num_errors">6</strong> input errors.
</p>
<div metal:define-slot="extra_info" tal:replace="nothing">
</div>
<div class="row" metal:define-slot="extra_top" tal:replace="nothing">
<div class="label">Extra top</div>
<div class="label"><input type="text" style="width:100%" /></div>
</div>
<div metal:use-macro="context/@@widget_macros/widget_rows" />
<div class="separator"></div>
<div class="row"
metal:define-slot="extra_bottom" tal:replace="nothing">
<div class="label">Extra bottom</div>
<div class="field"><input type="text" style="width:100%" /></div>
</div>
<div class="separator"></div>
</div>
<br/><br/>
<div class="row">
<div class="controls"><hr />
<input type='submit' value='Refresh'
i18n:attributes='value refresh-button' />
<input type='submit' value='Add' name='UPDATE_SUBMIT'
i18n:attributes='value add-button' />
<span tal:condition="context/nameAllowed|nothing" tal:omit-tag="">
&nbsp;&nbsp;<b i18n:translate="">Object Name</b>&nbsp;&nbsp;
<input type='text' name='add_input_name'
tal:attributes="value context/contentName" />
</span>
</div>
</div>
<div class="row" metal:define-slot="extra_buttons" tal:replace="nothing">
</div>
<div class="separator"></div>
</form>
</div>
</div>
</body>
</html>
<html metal:use-macro="here/five_template/macros/master">
<body>
<div metal:fill-slot="main">
<p>+ screen not yet supported by Five</p>
</div>
</body>
</html>
##############################################################################
#
# Copyright (c) 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.
#
##############################################################################
"""Adding View
The Adding View is used to add new objects to a container. It is sort of a
factory screen.
"""
__docformat__ = 'restructuredtext'
from warnings import warn
from zope.interface import implements
from zope.publisher.interfaces import IPublishTraverse
from zope.component.interfaces import IFactory
from zope.app.exception.interfaces import UserError
from zope.app.container.interfaces import IAdding, INameChooser
from zope.app.container.interfaces import IContainerNamesContainer
from zope.app.container.constraints import checkFactory, checkObject
from zope.app import zapi
from zope.app.event.objectevent import ObjectCreatedEvent
from zope.event import notify
from zExceptions import BadRequest
from Products.Five import BrowserView
from Products.Five.traversable import Traversable
from Products.Five.pagetemplatefile import ZopeTwoPageTemplateFile
from Acquisition import Implicit
from OFS.SimpleItem import SimpleItem
class BasicAdding(Implicit, BrowserView):
implements(IAdding, IPublishTraverse)
def add(self, content):
"""See zope.app.container.interfaces.IAdding
"""
container = self.context
name = self.contentName
chooser = INameChooser(container)
# check precondition
checkObject(container, name, content)
if IContainerNamesContainer.providedBy(container):
# The container picks it's own names.
# We need to ask it to pick one.
name = chooser.chooseName(self.contentName or '', content)
else:
request = self.request
name = request.get('add_input_name', name)
if name is None:
name = chooser.chooseName(self.contentName or '', content)
elif name == '':
name = chooser.chooseName('', content)
chooser.checkName(name, container)
content.id = name
container._setObject(name, content)
self.contentName = name # Set the added object Name
return container._getOb(name)
contentName = None # usually set by Adding traverser
def nextURL(self):
"""See zope.app.container.interfaces.IAdding"""
# XXX this is definitely not right for all or even most uses
# of Five, but can be overridden by an AddView subclass, using
# the class attribute of a zcml:addform directive
return (str(zapi.getView(self.context, "absolute_url", self.request))
+ '/manage_main')
# set in BrowserView.__init__
request = None
context = None
def renderAddButton(self):
warn("The renderAddButton method is deprecated, use nameAllowed",
DeprecationWarning, 2)
def publishTraverse(self, request, name):
"""See zope.app.container.interfaces.IAdding"""
if '=' in name:
view_name, content_name = name.split("=", 1)
self.contentName = content_name
if view_name.startswith('@@'):
view_name = view_name[2:]
return zapi.getView(self, view_name, request)
if name.startswith('@@'):
view_name = name[2:]
else:
view_name = name
view = zapi.queryView(self, view_name, request)
if view is not None:
return view
factory = zapi.queryUtility(IFactory, name)
if factory is None:
return super(BasicAdding, self).publishTraverse(request, name)
return factory
def action(self, type_name='', id=''):
if not type_name:
raise UserError("You must select the type of object to add.")
if type_name.startswith('@@'):
type_name = type_name[2:]
if '/' in type_name:
view_name = type_name.split('/', 1)[0]
else:
view_name = type_name
if zapi.queryView(self, view_name, self.request) is not None:
url = "%s/%s=%s" % (
zapi.getView(self, "absolute_url", self.request),
type_name, id)
self.request.response.redirect(url)
return
if not self.contentName:
self.contentName = id
factory = zapi.getUtility(IFactory, type_name)
content = factory()
notify(ObjectCreatedEvent(content))
self.add(content)
self.request.response.redirect(self.nextURL())
def namesAccepted(self):
return not IContainerNamesContainer.providedBy(self.context)
def nameAllowed(self):
"""Return whether names can be input by the user."""
return not IContainerNamesContainer.providedBy(self.context)
class Adding(BasicAdding):
menu_id = None
index = ZopeTwoPageTemplateFile("adding.pt")
def addingInfo(self):
"""Return menu data.
This is sorted by title.
"""
container = self.context
menu_service = zapi.getService("BrowserMenu")
result = []
for menu_id in (self.menu_id, 'zope.app.container.add'):
if not menu_id:
continue
for item in menu_service.getMenu(menu_id, self, self.request):
extra = item.get('extra')
if extra:
factory = extra.get('factory')
if factory:
factory = zapi.getUtility(IFactory, factory)
if not checkFactory(container, None, factory):
continue
elif item['extra']['factory'] != item['action']:
item['has_custom_add_view']=True
result.append(item)
result.sort(lambda a, b: cmp(a['title'], b['title']))
return result
def isSingleMenuItem(self):
"Return whether there is single menu item or not."
return len(self.addingInfo()) == 1
def hasCustomAddView(self):
"This should be called only if there is `singleMenuItem` else return 0"
if self.isSingleMenuItem():
menu_item = self.addingInfo()[0]
if 'has_custom_add_view' in menu_item:
return True
return False
class ContentAdding(Adding, Traversable, SimpleItem):
menu_id = "add_content"
class ObjectManagerNameChooser:
"""A name chooser for a Zope object manager.
"""
implements(INameChooser)
def __init__(self, context):
self.context = context
def checkName(self, name, object):
try:
self.context._checkId(name, allow_dup=False)
except BadRequest:
raise UserError, "Id is in use or invalid"
def chooseName(self, name, object):
if not name:
name = object.__class__.__name__
dot = name.rfind('.')
if dot >= 0:
suffix = name[dot:]
name = name[:dot]
else:
suffix = ''
n = name + suffix
i = 1
while True:
try:
container._getOb(n)
except AttributeError:
pass
else:
break
i += 1
n = name + '-' + str(i) + suffix
# Make sure tha name is valid. We may have started with something bad.
self.checkName(n, object)
return n
##############################################################################
#
# Copyright (c) 2004 Five Contributors. All rights reserved.
#
# This software is distributed under the terms of the Zope Public
# License (ZPL) v2.1. See COPYING.txt for more information.
#
##############################################################################
"""Convenience package for short imports
$Id: api.py 6174 2004-08-25 17:19:28Z faassen $
"""
import warnings
warnings.warn('The use of the Products.Five.api module has been deprecated. '
'Import directly from Products.Five instead for public API.',
DeprecationWarning)
from browser import BrowserView, StandardMacros
from traversable import Traversable
from viewable import Viewable
##############################################################################
#
# Copyright (c) 2004 Five Contributors. All rights reserved.
#
# This software is distributed under the terms of the Zope Public
# License (ZPL) v2.1. See COPYING.txt for more information.
#
##############################################################################
""" Z2 -> Z3 bridge utilities.
$Id$
"""
from Interface._InterfaceClass import Interface as Z2_InterfaceClass
from Interface import Interface as Z2_Interface
from Interface import Attribute as Z2_Attribute
from zope.interface.interface import InterfaceClass as Z3_InterfaceClass
from zope.interface.interface import Interface as Z3_Interface
from zope.interface.interface import Attribute as Z3_Attribute
def fromZ2Interface(z2i):
""" Return a Zope 3 interface corresponding to 'z2i'.
o 'z2i' must be a Zope 2 interface.
"""
if not isinstance(z2i, Z2_InterfaceClass):
raise ValueError, 'Not a Zope 2 interface!'
if z2i is Z2_Interface: # special case; root in new hierarchy!
return Z3_Interface
name = z2i.getName()
bases = [ fromZ2Interface(x) for x in z2i.getBases() ]
attrs = {}
for k, v in z2i.namesAndDescriptions():
if isinstance(v, Z2_Attribute):
v = fromZ2Attribute(v)
attrs[k] = v
# XXX: Note that we pass the original interface's __module__;
# we may live to regret that.
return Z3_InterfaceClass(name=name,
bases=bases,
attrs=attrs,
__doc__=z2i.getDoc(),
__module__=z2i.__module__,
)
def fromZ2Attribute(z2a):
""" Return a Zope 3 interface attribute corresponding to 'z2a'.
o 'z2a' must be a Zope 2 interface attribute.
"""
if not isinstance(z2a, Z2_Attribute):
raise ValueError, 'Not a Zope 2 interface attribute!'
return Z3_Attribute(z2a.getName(), z2a.getDoc())
This diff is collapsed.
This diff is collapsed.
<configure xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:five="http://namespaces.zope.org/five">
<include file="meta.zcml" />
<include file="services.zcml" />
<include file="interfaces.zcml" />
<include file="permissions.zcml" />
<include package="zope.app.traversing" />
<include package="zope.app.form.browser" />
<!-- do 'traditional' traversing by default; needed by ZPT -->
<adapter
for="*"
factory=".traversable.FiveTraversable"
provides="zope.app.traversing.interfaces.ITraversable"
/>
<adapter
for="*"
factory="zope.app.traversing.adapters.Traverser"
provides="zope.app.traversing.interfaces.ITraverser"
/>
<adapter
for="*"
factory=".viewable.BrowserDefault"
provides=".interfaces.IBrowserDefault"
/>
<browser:page
for="*"
name="absolute_url"
class=".browser.AbsoluteURL"
permission="zope.Public"
allowed_interface="zope.app.traversing.browser.interfaces.IAbsoluteURL"
/>
<browser:page
for="*"
template="five_template.pt"
name="five_template"
permission="zope.Public"
/>
<view
for="*"
factory=".browser.AbsoluteURL"
type="zope.publisher.interfaces.http.IHTTPRequest"
permission="zope.Public"
provides="zope.app.traversing.browser.interfaces.IAbsoluteURL"
/>
<browser:page
for="zope.app.traversing.interfaces.IContainmentRoot"
name="absolute_url"
class=".browser.SiteAbsoluteURL"
permission="zope.Public"
allowed_interface="zope.app.traversing.browser.interfaces.IAbsoluteURL"
/>
<view
for="zope.app.traversing.interfaces.IContainmentRoot"
factory=".browser.SiteAbsoluteURL"
type="zope.publisher.interfaces.http.IHTTPRequest"
permission="zope.Public"
provides="zope.app.traversing.browser.interfaces.IAbsoluteURL"
/>
<browser:view
for=".interfaces.IObjectManager"
name="+"
class=".adding.ContentAdding"
permission="zope2.ViewManagementScreens"
>
<browser:page name="index.html" template="adding.pt" />
<browser:page name="action.html" attribute="action" />
</browser:view>
<adapter
for=".interfaces.IObjectManager"
factory=".adding.ObjectManagerNameChooser"
provides="zope.app.container.interfaces.INameChooser"
/>
<!-- this is really lying, but it's to please checkContainer -->
<five:implements class="OFS.ObjectManager.ObjectManager"
interface="zope.app.container.interfaces.IContainer" />
<!-- make Zope 2's REQUEST implement the right thing -->
<five:implements class="ZPublisher.HTTPRequest.HTTPRequest"
interface="zope.publisher.interfaces.browser.IBrowserRequest"
/>
</configure>
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.
=================================
ZCML Directives supported by Five
=================================
Five tries to use the Zope 3 ZCML directives where possible, though
does sometimes subset the possible attributes. It also introduces a
few directives of its own under the ``five`` namespace.
Directives are listed per namespace, in alphabetic order.
zope ``http://namespaces.zope.org/zope``
========================================
adapter
-------
Hook an adapter factory to an interface.
content
-------
Declare interface and permissions on content object. Declares Zope 2
permissions.
permission
----------
Way to make Zope 2 permissions available to Five, ``title`` is
permission name.
redefinePermission
------------------
Redefine a permission in included ZCML as another one.
service
-------
Declare a global service
serviceType
-----------
Declare a type of service.
skin
----
Declare a skin, consisting of layers.
utility
-------
Declare a global utility.
browser ``http://namespaces.zope.org/browser``
==============================================
page
----
Declare a page view for an interface. Permission is a Zope 2
permission.
pages
-----
Declare multiple page views for an interface. Permissions are Zope 2
permissions.
defaultView
-----------
Declare the name of the view that should be used for the default when viewing
the object; i.e. when the object is traversed to without a view.
defaultSkin
-----------
Declare the default skin used.
interface
---------
Define an interface in ZCML.
layer
-----
Declare a layer.
menu
----
Declare a menu
menuItem, menuItems
-------------------
Declare menuItems
five ``http://namespaces.zope.org/five``
========================================
implements
----------
Make a class declare it implements an interface.
loadProducts
------------
Loads ZCML in all Zope 2 products. First processes all ``meta.zcml``
files, then processes all ``configure.zcml`` files.
loadProductsOverrides
---------------------
Loads overriding ZCML in all products (``overrides.zcml``).
traversable
-----------
Make a Zope 2 content class traversable in the Zope 3 manner using
Five. This is used to attached views, resources and other things to
Zope 2 objects.
defaultViewable
---------------
Make a Zope 2 content class use a Zope 3 default view when looking at
it without any paths appended to it. This works then instead of
``index_html`` in Zope 2.
pagesFromDirectory
------------------
Load all *.pt files in a directory as pages. Useful when you want to
share templates between Five and CMF, so you can declare pages like
this is a similar way to setting up skin folders in portal_skins.
browser:editform
----------------
Create an edit form based on a schema.
browser:addform
---------------
Create an add form based on a schema.
=============
Five features
=============
Five features are mostly Zope 3 features, though Five has some extras,
and some limitations.
Zope 3 interfaces
=================
Everything in the ``zope.interface`` package should work. Zope 3
interfaces are the foundation of the component architecture, and also
the foundation of schemas.
ZCML
====
ZCML is the Zope Configuration Markup Language, an XML application.
Zope 3 (and Five) code consists of a lot of components that can be
plugged together using ZCML.
If you put a ``site.zcml`` in the home directory of your Zope
instance, this is the root of the ZCML tree. An example of
``site.zcml`` is in ``site.zcml.in``. If you don't place a
``site.zcml``, Five falls back on ``fallback.zcml``.
ZCML in Five has special directive, ``five:loadProducts``, to load the
ZCML (``meta.zcml``, ``configure.zcml``) of all installed Zope 2
products, if available.
Another special directive, ``five:loadProductsOverrides`` is available
to load any overriding ZCML (``overrides.zcml``) in these products. In
the ``overrides.zcml`` you can override existing views or adapters, in
this or in other products.
Adapters
========
You can use adapters in Five, just like in Zope 3.
Zope 3 views
============
Zope 3 views work in Five, including layers and skins. To make them
work however, you need to make a Zope 2 class "traversable". This can
be done by using the ``five:traversable`` directive in ZCML.
Page templates
==============
Five before release 0.3 used to use Zope 3's page template engine, but
in the interests of increased compatibility with Zope 2, we've
switched to using Zope 2's. There should be no real difference to any
code, however. We may decide to switch back to Zope 3's engine again
eventually if we can resolve the compatibility issues.
One thing to be aware of is that the page template engine runs
completely in trusted mode, just like Python code. That is, as soon as
the page template engine is running, no Zope 2 or Zope 3 security
checks are made.
Edit and add forms
==================
Five supports edit and add forms. Typical Zope 3 examples of these
should work.
Security declarations
=====================
Five aims to eradicate ``declareProtected``, ``ClassSecurityInfo`` and
``initializeClass`` from your Zope 2 code.
In order to do this, Five provides the Zope 3 way of declaring
permissions from ZCML, but uses the Zope 2 mechanisms to actually set
them. To declare permissions for methods and templates on views you
use the ``permission`` attribute on the ``browser:page`` directive,
and specify a Zope 2 permission (given a Zope 3 name). You can find a
list of these permissions in ``permissions.zcml`` in Five. The
permission check takes place before the view is executed.
The ``content`` directive can also be used to declare permissions on
Zope 2 content classes. Note however that these permissions will be
ignored by views anyway, as they are trusted -- it only serves to
protect directly exposed methods on content classes (the python
scripts and the ZPublisher).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%deffont "standard" xfont "helvetica-medium-r"
%deffont "thick" xfont "helvetica-bold-r"
%deffont "typewriter" xfont "courier-medium-r"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Default settings per each line numbers.
%%
%default 1 area 90 90, leftfill, size 2, fore "gray20", back "white", font "standard", hgap 0
%default 2 size 7, vgap 10, prefix " ", ccolor "blue"
%default 3 size 2, bar "gray70", vgap 10
%default 4 size 5, fore "gray20", vgap 30, prefix " ", font "standard"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Default settings that are applied to TAB-indented lines.
%%
%tab 1 size 5, vgap 40, prefix " ", icon box "red" 50
%tab 2 size 4, vgap 40, prefix " ", icon arc "yellow" 50
%tab 3 size 3, vgap 40, prefix " ", icon delta3 "white" 40
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%page
Five - Zope 3 in Zope 2
%center
Martijn Faassen, Infrae
faassen@infrae.com
%page
Motto
It was the dawn of the third age of Zope. The Five project was a dream given form. Its goal: to use Zope 3 technologies in Zope 2.7 by creating a Zope 2 product where Zope 3 and Zope 2 could work out their differences peacefully.
(Babylon 5 season 1 intro, creatively quoted)
%page
Motto 2
The Law of Fives states simply that: ALL THINGS HAPPEN IN FIVES, OR ARE DIVISIBLE BY OR ARE MULTIPLES OF FIVE, OR ARE SOMEHOW DIRECTLY OR INDIRECTLY RELATED TO FIVE.
THE LAW OF FIVES IS NEVER WRONG.
(Principia Discordia)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%page
The problem
We're using Zope 2 in production
Zope 2 is showing its age
Zope 3 has better ways to do things
But can't just switch, we have customers!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%page
Benefits of using Zope 3 in Zope 2
Able to use Zope 3 technologies right away
Don't reinvent the wheel/APIs
Better prepared for Zope 3 transition
Evolution, not revolution
Convergence, not divergence
%page
What works now?
Interfaces (zope.interface)
Schema (zope.schema)
ZCML (zope.configuration)
Adapters (zope.component)
Views, including layers, skins (zope.component)
%page
Brief demo
Show ZCML, adapters and views in action
%page
Next?
Utilities (global ones should work)
Forms
Views (improve the current system)
Who knows?
%page
Plans
Relicense from BSD to generic ZPL 2.1
Move from CVS at Infrae into SVN at codespeak.net
Convergence; join us!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%deffont "standard" xfont "helvetica-medium-r"
%deffont "thick" xfont "helvetica-bold-r"
%deffont "typewriter" xfont "courier-medium-r"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Default settings per each line numbers.
%%
%default 1 area 90 90, leftfill, size 2, fore "gray20", back "white", font "standard", hgap 0
%default 2 size 7, vgap 10, prefix " ", ccolor "blue"
%default 3 size 2, bar "gray70", vgap 10
%default 4 size 5, fore "gray20", vgap 30, prefix " ", font "standard"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Default settings that are applied to TAB-indented lines.
%%
%tab 1 size 5, vgap 40, prefix " ", icon box "red" 50
%tab 2 size 4, vgap 40, prefix " ", icon arc "yellow" 50
%tab 3 size 3, vgap 40, prefix " ", icon delta3 "white" 40
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%page
Five - Zope 3 in Zope 2
%center
Martijn Faassen, Infrae
faassen@infrae.com
Five developer
%page
Five future directions
What might happen
%page
Unique id service support
Foundation is there in form of events
Unfortunately implementation can not be the same
Objects are referenced differently in Zope 3
Local services/utilities are difficult in Zope 2
Could lead to Zope 3 catalog support
%page
Page template engine improvements
Right now we already use Zope 3 page templates
These are unicode-only (and work with plain ascii)
To support Zope 2 content, need classic non-ascii string support
Issue in Plone, not in Silva (heh heh)
%page
Zope 2.8 and ZODB 3.3
Should be able to work much better with new-style objects
Things like local services/utilities might be doable
%page
Integration with Plone, CMF, Silva, UnionCMS etc
Sharing a common base is good
Zope 3 is good
That base should be Zope 3
Five can help us start sharing today
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%deffont "standard" xfont "helvetica-medium-r"
%deffont "thick" xfont "helvetica-bold-r"
%deffont "typewriter" xfont "courier-medium-r"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Default settings per each line numbers.
%%
%default 1 area 90 90, leftfill, size 2, fore "gray20", back "white", font "standard", hgap 0
%default 2 size 7, vgap 10, prefix " ", ccolor "blue"
%default 3 size 2, bar "gray70", vgap 10
%default 4 size 5, fore "gray20", vgap 30, prefix " ", font "standard"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Default settings that are applied to TAB-indented lines.
%%
%tab 1 size 5, vgap 40, prefix " ", icon box "red" 50
%tab 2 size 4, vgap 40, prefix " ", icon arc "yellow" 50
%tab 3 size 3, vgap 40, prefix " ", icon delta3 "white" 40
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%page
Five - Zope 3 in Zope 2
%center
Martijn Faassen, Infrae
faassen@infrae.com
Five developer
%page
Interfaces, adapters
What are interfaces?
What are adapters?
Why?
A very quick introduction
%page
Actually
This tutorial applies to Zope 3 as much as to Five
Indication Five reached its goal in this area
%page
Interface example
%size 4, fore "blue"
from zope.interface import Interface
class IElephant(Interface):
"""An elephant is a big grey animal.
"""
def getAngerLevel():
"Return anger level on scale 0 (placid) to 10 (raging)"
def trample(target):
"Trample the target."
def trumpet():
"Make loud noise with trunk."
%page
Interface example, continued
%size 4, fore "blue"
from zope.interface import implements
class AfricanElephant:
implements(IElephant)
def getAngerLevel(self):
return 5 # always pretty stroppy
def trample(self, target):
target.flatten()
def trumpet(self):
return "A terrible racket"
%page
Interfaces
Interfaces are about the what, not the how
Interfaces don't do anything, they just describe
Code can state what interfaces objects provide
Code can introspect whether objects provide interfaces
%page
Why interfaces?
They are documentation
Make multiple implementations of same interface easier
Allows you to program against published APIs
Allow glueing by interface
%page
Component architecture
zope.component part of Zope 3
allows glueing together of components in various ways
a component is an object which provides an interface
a Zope 2 object with a Zope 3 interface is a component
%page
Adapters, example
%size 4, fore "blue"
class INoiseMaker(Interface):
"""Something that makes noise.
"""
def makeNoise():
"Returns the noise that's made."
%page
Adapters, example continued
%size 4, fore "blue"
class ElephantNoiseMaker:
"""Adapts elephant to noise maker.
"""
implements(INoiseMaker)
def __init__(self, context):
self.context = context
def makeNoise(self):
return self.context.trumpet()
%page
Adapters, example continued 2
%size 4, fore "blue"
>>> elephant = AfricanElephant()
>>> noise_maker = ElephantNoiseMaker(elephant)
>>> print noise_maker.makeNoise()
'A terrible racket'
%page
Adapters
Add behavior to object without changing its class
More manageable than mixins
Define new behavior in terms of other behavior
%page
Adapters, continued
Less framework burden on adapted objects
They only need to be a component
Adapted doesn't know about the adapter
Adapter is a component itself
%page
Adapter lookup
We just manually glued the adapter to the adapted
What if we had INoiseMaker adapters for other objects?
We want a universal way to say: give me a INoiseMaker for this object
This allows use to write more generic code
%page
Adapter lookup, example
%size 4, fore "blue"
for animal in animal_farm:
noise_maker = INoiseMaker(animal)
print noise_maker.makeNoise()
%page
Adapter glueing
System need to be informed what can adapt what
Zope Configuration Markup Language (ZCML) is used for that
%page
ZCML example
%size 4, fore "blue"
<configure xmlns="http://namespaces.zope.org/zope">
<adapter
for=".module.IElephant"
provides=".module.INoiseMaker"
factory=".module.ElephantNoiseMaker" />
<adapter
for=".other.IChicken"
provides=".module.INoiseMaker"
factory=".other.ChickenNoiseMaker" />
</configure>
%page
ZCML, what we just said
The adapter ElephantNoiseMaker adapts any object that provides IElephant to a INoiseMaker
The adapter ChickenNoiseMaker adapts any object that provides IChicken to a INoiseMaker
%page
This works in Zope 2 with Five
This works in Zope 2 with Five
Your objects just need to be components (provide Zope 3 interfaces)
Your ZCML goes into configure.zcml in your product
That's it
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%deffont "standard" xfont "helvetica-medium-r"
%deffont "thick" xfont "helvetica-bold-r"
%deffont "typewriter" xfont "courier-medium-r"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Default settings per each line numbers.
%%
%default 1 area 90 90, leftfill, size 2, fore "gray20", back "white", font "standard", hgap 0
%default 2 size 7, vgap 10, prefix " ", ccolor "blue"
%default 3 size 2, bar "gray70", vgap 10
%default 4 size 5, fore "gray20", vgap 30, prefix " ", font "standard"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Default settings that are applied to TAB-indented lines.
%%
%tab 1 size 5, vgap 40, prefix " ", icon box "red" 50
%tab 2 size 4, vgap 40, prefix " ", icon arc "yellow" 50
%tab 3 size 3, vgap 40, prefix " ", icon delta3 "white" 40
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%page
Five - Zope 3 in Zope 2
%center
Martijn Faassen, Infrae
faassen@infrae.com
Five developer
%page
An Introduction to Five
Why Five?
What is Five?
Where are we, where are we going?
%page
Motto
It was the dawn of the third age of Zope. The Five project was a dream given form. Its goal: to use Zope 3 technologies in Zope 2.7 by creating a Zope 2 product where Zope 3 and Zope 2 could work out their differences peacefully.
(Babylon 5 season 1 intro, creatively quoted)
%page
Motto 2
The Law of Fives states simply that: ALL THINGS HAPPEN IN FIVES, OR ARE DIVISIBLE BY OR ARE MULTIPLES OF FIVE, OR ARE SOMEHOW DIRECTLY OR INDIRECTLY RELATED TO FIVE.
THE LAW OF FIVES IS NEVER WRONG.
(Principia Discordia)
%page
The problem
We're using Zope 2 in production
Zope 2 is showing its age
Zope 3 has better ways to do things
But can't just switch, we have codebases, customers!
%page
Benefits of using Zope 3 in Zope 2
Able to use Zope 3 technologies right away
Don't reinvent the wheel/APIs
Better prepared for Zope 3 transition
Evolution, not revolution
Convergence, not divergence (this is important)
%page
Divergence
Infrae created Silva, Nuxeo CPS, etc
Everybody else started using Plone (why?!)
I want to use cool Plone technology
Silva is cool too, you may want to use it
I don't want to have to reinvent every wheel (just some)
%page
What's stopping us from sharing?
Zope 2 components are hard to share between apps
Even CMF components need work to share
Especially if you don't use CMF... (Silva)
Zope 2 framework burden is making it hard
Clean Python code is easier to share
%page
Convergence
Unify our diverse efforts
Zope 3 allows you to write Python, less framework sacrifices
Zope 3 allows the glueing of components
Zope 3 is the future
Five makes some of the future available today
%page
What works now? - an overview
Interfaces
Schema
ZCML
Adapters
Views, including layers, skins
%page
What works now, continued
Zope 3 page template engine
Traversal, resources
Zope 2 security from ZCML
Events
Beginnings of forms machinery
%page
Progress made since June
Initial announcement at Europython
As promised, moved to SVN at codespeak.net
Got website, mailing list
People joined the project
%page
Progress made since June, continued
Lots of excellent contributions!
Much better view infrastructure (traversal)
ZCML's interaction with Zope 2 products much improved
UnionCMS and other projects are starting to use it!
%page
The Zope 3 Base
Five is part of the Zope 3 Base
Zope 3 Base - All Your Bobobase Are Belong To Us
Possibly the cutest Zope 3 website anywhere
http://codespeak.net/z3
%page
Zope 3 Base
%center
%image "z3-banner.png"
%page
Zope 3 Base, continued
Second area of Zope 3 related development
Equivalent of Plone collective, for Zope 3
More freewheeling than dev.zope.org
Less freewheeling than Plone collective, however
Cuter than both
%page
Evolution: Five-ification
Five is not just for new Zope 2 projects
Five can interoperate with existing Zope 2 applications
Five in Plone - Flon
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%deffont "standard" xfont "helvetica-medium-r"
%deffont "thick" xfont "helvetica-bold-r"
%deffont "typewriter" xfont "courier-medium-r"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Default settings per each line numbers.
%%
%default 1 area 90 90, leftfill, size 2, fore "gray20", back "white", font "standard", hgap 0
%default 2 size 7, vgap 10, prefix " ", ccolor "blue"
%default 3 size 2, bar "gray70", vgap 10
%default 4 size 5, fore "gray20", vgap 30, prefix " ", font "standard"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Default settings that are applied to TAB-indented lines.
%%
%tab 1 size 5, vgap 40, prefix " ", icon box "red" 50
%tab 2 size 4, vgap 40, prefix " ", icon arc "yellow" 50
%tab 3 size 3, vgap 40, prefix " ", icon delta3 "white" 40
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%page
Five - Zope 3 in Zope 2
%center
Martijn Faassen, Infrae
faassen@infrae.com
Five developer
%page
Five Misc Topics
A number of as-yet uncategorized Five-related topics
%page
Resources
Various kinds of resources available
File, image, page template resource
Accessible through ++resource++ namespace
%page
Resources, example
%size 4, fore "blue"
<browser:resource
image="z3base.png"
name="z3base.png"
permission="zope2.ViewManagementScreens"
/>
%page
Resources
Any Five traversable object now has can be used to get to resource
url: path/to/object/++resource++z3base.png
Jim says this is not exactly Zope 3 as it ruins caching
%page
ZCML
ZCML can optionally be put in etc/site.zcml
If not, Five will automatically use included zcml
This zcml is in skel
%page
ZCML continued
ZCML loads any configure.zcml in all products
This is driven by five:loadProducts in site.zcml
Overrides are possible in override.zcml
This is driven by five:loadProductsOverrides in site.zcml
%page
Bridging interfaces
"Bride of Frankenzope"
Utility functions in bridge.py
Can convert Zope 2 interface to Zope 3 interface
%page
Events
Can instruct Zope 2 object to send Zope 3 style events using five:sendEvents
These events sent upon copy/move/rename in Zope 2
IObjectMovedEvent, IObjectAddedEvent, IObjectCopiedEvent, IObjectRemovedEvent
Can set up functions to subscribe to these events
%page
Content directive and permissions
Use content directive to declare Zope 2 permissions Zope 3 style
Declare permissions from ZCML, no more declareProtected()
Your classes look cleaner as a result
%page
Macros
Zope 3 way to aggregate macros into single object
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%deffont "standard" xfont "helvetica-medium-r"
%deffont "thick" xfont "helvetica-bold-r"
%deffont "typewriter" xfont "courier-medium-r"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Default settings per each line numbers.
%%
%default 1 area 90 90, leftfill, size 2, fore "gray20", back "white", font "standard", hgap 0
%default 2 size 7, vgap 10, prefix " ", ccolor "blue"
%default 3 size 2, bar "gray70", vgap 10
%default 4 size 5, fore "gray20", vgap 30, prefix " ", font "standard"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Default settings that are applied to TAB-indented lines.
%%
%tab 1 size 5, vgap 40, prefix " ", icon box "red" 50
%tab 2 size 4, vgap 40, prefix " ", icon arc "yellow" 50
%tab 3 size 3, vgap 40, prefix " ", icon delta3 "white" 40
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%page
Five - Zope 3 in Zope 2
%center
Martijn Faassen, Infrae
faassen@infrae.com
Five developer
%page
Views with Five
What are views?
Why?
How to make them work?
%page
Actually
This tutorial contains only a few Five specific bits
Otherwise it applies to Zope 3 as much as to Five
The Five specific bits are mainly some extra ZCML directives
These are in their own ZCML namespace
%page
Page example: overview.pt
%size 4, fore "blue"
<html>
<body>
<p tal:content="context/objectIds"></p>
</body>
</html>
%page
Page example: configure.zcml
%size 4, fore "blue"
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:five="http://namespaces.zope.org/five">
<five:traversable
class="OFS.Folder.Folder"
/>
<browser:page
for="Products.Five.interfaces.IFolder"
name="overview.html"
template="overview.pt"
permission="zope2.ViewManagementScreens"
/>
</configure>
%page
What works now
some/folder/overview.html
%page
Hooking up the page, explanation
Much like hooking up an adapter
Adapter provides new interface (API) for developer
View provides new interface (UI) for user
Only five-specific thing is making Folder Zope-3 traversable
Well, and the Zope 2 permission.
%page
Hooking up a page, with class
We need some helper methods
Very similar to the way you'd use Python scripts in Zope 2
%page
View class example: overview2.pt
%size 4, fore "blue"
<html>
<body>
<p tal:content="view/reversedIds"></p>
</body>
</html>
%page
View class example: browser.py
%size 4, fore "blue"
from Products.Five import BrowserView
class Overview(BrowserView):
def reversedIds(self):
result = []
for id in self.context.objectIds():
l = list(id)
l.reverse()
reversed_id = ''.join(l)
result.append(reversed_id)
return result
%page
Example: configure.zcml
%size 4, fore "blue"
<browser:page
for="Products.Five.interfaces.IFolder"
name="overview2.html"
template="overview2.pt"
permission="zope2.ViewManagementScreens"
class=".browser.Overview"
/>
%page
A note on security
There is none: both python code and ZPT are trusted
Only checks are happening on the outside
Performance benefit
Advantage of simplicity
%page
Publishing an attribute
Expose python method on view directly to the web
%page
Attribute example: browser.py
%size 4, fore "blue"
def directlyPublished(self):
return "This is directly published"
%page
Attribute example: configure zcml
%size 4, fore "blue"
<browser:page
for="Products.Five.interfaces.IFolder"
name="test.html"
class=".browser.Overview"
attribute="directlyPublished"
permission="zope2.ViewManagementScreens"
/>
%page
Publishing multiple pages
Convenience directive: browser:pages
%page
Multiple pages example
%size 4, fore "blue"
<browser:pages
for="Products.Five.interfaces.IFolder"
class=".browser.NewExample"
permission="zope2.ViewManagementScreens"
>
<browser:page
name="one.html"
template="one.pt"
/>
<browser:page
name="two.html"
attribute="two"
/>
</browser:pages>
%page
Default view for object
We can now set views that are named
What if we traverse to the object itself?
Use five:defaultViewable and browser:defaultView
%page
Uh oh
This doesn't seem to work yet with Zope folders. Sidnei, help!
So we'll try it with a custom SimpleItem-based object
%page
DefaultView example
%size 4, fore "blue"
<five:defaultViewable class=".democontent.DemoContent" />
<browser:defaultView
for=".democontent.IDemoContent"
name="someview.html" />
%page
Conclusions
This works much the same way as Zope 3 does too
Can supplement existing view systems in Zope 2
Five specific code is mostly isolated in five:traversable and five:defaultViewable
\ No newline at end of file
Five, the Zope 3 in Zope 2 project
==================================
What is Five?
-------------
Five is a Zope 2 product that allows you to integrate Zope 3
technologies into Zope 2, today. Five right now allows you to use the
following Zope 3 technologies in Zope 2:
* Zope 3 interfaces
* adapters
* pages (views), including skins and layers, and edit and add forms
* ZCML
It is possible to add Zope 3 style views to your own Zope 2 objects,
or to existing ones, even normal Folders!
Five works with a straight Zope 2.7 installation, as long as Zope 3
has been installed. See Five's INSTALL.txt for more information on how
to set it up.
We're in the process of evaluating lots more Zope 3 technologies for
integration into Zope 2. This is the right moment for interested Zope
2 and Zope 3 developers to jump in. We're looking for cooperation
between different Zope 2 projects so that this can be a foundational
system for us all.
Download
--------
2005-003-11 -- We have released Five 0.3! Download it here:
http://codespeak.net/z3/five/release/Five-0.3.tgz
And changes here:
http://codespeak.net/z3/five/CHANGES.html
2004-09-24 -- Five 0.2b is released. Download it here:
http://codespeak.net/z3/five/release/Five-0.2b.tgz
2004-07-30 -- We have released Five 0.1! Download it here:
http://codespeak.net/z3/five/release/Five-0.1.tgz
Joining the project
-------------------
Five is kindly hosted on codespeak.net, and is part of the larger
*Zope 3 Base* project that offers an approachable area for
developers of Zope 3 related software.
Five has a mailing list:
http://codespeak.net/mailman/listinfo/z3-five
We're also active on IRC, at ``#z3-base`` on freenode.
Five is hosted in a subversion repository on codespeak.net. You can
browse this on the web here:
http://codespeak.net/svn/z3/Five/
You can check out Five using the following subversion command::
svn co http://codespeak.net/svn/z3/Five/trunk Five
There's also a checkins mailing list for the Z3 project, here:
http://codespeak.net/mailman/listinfo/z3-checkins
If you want checkin access, please join the z3-five mailing list or
the ``#z3-base`` IRC channel, and ask us there.
We hope to hear from you!
This diff is collapsed.
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:five="http://namespaces.zope.org/five"
>
<five:traversable class="OFS.Folder.Folder" />
<browser:resource
image="z3base.png"
name="z3base.png"
permission="zope2.ViewManagementScreens"
/>
</configure>
import module, other
def initialize(context):
print "*" * 70
module.demo_manual_adaptation()
other.demo_animal_farm()
print "*" * 70
<configure xmlns="http://namespaces.zope.org/zope">
<adapter
for=".module.IElephant"
provides=".module.INoiseMaker"
factory=".module.ElephantNoiseMaker" />
<adapter
for=".other.IChicken"
provides=".module.INoiseMaker"
factory=".other.ChickenNoiseMaker" />
</configure>
from zope.interface import Interface, implements
class IElephant(Interface):
"""An elephant is a big grey animal.
"""
def getAngerLevel():
"Return anger level on scale 0 (placid) to 10 (raging)"
def trample(target):
"Trample the target."
def trumpet():
"Make loud noise with trunk."
def terribleRacket():
return "A terrible racket"
class AfricanElephant:
implements(IElephant)
def getAngerLevel(self):
return 5 # always pretty stroppy
def trample(self, target):
target.flatten()
def trumpet(self):
return "A terrible racket"
class INoiseMaker(Interface):
"""Something that makes noise.
"""
def makeNoise():
"Returns the noise that's made."
class ElephantNoiseMaker:
"""Adapts elephant to noise maker.
"""
implements(INoiseMaker)
def __init__(self, context):
self.context = context
def makeNoise(self):
return self.context.trumpet()
def demo_manual_adaptation():
elephant = AfricanElephant()
noise_maker = ElephantNoiseMaker(elephant)
print noise_maker.makeNoise()
from zope.interface import Interface, implements
from module import INoiseMaker, IElephant, AfricanElephant
class IChicken(Interface):
def getConfusionLevel():
"Get the confusion level of this chicken, 0 asleep, 10 frantic"
def cluck():
"""Return clucking sound of the chicken.
"""
class Chicken:
implements(IChicken)
def __init__(self, confusion_level):
self._confusion_level = confusion_level
def getConfusionLevel(self):
return self._confusion_level
def cluck(self):
return ' '.join(["cluck"] * self.getConfusionLevel())
class IndianElephant:
implements(IElephant)
def __init__(self, anger_level):
self._anger_level = anger_level
def hit(self):
"""Hit the indian elephant with a stick.
"""
if self._anger_level <= 10:
self._anger_level += 1
def getAngerLevel(self):
return self._anger_level
def trumpet(self):
return "t" + ("o" * self._anger_level) + "t"
class ChickenNoiseMaker:
implements(INoiseMaker)
def __init__(self, context):
self.context = context
def makeNoise(self):
return self.context.cluck()
def demo_animal_farm():
animal_farm = [Chicken(5), AfricanElephant(),
Chicken(3), IndianElephant(3)]
for animal in animal_farm:
noise_maker = INoiseMaker(animal)
print noise_maker.makeNoise()
This directory contains Five tutorial products.
import democontent
def initialize(context):
context.registerClass(
democontent.DemoContent,
constructors = (democontent.manage_addDemoContentForm,
democontent.manage_addDemoContent),
)
from Products.Five import BrowserView
import random
class Overview(BrowserView):
def reversedIds(self):
result = []
for id in self.context.objectIds():
l = list(id)
l.reverse()
reversed_id = ''.join(l)
result.append(reversed_id)
return result
def directlyPublished(self):
return "This is directly published"
class NewExample(BrowserView):
def helpsWithOne(self):
return random.randrange(10)
def two(self):
return "Two got called"
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:five="http://namespaces.zope.org/five">
<five:traversable
class="OFS.Folder.Folder"
/>
<browser:page
for="Products.Five.interfaces.IFolder"
name="overview.html"
template="overview.pt"
permission="zope2.ViewManagementScreens"
/>
<browser:page
for="Products.Five.interfaces.IFolder"
name="overview2.html"
template="overview2.pt"
permission="zope2.ViewManagementScreens"
class=".browser.Overview"
/>
<browser:page
for="Products.Five.interfaces.IFolder"
name="test.html"
class=".browser.Overview"
attribute="directlyPublished"
permission="zope2.ViewManagementScreens"
/>
<browser:pages
for="Products.Five.interfaces.IFolder"
class=".browser.NewExample"
permission="zope2.ViewManagementScreens"
>
<browser:page
name="one.html"
template="one.pt"
/>
<browser:page
name="two.html"
attribute="two"
/>
</browser:pages>
<five:traversable class=".democontent.DemoContent" />
<browser:page
for=".democontent.IDemoContent"
name="someview.html"
template="someview.pt"
permission="zope2.ViewManagementScreens"
/>
<five:defaultViewable class=".democontent.DemoContent" />
<browser:defaultView
for=".democontent.IDemoContent"
name="someview.html" />
</configure>
from zope.interface import Interface, implements
from OFS.SimpleItem import SimpleItem
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
class IDemoContent(Interface):
def mymethod():
"Return some text"
class DemoContent(SimpleItem):
implements(IDemoContent)
meta_type = 'Five Demo Content'
def __init__(self, id, title):
self.id = id
self.title = title
def mymethod(self):
return "Hello world"
manage_addDemoContentForm = PageTemplateFile(
"www/demoContentAdd", globals(),
__name__ = 'manage_addDemoContentForm')
def manage_addDemoContent(self, id, title, REQUEST=None):
"""Add the demo content."""
id = self._setObject(id, DemoContent(id, title))
if REQUEST is None:
return
REQUEST.RESPONSE.redirect(REQUEST['URL1'] + '/manage_main')
<html>
<body>
<p>The random number is <span tal:replace="view/helpsWithOne">0</span></p>
</body>
</html>
<html>
<body>
<p tal:content="context/objectIds"></p>
</body>
</html>
<html>
<body>
<p tal:content="view/reversedIds"></p>
</body>
</html>
<html>
<body>
<p>Some view</p>
</body>
</html>
<h1 tal:replace="structure here/manage_page_header">Header</h1>
<h2 tal:define="form_title string:Add Demo Content"
tal:replace="structure here/manage_form_title">Form Title</h2>
<p class="form-help">
Add Demo Content
</p>
<form action="manage_addDemoContent" method="post">
<table cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
Id
</div>
</td>
<td align="left" valign="top">
<input type="text" name="id" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Title
</div>
</td>
<td align="left" valign="top">
<input type="text" name="title" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-element">
<input class="form-element" type="submit" name="submit_add"
value=" Add " />
</div>
</td>
</tr>
</table>
</form>
<h1 tal:replace="structure here/manage_page_footer">Footer</h1>
<tal:tag condition="view/update"/>
<html metal:use-macro="here/five_template/macros/master">
<body metal:fill-slot="main">
<div>
<div metal:define-macro="body">
<form action="." tal:attributes="action request/URL" method="POST"
enctype="multipart/form-data">
<div metal:define-macro="formbody">
<h3 tal:condition="view/label"
tal:content="view/label"
metal:define-slot="heading"
>Edit something</h3>
<p tal:define="status view/update"
tal:condition="status"
tal:content="status" />
<p tal:condition="view/errors" i18n:translate="">
There are <strong tal:content="python:len(view.errors)"
i18n:name="num_errors">6</strong> input errors.
</p>
<div metal:define-slot="extra_info" tal:replace="nothing">
</div>
<div class="row"
metal:define-slot="extra_top" tal:replace="nothing">
<div class="label">Extra top</div>
<div class="field"><input type="text" style="width:100%" /></div>
</div>
<div metal:use-macro="context/@@widget_macros/widget_rows" />
<div class="separator"></div>
<div class="row"
metal:define-slot="extra_bottom" tal:replace="nothing">
<div class="label">Extra bottom</div>
<div class="field"><input type="text" style="width:100%" /></div>
</div>
<div class="separator"></div>
</div>
<div class="row">
<div class="controls">
<input type="submit" value="Refresh"
i18n:attributes="value refresh-button" />
<input type="submit" name="UPDATE_SUBMIT" value="Change"
i18n:attributes="value submit-button"/>
</div>
</div>
<div class="row" metal:define-slot="extra_buttons" tal:replace="nothing">
</div>
<div class="separator"></div>
</form>
</div>
</div>
</body>
</html>
"""
Use 'structured monkey patching' to enable zope.app.container event sending for
Zope 2 objects.
"""
from Products.Five.fiveconfigure import isFiveMethod
from zope.event import notify
from zope.interface import implements
from zope.app.container.interfaces import IObjectAddedEvent,\
IObjectRemovedEvent
from zope.app.container.contained import ObjectMovedEvent
from zope.app.event.objectevent import ObjectCopiedEvent
# ObjectAddedEvent and ObjectRemovedEvent are different in Zope 2
class ObjectAddedEvent(ObjectMovedEvent):
implements(IObjectAddedEvent)
def __init__(self, object, newParent=None, newName=None):
if newParent is None:
newParent = object.aq_inner.aq_parent
if newName is None:
newName = object.id
ObjectMovedEvent.__init__(self, object, None, None, newParent, newName)
class ObjectRemovedEvent(ObjectMovedEvent):
implements(IObjectRemovedEvent)
def __init__(self, object, oldParent=None, oldName=None):
if oldParent is None:
oldParent = object.aq_inner.aq_parent
if oldName is None:
oldName = object.id
ObjectMovedEvent.__init__(self, object, oldParent, oldName, None, None)
def manage_afterAdd(self, item, container):
original_location_path = getattr(self, '__five_location_path__', None)
self.__five_location_path__ = self.getPhysicalPath()
# if there still is an object in the original location, we're copied
# we cannot rely on manage_afterClone, as this gets triggered only
# *after* a manage_afterAdd. This logic might fail in the case where
# something *is* somehow left in the original location that can
# be traversed to.
is_copied = original_location_path and (self.unrestrictedTraverse(
original_location_path, None) is not None)
if is_copied:
notify(ObjectCopiedEvent(self))
if original_location_path is None or is_copied:
notify(ObjectAddedEvent(self))
else:
original_location = self.unrestrictedTraverse(
original_location_path[:-1])
notify(ObjectMovedEvent(self,
original_location, original_location_path[-1],
container, self.id))
# call original
method = getattr(self, '__five_original_manage_afterAdd', None)
if method is not None:
self.__five_original_manage_afterAdd(item, container)
manage_afterAdd.__five_method__ = None
def manage_beforeDelete(self, item, container):
notify(ObjectRemovedEvent(self))
# call original
method = getattr(self, '__five_manage_beforeDelete', None)
if method is not None:
self._five_original_manage_beforeDelete(item, container)
manage_beforeDelete.__five_method__ = None
def classSendEvents(class_):
"""Make instances of the class send Object*Event.
"""
# tuck away original methods if necessary
for name in ['manage_afterAdd', 'manage_beforeDelete']:
method = getattr(class_, name, None)
if not isFiveMethod(method):
# if we haven't alread overridden this, tuck away originals
setattr(class_, '__five_original_' + name, method)
class_.manage_afterAdd = manage_afterAdd
class_.manage_beforeDelete = manage_beforeDelete
def sendEvents(_context, class_):
_context.action(
discriminator = ('five:sendEvents', class_),
callable = classSendEvents,
args=(class_,)
)
<html metal:define-macro="master">
<head>
<metal:block define-slot="css_slot">
</metal:block>
</head>
<body>
<metal:block define-slot="main">
</metal:block>
</body>
</html>
##############################################################################
#
# Copyright (c) 2004 Five Contributors. All rights reserved.
#
# This software is distributed under the terms of the Zope Public
# License (ZPL) v2.1. See COPYING.txt for more information.
#
##############################################################################
"""Five-specific directive handlers
These directives are specific to Five and have no equivalents in Zope 3.
$Id: fiveconfigure.py 8255 2005-01-13 14:05:46Z regebro $
"""
import os
import glob
import warnings
from zope.interface import classImplements
from zope.configuration import xmlconfig
from zope.app.component.interface import provideInterface
from viewable import Viewable
from traversable import Traversable
from bridge import fromZ2Interface
from browserconfigure import page
def findProducts():
import Products
from types import ModuleType
products = []
for name in dir(Products):
product = getattr(Products, name)
if isinstance(product, ModuleType) and hasattr(product, '__file__'):
products.append(product)
return products
def loadProducts(_context):
products = findProducts()
# first load meta.zcml files
for product in products:
zcml = os.path.join(os.path.dirname(product.__file__), 'meta.zcml')
if os.path.isfile(zcml):
xmlconfig.include(_context, zcml, package=product)
# now load their configure.zcml
for product in products:
zcml = os.path.join(os.path.dirname(product.__file__),
'configure.zcml')
if os.path.isfile(zcml):
xmlconfig.include(_context, zcml, package=product)
def loadProductsOverrides(_context):
for product in findProducts():
zcml = os.path.join(os.path.dirname(product.__file__),
'overrides.zcml')
if os.path.isfile(zcml):
xmlconfig.includeOverrides(_context, zcml, package=product)
def implements(_context, class_, interface):
for interface in interface:
_context.action(
discriminator = None,
callable = classImplements,
args = (class_, interface)
)
_context.action(
discriminator = None,
callable = provideInterface,
args = (interface.__module__ + '.' + interface.getName(),
interface)
)
def isFiveMethod(m):
return hasattr(m, '__five_method__')
def classTraversable(class_):
# If a class already has this attribute, it means it is either a
# subclass of Traversable or was already processed with this
# directive; in either case, do nothing... except in the case were
# the class overrides __bobo_traverse__ instead of getting it from
# a base class. In this case, we suppose that the class probably
# didn't bother with the base classes __bobo_traverse__ anyway and
# we step __fallback_traverse__.
if hasattr(class_, '__five_traversable__'):
if (hasattr(class_, '__bobo_traverse__') and
isFiveMethod(class_.__bobo_traverse__)):
return
if hasattr(class_, '__bobo_traverse__'):
if not isFiveMethod(class_.__bobo_traverse__):
# if there's an existing bobo_traverse hook already, use that
# as the traversal fallback method
setattr(class_, '__fallback_traverse__', class_.__bobo_traverse__)
if not hasattr(class_, '__fallback_traverse__'):
setattr(class_, '__fallback_traverse__',
Traversable.__fallback_traverse__.im_func)
setattr(class_, '__bobo_traverse__',
Traversable.__bobo_traverse__.im_func)
setattr(class_, '__five_traversable__', True)
def traversable(_context, class_):
_context.action(
discriminator = None,
callable = classTraversable,
args = (class_,)
)
def classDefaultViewable(class_):
# If a class already has this attribute, it means it is either a
# subclass of DefaultViewable or was already processed with this
# directive; in either case, do nothing... except in the case were
# the class overrides the attribute instead of getting it from
# a base class. In this case, we suppose that the class probably
# didn't bother with the base classes attribute anyway.
if hasattr(class_, '__five_viewable__'):
if (hasattr(class_, '__browser_default__') and
isFiveMethod(class_.__browser_default__)):
return
if hasattr(class_, '__browser_default__'):
# if there's an existing __browser_default__ hook already, use that
# as the fallback
if not isFiveMethod(class_.__browser_default__):
setattr(class_, '__fallback_default__', class_.__browser_default__)
if not hasattr(class_, '__fallback_default__'):
setattr(class_, '__fallback_default__',
Viewable.__fallback_default__.im_func)
setattr(class_, '__browser_default__',
Viewable.__browser_default__.im_func)
setattr(class_, '__five_viewable__', True)
def defaultViewable(_context, class_):
_context.action(
discriminator = None,
callable = classDefaultViewable,
args = (class_,)
)
def viewable(_context, class_):
# XXX do not need to mark where this is used, as simple search
# should find all instances easily
warnings.warn(
'The five:viewable directive has been deprecated. '
'Please use the five:traversable directive instead.',
DeprecationWarning)
_context.action(
discriminator = None,
callable = classTraversable,
args=(class_,)
)
def createZope2Bridge(zope2, package, name):
# Map a Zope 2 interface into a Zope3 interface, seated within 'package'
# as 'name'.
z3i = fromZ2Interface(zope2)
if name is not None:
z3i.__dict__['__name__'] = name
z3i.__dict__['__module__'] = package.__name__
setattr(package, z3i.getName(), z3i)
def bridge(_context, zope2, package, name=None):
# Directive handler for <five:bridge> directive.
# N.B.: We have to do the work early, or else we won't be able
# to use the synthesized interface in other ZCML directives.
createZope2Bridge(zope2, package, name)
# Faux action, only for conflict resolution.
_context.action(
discriminator = (zope2,),
)
def pagesFromDirectory(_context, directory, module, for_=None,
layer='default', permission='zope.Public'):
if isinstance(module, basestring):
module = _context.resolve(module)
_prefix = os.path.dirname(module.__file__)
directory = os.path.join(_prefix, directory)
if not os.path.isdir(directory):
raise ConfigurationError(
"Directory %s does not exist" % directory
)
for fname in glob.glob(os.path.join(directory, '*.pt')):
name = os.path.splitext(os.path.basename(fname))[0]
page(_context, name=name, permission=permission,
layer=layer, for_=for_, template=fname)
##############################################################################
#
# Copyright (c) 2004 Five Contributors. All rights reserved.
#
# This software is distributed under the terms of the Zope Public
# License (ZPL) v2.1. See COPYING.txt for more information.
#
##############################################################################
"""Five ZCML directive schemas
$Id: fivedirectives.py 8255 2005-01-13 14:05:46Z regebro $
"""
from zope.interface import Interface
from zope.app.publisher.browser.metadirectives import IBasicResourceInformation
from zope.configuration.fields import GlobalObject, Tokens, PythonIdentifier
from zope.schema import TextLine
class IImplementsDirective(Interface):
"""State that a class implements something.
"""
class_ = GlobalObject(
title=u"Class",
required=True
)
interface = Tokens(
title=u"One or more interfaces",
required=True,
value_type=GlobalObject()
)
class ITraversableDirective(Interface):
"""Make instances of class traversable publically.
This can be used to browse to pages, resources, etc.
Traversal can be controlled by registering an ITraverser adapter.
"""
class_ = GlobalObject(
title=u"Class",
required=True
)
class IDefaultViewableDirective(Interface):
"""Make instances of class viewable publically.
The default view is looked up using a IBrowserDefault adapter.
"""
class_ = GlobalObject(
title=u"Class",
required=True
)
class ISendEventsDirective(Interface):
"""Make instances of class send events.
"""
class_ = GlobalObject(
title=u"Class",
required=True
)
class IBridgeDirective(Interface):
"""Bridge from a Zope 2 interface to an equivalent Zope3 interface.
"""
zope2 = GlobalObject(
title=u"Zope2",
required=True
)
package = GlobalObject(
title=u"Target package",
required=True
)
name = PythonIdentifier(
title=u"Zope3 Interface name",
description=u"If not supplied, the new interface will have the same "
u"name as the source interface.",
required=False
)
class IPagesFromDirectoryDirective(IBasicResourceInformation):
"""Register each file in a skin directory as a page resource
"""
for_ = GlobalObject(
title=u"The interface this view is for.",
required=False
)
module = GlobalObject(
title=u"Module",
required=True
)
directory = TextLine(
title=u"Directory",
description=u"The directory containing the resource data.",
required=True
)
This diff is collapsed.
<configure xmlns="http://namespaces.zope.org/five">
<!-- IPersistent, IPersistentExtra -->
<!-- Acquisition -->
<implements
class="Acquisition.ImplicitAcquisitionWrapper"
interface=".interfaces.IAcquisitionWrapper"
/>
<implements
class="Acquisition.ExplicitAcquisitionWrapper"
interface=".interfaces.IAcquisitionWrapper"
/>
<implements
class="Acquisition.Implicit"
interface=".interfaces.IAcquisition"
/>
<implements
class="Acquisition.Explicit"
interface=".interfaces.IAcquisition"
/>
<!-- DAV -->
<implements
class="webdav.Lockable.LockableItem"
interface=".interfaces.IWriteLock"
/>
<implements
class="webdav.Resource.Resource"
interface=".interfaces.IDAVResource"
/>
<implements
class="webdav.Collection.Collection"
interface=".interfaces.IDAVCollection"
/>
<!-- OFS -->
<implements
class="OFS.CopySupport.CopySource"
interface=".interfaces.ICopySource"
/>
<implements
class="OFS.CopySupport.CopyContainer"
interface=".interfaces.ICopyContainer"
/>
<implements
class="OFS.Traversable.Traversable"
interface=".interfaces.ITraversable"
/>
<implements
class="OFS.SimpleItem.Item"
interface=".interfaces.IItem"
/>
<implements
class="OFS.SimpleItem.Item_w__name__"
interface=".interfaces.IItemWithName"
/>
<implements
class="OFS.SimpleItem.SimpleItem"
interface=".interfaces.ISimpleItem"
/>
<implements
class="OFS.ObjectManager.ObjectManager"
interface=".interfaces.IObjectManager"
/>
<implements
class="OFS.PropertyManager.PropertyManager"
interface=".interfaces.IPropertyManager"
/>
<implements
class="OFS.FindSupport.FindSupport"
interface=".interfaces.IFindSupport"
/>
<implements
class="OFS.Folder.Folder"
interface=".interfaces.IFolder"
/>
<implements
class="OFS.OrderSupport.OrderSupport"
interface=".interfaces.IOrderedContainer"
/>
<implements
class="OFS.OrderedFolder.OrderedFolder"
interface=".interfaces.IOrderedFolder"
/>
<implements
class="OFS.Application.Application"
interface=".interfaces.IApplication"
/>
<!-- App -->
<implements
class="App.Undo.UndoSupport"
interface=".interfaces.IUndoSupport"
/>
<implements
class="App.Management.Navigation"
interface=".interfaces.INavigation"
/>
<!-- AccessControl -->
<implements
class="AccessControl.Owned.Owned"
interface=".interfaces.IOwned"
/>
<implements
class="AccessControl.PermissionMapping.RoleManager"
interface=".interfaces.IPermissionMapping"
/>
<implements
class="AccessControl.Role.RoleManager"
interface=".interfaces.IRoleManager"
/>
</configure>
NAME=Five
PYTHON="/usr/bin/python"
TMPDIR=~/tmp
CURDIR=~/src/projects/Five
BASE_DIR=${CURDIR}/..
SOFTWARE_HOME=~/src/zope/2_7/lib/python
INSTANCE_HOME=~/src/instance/five
ZOPE_CONFIG=~/src/instance/five/etc/zope.conf
Z3=~/src/z3/five
.PHONY : clean test reindent reindent_clean
.PHONY : default
# default: The default step (invoked when make is called without a target)
default: clean test
clean :
find . \( -name '*~' -o -name '*.py[co]' -o -name '*.bak' -o -name '\.#*' \) -exec rm {} \; -print
reindent :
~/src/reindent.py -r -v .
test :
export INSTANCE_HOME=${INSTANCE_HOME}; \
export SOFTWARE_HOME=${SOFTWARE_HOME}; \
export PYTHONPATH=${Z3}; \
export ZOPE_CONFIG=${ZOPE_CONFIG}; \
cd ${CURDIR}/tests && ${PYTHON} -O runalltests.py
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:meta="http://namespaces.zope.org/meta">
<meta:directives namespace="http://namespaces.zope.org/zope">
<meta:directive
name="permission"
schema="zope.app.security.metadirectives.IDefinePermissionDirective"
handler="zope.app.security.metaconfigure.definePermission"
/>
<meta:directive
name="redefinePermission"
schema="zope.app.security.metadirectives.IRedefinePermission"
handler="zope.app.security.metaconfigure.redefinePermission"
/>
<meta:directive
name="interface"
schema="zope.app.component.metadirectives.IInterfaceDirective"
handler="zope.app.component.metaconfigure.interface"
/>
<meta:directive
name="view"
schema="zope.app.component.metadirectives.IViewDirective"
handler="zope.app.component.metaconfigure.view"
/>
<meta:directive
name="adapter"
schema="zope.app.component.metadirectives.IAdapterDirective"
handler="zope.app.component.metaconfigure.adapter"
/>
<meta:directive
name="subscriber"
schema="zope.app.component.metadirectives.ISubscriberDirective"
handler="zope.app.component.metaconfigure.subscriber"
/>
<meta:directive
name="utility"
schema="zope.app.component.metadirectives.IUtilityDirective"
handler="zope.app.component.metaconfigure.utility"
/>
<meta:directive
name="serviceType"
schema="zope.app.component.metadirectives.IServiceTypeDirective"
handler="zope.app.component.metaconfigure.serviceType"
/>
<meta:directive
name="service"
schema="zope.app.component.metadirectives.IServiceDirective"
handler="zope.app.component.metaconfigure.service"
/>
<meta:complexDirective
name="content"
schema="zope.app.component.metadirectives.IClassDirective"
handler=".metaconfigure.ContentDirective"
>
<meta:subdirective
name="implements"
schema="zope.app.component.metadirectives.IImplementsSubdirective"
/>
<meta:subdirective
name="require"
schema="zope.app.component.metadirectives.IRequireSubdirective"
/>
<meta:subdirective
name="allow"
schema="zope.app.component.metadirectives.IAllowSubdirective"
/>
</meta:complexDirective>
</meta:directives>
<meta:directives namespace="http://namespaces.zope.org/browser">
<meta:directive
name="layer"
schema="zope.app.publisher.browser.metadirectives.ILayerDirective"
handler="zope.app.publisher.browser.metaconfigure.layer"
/>
<meta:directive
name="skin"
schema="zope.app.publisher.browser.metadirectives.ISkinDirective"
handler="zope.app.publisher.browser.metaconfigure.skin"
/>
<meta:directive
name="defaultSkin"
schema="zope.app.publisher.browser.metadirectives.IDefaultSkinDirective"
handler="zope.app.publisher.browser.metaconfigure.defaultSkin"
/>
<meta:directive
name="defaultView"
schema="zope.app.publisher.browser.metadirectives.IDefaultViewDirective"
handler=".browserconfigure.defaultView"
/>
<meta:directive
name="page"
schema="zope.app.publisher.browser.metadirectives.IPageDirective"
handler=".browserconfigure.page"
/>
<meta:complexDirective
name="pages"
schema="zope.app.publisher.browser.metadirectives.IPagesDirective"
handler=".browserconfigure.pages"
>
<meta:subdirective
name="page"
schema="zope.app.publisher.browser.metadirectives.IPagesPageSubdirective"
/>
</meta:complexDirective>
<meta:directive
name="resource"
schema="zope.app.publisher.browser.metadirectives.IResourceDirective"
handler=".browserconfigure.resource"
/>
<meta:directive
name="resourceDirectory"
schema="zope.app.publisher.browser.metadirectives.IResourceDirectoryDirective"
handler=".browserconfigure.resourceDirectory"
/>
<meta:directive
name="menu"
schema="zope.app.publisher.browser.metadirectives.IMenuDirective"
handler="zope.app.publisher.browser.globalbrowsermenuservice.menuDirective"
/>
<meta:directive
name="menuItem"
schema="zope.app.publisher.browser.metadirectives.IMenuItemDirective"
handler="zope.app.publisher.browser.globalbrowsermenuservice.menuItemDirective"
/>
<meta:complexDirective
name="menuItems"
schema="zope.app.publisher.browser.metadirectives.IMenuItemsDirective"
handler="zope.app.publisher.browser.globalbrowsermenuservice.menuItemsDirective"
>
<meta:subdirective
name="menuItem"
schema="zope.app.publisher.browser.metadirectives.IMenuItemSubdirective"
/>
</meta:complexDirective>
<meta:complexDirective
name="view"
schema="zope.app.publisher.browser.metadirectives.IViewDirective"
handler=".browserconfigure.view"
>
<meta:subdirective
name="page"
schema="zope.app.publisher.browser.metadirectives.IViewPageSubdirective"
/>
<meta:subdirective
name="defaultPage"
schema="zope.app.publisher.browser.metadirectives.IViewDefaultPageSubdirective"
/>
</meta:complexDirective>
<meta:complexDirective
name="editform"
schema="zope.app.form.browser.metadirectives.IEditFormDirective"
handler=".browserconfigure.EditFormDirective"
>
<meta:subdirective
name="widget"
schema="zope.app.form.browser.metadirectives.IWidgetSubdirective"
/>
</meta:complexDirective>
<meta:complexDirective
name="addform"
schema="zope.app.form.browser.metadirectives.IAddFormDirective"
handler=".browserconfigure.AddFormDirective"
>
<meta:subdirective
name="widget"
schema="zope.app.form.browser.metadirectives.IWidgetSubdirective"
/>
</meta:complexDirective>
</meta:directives>
<meta:directives namespace="http://namespaces.zope.org/five">
<!-- specific to Five -->
<meta:directive
name="loadProducts"
schema="zope.interface.Interface"
handler=".fiveconfigure.loadProducts"
/>
<meta:directive
name="loadProductsOverrides"
schema="zope.interface.Interface"
handler=".fiveconfigure.loadProductsOverrides"
/>
<meta:directive
name="implements"
schema=".fivedirectives.IImplementsDirective"
handler=".fiveconfigure.implements"
/>
<meta:directive
name="defaultViewable"
schema=".fivedirectives.IDefaultViewableDirective"
handler=".fiveconfigure.defaultViewable"
/>
<meta:directive
name="traversable"
schema=".fivedirectives.ITraversableDirective"
handler=".fiveconfigure.traversable"
/>
<meta:directive
name="sendEvents"
schema=".fivedirectives.ISendEventsDirective"
handler=".eventconfigure.sendEvents"
/>
<meta:directive
name="pagesFromDirectory"
schema=".fivedirectives.IPagesFromDirectoryDirective"
handler=".fiveconfigure.pagesFromDirectory"
/>
<!-- viewable is deprecated, use traversable instead -->
<meta:directive
name="viewable"
schema=".fivedirectives.ITraversableDirective"
handler=".fiveconfigure.viewable"
/>
<meta:directive
name="bridge"
schema=".fivedirectives.IBridgeDirective"
handler=".fiveconfigure.bridge"
/>
</meta:directives>
</configure>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<html metal:define-macro="birdmacro"><head><title>bird macro</title></head><body>Color: <metal:block define-slot="color" /><metal:block define-slot="birdinfo" /></body></html>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<html metal:define-macro="dogmacro"><head><title>dog macro</title></head><body>Breed: <metal:block define-slot="breed" /></body></html>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment