Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
Zope
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
Zope
Commits
528f46df
Commit
528f46df
authored
Nov 02, 2005
by
Philipp von Weitershausen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Integrate Five 1.3b.
parent
ce126e73
Changes
114
Show whitespace changes
Inline
Side-by-side
Showing
114 changed files
with
4043 additions
and
1226 deletions
+4043
-1226
lib/python/Products/Five/CHANGES.txt
lib/python/Products/Five/CHANGES.txt
+90
-1
lib/python/Products/Five/CREDITS.txt
lib/python/Products/Five/CREDITS.txt
+4
-1
lib/python/Products/Five/browser/TrustedExpression.py
lib/python/Products/Five/browser/TrustedExpression.py
+1
-1
lib/python/Products/Five/browser/__init__.py
lib/python/Products/Five/browser/__init__.py
+6
-13
lib/python/Products/Five/browser/absoluteurl.py
lib/python/Products/Five/browser/absoluteurl.py
+1
-1
lib/python/Products/Five/browser/adding.py
lib/python/Products/Five/browser/adding.py
+7
-6
lib/python/Products/Five/browser/configure.zcml
lib/python/Products/Five/browser/configure.zcml
+0
-11
lib/python/Products/Five/browser/menu.py
lib/python/Products/Five/browser/menu.py
+3
-5
lib/python/Products/Five/browser/meta.zcml
lib/python/Products/Five/browser/meta.zcml
+4
-4
lib/python/Products/Five/browser/metaconfigure.py
lib/python/Products/Five/browser/metaconfigure.py
+27
-79
lib/python/Products/Five/browser/resource.py
lib/python/Products/Five/browser/resource.py
+8
-6
lib/python/Products/Five/browser/tests/adding.txt
lib/python/Products/Five/browser/tests/adding.txt
+1
-1
lib/python/Products/Five/browser/tests/defaultview.zcml
lib/python/Products/Five/browser/tests/defaultview.zcml
+6
-6
lib/python/Products/Five/browser/tests/overrides.zcml
lib/python/Products/Five/browser/tests/overrides.zcml
+2
-2
lib/python/Products/Five/browser/tests/pages.py
lib/python/Products/Five/browser/tests/pages.py
+5
-0
lib/python/Products/Five/browser/tests/pages.txt
lib/python/Products/Five/browser/tests/pages.txt
+9
-7
lib/python/Products/Five/browser/tests/pages.zcml
lib/python/Products/Five/browser/tests/pages.zcml
+31
-24
lib/python/Products/Five/browser/tests/pages_ftest.txt
lib/python/Products/Five/browser/tests/pages_ftest.txt
+17
-2
lib/python/Products/Five/browser/tests/pts_test_languages.txt
...python/Products/Five/browser/tests/pts_test_languages.txt
+1
-1
lib/python/Products/Five/browser/tests/resource.txt
lib/python/Products/Five/browser/tests/resource.txt
+4
-4
lib/python/Products/Five/browser/tests/resource_ftest.txt
lib/python/Products/Five/browser/tests/resource_ftest.txt
+2
-2
lib/python/Products/Five/browser/tests/test_absoluteurl.py
lib/python/Products/Five/browser/tests/test_absoluteurl.py
+2
-2
lib/python/Products/Five/browser/tests/test_defaultview.py
lib/python/Products/Five/browser/tests/test_defaultview.py
+4
-4
lib/python/Products/Five/browser/tests/test_i18n.py
lib/python/Products/Five/browser/tests/test_i18n.py
+3
-3
lib/python/Products/Five/browser/tests/test_menu.py
lib/python/Products/Five/browser/tests/test_menu.py
+89
-49
lib/python/Products/Five/browser/tests/test_pages.py
lib/python/Products/Five/browser/tests/test_pages.py
+4
-5
lib/python/Products/Five/browser/tests/test_recurse.py
lib/python/Products/Five/browser/tests/test_recurse.py
+6
-8
lib/python/Products/Five/browser/tests/test_resource.py
lib/python/Products/Five/browser/tests/test_resource.py
+1
-1
lib/python/Products/Five/browser/tests/test_traversable.py
lib/python/Products/Five/browser/tests/test_traversable.py
+7
-7
lib/python/Products/Five/configure.zcml
lib/python/Products/Five/configure.zcml
+4
-2
lib/python/Products/Five/deprecated.zcml
lib/python/Products/Five/deprecated.zcml
+51
-0
lib/python/Products/Five/doc/directives.txt
lib/python/Products/Five/doc/directives.txt
+42
-18
lib/python/Products/Five/doc/features.txt
lib/python/Products/Five/doc/features.txt
+16
-1
lib/python/Products/Five/doc/five14goals.txt
lib/python/Products/Five/doc/five14goals.txt
+107
-0
lib/python/Products/Five/doc/localsite.txt
lib/python/Products/Five/doc/localsite.txt
+126
-0
lib/python/Products/Five/doc/main.txt
lib/python/Products/Five/doc/main.txt
+26
-17
lib/python/Products/Five/doc/products/ViewsTutorial/__init__.py
...thon/Products/Five/doc/products/ViewsTutorial/__init__.py
+1
-22
lib/python/Products/Five/doc/products/ViewsTutorial/addDemoContent.pt
...roducts/Five/doc/products/ViewsTutorial/addDemoContent.pt
+46
-0
lib/python/Products/Five/doc/products/ViewsTutorial/browser.py
...ython/Products/Five/doc/products/ViewsTutorial/browser.py
+28
-17
lib/python/Products/Five/doc/products/ViewsTutorial/configure.zcml
...n/Products/Five/doc/products/ViewsTutorial/configure.zcml
+63
-37
lib/python/Products/Five/doc/products/ViewsTutorial/democontent.py
...n/Products/Five/doc/products/ViewsTutorial/democontent.py
+7
-30
lib/python/Products/Five/doc/products/ViewsTutorial/green5.png
...ython/Products/Five/doc/products/ViewsTutorial/green5.png
+0
-0
lib/python/Products/Five/event.zcml
lib/python/Products/Five/event.zcml
+36
-0
lib/python/Products/Five/eventconfigure.py
lib/python/Products/Five/eventconfigure.py
+23
-94
lib/python/Products/Five/fiveconfigure.py
lib/python/Products/Five/fiveconfigure.py
+69
-18
lib/python/Products/Five/fivedirectives.py
lib/python/Products/Five/fivedirectives.py
+65
-1
lib/python/Products/Five/form/__init__.py
lib/python/Products/Five/form/__init__.py
+8
-13
lib/python/Products/Five/form/metaconfigure.py
lib/python/Products/Five/form/metaconfigure.py
+31
-15
lib/python/Products/Five/form/objectwidget.pt
lib/python/Products/Five/form/objectwidget.pt
+15
-0
lib/python/Products/Five/form/objectwidget.py
lib/python/Products/Five/form/objectwidget.py
+66
-0
lib/python/Products/Five/form/tests/configure.zcml
lib/python/Products/Five/form/tests/configure.zcml
+1
-1
lib/python/Products/Five/form/tests/forms.txt
lib/python/Products/Five/form/tests/forms.txt
+14
-5
lib/python/Products/Five/form/tests/schemacontent.py
lib/python/Products/Five/form/tests/schemacontent.py
+3
-3
lib/python/Products/Five/form/tests/test_forms.py
lib/python/Products/Five/form/tests/test_forms.py
+6
-5
lib/python/Products/Five/i18n.py
lib/python/Products/Five/i18n.py
+10
-4
lib/python/Products/Five/interfaces.py
lib/python/Products/Five/interfaces.py
+1
-21
lib/python/Products/Five/interfaces.zcml
lib/python/Products/Five/interfaces.zcml
+0
-140
lib/python/Products/Five/meta.zcml
lib/python/Products/Five/meta.zcml
+20
-28
lib/python/Products/Five/metaconfigure.py
lib/python/Products/Five/metaconfigure.py
+8
-56
lib/python/Products/Five/permissions.zcml
lib/python/Products/Five/permissions.zcml
+5
-0
lib/python/Products/Five/security.py
lib/python/Products/Five/security.py
+9
-12
lib/python/Products/Five/services.zcml
lib/python/Products/Five/services.zcml
+0
-27
lib/python/Products/Five/site/__init__.py
lib/python/Products/Five/site/__init__.py
+1
-0
lib/python/Products/Five/site/browser.py
lib/python/Products/Five/site/browser.py
+61
-0
lib/python/Products/Five/site/configure.zcml
lib/python/Products/Five/site/configure.zcml
+35
-0
lib/python/Products/Five/site/interfaces.py
lib/python/Products/Five/site/interfaces.py
+95
-0
lib/python/Products/Five/site/localsite.py
lib/python/Products/Five/site/localsite.py
+151
-0
lib/python/Products/Five/site/managesite.pt
lib/python/Products/Five/site/managesite.pt
+25
-0
lib/python/Products/Five/site/meta.zcml
lib/python/Products/Five/site/meta.zcml
+15
-0
lib/python/Products/Five/site/metaconfigure.py
lib/python/Products/Five/site/metaconfigure.py
+69
-0
lib/python/Products/Five/site/metadirectives.py
lib/python/Products/Five/site/metadirectives.py
+36
-0
lib/python/Products/Five/site/tests/__init__.py
lib/python/Products/Five/site/tests/__init__.py
+1
-0
lib/python/Products/Five/site/tests/dummy.py
lib/python/Products/Five/site/tests/dummy.py
+42
-0
lib/python/Products/Five/site/tests/framework.py
lib/python/Products/Five/site/tests/framework.py
+107
-0
lib/python/Products/Five/site/tests/functional.txt
lib/python/Products/Five/site/tests/functional.txt
+147
-0
lib/python/Products/Five/site/tests/sitemanager.txt
lib/python/Products/Five/site/tests/sitemanager.txt
+124
-0
lib/python/Products/Five/site/tests/test_functional.py
lib/python/Products/Five/site/tests/test_functional.py
+59
-0
lib/python/Products/Five/site/tests/test_localsite.py
lib/python/Products/Five/site/tests/test_localsite.py
+215
-0
lib/python/Products/Five/site/tests/test_sitemanager.py
lib/python/Products/Five/site/tests/test_sitemanager.py
+12
-10
lib/python/Products/Five/site/tests/test_utility.py
lib/python/Products/Five/site/tests/test_utility.py
+228
-0
lib/python/Products/Five/site/utility.py
lib/python/Products/Five/site/utility.py
+129
-0
lib/python/Products/Five/skin/standardmacros.py
lib/python/Products/Five/skin/standardmacros.py
+6
-6
lib/python/Products/Five/skin/tests/test_standardmacros.py
lib/python/Products/Five/skin/tests/test_standardmacros.py
+2
-2
lib/python/Products/Five/tests/README.txt
lib/python/Products/Five/tests/README.txt
+3
-11
lib/python/Products/Five/tests/boilerplate.py
lib/python/Products/Five/tests/boilerplate.py
+4
-4
lib/python/Products/Five/tests/directives.zcml
lib/python/Products/Five/tests/directives.zcml
+3
-3
lib/python/Products/Five/tests/event.txt
lib/python/Products/Five/tests/event.txt
+382
-283
lib/python/Products/Five/tests/test_directives.py
lib/python/Products/Five/tests/test_directives.py
+3
-5
lib/python/Products/Five/tests/test_event.py
lib/python/Products/Five/tests/test_event.py
+57
-2
lib/python/Products/Five/tests/test_i18n.py
lib/python/Products/Five/tests/test_i18n.py
+3
-3
lib/python/Products/Five/tests/test_registerclass.py
lib/python/Products/Five/tests/test_registerclass.py
+151
-0
lib/python/Products/Five/tests/test_security.py
lib/python/Products/Five/tests/test_security.py
+2
-2
lib/python/Products/Five/tests/test_size.py
lib/python/Products/Five/tests/test_size.py
+7
-7
lib/python/Products/Five/tests/test_viewable.py
lib/python/Products/Five/tests/test_viewable.py
+7
-10
lib/python/Products/Five/tests/testing/__init__.py
lib/python/Products/Five/tests/testing/__init__.py
+6
-6
lib/python/Products/Five/tests/testing/fancycontent.py
lib/python/Products/Five/tests/testing/fancycontent.py
+1
-1
lib/python/Products/Five/tests/testing/folder.py
lib/python/Products/Five/tests/testing/folder.py
+1
-1
lib/python/Products/Five/tests/testing/restricted.py
lib/python/Products/Five/tests/testing/restricted.py
+1
-1
lib/python/Products/Five/tests/testing/simplecontent.py
lib/python/Products/Five/tests/testing/simplecontent.py
+1
-10
lib/python/Products/Five/traversable.py
lib/python/Products/Five/traversable.py
+19
-13
lib/python/Products/Five/utilities/__init__.py
lib/python/Products/Five/utilities/__init__.py
+1
-0
lib/python/Products/Five/utilities/browser/__init__.py
lib/python/Products/Five/utilities/browser/__init__.py
+1
-0
lib/python/Products/Five/utilities/browser/configure.zcml
lib/python/Products/Five/utilities/browser/configure.zcml
+20
-0
lib/python/Products/Five/utilities/browser/edit_markers.pt
lib/python/Products/Five/utilities/browser/edit_markers.pt
+63
-0
lib/python/Products/Five/utilities/browser/manage_interfaces.pt
...thon/Products/Five/utilities/browser/manage_interfaces.pt
+7
-0
lib/python/Products/Five/utilities/browser/marker.py
lib/python/Products/Five/utilities/browser/marker.py
+62
-0
lib/python/Products/Five/utilities/browser/tests/__init__.py
lib/python/Products/Five/utilities/browser/tests/__init__.py
+1
-0
lib/python/Products/Five/utilities/browser/tests/framework.py
...python/Products/Five/utilities/browser/tests/framework.py
+107
-0
lib/python/Products/Five/utilities/browser/tests/test_marker.py
...thon/Products/Five/utilities/browser/tests/test_marker.py
+96
-0
lib/python/Products/Five/utilities/configure.zcml
lib/python/Products/Five/utilities/configure.zcml
+12
-0
lib/python/Products/Five/utilities/interfaces.py
lib/python/Products/Five/utilities/interfaces.py
+74
-0
lib/python/Products/Five/utilities/marker.py
lib/python/Products/Five/utilities/marker.py
+133
-0
lib/python/Products/Five/version.txt
lib/python/Products/Five/version.txt
+1
-1
lib/python/Products/Five/viewable.py
lib/python/Products/Five/viewable.py
+2
-2
No files found.
lib/python/Products/Five/CHANGES.txt
View file @
528f46df
...
...
@@ -2,6 +2,95 @@
Five Changes
============
Five 1.3b (2005-11-02)
======================
This version is also included in Zope 2.9b1.
Restructuring
-------------
* Support for Zope 3.2 was added. Five now requires Zope 2.9 (which
ships with Zope 3.2).
* As scheduled, the temporary fork of the new test runner
(``zope.testing``) at ``Five.testing`` was removed. So was the
``runtests.py`` script. Use the regular Zope test runner
(``test.py`` or ``bin/zopectl test``) to run tests.
* To reflect the Component Architecture simplification in Zope 3 since
the X3 3.0 release, ``IFiveUtilityService`` was renamed to
``IFiveUtilityRegistry`` and ``SimpleLocalUtilityService`` was
renamed to ``SimpleLocalUtilityRegistry``. The old names are still
available for a short period of time.
* Event support: ``<five:containerEvents/>`` is the default.
* Due to an incompatability with Zope 3.2's ObjectWidget and Zope 2's
Page Templates, Five now ships with its own ObjectWidget
implementation (which is just a thin wrapper around Zope's one to
make it work in Zope 2). If you use the ObjectWidget, please change
your imports to ``Products.Five.form.objectwidget.ObjectWidget``.
* Backwards compatability for Zope 3-style interfaces of Zope 2
components has been removed as that functionality is now in the Zope
2 core as of Zope 2.9.
Five 1.2b (2005-11-02)
======================
Features
--------
* Added IMarkerInterfaces adapter: This adapter provides methods for
inspecting and assigning marker interfaces. 'edit-markers.html' (or
'manage_interfaces' in the ZMI) allows to change the behavior of specific
objects by adding or removing marker interfaces TTW.
* Added the five:registerClass directive: This does the necessary Zope 2
registration for Five-based content. It is no longer necessary to add an
``initialize()`` function to the product's __init__ in order to register
a meta type to be addable through the ZMI. See doc/products/ViewsTutorial
for an example how to use the directive.
* Local site support: Five has now support for creating local sites
and thereby local utilities. This is mostly needed for allowing CMF
to convert it's portal tools into local utilities. See
doc/localsite.txt for more information
* Event support: When ``<five:containerEvents/>`` is specified, Five
makes the standard Zope 2 containers send events instead of using
manage_afterAdd, manage_beforeDelete and manage_afterClone. These
methods are still called for a class declared
``<five:deprecatedManageAddDelete class=.../>``, and are called in
compatibility mode with a deprecation warning for classes that don't
use this directive.
Restructuring
-------------
* Removed backwards compatibility for Five 1.0 Zope core interfaces.
* Removed backwards compatibility for Zope 2.7 and 2.8.0.
* Added a (temporarily) forked copy of the "new-and-improved" test
runner and supporting 'zope.testing' package, lifted from
http://svn.zope.org/zope.testing. This code should be removed for
Five 1.3, which will use the updated version of 'zope.testing' in
the Zope 2.9 / Zope 3.2 tree.
There is a test runner invoking script in the ``Five`` package. For
example, to run the Five tests with the new test runner, simply
execute the following command line from your instance home::
$ bin/zopectl run Products/Five/runtests.py -v -s Products.Five
* Moved the 'Five.testing' package down to 'Five.tests.testing', in
order to make room for the 'zope.testing' code.
* Removed backwards compatibility for some moved classes (AddForm,
EditForm, ContentAdding)
Five 1.1 (2005-10-04)
=====================
...
...
@@ -100,7 +189,7 @@ Restructuring
* The former test product, ``FiveTest``, was converted into separate
modules that provide the mock objects for the corresponding tests
and are located right next to them. Common test helpers have been
moved to the Five.testing package. Overall, the testing framework
moved to the Five.test
s.test
ing package. Overall, the testing framework
was much simplified and the individual tests clean up after
themselves much like they do in Zope 3.
...
...
lib/python/Products/Five/CREDITS.txt
View file @
528f46df
...
...
@@ -9,7 +9,7 @@ Five contributors
- Lennart Regebro (regebro@nuxeo.com)
- Tres Seaver (t
res@zope
.com)
- Tres Seaver (t
seaver@palladion
.com)
- Jan-Wijbrand Kolman (jw@infrae.com)
...
...
@@ -33,6 +33,9 @@ Five contributors
- Tarek Ziad (tziade@nuxeo.com)
- Whit Morriss (whit@longnow.org)
Thank you
---------
...
...
lib/python/Products/Five/browser/TrustedExpression.py
View file @
528f46df
...
...
@@ -70,7 +70,7 @@ def trustedTraverse(ob, path, ignored,):
o
=
get
(
object
,
name
,
M
)
if
o
is
M
:
try
:
o
=
object
[
name
]
except
AttributeError
:
# better exception
except
(
AttributeError
,
TypeError
)
:
# better exception
raise
AttributeError
(
name
)
object
=
o
...
...
lib/python/Products/Five/browser/__init__.py
View file @
528f46df
...
...
@@ -13,20 +13,13 @@
##############################################################################
"""Provide basic browser functionality
$Id: __init__.py 1
8841 2005-10-23 09:57:38
Z philikon $
$Id: __init__.py 1
9283 2005-10-31 17:43:51
Z philikon $
"""
import
Acquisition
from
AccessControl
import
ClassSecurityInfo
from
Globals
import
InitializeClass
import
zope.app.publisher.browser
class
BrowserView
(
Acquisition
.
Explicit
):
security
=
ClassSecurityInfo
()
class
BrowserView
(
Acquisition
.
Explicit
,
zope
.
app
.
publisher
.
browser
.
BrowserView
):
"""Five browser view
def
__init__
(
self
,
context
,
request
):
self
.
context
=
context
self
.
request
=
request
# XXX do not create any methods on the subclass called index_html,
# as this makes Zope 2 traverse into that first!
InitializeClass
(
BrowserView
)
Mixes in explicit acquisition so that security can be acquired for
views"""
lib/python/Products/Five/browser/absoluteurl.py
View file @
528f46df
...
...
@@ -52,7 +52,7 @@ class AbsoluteURL(BrowserView):
return
(
{
'name'
:
name
,
'url'
:
context
.
absolute_url
()},)
view
=
zapi
.
get
ViewProviding
(
container
,
IAbsoluteURL
,
request
)
view
=
zapi
.
get
MultiAdapter
((
container
,
request
),
IAbsoluteURL
)
base
=
tuple
(
view
.
breadcrumbs
())
base
+=
(
{
'name'
:
name
,
'url'
:
(
"%s/%s"
%
(
base
[
-
1
][
'url'
],
name
))},)
...
...
lib/python/Products/Five/browser/adding.py
View file @
528f46df
...
...
@@ -28,6 +28,8 @@ 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.publisher.browser.menu
import
getMenu
from
zope.app
import
zapi
from
zope.app.event.objectevent
import
ObjectCreatedEvent
from
zope.event
import
notify
...
...
@@ -84,8 +86,8 @@ class BasicAdding(Implicit, BrowserView):
# 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'
)
return
str
(
zapi
.
getMultiAdapter
((
self
.
context
,
self
.
request
),
name
=
u"absolute_url"
))
+
'/manage_main'
# set in BrowserView.__init__
request
=
None
...
...
@@ -104,7 +106,7 @@ class BasicAdding(Implicit, BrowserView):
if
view_name
.
startswith
(
'@@'
):
view_name
=
view_name
[
2
:]
return
zapi
.
get
View
(
self
,
view_name
,
request
)
return
zapi
.
get
MultiAdapter
((
self
,
request
),
name
=
view_name
)
if
name
.
startswith
(
'@@'
):
view_name
=
name
[
2
:]
...
...
@@ -135,7 +137,7 @@ class BasicAdding(Implicit, BrowserView):
if
zapi
.
queryView
(
self
,
view_name
,
self
.
request
)
is
not
None
:
url
=
"%s/%s=%s"
%
(
zapi
.
get
View
(
self
,
"absolute_url"
,
self
.
request
),
zapi
.
get
MultiAdapter
((
self
,
self
.
request
),
name
=
u"absolute_url"
),
type_name
,
id
)
self
.
request
.
response
.
redirect
(
url
)
return
...
...
@@ -169,12 +171,11 @@ class Adding(BasicAdding):
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
):
for
item
in
getMenu
(
menu_id
,
self
,
self
.
request
):
extra
=
item
.
get
(
'extra'
)
if
extra
:
factory
=
extra
.
get
(
'factory'
)
...
...
lib/python/Products/Five/browser/configure.zcml
View file @
528f46df
<configure xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
<serviceType
id="BrowserMenu"
interface="zope.app.publisher.interfaces.browser.IBrowserMenuService"
/>
<service
serviceType="BrowserMenu"
permission="zope.Public"
component="zope.app.publisher.browser.globalbrowsermenuservice.globalBrowserMenuService"
/>
<browser:defaultView name="index.html" />
<browser:page
...
...
lib/python/Products/Five/browser/menu.py
View file @
528f46df
...
...
@@ -13,17 +13,15 @@
##############################################################################
"""Some menu code
$Id: menu.py 1
4512 2005-07-11 18:40
:51Z philikon $
$Id: menu.py 1
9283 2005-10-31 17:43
:51Z philikon $
"""
from
zope.interface
import
implements
from
zope.app
import
zapi
from
zope.app.publisher.interfaces.browser
import
IMenuAccessView
from
zope.app.
servicenames
import
Browser
Menu
from
zope.app.
publisher.browser.menu
import
get
Menu
from
Products.Five
import
BrowserView
class
MenuAccessView
(
BrowserView
):
implements
(
IMenuAccessView
)
def
__getitem__
(
self
,
menu_id
):
browser_menu_service
=
zapi
.
getService
(
BrowserMenu
)
return
browser_menu_service
.
getMenu
(
menu_id
,
self
.
context
,
self
.
request
)
return
getMenu
(
menu_id
,
self
.
context
,
self
.
request
)
lib/python/Products/Five/browser/meta.zcml
View file @
528f46df
...
...
@@ -25,7 +25,7 @@
<meta:directive
name="defaultView"
schema="zope.app.publisher.browser.metadirectives.IDefaultViewDirective"
handler=".metaconfigure.defaultView"
handler="
zope.app.publisher.browser
.metaconfigure.defaultView"
/>
<meta:directive
...
...
@@ -62,19 +62,19 @@
<meta:directive
name="menu"
schema="zope.app.publisher.browser.metadirectives.IMenuDirective"
handler="zope.app.publisher.browser.
globalbrowsermenuservice
.menuDirective"
handler="zope.app.publisher.browser.
menumeta
.menuDirective"
/>
<meta:directive
name="menuItem"
schema="zope.app.publisher.browser.metadirectives.IMenuItemDirective"
handler="zope.app.publisher.browser.
globalbrowsermenuservice
.menuItemDirective"
handler="zope.app.publisher.browser.
menumeta
.menuItemDirective"
/>
<meta:complexDirective
name="menuItems"
schema="zope.app.publisher.browser.metadirectives.IMenuItemsDirective"
handler="zope.app.publisher.browser.
globalbrowsermenuservice
.menuItemsDirective"
handler="zope.app.publisher.browser.
menumeta
.menuItemsDirective"
>
<meta:subdirective
...
...
lib/python/Products/Five/browser/metaconfigure.py
View file @
528f46df
...
...
@@ -21,18 +21,16 @@ $Id: metaconfigure.py 13257 2005-06-09 21:56:39Z philikon $
import
os
from
zope.interface
import
Interface
from
zope.component
import
getGlobalService
,
ComponentLookupError
from
zope.configuration.exceptions
import
ConfigurationError
from
zope.component.servicenames
import
Presentation
from
zope.publisher.interfaces.browser
import
IBrowserRequest
from
zope.publisher.interfaces.browser
import
IBrowserRequest
,
\
IDefaultBrowserLayer
from
zope.app.publisher.browser.viewmeta
import
pages
as
zope_app_pages
from
zope.app.publisher.browser.viewmeta
import
view
as
zope_app_view
from
zope.app.publisher.browser.viewmeta
import
providesCallable
from
zope.app.publisher.browser.globalbrowsermenuservice
import
\
menuItemDirective
from
zope.app.publisher.browser.viewmeta
import
providesCallable
,
\
_handle_menu
,
_handle_for
from
zope.app.component.metaconfigure
import
handler
from
zope.app.component.interface
import
provideInterface
from
zope.app.container.interfaces
import
IAdding
from
Products.Five.browser
import
BrowserView
from
Products.Five.browser.resource
import
FileResourceFactory
,
ImageResourceFactory
...
...
@@ -40,22 +38,16 @@ from Products.Five.browser.resource import PageTemplateResourceFactory
from
Products.Five.browser.resource
import
DirectoryResourceFactory
from
Products.Five.browser.pagetemplatefile
import
ZopeTwoPageTemplateFile
from
Products.Five.metaclass
import
makeClass
from
Products.Five.security
import
getSecurityInfo
,
protectClass
,
\
protectName
,
initializeClass
from
Products.Five.security
import
getSecurityInfo
,
protectClass
,
protectName
import
Extension
Class
from
Globals
import
InitializeClass
as
initialize
Class
def
page
(
_context
,
name
,
permission
,
for_
,
layer
=
'default'
,
template
=
None
,
class_
=
None
,
layer
=
IDefaultBrowserLayer
,
template
=
None
,
class_
=
None
,
allowed_interface
=
None
,
allowed_attributes
=
None
,
attribute
=
'__call__'
,
menu
=
None
,
title
=
None
,
):
try
:
s
=
getGlobalService
(
Presentation
)
except
ComponentLookupError
,
err
:
pass
_handle_menu
(
_context
,
menu
,
title
,
[
for_
],
name
,
permission
)
if
not
(
class_
or
template
):
...
...
@@ -64,8 +56,7 @@ def page(_context, name, permission, for_,
allowed_attributes
=
[]
if
allowed_interface
is
not
None
:
for
interface
in
allowed_interface
:
attrs
=
[
n
for
n
,
d
in
interface
.
namesAndDescriptions
(
1
)]
allowed_attributes
.
extend
(
attrs
)
allowed_attributes
.
extend
(
interface
.
names
())
if
attribute
!=
'__call__'
:
if
template
:
...
...
@@ -92,9 +83,10 @@ def page(_context, name, permission, for_,
"The provided class doesn't have the specified attribute "
)
cdict
=
getSecurityInfo
(
class_
)
cdict
[
'__name__'
]
=
name
if
template
:
new_class
=
makeClassForTemplate
(
template
,
bases
=
(
class_
,
),
cdict
=
cdict
)
cdict
=
cdict
,
name
=
name
)
elif
attribute
!=
"__call__"
:
# we're supposed to make a page for an attribute (read:
# method) and it's not __call__. We thus need to create a
...
...
@@ -125,16 +117,15 @@ def page(_context, name, permission, for_,
else
:
# template
new_class
=
makeClassForTemplate
(
template
)
new_class
=
makeClassForTemplate
(
template
,
name
=
name
)
_handle_for
(
_context
,
for_
)
_context
.
action
(
discriminator
=
(
'view'
,
for_
,
name
,
IBrowserRequest
,
layer
),
callable
=
handler
,
args
=
(
Presentation
,
'provideAdapter'
,
IBrowserRequest
,
new_class
,
name
,
[
for_
],
Interface
,
layer
,
_context
.
info
),
args
=
(
'provideAdapter'
,
(
for_
,
layer
),
Interface
,
name
,
new_class
,
_context
.
info
),
)
_context
.
action
(
discriminator
=
(
'five:protectClass'
,
new_class
),
...
...
@@ -165,19 +156,6 @@ class pages(zope_app_pages):
menu
=
menu
,
title
=
title
,
**
(
self
.
opts
))
def
defaultView
(
_context
,
name
,
for_
=
None
):
type
=
IBrowserRequest
_context
.
action
(
discriminator
=
(
'defaultViewName'
,
for_
,
type
,
name
),
callable
=
handler
,
args
=
(
Presentation
,
'setDefaultViewName'
,
for_
,
type
,
name
),
)
_handle_for
(
_context
,
for_
)
# view (named view with pages)
class
view
(
zope_app_view
):
...
...
@@ -192,11 +170,6 @@ class view(zope_app_view):
pages
=
{}
for
pname
,
attribute
,
template
in
self
.
pages
:
try
:
s
=
getGlobalService
(
Presentation
)
except
ComponentLookupError
,
err
:
pass
if
template
:
cdict
[
pname
]
=
ZopeTwoPageTemplateFile
(
template
)
if
attribute
and
attribute
!=
name
:
...
...
@@ -255,7 +228,7 @@ class view(zope_app_view):
if
class_
is
not
None
:
bases
=
(
class_
,
ViewMixinForTemplates
)
else
:
bases
=
(
ViewMixinForTemplates
)
bases
=
(
ViewMixinForTemplates
,
)
try
:
cname
=
str
(
name
)
...
...
@@ -277,37 +250,11 @@ class view(zope_app_view):
discriminator
=
(
'view'
,
for_
,
name
,
IBrowserRequest
,
layer
,
self
.
provides
),
callable
=
handler
,
args
=
(
Presentation
,
'provideAdapter'
,
IBrowserRequest
,
newclass
,
name
,
[
for_
],
self
.
provides
,
layer
,
_context
.
info
),
)
def
_handle_for
(
_context
,
for_
):
if
for_
is
not
None
:
_context
.
action
(
discriminator
=
None
,
callable
=
provideInterface
,
args
=
(
''
,
for_
)
args
=
(
'provideAdapter'
,
(
for_
,
layer
),
self
.
provides
,
name
,
newclass
,
_context
.
info
),
)
def
_handle_menu
(
_context
,
menu
,
title
,
for_
,
name
,
permission
):
if
menu
or
title
:
if
not
(
menu
and
title
):
raise
ConfigurationError
(
"If either menu or title are specified, they must "
"both be specified."
)
if
len
(
for_
)
!=
1
:
raise
ConfigurationError
(
"Menus can be specified only for single-view, not for "
"multi-views."
)
return
menuItemDirective
(
_context
,
menu
,
for_
[
0
],
'@@'
+
str
(
name
),
title
,
permission
=
permission
)
return
[]
_factory_map
=
{
'image'
:{
'prefix'
:
'ImageResource'
,
'count'
:
0
,
'factory'
:
ImageResourceFactory
},
...
...
@@ -319,7 +266,7 @@ _factory_map = {'image':{'prefix':'ImageResource',
'factory'
:
PageTemplateResourceFactory
}
}
def
resource
(
_context
,
name
,
layer
=
'default'
,
permission
=
'zope.Public'
,
def
resource
(
_context
,
name
,
layer
=
IDefaultBrowserLayer
,
permission
=
'zope.Public'
,
file
=
None
,
image
=
None
,
template
=
None
):
if
((
file
and
image
)
or
(
file
and
template
)
or
...
...
@@ -343,8 +290,8 @@ def resource(_context, name, layer='default', permission='zope.Public',
_context
.
action
(
discriminator
=
(
'resource'
,
name
,
IBrowserRequest
,
layer
),
callable
=
handler
,
args
=
(
Presentation
,
'provideResource
'
,
name
,
IBrowserRequest
,
factory
,
layer
),
args
=
(
'provideAdapter
'
,
(
layer
,),
Interface
,
name
,
factory
,
_context
.
info
),
)
_context
.
action
(
discriminator
=
(
'five:protectClass'
,
new_class
),
...
...
@@ -367,7 +314,7 @@ _rd_map = {ImageResourceFactory:{'prefix':'DirContainedImageResource',
'count'
:
0
}
}
def
resourceDirectory
(
_context
,
name
,
directory
,
layer
=
'default'
,
def
resourceDirectory
(
_context
,
name
,
directory
,
layer
=
IDefaultBrowserLayer
,
permission
=
'zope.Public'
):
if
not
os
.
path
.
isdir
(
directory
):
...
...
@@ -410,8 +357,8 @@ def resourceDirectory(_context, name, directory, layer='default',
_context
.
action
(
discriminator
=
(
'resource'
,
name
,
IBrowserRequest
,
layer
),
callable
=
handler
,
args
=
(
Presentation
,
'provideResource
'
,
name
,
IBrowserRequest
,
factory
,
layer
),
args
=
(
'provideAdapter
'
,
(
layer
,),
Interface
,
name
,
factory
,
_context
.
info
),
)
for
new_class
in
new_classes
:
_context
.
action
(
...
...
@@ -456,11 +403,12 @@ class ViewMixinForTemplates(BrowserView):
return
self
.
index
(
self
,
*
args
,
**
kw
)
def
makeClassForTemplate
(
filename
,
globals
=
None
,
used_for
=
None
,
bases
=
(),
cdict
=
None
):
bases
=
(),
cdict
=
None
,
name
=
u''
):
# XXX needs to deal with security from the bases?
if
cdict
is
None
:
cdict
=
{}
cdict
.
update
({
'index'
:
ZopeTwoPageTemplateFile
(
filename
,
globals
)})
cdict
.
update
({
'index'
:
ZopeTwoPageTemplateFile
(
filename
,
globals
),
'__name__'
:
name
})
bases
+=
(
ViewMixinForTemplates
,)
class_
=
makeClass
(
"SimpleViewClass from %s"
%
filename
,
bases
,
cdict
)
...
...
lib/python/Products/Five/browser/resource.py
View file @
528f46df
...
...
@@ -18,15 +18,15 @@ $Id: resource.py 13268 2005-06-10 14:18:23Z philikon $
import
os
import
urllib
from
Acquisition
import
Explicit
import
Acquisition
from
ComputedAttribute
import
ComputedAttribute
from
OFS.Traversable
import
Traversable
as
OFSTraversable
from
zope.exceptions
import
NotFoundError
from
zope.interface
import
implements
from
zope.component.interfaces
import
IResource
from
zope.component
import
getViewProviding
from
zope.publisher.interfaces.browser
import
IBrowserPublisher
from
zope.app
import
zapi
from
zope.app.traversing.browser.interfaces
import
IAbsoluteURL
from
zope.app.datetimeutils
import
time
as
timeFromDateTimeString
from
zope.app.publisher.fileresource
import
File
,
Image
...
...
@@ -37,7 +37,7 @@ from Products.Five.browser import BrowserView
_marker
=
[]
class
Resource
(
Explicit
):
class
Resource
(
Acquisition
.
Explicit
):
"""A publishable resource
"""
implements
(
IResource
)
...
...
@@ -49,7 +49,9 @@ class Resource(Explicit):
name
=
self
.
__name__
container
=
self
.
__parent__
url
=
str
(
getViewProviding
(
container
,
IAbsoluteURL
,
self
.
request
))
# TODO Zope 3 uses site = getSite() instead of container here
# and the @@ resource access view
url
=
str
(
zapi
.
getMultiAdapter
((
container
,
self
.
request
),
IAbsoluteURL
))
url
=
urllib
.
unquote
(
url
)
if
not
isinstance
(
container
,
DirectoryResource
):
name
=
'++resource++%s'
%
name
...
...
@@ -213,7 +215,7 @@ class DirectoryResource(BrowserView, Resource, OFSTraversable):
filename
=
os
.
path
.
join
(
path
,
name
)
if
not
os
.
path
.
isfile
(
filename
):
if
default
is
_marker
:
raise
NotFound
Error
(
name
)
raise
Key
Error
(
name
)
return
default
ext
=
name
.
split
(
'.'
)[
-
1
]
factory
=
self
.
resource_factories
.
get
(
ext
,
self
.
default_factory
)
...
...
lib/python/Products/Five/browser/tests/adding.txt
View file @
528f46df
...
...
@@ -7,7 +7,7 @@ ObjectManagerNameChooser
First we need to import and setup some prerequisites:
>>> from Products.Five.testing import manage_addFiveTraversableFolder
>>> from Products.Five.test
s.test
ing import manage_addFiveTraversableFolder
>>> from Products.Five.browser.adding import ObjectManagerNameChooser
>>> manage_addFiveTraversableFolder(self.folder, 'testoid', 'Testoid')
...
...
lib/python/Products/Five/browser/tests/defaultview.zcml
View file @
528f46df
...
...
@@ -3,15 +3,15 @@
xmlns:five="http://namespaces.zope.org/five">
<five:defaultViewable
class="Products.Five.testing.simplecontent.SimpleContent" />
class="Products.Five.test
s.test
ing.simplecontent.SimpleContent" />
<browser:defaultView
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
name="eagledefaultview.txt"
/>
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
name="eagledefaultview.txt"
class=".pages.SimpleView"
attribute="eagle"
...
...
@@ -22,16 +22,16 @@
already provides __call__, such as our CallableSimpleContent -->
<five:defaultViewable
class="Products.Five.testing.simplecontent.CallableSimpleContent" />
class="Products.Five.test
s.test
ing.simplecontent.CallableSimpleContent" />
<!-- this tests whether five:defaultViewable can be called on a class that
already provides index_html, such as our IndexSimpleContent -->
<five:defaultViewable
class="Products.Five.testing.simplecontent.IndexSimpleContent" />
class="Products.Five.test
s.test
ing.simplecontent.IndexSimpleContent" />
<browser:defaultView
for="Products.Five.testing.simplecontent.IIndexSimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.IIndexSimpleContent"
name="index_html"
/>
...
...
lib/python/Products/Five/browser/tests/overrides.zcml
View file @
528f46df
...
...
@@ -3,7 +3,7 @@
<!-- mouse instead of eagle -->
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
class=".pages.SimpleView"
attribute="mouse"
name="overridden_view"
...
...
lib/python/Products/Five/browser/tests/pages.py
View file @
528f46df
...
...
@@ -34,6 +34,11 @@ class FancyView(BrowserView):
def
view
(
self
):
return
"Fancy, fancy"
class
CallView
(
BrowserView
):
def
__call__
(
self
):
return
"I was __call__()'ed"
class
CallableNoDocstring
:
def
__call__
(
self
):
...
...
lib/python/Products/Five/browser/tests/pages.txt
View file @
528f46df
...
...
@@ -10,7 +10,7 @@ Let's register a quite large amount of test pages:
Let's add a test object that we view most of the pages off of:
>>> from Products.Five.testing.simplecontent import manage_addSimpleContent
>>> from Products.Five.test
s.test
ing.simplecontent import manage_addSimpleContent
>>> manage_addSimpleContent(self.folder, 'testoid', 'Testoid')
We also need to create a stub user account and login; otherwise we
...
...
@@ -29,7 +29,7 @@ Simple pages
A browser page that is a view class's attribute (method):
>>> view = self.folder.unrestrictedTraverse('testoid/eagle.txt')
>>> view
!=
None
>>> view
is not
None
True
>>> from Products.Five.browser.tests.pages import SimpleView
>>> isinstance(view, SimpleView)
...
...
@@ -196,8 +196,10 @@ high-level security tests). Let's manually look up a protected view:
>>> from Products.Five.traversable import FakeRequest
>>> from zope.app import zapi
>>> from zope.app.publication.browser import setDefaultSkin
>>> request = FakeRequest()
>>> view = zapi.getView(self.folder.testoid, 'eagle.txt', request)
>>> setDefaultSkin(request)
>>> view = zapi.getMultiAdapter((self.folder.testoid, request), name=u'eagle.txt')
It's protecting the object with the permission, and not the attribute,
so we get ('',) instead of ('eagle',):
...
...
@@ -213,7 +215,7 @@ evaluated. __roles__ is a imPermissionRole object:
>>> view_roles
('Manager',)
Check to see if view's context properly acquires it
'
s true
Check to see if view's context properly acquires its true
parent
>>> from Acquisition import aq_parent, aq_base, aq_inner
...
...
@@ -255,8 +257,8 @@ High-level security
... 'nodoc-method', 'nodoc-function', 'nodoc-object',
... 'dirpage1', 'dirpage2']
>>> from Products.Five.testing.restricted import checkRestricted
>>> from Products.Five.testing.restricted import checkUnauthorized
>>> from Products.Five.test
s.test
ing.restricted import checkRestricted
>>> from Products.Five.test
s.test
ing.restricted import checkUnauthorized
As long as we're not authenticated, we should get Unauthorized for
protected views, but we should be able to view the public ones:
...
...
@@ -312,5 +314,5 @@ Test traversal to resources from within ZPT pages:
Clean up
--------
>>> from zope.app.test
s
.placelesssetup import tearDown
>>> from zope.app.test
ing
.placelesssetup import tearDown
>>> tearDown()
lib/python/Products/Five/browser/tests/pages.zcml
View file @
528f46df
...
...
@@ -8,7 +8,7 @@
<!-- attribute page -->
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
class=".pages.SimpleView"
attribute="eagle"
name="eagle.txt"
...
...
@@ -16,7 +16,7 @@
/>
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
class=".pages.SimpleView"
name="eagle.method"
permission="zope2.ViewManagementScreens"
...
...
@@ -25,7 +25,7 @@
<!-- attribute page -->
<browser:pages
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
class=".pages.SimpleView"
permission="zope2.ViewManagementScreens"
>
...
...
@@ -41,7 +41,7 @@
<!-- template/class page -->
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
class=".pages.SimpleView"
template="falcon.pt"
name="falcon.html"
...
...
@@ -50,7 +50,7 @@
<!-- template page (with simple python expression) -->
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
template="owl.pt"
name="owl.html"
permission="zope2.ViewManagementScreens"
...
...
@@ -59,7 +59,7 @@
<!-- template page which calls on context using python and path
expressions -->
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
template="flamingo.pt"
name="flamingo.html"
permission="zope2.ViewManagementScreens"
...
...
@@ -67,7 +67,7 @@
<!-- template/class page which calls on context, view, views -->
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
class=".pages.SimpleView"
template="condor.pt"
name="condor.html"
...
...
@@ -76,7 +76,7 @@
<!-- template page that defines a macro page -->
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
template="birdmacro.pt"
name="bird.html"
permission="zope2.ViewManagementScreens"
...
...
@@ -84,7 +84,7 @@
<!-- template page that uses macro page -->
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
template="seagull.pt"
name="seagull.html"
permission="zope2.ViewManagementScreens"
...
...
@@ -92,21 +92,21 @@
<!-- test TALES -->
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
template="ostrich.pt"
name="ostrich.html"
permission="zope2.ViewManagementScreens"
/>
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
template="tales_traversal.pt"
name="tales_traversal.html"
permission="zope2.ViewManagementScreens"
/>
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
template="template_variables.pt"
name="template_variables.html"
permission="zope2.ViewManagementScreens"
...
...
@@ -115,7 +115,7 @@
<!-- template security -->
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
template="security.pt"
name="security.html"
permission="zope2.View"
...
...
@@ -124,7 +124,7 @@
<!-- a publicly accessible page, attribute, template, template/class -->
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
class=".pages.SimpleView"
attribute="eagle"
name="public_attribute_page"
...
...
@@ -132,14 +132,14 @@
/>
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
template="owl.pt"
name="public_template_page"
permission="zope2.Public"
/>
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
class=".pages.SimpleView"
template="falcon.pt"
name="public_template_class_page"
...
...
@@ -147,16 +147,23 @@
/>
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
class=".pages.SimpleView"
template="parakeet.pt"
name="parakeet.html"
permission="zope2.ViewManagementScreens"
/>
<browser:page
for="Products.Five.tests.testing.simplecontent.ISimpleContent"
class=".pages.CallView"
name="callview.html"
permission="zope2.Public"
/>
<!-- pages from methods/functions/callables that don't have docstrings -->
<browser:pages
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
class="Products.Five.browser.tests.pages.NoDocstringView"
permission="zope2.Public">
<browser:page
...
...
@@ -177,7 +184,7 @@
This is mainly used to load Zope2 skin templates so they can be used
in five skins and layers. -->
<five:pagesFromDirectory
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
module="Products.Five.browser.tests"
directory="pages"
permission="zope2.Public"
...
...
@@ -186,7 +193,7 @@
<!-- browser:page directives with new style classes are ignored -->
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
class=".pages.NewStyleClass"
name="new_style_class"
attribute="method"
...
...
@@ -198,7 +205,7 @@
<browser:view
name=""
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
class=".pages.SimpleView"
permission="zope2.Public"
/>
...
...
@@ -207,14 +214,14 @@
<!-- protected edit form for permission check -->
<browser:editform
schema="Products.Five.testing.simplecontent.ISimpleContent"
schema="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
name="protectededitform.html"
permission="zope2.ViewManagementScreens"
/>
<!-- stuff that we'll override in overrides.zcml -->
<browser:page
for="Products.Five.testing.simplecontent.ISimpleContent"
for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
class=".pages.SimpleView"
attribute="eagle"
name="overridden_view"
...
...
lib/python/Products/Five/browser/tests/pages_ftest.txt
View file @
528f46df
...
...
@@ -11,7 +11,7 @@ some:
Let's also add one of our stub objects to play with:
>>> from Products.Five.testing.simplecontent import manage_addSimpleContent
>>> from Products.Five.test
s.test
ing.simplecontent import manage_addSimpleContent
>>> manage_addSimpleContent(self.folder, 'testoid', 'Testoid')
...
...
@@ -122,8 +122,23 @@ All public views should always be accessible by anyone:
... self.failUnless(status == 200, (status, 200, view_name))
Miscellaneous
-------------
Zope 2 always wants objects in the traversal graph to have a __name__.
That is also true for views, e.g. a view constructed from a simple
class bearing only a __call__ method:
>>> print http(r'''
... GET /test_folder_1_/testoid/callview.html HTTP/1.1
... ''')
HTTP/1.1 200 OK
...
I was __call__()'ed
Clean up
--------
>>> from zope.app.test
s
.placelesssetup import tearDown
>>> from zope.app.test
ing
.placelesssetup import tearDown
>>> tearDown()
lib/python/Products/Five/browser/tests/pts_test_languages.txt
View file @
528f46df
...
...
@@ -42,7 +42,7 @@ the PTS languagees adapter and 3) register our test page:
Finally, we need a traversable folder so that the test page we
registered is found:
>>> from Products.Five.testing import manage_addFiveTraversableFolder
>>> from Products.Five.test
s.test
ing import manage_addFiveTraversableFolder
>>> manage_addFiveTraversableFolder(self.folder, 'ftf')
Now for some actual testing... Our test page is a simple ZPT
...
...
lib/python/Products/Five/browser/tests/resource.txt
View file @
528f46df
...
...
@@ -8,7 +8,7 @@ Set up the test fixtures:
>>> zcml.load_config("configure.zcml", Products.Five)
>>> zcml.load_config('resource.zcml', package=Products.Five.browser.tests)
>>> from Products.Five.testing import manage_addFiveTraversableFolder
>>> from Products.Five.test
s.test
ing import manage_addFiveTraversableFolder
>>> manage_addFiveTraversableFolder(self.folder, 'testoid', 'Testoid')
>>> import os, glob
...
...
@@ -73,8 +73,8 @@ PageTemplateResource's __call__ renders the template
Security
--------
>>> from Products.Five.testing.restricted import checkRestricted
>>> from Products.Five.testing.restricted import checkUnauthorized
>>> from Products.Five.test
s.test
ing.restricted import checkRestricted
>>> from Products.Five.test
s.test
ing.restricted import checkUnauthorized
>>> resource_names = ['cockatiel.html', 'style.css', 'pattern.png']
...
...
@@ -112,5 +112,5 @@ We can now view them all:
Clean up
--------
>>> from zope.app.test
s
.placelesssetup import tearDown
>>> from zope.app.test
ing
.placelesssetup import tearDown
>>> tearDown()
lib/python/Products/Five/browser/tests/resource_ftest.txt
View file @
528f46df
...
...
@@ -8,7 +8,7 @@ Set up the test fixtures:
>>> zcml.load_config("configure.zcml", Products.Five)
>>> zcml.load_config('resource.zcml', package=Products.Five.browser.tests)
>>> from Products.Five.testing import manage_addFiveTraversableFolder
>>> from Products.Five.test
s.test
ing import manage_addFiveTraversableFolder
>>> manage_addFiveTraversableFolder(self.folder, 'testoid', 'Testoid')
>>> import os, glob
...
...
@@ -69,5 +69,5 @@ Page templates aren't guaranteed to render, so exclude them from the test:
Clean up
--------
>>> from zope.app.test
s
.placelesssetup import tearDown
>>> from zope.app.test
ing
.placelesssetup import tearDown
>>> tearDown()
lib/python/Products/Five/browser/tests/test_absoluteurl.py
View file @
528f46df
...
...
@@ -29,7 +29,7 @@ def test_absoluteurl():
>>> from Products.Five import zcml
>>> zcml.load_config("configure.zcml", Products.Five)
>>> from Products.Five.testing import manage_addFiveTraversableFolder
>>> from Products.Five.test
s.test
ing import manage_addFiveTraversableFolder
>>> manage_addFiveTraversableFolder(self.folder, 'testoid', 'Testoid')
A simple traversal will yield us the @@absolute_url view:
...
...
@@ -86,7 +86,7 @@ def test_absoluteurl():
Clean up:
>>> from zope.app.test
s
.placelesssetup import tearDown
>>> from zope.app.test
ing
.placelesssetup import tearDown
>>> tearDown()
"""
...
...
lib/python/Products/Five/browser/tests/test_defaultview.py
View file @
528f46df
...
...
@@ -33,9 +33,9 @@ def test_default_view():
Now let's add a couple of stub objects:
>>> from Products.Five.testing.simplecontent import manage_addSimpleContent
>>> from Products.Five.testing.simplecontent import manage_addCallableSimpleContent
>>> from Products.Five.testing.simplecontent import manage_addIndexSimpleContent
>>> from Products.Five.test
s.test
ing.simplecontent import manage_addSimpleContent
>>> from Products.Five.test
s.test
ing.simplecontent import manage_addCallableSimpleContent
>>> from Products.Five.test
s.test
ing.simplecontent import manage_addIndexSimpleContent
>>> manage_addSimpleContent(self.folder, 'testoid', 'Testoid')
>>> manage_addCallableSimpleContent(self.folder, 'testcall', 'TestCall')
...
...
@@ -79,7 +79,7 @@ def test_default_view():
Clean up:
>>> from zope.app.test
s
.placelesssetup import tearDown
>>> from zope.app.test
ing
.placelesssetup import tearDown
>>> tearDown()
"""
...
...
lib/python/Products/Five/browser/tests/test_i18n.py
View file @
528f46df
...
...
@@ -33,7 +33,7 @@ def test_zpt_i18n():
... </configure>
... <configure package="Products.Five.browser.tests">
... <browser:page
... for="
Products.Five
.interfaces.IFolder"
... for="
OFS
.interfaces.IFolder"
... template="i18n.pt"
... name="i18n.html"
... permission="zope2.View"
...
...
@@ -49,7 +49,7 @@ def test_zpt_i18n():
In order to be able to traverse to the PageTemplate view, we need
a traversable object:
>>> from Products.Five.testing import manage_addFiveTraversableFolder
>>> from Products.Five.test
s.test
ing import manage_addFiveTraversableFolder
>>> manage_addFiveTraversableFolder(self.folder, 'testoid', 'Testoid')
We tell Zope to translate the messages by passing the
...
...
@@ -80,7 +80,7 @@ def test_zpt_i18n():
Clean up:
>>> from zope.app.test
s
.placelesssetup import tearDown
>>> from zope.app.test
ing
.placelesssetup import tearDown
>>> tearDown()
"""
...
...
lib/python/Products/Five/browser/tests/test_menu.py
View file @
528f46df
...
...
@@ -28,7 +28,8 @@ def test_menu():
>>> import Products.Five.browser.tests
>>> from Products.Five import zcml
>>> zcml.load_config("configure.zcml", Products.Five)
>>> zcml.load_config("meta.zcml", Products.Five)
>>> zcml.load_config("permissions.zcml", Products.Five)
>>> zcml.load_config('menu.zcml', package=Products.Five.browser.tests)
>>> from Products.Five.security import newInteraction
...
...
@@ -37,12 +38,12 @@ def test_menu():
Now for some actual testing... Let's look up the menu we registered:
>>> from Products.Five.traversable import FakeRequest
>>> from zope.app.publi
sher.browser.globalbrowsermenuservice import
\
\
... globalBrowserMenuService
>>> from zope.app.publi
cation.browser import setDefaultSkin
>>> from zope.app.publisher.browser.menu import getMenu
>>> request = FakeRequest()
>>>
menu = globalBrowserMenuService.getMenu(
...
'testmenu', self.folder, request)
>>>
setDefaultSkin(request)
>>> menu = getMenu(
'testmenu', self.folder, request)
It should have
...
...
@@ -53,27 +54,41 @@ def test_menu():
>>> menu.sort(lambda x, y: cmp(x['title'], y['title']))
>>> from pprint import pprint
>>> pprint(menu)
[{'action':
'@@cockatiel_menu_public.html',
'description':
'',
>>> pprint(menu
[0]
)
{'action': u
'@@cockatiel_menu_public.html',
'description': u
'',
'extra': None,
'selected': '',
'title': u'Page in a menu (public)'},
'icon': None,
'selected': u'',
'submenu': None,
'title': u'Page in a menu (public)'}
>>> pprint(menu[1])
{'action': u'seagull.html',
'description': u'This is a test menu item',
'extra': None,
'selected': '',
'title': u'Test Menu Item'},
'icon': None,
'selected': u'',
'submenu': None,
'title': u'Test Menu Item'}
>>> pprint(menu[2])
{'action': u'parakeet.html',
'description': u'This is a test menu item',
'extra': None,
'selected': '',
'title': u'Test Menu Item 2'},
'icon': None,
'selected': u'',
'submenu': None,
'title': u'Test Menu Item 2'}
>>> pprint(menu[3])
{'action': u'falcon.html',
'description': u'This is a test menu item',
'extra': None,
'selected': '',
'title': u'Test Menu Item 3'}]
'icon': None,
'selected': u'',
'submenu': None,
'title': u'Test Menu Item 3'}
Let's create a manager user account and log in.
...
...
@@ -82,8 +97,7 @@ def test_menu():
>>> self.login('manager')
>>> newInteraction()
>>> menu = globalBrowserMenuService.getMenu(
... 'testmenu', self.folder, request)
>>> menu = getMenu('testmenu', self.folder, request)
We should get the protected menu items now:
...
...
@@ -91,47 +105,73 @@ def test_menu():
7
>>> menu.sort(lambda x, y: cmp(x['title'], y['title']))
>>> pprint(menu)
[{'action':
'@@cockatiel_menu_protected.html',
'description':
'',
>>> pprint(menu
[0]
)
{'action': u
'@@cockatiel_menu_protected.html',
'description': u
'',
'extra': None,
'selected': '',
'title': u'Page in a menu (protected)'},
{'action': '@@cockatiel_menu_public.html',
'description': '',
'icon': None,
'selected': u'',
'submenu': None,
'title': u'Page in a menu (protected)'}
>>> pprint(menu[1])
{'action': u'@@cockatiel_menu_public.html',
'description': u'',
'extra': None,
'selected': '',
'title': u'Page in a menu (public)'},
'icon': None,
'selected': u'',
'submenu': None,
'title': u'Page in a menu (public)'}
>>> pprint(menu[2])
{'action': u'seagull.html',
'description': u'This is a protected test menu item',
'extra': None,
'selected': '',
'title': u'Protected Test Menu Item'},
'icon': None,
'selected': u'',
'submenu': None,
'title': u'Protected Test Menu Item'}
>>> pprint(menu[3])
{'action': u'falcon.html',
'description': u'This is a protected test menu item',
'extra': None,
'selected': '',
'title': u'Protected Test Menu Item 2'},
'icon': None,
'selected': u'',
'submenu': None,
'title': u'Protected Test Menu Item 2'}
>>> pprint(menu[4])
{'action': u'seagull.html',
'description': u'This is a test menu item',
'extra': None,
'selected': '',
'title': u'Test Menu Item'},
'icon': None,
'selected': u'',
'submenu': None,
'title': u'Test Menu Item'}
>>> pprint(menu[5])
{'action': u'parakeet.html',
'description': u'This is a test menu item',
'extra': None,
'selected': '',
'title': u'Test Menu Item 2'},
'icon': None,
'selected': u'',
'submenu': None,
'title': u'Test Menu Item 2'}
>>> pprint(menu[6])
{'action': u'falcon.html',
'description': u'This is a test menu item',
'extra': None,
'selected': '',
'title': u'Test Menu Item 3'}]
'icon': None,
'selected': u'',
'submenu': None,
'title': u'Test Menu Item 3'}
Clean up:
>>> from zope.app.test
s
.placelesssetup import tearDown
>>> from zope.app.test
ing
.placelesssetup import tearDown
>>> tearDown()
"""
...
...
lib/python/Products/Five/browser/tests/test_pages.py
View file @
528f46df
...
...
@@ -26,7 +26,7 @@ def test_ViewAcquisitionWrapping():
>>> zcml.load_config("configure.zcml", Products.Five)
>>> zcml.load_config('pages.zcml', package=Products.Five.browser.tests)
>>> from Products.Five.testing.simplecontent import manage_addSimpleContent
>>> from Products.Five.test
s.test
ing.simplecontent import manage_addSimpleContent
>>> manage_addSimpleContent(self.folder, 'testoid', 'Testoid')
>>> uf = self.folder.acl_users
>>> uf._doAddUser('manager', 'r00t', ['Manager'], [])
...
...
@@ -56,7 +56,7 @@ def test_ViewAcquisitionWrapping():
Clean up:
>>> from zope.app.test
s
.placelesssetup import tearDown
>>> from zope.app.test
ing
.placelesssetup import tearDown
>>> tearDown()
"""
...
...
@@ -65,11 +65,10 @@ def test_suite():
from
Testing.ZopeTestCase
import
installProduct
,
ZopeDocTestSuite
from
Testing.ZopeTestCase
import
ZopeDocFileSuite
from
Testing.ZopeTestCase
import
FunctionalDocFileSuite
installProduct
(
'PythonScripts'
)
# for Five.testing.restricted
installProduct
(
'PythonScripts'
)
# for Five.test
s.test
ing.restricted
return
unittest
.
TestSuite
((
ZopeDocTestSuite
(),
ZopeDocFileSuite
(
'pages.txt'
,
package
=
'Products.Five.browser.tests'
),
ZopeDocFileSuite
(
'pages.txt'
,
package
=
'Products.Five.browser.tests'
),
FunctionalDocFileSuite
(
'pages_ftest.txt'
,
package
=
'Products.Five.browser.tests'
)
))
...
...
lib/python/Products/Five/browser/tests/test_recurse.py
View file @
528f46df
...
...
@@ -23,9 +23,6 @@ def test_recursion():
"""
Test recursion
>>> from zope.app.tests.placelesssetup import setUp, tearDown
>>> setUp()
This test makes sure that recursion is avoided for view lookup.
First, we need to set up a stub interface...
...
...
@@ -51,10 +48,10 @@ def test_recursion():
>>> from Products.Five.fiveconfigure import classDefaultViewable
>>> classDefaultViewable(Recurse)
>>> from zope.
app import zapi
>>> from zope.
component import provideAdapter
>>> from zope.publisher.interfaces.browser import IBrowserRequest
>>>
pres = zapi.getGlobalService('Presentation')
>>> pr
es.setDefaultViewName(IRecurse, IBrowserRequest, 'view'
)
>>>
from zope.component.interfaces import IDefaultViewName
>>> pr
ovideAdapter(u'view', (IRecurse, IBrowserRequest), IDefaultViewName
)
Here comes the actual test:
...
...
@@ -65,9 +62,10 @@ def test_recursion():
'foo'
Clean up:
Clean up
adapter registry and monkey patches to classes
:
>>> tearDown()
>>> from zope.testing.cleanup import cleanUp
>>> cleanUp()
"""
def
test_suite
():
...
...
lib/python/Products/Five/browser/tests/test_resource.py
View file @
528f46df
...
...
@@ -23,7 +23,7 @@ def test_suite():
import
unittest
from
Testing.ZopeTestCase
import
installProduct
,
ZopeDocFileSuite
from
Testing.ZopeTestCase
import
FunctionalDocFileSuite
installProduct
(
'PythonScripts'
)
# for Five.testing.restricted
installProduct
(
'PythonScripts'
)
# for Five.test
s.test
ing.restricted
return
unittest
.
TestSuite
((
ZopeDocFileSuite
(
'resource.txt'
,
package
=
'Products.Five.browser.tests'
),
...
...
lib/python/Products/Five/browser/tests/test_traversable.py
View file @
528f46df
...
...
@@ -33,7 +33,7 @@ def test_traversable():
the wrong reason: None doesn't have a docstring so BaseRequest
raises NotFoundError.)
>>> from Products.Five.testing.simplecontent import manage_addSimpleContent
>>> from Products.Five.test
s.test
ing.simplecontent import manage_addSimpleContent
>>> manage_addSimpleContent(self.folder, 'testoid', 'Testoid')
>>> print http(r'''
... GET /test_folder_1_/testoid/doesntexist HTTP/1.1
...
...
@@ -54,21 +54,21 @@ def test_traversable():
... <meta:redefinePermission from="zope2.Public" to="zope.Public" />
...
... <five:traversable
... class="Products.Five.testing.fancycontent.FancyContent"
... class="Products.Five.test
s.test
ing.fancycontent.FancyContent"
... />
...
... <browser:page
... for="Products.Five.testing.fancycontent.IFancyContent"
... for="Products.Five.test
s.test
ing.fancycontent.IFancyContent"
... class="Products.Five.browser.tests.pages.FancyView"
... attribute="view"
... name="fancy"
... name="fancy
view
"
... permission="zope2.Public"
... />
...
... </configure>'''
>>> zcml.load_string(configure_zcml)
>>> from Products.Five.testing.fancycontent import manage_addFancyContent
>>> from Products.Five.test
s.test
ing.fancycontent import manage_addFancyContent
>>> info = manage_addFancyContent(self.folder, 'fancy', '')
In the following test we let the original __bobo_traverse__ method
...
...
@@ -85,7 +85,7 @@ def test_traversable():
actually works:
>>> print http(r'''
... GET /test_folder_1_/fancy/fancy HTTP/1.1
... GET /test_folder_1_/fancy/fancy
view
HTTP/1.1
... ''')
HTTP/1.1 200 OK
...
...
...
@@ -94,7 +94,7 @@ def test_traversable():
Clean up:
>>> from zope.app.test
s
.placelesssetup import tearDown
>>> from zope.app.test
ing
.placelesssetup import tearDown
>>> tearDown()
"""
...
...
lib/python/Products/Five/configure.zcml
View file @
528f46df
...
...
@@ -2,13 +2,15 @@
xmlns:five="http://namespaces.zope.org/five">
<include file="meta.zcml" />
<include file="services.zcml" />
<include file="interfaces.zcml" />
<include file="permissions.zcml" />
<include file="i18n.zcml" />
<include file="event.zcml"/>
<include file="deprecated.zcml"/>
<include package=".site" />
<include package=".browser" />
<include package=".form" />
<include package=".skin" />
<include package=".utilities" />
<include package="zope.app.event" />
<include package="zope.app.traversing" />
...
...
lib/python/Products/Five/deprecated.zcml
0 → 100644
View file @
528f46df
<configure xmlns="http://namespaces.zope.org/zope"
xmlns:five="http://namespaces.zope.org/five">
<!-- deprecated in core Zope, should be fixed there in Zope 2.9 -->
<five:deprecatedManageAddDelete
class="AccessControl.User.BasicUserFolder"/>
<five:deprecatedManageAddDelete
class="App.Factory.Factory"/>
<five:deprecatedManageAddDelete
class="App.Permission.Permission"/>
<five:deprecatedManageAddDelete
class="HelpSys.HelpTopic.HelpTopicBase"/>
<five:deprecatedManageAddDelete
class="OFS.Cache.CacheManager"/>
<five:deprecatedManageAddDelete
class="Products.OFSP.Draft.Draft"/>
<five:deprecatedManageAddDelete
class="Products.OFSP.Version.Version"/>
<five:deprecatedManageAddDelete
class="Products.PythonScripts.PythonScript.PythonScript"/>
<five:deprecatedManageAddDelete
class="Products.Sessions.BrowserIdManager.BrowserIdManager"/>
<five:deprecatedManageAddDelete
class="Products.Sessions.SessionDataManager.SessionDataManager"/>
<five:deprecatedManageAddDelete
class="Products.SiteAccess.VirtualHostMonster.VirtualHostMonster"/>
<five:deprecatedManageAddDelete
class="Products.SiteAccess.SiteRoot.Traverser"/>
<five:deprecatedManageAddDelete
class="Products.SiteErrorLog.SiteErrorLog.SiteErrorLog"/>
<five:deprecatedManageAddDelete
class="Products.ZCatalog.CatalogAwareness.CatalogAware"/>
<five:deprecatedManageAddDelete
class="Products.ZCatalog.CatalogPathAwareness.CatalogAware"/>
<five:deprecatedManageAddDelete
class="ZClasses.Property.ZCommonSheet"/>
<five:deprecatedManageAddDelete
class="ZClasses.ZClass.ZClass"/>
</configure>
lib/python/Products/Five/doc/directives.txt
View file @
528f46df
...
...
@@ -33,16 +33,6 @@ redefinePermission
Redefine a permission in included ZCML as another one.
service
-------
Declare a global service
serviceType
-----------
Declare a type of service.
skin
----
...
...
@@ -55,8 +45,24 @@ Declare a global utility.
interface
---------
Register an interface in ZCML.
factory
-------
Register an object factory.
modulealias
-----------
Provide a module under an alias name, e.g. for persistent backward
compatability.
hook
----
Install a hook on a hookable object.
browser ``http://namespaces.zope.org/browser``
==============================================
...
...
@@ -148,16 +154,34 @@ sizable
Retrieve size information for a Zope 2 content class via a Zope 3
style ``ISized`` adapter.
sendEvents
----------
containerEvents
---------------
Make events be sent for Zope 2 container objects, instead of calling old
methods like ``manage_afterAdd``. These old methods will still be called
for classes specified in a ``deprecatedManageAddDelete`` directive.
Lets a Zope 2 content class send out Zope 3 object events that
correspond to the Zope 2 methods ``manage_afterAdd`` and
``manage_beforeDelete``.
deprecatedManageAddDelete
-------------------------
Specify a class that needs its old deprecated methods like
``manage_afterAdd``, ``manage_beforeDelete`` and ``manage_afterClone``
to be called. Modern classes should use event subscribers instead.
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.
Loads all files with .pt extension in a directory as pages.
registerClass
-------------
Registers Five content with Zope 2.
localsite
---------
Turns a class into an implementation of ``IPossibleSite`` so that its
instances can be serve as local sites. Unless otherwise specified, a
default implementation's methods will be used to make the class comply
with the ``IPossibleSite`` interface.
lib/python/Products/Five/doc/features.txt
View file @
528f46df
...
...
@@ -8,7 +8,7 @@ and some limitations.
Zope 3 interfaces
=================
Everything
in the ``zope.interface`` package should work.
Zope 3
Everything
from the ``zope.interface`` package works.
Zope 3
interfaces are the foundation of the component architecture, and also
the foundation of schemas.
...
...
@@ -84,3 +84,18 @@ 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).
Local Sites
===========
Five supports the concept of a local sites and local site managers.
See localsite.txt_ for more information.
.. _localsite.txt: localsite.html
Object events
=============
Five supports sending Zope 3 object events when objects are added,
moved, renamed, copied and deleted. The use of ``manage_afterAdd`` & co
methods is deprecated.
lib/python/Products/Five/doc/five14goals.txt
0 → 100644
View file @
528f46df
===============================
Porting Five to Zope 3.1+ notes
===============================
Introduction
------------
Five needs to work in Zope 2.9. Zope 2.9 will ship with Zope 3.2. This
means Five will need to work with Zope 3.2. Since Zope 3.2 doesn't
truly exist yet we'll target Zope 3.1 for now.
A Five Roadmap
--------------
Here is a tentative Five roadmap:
Five 1.1 is to be released shortly, and its main feature is a
refactored directory structure and Zope 3 i18n for Zope 2. It's still
targeting the Zope X3.0 that's in Zope 2.8.
Five 1.2 is still targetting Zope 2.8, and its main expected feature
is support for local utilities.
Five 1.3 is targetting Zope 2.9 and thus Zope 3.2. We're talking about
this release of Five in this document.
Main problem
------------
Zope 3.1 has internal changes that Five needs to support. Five works
by reimplementing ZCML statements it supplies in the context of Zope
2. This reimplementation is hard to maintain, as for each Zope 3
upgrade we need to review all these ZCML statements and port them into
Five again.
The straightforward way to start supporting Zope 3.1+ with Five would
be to review all the ZCML statements in Five and update them to work
with Zope 3.1+.
A more ambitious but nicer solution would be if we could reuse the
Zope 3 ZCML statements directly. If we could accomplish this,
maintainability of Five would be improved by a lot. Far less review of
Five would be necessary for each Zope 3 upgrade. In the rest of this
document we'll be discussing this scenario.
Reasons for Five's modified ZCML statements
-------------------------------------------
Five ships with modified implementations of Zope 3 ZCML statements for
a number of reasons:
* could not use new-style classes that are in Zope 3 due to
ExtensionClass.
* Five views need to work with the Zope 2 publisher, and this expects
different things than the Zope 3 publisher.
* cannot use the Zope 3 security system, while the Zope 3 ZCML calls
into this to configure it.
* Five views need to work with the Zope 2 security system. This means
Five needs to issue Zope 2 style security declarations for views.
We'll go into more detail about each of these points below.
New-style ExtensionClass
========================
Five needed to be compatible with Zope 2.7, which uses old-style
ExtensionClass. This made life difficult for Five, as Zope 3 uses
new-style Python classes in many places. It's not easy to mix the two.
Zope 2.8 changed to allow new-style ExtensionClasses, which are
compatible with new-style Python classes. This means Five can
hopefully be simplified as we can forget about old-style
ExtensionClasses.
Five views need to work with the Zope 2 publisher
=================================================
The Zope 2 publisher expects something quite different than the Zope 3
publisher.
* does what is returned to the publisher need to inherit from
Acquisition.Explicit? (security reasons?)
* we may need something that calls the right methods on the Zope 3
view (such as browserDefault, __call__ and publishTraverse)
Cannot use the Zope 3 security system
=====================================
Do the Zope 3 security calls get in the way? Five currently removes
these calls, but perhaps doing the calls does not harm.
If they do interface, we could perhaps still trick things into
working harmlessly.
Five must issue Zope 2 security declarations for views
======================================================
This cannot be done by the ZCML implementation of Zope 3. We could
hopefully do this by following the following pattern::
def our_directive_implementation(...):
original_directive_implementation(...)
do_the_zope2_work(...)
lib/python/Products/Five/doc/localsite.txt
0 → 100644
View file @
528f46df
Local sites in Five
===================
Intro
-----
Zope 3 has a concept of local sites and site managers. They allow one
to locally override component registrations and have components and
their configuration be persisted in the ZODB as well as managed
through the web interface.
By default, Zope 3 has a global site which is configured through ZCML.
It provides the fallback for all component look-up. Local sites are
typically set during traversal, when the traverser encounters an
``ISite`` object. The last encountered ``ISite`` wins. Component
look-up will cascade through all the sites in the hierarchy and fall
back to the global site where it can finally fail.
Five also supports local sites, however by default only local
utilities. Local adapters, such as ZODB-based views, could be
supported with a custom implementation of the local site manager and
local adapter registry. This is not the focus of local sites in Five,
though.
Turning possible sites into sites
---------------------------------
Five uses the same technique as Zope 3 for determining local sites:
sites are found during URL traversal. However, since the Zope 2
ZPublisher doesn't emit the necessary events by default, Five needs to
set a ``BeforeTraverse`` hook on site objects.
Setting this hook needs to be done an object-per-object basis and can
be performed through the ``manage_site.html`` browser page. This view
operates on ``IPossibleSite`` objects (in other words, objects that
*can* be sites but aren't yet). It sets the traversal hook on the
object and then marks it with the ``ISite`` interface to indicate that
it is a real site now, not just a possible site.
Note that unlike the Zope 3 equivalent of this view, it does not set
the site manager to site; it is assumed that the site already knows
how to get its site manager.
Also note that in order for the view to work, the object's class needs
to be Five-traversable, e.g. with the following ZCML statement:
<five:traversable class=".module.MyClass" />
Custom site implementations
---------------------------
Anything can be a site, there are no restrictions (sites don't have to
be folders, for examples). Sites can also be nested. For all the
Component Architecture cares, every object in your URL graph could be
a site.
The only requirement are two interfaces:
``IPossibleSite``
Objects that can potentially be turned into a site need to provide
this interface. That requires them to have a ``setSiteManager()``
and ``getSiteManager()`` method for setting and getting the local
site manager of that site. The site manager is the registry that
takes care of local component look-up.
``IFiveSiteManager``
This interface is a slight extension of the ``IServiceService`` or
``ISiteManager`` interface, respectively (the former in Zope X3
3.0, the latter in later versions). It defines the API of a local
site manager that is to be used in a Five environment. The site's
``getSiteManager()`` method should return an object providing this
interface.
Five's default site manager
----------------------------
If you want to instantly make your custom class an ``IPossibleSite``
implementation, you can use a default mix-in class from Five, e.g.::
class MySite(OFS.Folder, Products.Five.site.localsite.FiveSite):
pass
This default implementation of ``IPossibleSite`` features a site
manager implementation that knows how to register and look-up local
utilities. It does so by adapting the site to
``IFiveUtilityRegistry``.
The default adapter for this local utility registry simply stores the
utilities in a standard OFS Folder on called ``utilities`` on the site
object. You probably want to exchange that simple behaviour with
something that works better in your application. You can do so by
plugging in your own utility registry adapter, e.g.::
<adapter for=".interfaces.IMySite"
provides="Products.Five.site.interfaces.IFiveUtilityRegistry"
fatory=".module.MyUtilityRegistry" />
All this implementation needs to do is comply with the
``IFiveUtilityRegistry`` interface, which essentially means the
standard utility look-up methods like ``queryUtility()``,
``getUtilitiesFor()``, etc.
Turning existing classes into possible sites
--------------------------------------------
If you cannot or do not want to modify existing classes to mix in the
``FiveSite`` class, you can also use a structured monkey patch via
ZCML::
<five:localsite class=".module.MyClass" />
This makes ``MyClass`` an ``IPossibleSite`` and sticks ``FiveSite``'s
``getSiteManager()`` and ``setSiteManager()`` methods on the class as
well. You can also tell it to use a different site implementation's
methods for the monkey patch::
<five:localsite class=".module.MyClass"
site_class=".module.MySiteImpl" />
Just make sure that this class implements ``IPossibleSite``.
lib/python/Products/Five/doc/main.txt
View file @
528f46df
...
...
@@ -5,23 +5,19 @@ 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:
technologies into Zope 2, today. Among others, it allows you to use
Zope 3 interfaces, ZCML-based configuration, adapters, browser pages
(including skins, layers, and resources), automated add and edit forms
based on schemas, object events, as well as Zope 3-style i18n message
catalogs.
* Zope 3 interfaces
We've tried to keep the Five experience as close to Zope 3 as
possible, so this means that what you learn while using Five should
also be applicable to Zope 3, and viceversa.
* 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.
Five 1.0 and 1.1 work on a straight Zope 2.7 installation, as long as
Zope 3 has been installed. Five 1.2 requires Zope 2.8 which already
ships with Zope 3, Five 1.3 is included in Zope 2.9.
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
...
...
@@ -32,6 +28,19 @@ system for us all.
Download
--------
2005-11-02 -- We have released Five 1.2b and 1.3b! Download Five 1.2b
here:
http://codespeak.net/z3/five/release/Five-1.2b.tgz
2005-10-04 -- We have released Five 1.1! Download it here:
http://codespeak.net/z3/five/release/Five-1.1.tgz
2005-07-13 -- We have released Five 1.1b! Download it here:
http://codespeak.net/z3/five/release/Five-1.1b.tgz
2005-07-12 -- We have released Five 1.0.2! This is also the version
that will be included in Zope 2.8.1. Download it here:
...
...
lib/python/Products/Five/doc/products/ViewsTutorial/__init__.py
View file @
528f46df
##############################################################################
#
# Copyright (c) 2005 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.
#
##############################################################################
import
democontent
def
initialize
(
context
):
context
.
registerClass
(
democontent
.
DemoContent
,
constructors
=
(
democontent
.
manage_addDemoContentForm
,
democontent
.
manage_addDemoContent
),
)
# make this directory a package
lib/python/Products/Five/doc/products/ViewsTutorial/addDemoContent.pt
0 → 100644
View file @
528f46df
<h1 tal:replace="structure context/manage_page_header">Header</h1>
<h2 tal:define="form_title string:Add Demo Content"
tal:replace="structure context/manage_form_title">Form Title</h2>
<p class="form-help">
Add Demo Content
</p>
<form action="." method="post"
tal:attributes="action request/ACTUAL_URL">
<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="add_input_name" 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 context/manage_page_footer">Footer</h1>
lib/python/Products/Five/doc/products/ViewsTutorial/browser.py
View file @
528f46df
##############################################################################
#
# Copyright (c) 2005 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.
#
##############################################################################
from
Products.Five
import
BrowserView
import
random
from
democontent
import
DemoContent
class
Overview
:
"""View for overview.
"""
class
Overview
(
BrowserView
):
def
reversedIds
(
self
):
result
=
[]
for
id
in
self
.
context
.
objectIds
():
...
...
@@ -27,9 +19,28 @@ class Overview(BrowserView):
def
directlyPublished
(
self
):
return
"This is directly published"
class
NewExample
(
BrowserView
):
class
NewExample
:
"""View for new example.
"""
def
helpsWithOne
(
self
):
return
random
.
randrange
(
10
)
def
two
(
self
):
return
"Two got called"
class
DemoContentAddView
:
"""Add view for demo content.
"""
def
__call__
(
self
,
add_input_name
=
''
,
title
=
''
,
submit_add
=
''
):
if
submit_add
:
obj
=
DemoContent
(
add_input_name
,
title
)
self
.
context
.
add
(
obj
)
self
.
request
.
response
.
redirect
(
self
.
context
.
nextURL
())
return
''
return
self
.
index
()
lib/python/Products/Five/doc/products/ViewsTutorial/configure.zcml
View file @
528f46df
...
...
@@ -3,27 +3,29 @@
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:five="http://namespaces.zope.org/five">
<five:traversable
class="OFS.Folder.Folder"
/>
<five:traversable class="OFS.Application.Application"/>
<!-- OFS.Folder.Folder views -->
<five:traversable class="OFS.Folder.Folder"/>
<browser:page
for="Products.Five
.interfaces.IFolder"
for="OFS
.interfaces.IFolder"
name="overview.html"
template="overview.pt"
permission="zope2.ViewManagementScreens"
/>
<browser:page
for="Products.Five
.interfaces.IFolder"
for="OFS
.interfaces.IFolder"
name="overview2.html"
template="overview2.pt"
permission="zope2.ViewManagementScreens"
class=".browser.Overview"
permission="zope2.ViewManagementScreens"
/>
<browser:page
for="Products.Five
.interfaces.IFolder"
for="OFS
.interfaces.IFolder"
name="test.html"
class=".browser.Overview"
attribute="directlyPublished"
...
...
@@ -31,7 +33,7 @@
/>
<browser:pages
for="
Products.Five
.interfaces.IFolder"
for="
OFS
.interfaces.IFolder"
class=".browser.NewExample"
permission="zope2.ViewManagementScreens"
>
...
...
@@ -45,7 +47,30 @@
/>
</browser:pages>
<five:traversable class=".democontent.DemoContent" />
<!-- .democontent.IDemoContent views -->
<five:traversable class=".democontent.DemoContent"/>
<browser:page
for="zope.app.container.interfaces.IAdding"
name="addDemoContent.html"
template="addDemoContent.pt"
class=".browser.DemoContentAddView"
permission="zope2.ViewManagementScreens"
/>
<browser:resource
name="green5.png"
image="green5.png"
/>
<five:registerClass
class=".democontent.DemoContent"
meta_type="Five Demo Content"
addview="addDemoContent.html"
icon="green5.png"
permission="zope2.ViewManagementScreens"
/>
<browser:page
for=".democontent.IDemoContent"
...
...
@@ -54,10 +79,11 @@
permission="zope2.ViewManagementScreens"
/>
<five:defaultViewable class=".democontent.DemoContent"
/>
<five:defaultViewable class=".democontent.DemoContent"/>
<browser:defaultView
for=".democontent.IDemoContent"
name="someview.html" />
name="someview.html"
/>
</configure>
lib/python/Products/Five/doc/products/ViewsTutorial/democontent.py
View file @
528f46df
##############################################################################
#
# Copyright (c) 2005 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.
#
##############################################################################
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"
"""Return some text.
"""
class
DemoContent
(
SimpleItem
):
implements
(
IDemoContent
)
meta_type
=
'Five Demo Content'
implements
(
IDemoContent
)
def
__init__
(
self
,
id
,
title
):
self
.
id
=
id
...
...
@@ -30,15 +19,3 @@ class DemoContent(SimpleItem):
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'
)
lib/python/Products/Five/doc/products/ViewsTutorial/green5.png
0 → 100644
View file @
528f46df
138 Bytes
lib/python/Products/Five/event.zcml
0 → 100644
View file @
528f46df
<configure xmlns="http://namespaces.zope.org/zope">
<!-- Adapter giving sublocations for ObjectManagers, used
by dispatchToSublocations -->
<adapter
for="OFS.interfaces.IObjectManager"
provides="zope.app.location.interfaces.ISublocations"
factory="OFS.subscribers.ObjectManagerSublocations"
/>
<!-- dispatch IObjectWillBeMovedEvent with "bottom-up" semantics -->
<subscriber
for="OFS.interfaces.IItem
OFS.interfaces.IObjectWillBeMovedEvent"
handler="OFS.subscribers.dispatchObjectWillBeMovedEvent"
/>
<!-- dispatch IObjectMovedEvent with "top-down" semantics -->
<subscriber
for="OFS.interfaces.IItem
zope.app.container.interfaces.IObjectMovedEvent"
handler="OFS.subscribers.dispatchObjectMovedEvent"
/>
<!-- dispatch IObjectClonedEvent with "top-down" semantics -->
<subscriber
for="OFS.interfaces.IItem
OFS.interfaces.IObjectClonedEvent"
handler="OFS.subscribers.dispatchObjectClonedEvent"
/>
</configure>
lib/python/Products/Five/eventconfigure.py
View file @
528f46df
##############################################################################
#
# Copyright (c) 200
4, 200
5 Zope Corporation and Contributors.
# Copyright (c) 2005 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
...
...
@@ -15,109 +15,38 @@
Use 'structured monkey patching' to enable zope.app.container event sending for
Zope 2 objects.
$Id: eventconfigure.py 1
7810 2005-09-24 09:12:59
Z efge $
$Id: eventconfigure.py 1
9413 2005-11-02 14:37:52
Z efge $
"""
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
# holds classes that were monkeyed with; for clean up
_monkied
=
[]
import
warnings
from
OFS.subscribers
import
deprecatedManageAddDeleteClasses
# ObjectAddedEvent and ObjectRemovedEvent are different in Zope 2
class
ObjectAddedEvent
(
ObjectMovedEvent
):
implements
(
IObjectAddedEvent
)
def
setContainerEvents
():
warnings
.
warn
(
"Using <five:containerEvents/> is deprecated (it is now "
"the default), it will be removed in Zope 2.11"
,
DeprecationWarning
)
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
)
def
setDeprecatedManageAddDelete
(
class_
):
"""Instances of the class will still see their old methods called."""
deprecatedManageAddDeleteClasses
.
append
(
class_
)
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__
=
True
def
manage_beforeDelete
(
self
,
item
,
container
):
notify
(
ObjectRemovedEvent
(
self
))
# call original
method
=
getattr
(
self
,
'__five_original_manage_beforeDelete'
,
None
)
if
method
is
not
None
:
self
.
__five_original_manage_beforeDelete
(
item
,
container
)
manage_beforeDelete
.
__five_method__
=
True
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
)
def
cleanUp
():
deprecatedManageAddDeleteClasses
[:]
=
[]
class_
.
manage_afterAdd
=
manage_afterAdd
class_
.
manage_beforeDelete
=
manage_beforeDelete
# remember class for clean up
_monkied
.
append
(
class_
)
def
containerEvents
(
_context
):
_context
.
action
(
discriminator
=
None
,
callable
=
setContainerEvents
,
args
=
(),
)
def
sendEvents
(
_context
,
class_
):
def
deprecatedManageAddDelete
(
_context
,
class_
):
_context
.
action
(
discriminator
=
(
'five:sendEvents
'
,
class_
),
callable
=
classSendEvents
,
args
=
(
class_
,)
discriminator
=
(
'five:deprecatedManageAddDelete
'
,
class_
),
callable
=
setDeprecatedManageAddDelete
,
args
=
(
class_
,)
,
)
# clean up code
from
Products.Five.fiveconfigure
import
killMonkey
from
zope.testing.cleanup
import
addCleanUp
def
unsendEvents
(
class_
):
"""Restore class's initial state with respect to sending events"""
for
name
in
[
'manage_afterAdd'
,
'manage_beforeDelete'
]:
killMonkey
(
class_
,
name
,
'__five_original_'
+
name
)
def
cleanUp
():
for
class_
in
_monkied
:
unsendEvents
(
class_
)
addCleanUp
(
cleanUp
)
del
addCleanUp
lib/python/Products/Five/fiveconfigure.py
View file @
528f46df
...
...
@@ -22,12 +22,20 @@ import sys
import
glob
import
warnings
import
App
import
App.config
import
Products
from
zLOG
import
LOG
,
ERROR
from
zope.interface
import
classImplements
from
zope.interface
import
classImplements
,
classImplementsOnly
,
implementedBy
from
zope.interface.interface
import
InterfaceClass
from
zope.configuration
import
xmlconfig
from
zope.configuration.exceptions
import
ConfigurationError
from
zope.publisher.interfaces.browser
import
IDefaultBrowserLayer
from
zope.app
import
zapi
from
zope.app.component.interface
import
provideInterface
from
zope.app.component.metaconfigure
import
adapter
from
zope.app.security.interfaces
import
IPermission
from
viewable
import
Viewable
from
traversable
import
Traversable
...
...
@@ -55,7 +63,7 @@ def handleBrokenProduct(product):
# in the control panel. However, all attempts to do so has failed from my
# side. //regebro
exc
=
sys
.
exc_info
()
LOG
(
'Five'
,
ERROR
,
'Could not import Product %s'
%
name
,
error
=
exc
)
LOG
(
'Five'
,
ERROR
,
'Could not import Product %s'
%
product
.
__name__
,
error
=
exc
)
def
loadProducts
(
_context
):
products
=
findProducts
()
...
...
@@ -177,20 +185,6 @@ def defaultViewable(_context, class_):
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'.
...
...
@@ -215,7 +209,7 @@ def bridge(_context, zope2, package, name=None):
)
def
pagesFromDirectory
(
_context
,
directory
,
module
,
for_
=
None
,
layer
=
'default'
,
permission
=
'zope.Public'
):
layer
=
IDefaultBrowserLayer
,
permission
=
'zope.Public'
):
if
isinstance
(
module
,
basestring
):
module
=
_context
.
resolve
(
module
)
...
...
@@ -233,6 +227,41 @@ def pagesFromDirectory(_context, directory, module, for_=None,
page
(
_context
,
name
=
name
,
permission
=
permission
,
layer
=
layer
,
for_
=
for_
,
template
=
fname
)
_register_monkies
=
[]
_meta_type_regs
=
[]
def
_registerClass
(
class_
,
meta_type
,
permission
,
addview
,
icon
,
global_
):
setattr
(
class_
,
'meta_type'
,
meta_type
)
permission_obj
=
zapi
.
getUtility
(
IPermission
,
permission
)
if
icon
:
setattr
(
class_
,
'icon'
,
'++resource++%s'
%
icon
)
interfaces
=
tuple
(
implementedBy
(
class_
))
info
=
{
'name'
:
meta_type
,
'action'
:
addview
and
(
'+/%s'
%
addview
)
or
''
,
'product'
:
'Five'
,
'permission'
:
str
(
permission_obj
.
title
),
'visibility'
:
global_
and
'Global'
or
None
,
'interfaces'
:
interfaces
,
'instance'
:
class_
,
'container_filter'
:
None
}
Products
.
meta_types
+=
(
info
,)
_register_monkies
.
append
(
class_
)
_meta_type_regs
.
append
(
meta_type
)
def
registerClass
(
_context
,
class_
,
meta_type
,
permission
,
addview
=
None
,
icon
=
None
,
global_
=
True
):
_context
.
action
(
discriminator
=
(
'registerClass'
,
meta_type
),
callable
=
_registerClass
,
args
=
(
class_
,
meta_type
,
permission
,
addview
,
icon
,
global_
)
)
# clean up code
def
killMonkey
(
class_
,
name
,
fallback
,
attr
=
None
):
...
...
@@ -265,11 +294,33 @@ def undefaultViewable(class_):
killMonkey
(
class_
,
'__browser_default__'
,
'__fallback_default__'
,
'__five_viewable__'
)
def
unregisterClass
(
class_
):
delattr
(
class_
,
'meta_type'
)
try
:
delattr
(
class_
,
'icon'
)
except
AttributeError
:
pass
def
cleanUp
():
global
_traversable_monkies
for
class_
in
_traversable_monkies
:
untraversable
(
class_
)
_traversable_monkies
=
[]
global
_defaultviewable_monkies
for
class_
in
_defaultviewable_monkies
:
undefaultViewable
(
class_
)
_defaultviewable_monkies
=
[]
global
_register_monkies
for
class_
in
_register_monkies
:
unregisterClass
(
class_
)
_register_monkies
=
[]
global
_meta_type_regs
Products
.
meta_types
=
tuple
([
info
for
info
in
Products
.
meta_types
if
info
[
'name'
]
not
in
_meta_type_regs
])
_meta_type_regs
=
[]
from
zope.testing.cleanup
import
addCleanUp
addCleanUp
(
cleanUp
)
...
...
lib/python/Products/Five/fivedirectives.py
View file @
528f46df
...
...
@@ -17,7 +17,10 @@ $Id: fivedirectives.py 12884 2005-05-30 13:10:41Z philikon $
"""
from
zope.interface
import
Interface
from
zope.app.publisher.browser.metadirectives
import
IBasicResourceInformation
from
zope.app.security.fields
import
Permission
from
zope.configuration.fields
import
GlobalObject
,
Tokens
,
PythonIdentifier
from
zope.configuration.fields
import
Bool
from
zope.schema
import
ASCII
from
zope.schema
import
TextLine
class
IImplementsDirective
(
Interface
):
...
...
@@ -56,7 +59,7 @@ class IDefaultViewableDirective(Interface):
required
=
True
)
class
IS
endEvents
Directive
(
Interface
):
class
IS
izable
Directive
(
Interface
):
"""Make instances of class send events.
"""
...
...
@@ -65,6 +68,19 @@ class ISendEventsDirective(Interface):
required
=
True
)
class
IContainerEventsDirective
(
Interface
):
"""Global switch to enable container events
"""
class
IDeprecatedManageAddDeleteDirective
(
Interface
):
"""Call manage_afterAdd & co for these contained content classes.
"""
class_
=
GlobalObject
(
title
=
u"Class"
,
required
=
True
,
)
class
IBridgeDirective
(
Interface
):
"""Bridge from a Zope 2 interface to an equivalent Zope3 interface.
"""
...
...
@@ -104,3 +120,51 @@ class IPagesFromDirectoryDirective(IBasicResourceInformation):
description
=
u"The directory containing the resource data."
,
required
=
True
)
class
IRegisterClassDirective
(
Interface
):
"""registerClass directive schema.
Register Five content with Zope 2.
"""
class_
=
GlobalObject
(
title
=
u'Instance Class'
,
description
=
u'Dotted name of the class that is registered.'
,
required
=
True
)
meta_type
=
ASCII
(
title
=
u'Meta Type'
,
description
=
u'A human readable unique identifier for the class.'
,
required
=
True
)
permission
=
Permission
(
title
=
u'Add Permission'
,
description
=
u'The permission for adding objects of this class.'
,
required
=
True
)
addview
=
ASCII
(
title
=
u'Add View ID'
,
description
=
u'The ID of the add view used in the ZMI. Consider this '
u'required unless you know exactly what you do.'
,
default
=
None
,
required
=
False
)
icon
=
ASCII
(
title
=
u'Icon ID'
,
description
=
u'The ID of the icon used in the ZMI.'
,
default
=
None
,
required
=
False
)
global_
=
Bool
(
title
=
u'Global scope?'
,
description
=
u'If "global" is False the class is only available in '
u'containers that explicitly allow one of its interfaces.'
,
default
=
True
,
required
=
False
)
lib/python/Products/Five/form/__init__.py
View file @
528f46df
...
...
@@ -33,7 +33,7 @@ from zope.app.form.interfaces import WidgetsError, MissingInputError
from
zope.app.form.utility
import
setUpWidgets
,
getWidgetsData
from
zope.app.form.interfaces
import
IInputWidget
,
WidgetsError
from
zope.app.event.objectevent
import
ObjectCreatedEvent
,
ObjectModifiedEvent
from
zope.app.i18n
import
ZopeMessage
ID
Factory
as
_
from
zope.app.i18n
import
ZopeMessageFactory
as
_
from
Products.Five.browser
import
BrowserView
from
Products.Five.browser.pagetemplatefile
import
ZopeTwoPageTemplateFile
...
...
@@ -144,12 +144,13 @@ class EditView(BrowserView):
if
changed
:
self
.
changed
()
# XXX: Needs locale support:
#
formatter = self.request.locale.dates.getFormatter(
#formatter = self.request.locale.dates.getFormatter(
# 'dateTime', 'medium')
status
=
_
(
"Updated on ${date_time}"
)
# status.mapping = {'date_time': formatter.format(
# datetime.utcnow())}
status
.
mapping
=
{
'date_time'
:
str
(
datetime
.
utcnow
())}
#status = _("Updated on ${date_time}",
# mapping={'date_time':
# formatter.format(datetime.utcnow())})
status
=
_
(
"Updated on ${date_time}"
,
mapping
=
{
'date_time'
:
str
(
datetime
.
utcnow
())})
self
.
update_status
=
status
return
status
...
...
@@ -249,9 +250,3 @@ class AddView(EditView):
def
nextURL
(
self
):
return
self
.
context
.
nextURL
()
# BBB: Will be removed in future versions
from
Products.Five
import
browser
browser
.
AddView
=
AddView
browser
.
EditView
=
EditView
lib/python/Products/Five/form/metaconfigure.py
View file @
528f46df
...
...
@@ -13,28 +13,29 @@
##############################################################################
"""Edit form directives
$Id: metaconfigure.py 1
2884 2005-05-30 13:10:4
1Z philikon $
$Id: metaconfigure.py 1
9283 2005-10-31 17:43:5
1Z philikon $
"""
import
ExtensionClass
from
Globals
import
InitializeClass
as
initializeClass
from
zope.component
import
getGlobalService
from
zope.component.servicenames
import
Presentation
from
zope.interface
import
Interface
from
zope.publisher.interfaces.browser
import
IBrowserRequest
from
zope.app.publisher.browser.globalbrowsermenuservice
import
\
menuItemDirective
from
zope.app
import
zapi
from
zope.app.publisher.browser.menumeta
import
menuItemDirective
from
zope.app.form.browser.metaconfigure
import
BaseFormDirective
from
zope.app.container.interfaces
import
IAdding
from
zope.app.i18n
import
ZopeMessageFactory
as
_
from
Products.Five.form
import
EditView
,
AddView
from
Products.Five.metaclass
import
makeClass
from
Products.Five.security
import
protectClass
,
initializeClass
from
Products.Five.security
import
protectClass
from
Products.Five.browser.pagetemplatefile
import
ZopeTwoPageTemplateFile
from
Products.Five.browser.metaconfigure
import
makeClassForTemplate
def
EditViewFactory
(
name
,
schema
,
label
,
permission
,
layer
,
template
,
default_template
,
bases
,
for_
,
fields
,
fulledit_path
=
None
,
fulledit_label
=
None
,
menu
=
u''
):
s
=
getGlobalService
(
Presentation
)
class_
=
makeClassForTemplate
(
template
,
globals
(),
used_for
=
schema
,
bases
=
bases
)
class_
.
schema
=
schema
...
...
@@ -49,8 +50,15 @@ def EditViewFactory(name, schema, label, permission, layer,
class_
.
generated_form
=
ZopeTwoPageTemplateFile
(
default_template
)
if
layer
is
None
:
layer
=
IDefaultBrowserLayer
s
=
zapi
.
getGlobalSiteManager
()
s
.
provideAdapter
((
for_
,
layer
),
Interface
,
name
,
class_
)
s
.
provideView
(
for_
,
name
,
IBrowserRequest
,
class_
,
layer
)
# Reminder: the permission we got has already been processed by
# BaseFormDirective, that means that zope.Public has been
# translated to the CheckerPublic object
protectClass
(
class_
,
permission
)
initializeClass
(
class_
)
...
...
@@ -58,20 +66,22 @@ class FiveFormDirective(BaseFormDirective):
def
_processWidgets
(
self
):
if
self
.
_widgets
:
customWidgetsObject
=
makeClass
(
'CustomWidgetsMixin'
,
(
ExtensionClass
.
Base
,),
self
.
_widgets
)
customWidgetsObject
=
makeClass
(
'CustomWidgetsMixin'
,
(
ExtensionClass
.
Base
,),
self
.
_widgets
)
self
.
bases
=
self
.
bases
+
(
customWidgetsObject
,)
class
EditFormDirective
(
FiveFormDirective
):
view
=
EditView
default_template
=
'edit.pt'
title
=
'Edit'
title
=
_
(
'Edit'
)
def
_handle_menu
(
self
):
if
self
.
menu
:
menuItemDirective
(
self
.
_context
,
self
.
menu
,
self
.
for_
or
self
.
schema
,
'@@'
+
self
.
name
,
self
.
title
,
permission
=
self
.
permission
)
'@@'
+
self
.
name
,
self
.
title
,
permission
=
self
.
permission
,
layer
=
self
.
layer
)
def
__call__
(
self
):
self
.
_processWidgets
()
...
...
@@ -89,8 +99,6 @@ def AddViewFactory(name, schema, label, permission, layer,
fields
,
content_factory
,
arguments
,
keyword_arguments
,
set_before_add
,
set_after_add
,
menu
=
u''
):
s
=
getGlobalService
(
Presentation
)
class_
=
makeClassForTemplate
(
template
,
globals
(),
used_for
=
schema
,
bases
=
bases
)
...
...
@@ -105,7 +113,15 @@ def AddViewFactory(name, schema, label, permission, layer,
class_
.
generated_form
=
ZopeTwoPageTemplateFile
(
default_template
)
s
.
provideView
(
for_
,
name
,
IBrowserRequest
,
class_
,
layer
)
if
layer
is
None
:
layer
=
IDefaultBrowserLayer
s
=
zapi
.
getGlobalSiteManager
()
s
.
provideAdapter
((
for_
,
layer
),
Interface
,
name
,
class_
)
# Reminder: the permission we got has already been processed by
# BaseFormDirective, that means that zope.Public has been
# translated to the CheckerPublic object
protectClass
(
class_
,
permission
)
initializeClass
(
class_
)
...
...
@@ -132,7 +148,7 @@ class AddFormDirective(FiveFormDirective):
# for=self.schema.
menuItemDirective
(
self
.
_context
,
self
.
menu
,
self
.
for_
,
'@@'
+
self
.
name
,
self
.
title
,
permission
=
self
.
permission
,
self
.
title
,
permission
=
self
.
permission
,
layer
=
self
.
layer
,
description
=
self
.
description
)
def
_handle_arguments
(
self
,
leftover
=
None
):
...
...
lib/python/Products/Five/form/objectwidget.pt
0 → 100644
View file @
528f46df
<fieldset>
<legend tal:content="context/legendTitle"
i18n:translate="">The Legend</legend>
<div class="row" tal:repeat="widget context/subwidgets">
<tal:comment condition="nothing">
This is why we have to duplicate this template: we want to look
up the @@form_macros browser page from something that's
definitely five:traversable (it doesn't really matter where we
look it up, just *that* we look it up); we know the object we're
editing is five:traversable, so we just use that. Yes, three
times context. Weird, eh?
</tal:comment>
<metal:block use-macro="context/context/context/@@form_macros/widget_row" />
</div>
</fieldset>
lib/python/Products/Five/form/objectwidget.py
0 → 100644
View file @
528f46df
##############################################################################
#
# Copyright (c) 2005 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.
#
##############################################################################
"""Five-compatible version of ObjectWidget
This is needed because ObjectWidget uses ViewPageTemplateFile whose
macro definition is unfortunately incompatible with
ZopeTwoPageTemplateFile. So this subclass uses
ZopeTwoPageTemplateFile for the template that renders the widget's
sub-editform. Acquisition has to be mixed in to provide the
ZopeTwoPageTemplateFile with the proper acquisition context.
$Id$
"""
import
os.path
import
Acquisition
import
zope.app.form.browser.objectwidget
from
AccessControl
import
ClassSecurityInfo
from
Globals
import
InitializeClass
as
initializeClass
from
Products.Five.browser.pagetemplatefile
import
ZopeTwoPageTemplateFile
class
ObjectWidgetView
(
Acquisition
.
Explicit
,
zope
.
app
.
form
.
browser
.
objectwidget
.
ObjectWidgetView
):
security
=
ClassSecurityInfo
()
security
.
declareObjectPublic
()
template
=
ZopeTwoPageTemplateFile
(
'objectwidget.pt'
)
initializeClass
(
ObjectWidgetView
)
class
ObjectWidgetClass
(
Acquisition
.
Explicit
,
zope
.
app
.
form
.
browser
.
objectwidget
.
ObjectWidget
):
def
__init__
(
self
,
context
,
request
,
factory
,
**
kw
):
super
(
ObjectWidgetClass
,
self
).
__init__
(
context
,
request
,
factory
,
**
kw
)
self
.
view
=
ObjectWidgetView
(
self
,
request
)
def
setRenderedValue
(
self
,
value
):
"""Slightly more robust re-implementation this method."""
# re-call setupwidgets with the content
self
.
_setUpEditWidgets
()
for
name
in
self
.
names
:
val
=
getattr
(
value
,
name
,
None
)
if
val
is
None
:
# this is where we are more robust than Zope 3.2's
# object widget: we supply subwidgets with the default
# from the schema, not None (Zope 3.2's list widget
# breaks when the rendered value is None)
val
=
self
.
context
.
schema
[
name
].
default
self
.
getSubWidget
(
name
).
setRenderedValue
(
val
)
def
ObjectWidget
(
context
,
request
,
factory
,
**
kw
):
"""Return an ObjectWidget suitable in the Five environment, with
right acquisition context"""
return
ObjectWidgetClass
(
context
,
request
,
factory
,
**
kw
).
__of__
(
context
.
context
)
lib/python/Products/Five/form/tests/configure.zcml
View file @
528f46df
...
...
@@ -34,7 +34,7 @@
type="zope.publisher.interfaces.browser.IBrowserRequest"
for="zope.schema.interfaces.IObject"
provides="zope.app.form.interfaces.IInputWidget"
factory="
zope.app.form.browser
.objectwidget.ObjectWidget"
factory="
Products.Five.form
.objectwidget.ObjectWidget"
permission="zope.Public"
/>
...
...
lib/python/Products/Five/form/tests/forms.txt
View file @
528f46df
...
...
@@ -17,7 +17,7 @@ We need to configure all of Five for the functional test:
Finally, we need to setup a traversable folder. Otherwise, Five won't
get to to do its view lookup:
>>> from Products.Five.testing import manage_addFiveTraversableFolder
>>> from Products.Five.test
s.test
ing import manage_addFiveTraversableFolder
>>> manage_addFiveTraversableFolder(self.folder, 'ftf')
...
...
@@ -47,9 +47,10 @@ which incorrectly ignored its 'handle_errors' argument):
>>> print http(r"""
... GET /test_folder_1_/ftf/+/protectedaddform.html HTTP/1.1
... """, handle_errors=
Tru
e)
HTTP/1.1 401 Unauthorized
... """, handle_errors=
Fals
e)
Traceback (most recent call last):
...
Unauthorized: ...
Now let's add a piece of our sample content object to test more things
on it:
...
...
@@ -372,7 +373,11 @@ element to the list:
... -----------------------------968064918930967154199105236
... Content-Disposition: form-data; name="field.somelist.add"
...
... Add
... Add Some item
... -----------------------------968064918930967154199105236
... Content-Disposition: form-data; name="field.somelist.count"
...
... 0
... -----------------------------968064918930967154199105236--
... """ % (wo_hen_hao, ni_hao), handle_errors=False)
HTTP/1.1 200 OK
...
...
@@ -408,6 +413,10 @@ Now, let's enter some more Chinese:
...
... %s
... -----------------------------968064918930967154199105236
... Content-Disposition: form-data; name="field.somelist.count"
...
... 1
... -----------------------------968064918930967154199105236
... Content-Disposition: form-data; name="UPDATE_SUBMIT"
...
... Change
...
...
@@ -572,5 +581,5 @@ Clean up
Finally, we need to clean up:
>>> from zope.app.test
s
.placelesssetup import tearDown
>>> from zope.app.test
ing
.placelesssetup import tearDown
>>> tearDown()
lib/python/Products/Five/form/tests/schemacontent.py
View file @
528f46df
...
...
@@ -18,13 +18,13 @@ $Id: schemacontent.py 15514 2005-08-02 16:37:34Z yuppie $
from
OFS.SimpleItem
import
SimpleItem
from
Globals
import
InitializeClass
from
zope.i18nmessageid
import
Message
ID
Factory
from
zope.i18nmessageid
import
MessageFactory
from
zope.interface
import
implements
,
Interface
from
zope.schema
import
TextLine
,
Text
,
Object
,
Int
,
List
from
zope.app.form
import
CustomWidgetFactory
from
zope.app.form.browser
import
ObjectWidget
from
Products.Five.form.objectwidget
import
ObjectWidget
_
=
Message
ID
Factory
(
'formtest'
)
_
=
MessageFactory
(
'formtest'
)
class
IFieldContent
(
Interface
):
...
...
lib/python/Products/Five/form/tests/test_forms.py
View file @
528f46df
...
...
@@ -46,25 +46,26 @@ def test_get_widgets_for_schema_fields():
>>> from zope.app.form.browser.textwidgets import TextWidget
>>> from zope.app.form.browser.itemswidgets import DropdownWidget
>>> view1 = zapi.get
ViewProviding(contactname, IInputWidget, reques
t)
>>> view1 = zapi.get
MultiAdapter((contactname, request), IInputWidge
t)
>>> view1.__class__ == TextWidget
True
>>> view2 = zapi.get
ViewProviding(salutation, IInputWidget, reques
t)
>>> view2 = zapi.get
MultiAdapter((salutation, request), IInputWidge
t)
>>> view2.__class__ == DropdownWidget
True
Clean up:
>>> from zope.app.test
s
.placelesssetup import tearDown
>>> from zope.app.test
ing
.placelesssetup import tearDown
>>> tearDown()
"""
def
test_suite
():
import
unittest
from
Testing.ZopeTestCase
import
ZopeDocTestSuite
,
FunctionalDocFileSuite
from
zope.testing.doctest
import
DocTestSuite
from
Testing.ZopeTestCase
import
FunctionalDocFileSuite
return
unittest
.
TestSuite
((
Zope
DocTestSuite
(),
DocTestSuite
(),
FunctionalDocFileSuite
(
'forms.txt'
,
package
=
"Products.Five.form.tests"
,),
))
...
...
lib/python/Products/Five/i18n.py
View file @
528f46df
...
...
@@ -13,15 +13,21 @@
##############################################################################
"""Mimick Zope3 i18n machinery for Zope 2
$Id: i18n.py 1
4400 2005-07-07 17:55:0
8Z philikon $
$Id: i18n.py 1
9435 2005-11-02 16:34:5
8Z philikon $
"""
from
Acquisition
import
aq_acquire
from
zope.interface
import
implements
from
zope.i18n
import
interpolate
from
zope.i18n.interfaces
import
ITranslationDomain
,
IUserPreferredLanguages
from
zope.i18nmessageid
import
MessageID
from
zope.app
import
zapi
from
zope.publisher.browser
import
BrowserLanguages
# BBB 2005/10/10 -- MessageIDs are to be removed for Zope 3.3
import
zope.deprecation
zope
.
deprecation
.
__show__
.
off
()
from
zope.i18nmessageid
import
MessageID
,
Message
zope
.
deprecation
.
__show__
.
on
()
class
FiveTranslationService
:
"""Translation service that delegates to ``zope.i18n`` machinery.
"""
...
...
@@ -29,7 +35,7 @@ class FiveTranslationService:
# regarding fallback and Zope 2 compatability
def
translate
(
self
,
domain
,
msgid
,
mapping
=
None
,
context
=
None
,
target_language
=
None
,
default
=
None
):
if
isinstance
(
msgid
,
MessageID
):
if
isinstance
(
msgid
,
(
Message
,
MessageID
)
):
domain
=
msgid
.
domain
default
=
msgid
.
default
mapping
=
msgid
.
mapping
...
...
@@ -46,7 +52,7 @@ class FiveTranslationService:
# in Zope3, context is adapted to IUserPreferredLanguages,
# which means context should be the request in this case.
if
context
is
not
None
:
context
=
context
.
REQUEST
context
=
aq_acquire
(
context
,
'REQUEST'
,
None
)
return
util
.
translate
(
msgid
,
mapping
=
mapping
,
context
=
context
,
target_language
=
target_language
,
default
=
default
)
...
...
lib/python/Products/Five/interfaces.py
View file @
528f46df
...
...
@@ -13,7 +13,7 @@
##############################################################################
"""Five interfaces
$Id: interfaces.py 1
4613 2005-07-13 10:39:05
Z philikon $
$Id: interfaces.py 1
9283 2005-10-31 17:43:51
Z philikon $
"""
from
zope.interface
import
Interface
from
zope.interface.interfaces
import
IInterface
...
...
@@ -33,23 +33,3 @@ class IMenuItemType(IInterface):
Menu item types are interfaces that define classes of
menu items.
"""
#
# BBB: Zope core interfaces
#
# The interfaces here are only provided for backwards compatibility and will
# be removed in Five 1.2. Please import interfaces from the corresponding Zope
# package instead.
#
from
persistent.interfaces
import
IPersistent
from
AccessControl.interfaces
import
*
from
Acquisition.interfaces
import
*
from
App.interfaces
import
*
from
OFS.interfaces
import
*
from
webdav.interfaces
import
*
# BBB: for old names used in Five 1.0
IAcquisition
=
IAcquirer
IPermissionMapping
=
IPermissionMappingSupport
lib/python/Products/Five/interfaces.zcml
deleted
100644 → 0
View file @
ce126e73
<configure xmlns="http://namespaces.zope.org/five">
<!-- IPersistent, IPersistentExtra -->
<!-- Acquisition -->
<implements
class="Acquisition.ImplicitAcquisitionWrapper"
interface="Acquisition.interfaces.IAcquisitionWrapper"
/>
<implements
class="Acquisition.ExplicitAcquisitionWrapper"
interface="Acquisition.interfaces.IAcquisitionWrapper"
/>
<implements
class="Acquisition.Implicit"
interface="Acquisition.interfaces.IAcquirer"
/>
<implements
class="Acquisition.Explicit"
interface="Acquisition.interfaces.IAcquirer"
/>
<!-- DAV -->
<implements
class="webdav.Lockable.LockableItem"
interface="webdav.interfaces.IWriteLock"
/>
<implements
class="webdav.Resource.Resource"
interface="webdav.interfaces.IDAVResource"
/>
<implements
class="webdav.Collection.Collection"
interface="webdav.interfaces.IDAVCollection"
/>
<!-- OFS -->
<implements
class="OFS.CopySupport.CopySource"
interface="OFS.interfaces.ICopySource"
/>
<implements
class="OFS.CopySupport.CopyContainer"
interface="OFS.interfaces.ICopyContainer"
/>
<implements
class="OFS.Traversable.Traversable"
interface="OFS.interfaces.ITraversable"
/>
<implements
class="OFS.SimpleItem.Item"
interface="OFS.interfaces.IItem"
/>
<implements
class="OFS.SimpleItem.Item_w__name__"
interface="OFS.interfaces.IItemWithName"
/>
<implements
class="OFS.SimpleItem.SimpleItem"
interface="OFS.interfaces.ISimpleItem"
/>
<implements
class="OFS.ObjectManager.ObjectManager"
interface="OFS.interfaces.IObjectManager"
/>
<implements
class="OFS.PropertyManager.PropertyManager"
interface="OFS.interfaces.IPropertyManager"
/>
<implements
class="OFS.FindSupport.FindSupport"
interface="OFS.interfaces.IFindSupport"
/>
<implements
class="OFS.Folder.Folder"
interface="OFS.interfaces.IFolder"
/>
<implements
class="OFS.OrderSupport.OrderSupport"
interface="OFS.interfaces.IOrderedContainer"
/>
<implements
class="OFS.OrderedFolder.OrderedFolder"
interface="OFS.interfaces.IOrderedFolder"
/>
<implements
class="OFS.Application.Application"
interface="OFS.interfaces.IApplication"
/>
<!-- App -->
<implements
class="App.Undo.UndoSupport"
interface="App.interfaces.IUndoSupport"
/>
<implements
class="App.Management.Navigation"
interface="App.interfaces.INavigation"
/>
<!-- AccessControl -->
<implements
class="AccessControl.Owned.Owned"
interface="AccessControl.interfaces.IOwned"
/>
<implements
class="AccessControl.PermissionMapping.RoleManager"
interface="AccessControl.interfaces.IPermissionMappingSupport"
/>
<implements
class="AccessControl.Role.RoleManager"
interface="AccessControl.interfaces.IRoleManager"
/>
</configure>
lib/python/Products/Five/meta.zcml
View file @
528f46df
...
...
@@ -2,13 +2,10 @@
xmlns="http://namespaces.zope.org/zope"
xmlns:meta="http://namespaces.zope.org/meta">
<include package=".site" file="meta.zcml" />
<include package=".browser" file="meta.zcml" />
<include package=".form" file="meta.zcml" />
<!-- load the zope:modulealias and zope:hook directives -->
<include package="zope.modulealias" file="meta.zcml" />
<include package="zope.configuration" file="meta.zcml" />
<meta:directives namespace="http://namespaces.zope.org/zope">
<meta:directive
...
...
@@ -53,18 +50,6 @@
handler="zope.app.component.metaconfigure.factory"
/>
<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"
...
...
@@ -131,14 +116,20 @@
/>
<meta:directive
name="sendEvents"
schema=".fivedirectives.ISendEventsDirective"
handler=".eventconfigure.sendEvents"
name="containerEvents"
schema=".fivedirectives.IContainerEventsDirective"
handler=".eventconfigure.containerEvents"
/>
<meta:directive
name="deprecatedManageAddDelete"
schema=".fivedirectives.IDeprecatedManageAddDeleteDirective"
handler=".eventconfigure.deprecatedManageAddDelete"
/>
<meta:directive
name="sizable"
schema=".fivedirectives.IS
endEvents
Directive"
schema=".fivedirectives.IS
izable
Directive"
handler=".sizeconfigure.sizable"
/>
...
...
@@ -148,20 +139,18 @@
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:directive
name="registerClass"
schema=".fivedirectives.IRegisterClassDirective"
handler=".fiveconfigure.registerClass"
/>
</meta:directives>
<meta:directive
...
...
@@ -171,6 +160,9 @@
handler="zope.app.security.metaconfigure.redefinePermission"
/>
<!-- load the zope:modulealias directive -->
<include package="zope.modulealias" file="meta.zcml" />
<!-- load the i18n:registerTranslations directive -->
<include package="zope.app.i18n" file="meta.zcml" />
...
...
lib/python/Products/Five/metaconfigure.py
View file @
528f46df
...
...
@@ -13,73 +13,25 @@
##############################################################################
"""Generic Components ZCML Handlers
$Id: metaconfigure.py 1
2884 2005-05-30 13:10:4
1Z philikon $
$Id: metaconfigure.py 1
9283 2005-10-31 17:43:5
1Z philikon $
"""
from
types
import
ModuleType
from
Products.Five.security
import
CheckerPublic
,
protectName
from
Globals
import
InitializeClass
as
initializeClass
from
zope.
interface
import
classImplements
from
zope.configuration.exceptions
import
ConfigurationError
from
zope.
app.component.contentdirective
import
ContentDirective
as
\
zope_app_ContentDirective
from
security
import
CheckerPublic
from
security
import
protectName
,
initializeClass
class
ContentDirective
:
def
__init__
(
self
,
_context
,
class_
):
self
.
__class
=
class_
if
isinstance
(
self
.
__class
,
ModuleType
):
raise
ConfigurationError
(
'Content class attribute must be a class'
)
self
.
__context
=
_context
def
implements
(
self
,
_context
,
interface
):
for
interface
in
interface
:
_context
.
action
(
discriminator
=
(
'five::directive:content'
,
self
.
__class
,
object
()),
callable
=
classImplements
,
args
=
(
self
.
__class
,
interface
),
)
interface
(
_context
,
interface
)
def
require
(
self
,
_context
,
permission
=
None
,
attributes
=
None
,
interface
=
None
):
"""Require a the permission to access a specific aspect"""
if
not
(
interface
or
attributes
):
raise
ConfigurationError
(
"Nothing required"
)
if
interface
:
for
i
in
interface
:
if
i
:
self
.
__protectByInterface
(
i
,
permission
)
if
attributes
:
self
.
__protectNames
(
attributes
,
permission
)
def
allow
(
self
,
_context
,
attributes
=
None
,
interface
=
None
):
"""Like require, but with permission_id zope.Public"""
return
self
.
require
(
_context
,
CheckerPublic
,
attributes
,
interface
)
def
__protectByInterface
(
self
,
interface
,
permission_id
):
"Set a permission on names in an interface."
for
n
,
d
in
interface
.
namesAndDescriptions
(
1
):
self
.
__protectName
(
n
,
permission_id
)
interface
(
self
.
__context
,
interface
)
class
ContentDirective
(
zope_app_ContentDirective
):
def
__protectName
(
self
,
name
,
permission_id
):
"Set a permission on a particular name."
self
.
__context
.
action
(
discriminator
=
(
'five:protectName'
,
self
.
__class
,
name
),
callable
=
protectName
,
args
=
(
self
.
__class
,
name
,
permission_id
)
)
def
__protectNames
(
self
,
names
,
permission_id
):
"Set a permission on a bunch of names."
for
name
in
names
:
self
.
__protectName
(
name
,
permission_id
)
def
__call__
(
self
):
"
Handle empty/simple declaration.
"
"
""Handle empty/simple declaration.""
"
return
self
.
__context
.
action
(
discriminator
=
(
'five:initialize:class'
,
self
.
__class
),
callable
=
initializeClass
,
...
...
lib/python/Products/Five/permissions.zcml
View file @
528f46df
<configure xmlns="http://namespaces.zope.org/zope"
i18n_domain="Five">
<permission
id="five.ManageSite"
title="Manage Five local sites"
/>
<!-- Give common Zope2 and CMF permissions a permission ID
The title of the permission is what Zope 2 knows it under -->
...
...
lib/python/Products/Five/security.py
View file @
528f46df
...
...
@@ -24,7 +24,7 @@ from zope.app.security.interfaces import IPermission
from
zope.app
import
zapi
from
AccessControl
import
ClassSecurityInfo
,
getSecurityManager
from
Globals
import
InitializeClass
from
Globals
import
InitializeClass
as
initializeClass
from
types
import
StringTypes
CheckerPublicId
=
'zope.Public'
...
...
@@ -99,9 +99,6 @@ def newInteraction():
if
getattr
(
thread_local
,
'interaction'
,
None
)
is
None
:
thread_local
.
interaction
=
FiveSecurityPolicy
()
def
initializeClass
(
klass
):
InitializeClass
(
klass
)
def
_getSecurity
(
klass
):
# a Zope 2 class can contain some attribute that is an instance
# of ClassSecurityInfo. Zope 2 scans through things looking for
...
...
@@ -121,15 +118,12 @@ def protectName(klass, name, permission_id):
"""Protect the attribute 'name' on 'klass' using the given
permission"""
security
=
_getSecurity
(
klass
)
# XXX: Sometimes, the object CheckerPublic is used instead of the
# string zope.Public. I haven't ben able to figure out why, or if
# it is correct, or a bug. So this is a workaround.
if
permission_id
is
CheckerPublic
:
security
.
declarePublic
(
name
)
return
# Zope 2 uses string, not unicode yet
name
=
str
(
name
)
if
permission_id
==
CheckerPublicId
:
if
permission_id
==
CheckerPublicId
or
permission_id
is
CheckerPublic
:
# Sometimes, we already get a processed permission id, which
# can mean that 'zope.Public' has been interchanged for the
# CheckerPublic object
security
.
declarePublic
(
name
)
elif
permission_id
==
CheckerPrivateId
:
security
.
declarePrivate
(
name
)
...
...
@@ -142,7 +136,10 @@ def protectName(klass, name, permission_id):
def
protectClass
(
klass
,
permission_id
):
"""Protect the whole class with the given permission"""
security
=
_getSecurity
(
klass
)
if
permission_id
==
CheckerPublicId
:
if
permission_id
==
CheckerPublicId
or
permission_id
is
CheckerPublic
:
# Sometimes, we already get a processed permission id, which
# can mean that 'zope.Public' has been interchanged for the
# CheckerPublic object
security
.
declareObjectPublic
()
elif
permission_id
==
CheckerPrivateId
:
security
.
declareObjectPrivate
()
...
...
lib/python/Products/Five/services.zcml
deleted
100644 → 0
View file @
ce126e73
<configure xmlns="http://namespaces.zope.org/zope">
<serviceType
id="Utilities"
interface="zope.component.interfaces.IUtilityService" />
<service
serviceType="Utilities"
factory="zope.component.utility.GlobalUtilityService" />
<serviceType
id="Adapters"
interface="zope.component.interfaces.IAdapterService" />
<service
serviceType="Adapters"
factory="zope.component.adapter.GlobalAdapterService" />
<serviceType
id="Presentation"
interface="zope.component.interfaces.IPresentationService" />
<service
serviceType="Presentation"
factory="zope.component.presentation.GlobalPresentationService" />
</configure>
lib/python/Products/Five/site/__init__.py
0 → 100644
View file @
528f46df
# make this directory a package
lib/python/Products/Five/site/browser.py
0 → 100644
View file @
528f46df
##############################################################################
#
# Copyright (c) 2005 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.
#
##############################################################################
"""Local sites browser views
$Id$
"""
from
zope.app.component.interfaces
import
ISite
from
zope.app.component.hooks
import
clearSite
from
Products.Five.browser
import
BrowserView
from
Products.Five.site.localsite
import
enableLocalSiteHook
,
\
disableLocalSiteHook
class
LocalSiteView
(
BrowserView
):
"""View for convering a possible site to a site
"""
def
update
(
self
):
form
=
self
.
request
.
form
if
form
.
has_key
(
'UPDATE_MAKESITE'
):
self
.
makeSite
()
elif
form
.
has_key
(
'UPDATE_UNMAKESITE'
):
self
.
unmakeSite
()
def
isSite
(
self
):
return
ISite
.
providedBy
(
self
.
context
)
def
makeSite
(
self
):
"""Convert a possible site to a site"""
if
self
.
isSite
():
raise
ValueError
(
'This is already a site'
)
enableLocalSiteHook
(
self
.
context
)
return
"This object is now a site"
def
unmakeSite
(
self
):
"""Convert a site to a possible site"""
if
not
self
.
isSite
():
raise
ValueError
(
'This is not a site'
)
disableLocalSiteHook
(
self
.
context
)
# disableLocalSiteHook circumcised our context so that it's
# not an ISite anymore. That can mean that certain things for
# it can't be found anymore. So, for the rest of this request
# (which will be over in about 20 CPU cycles), already clear
# the local site from the thread local.
clearSite
()
return
"This object is no longer a site"
lib/python/Products/Five/site/configure.zcml
0 → 100644
View file @
528f46df
<configure xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
<adapter
for="*"
provides="zope.component.interfaces.ISiteManager"
factory=".localsite.siteManagerAdapter"
/>
<adapter
for="zope.app.site.interfaces.ISite"
provides=".interfaces.IFiveUtilityRegistry"
factory=".utility.SimpleLocalUtilityRegistry"
/>
<subscriber
for="zope.app.component.interfaces.ISite
zope.app.publication.interfaces.IBeforeTraverseEvent"
handler="zope.app.component.site.threadSiteSubscriber"
/>
<subscriber
for="zope.app.publication.interfaces.IEndRequestEvent"
handler="zope.app.component.site.clearThreadSiteSubscriber"
/>
<browser:page
for="zope.app.component.interfaces.IPossibleSite"
name="manage_site.html"
permission="five.ManageSite"
class=".browser.LocalSiteView"
template="managesite.pt"
/>
</configure>
lib/python/Products/Five/site/interfaces.py
0 → 100644
View file @
528f46df
##############################################################################
#
# Copyright (c) 2004, 2005 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.
#
##############################################################################
"""Five interfaces
$Id: interfaces.py 18584 2005-10-14 17:13:27Z regebro $
"""
from
zope.interface
import
Interface
,
Attribute
from
zope.component.interfaces
import
ISiteManager
class
IRegisterUtilitySimply
(
Interface
):
"""Register utilities simply
Allow local registrations of utilities, in a much simpler
manner than Zope 3 does it currently.
Note: The name of this interface is expressed as a verb
(describing the action it expresses, namely registering
utilities). The reason for that is that the names *utility
registry* (successor of the Zope 3 utility service) and *utility
registration* (object in a registration stack, part of the
complicated registration framework in Zope 3) have different
connotations in Zope 3 than we want to express here.
"""
def
registerUtility
(
self
,
interface
,
utility
,
name
=
''
):
"""Registers a utility in the local context"""
# TODO Define an exception than is to be thrown when a local
# utility of that interface and name is already registered.
next
=
Attribute
(
"The next local registry in the tree. This attribute "
"represents the parent of this registry node. If the "
"value is ``None``, then this registry represents the "
"root of the tree"
)
class
IFiveUtilityRegistry
(
IRegisterUtilitySimply
):
"""Look up and register utilities"""
def
getUtility
(
interface
,
name
=
''
,
context
=
None
):
"""Get the utility that provides interface
Returns the nearest utility to the context that implements the
specified interface. If one is not found, raises
ComponentLookupError.
"""
def
queryUtility
(
interface
,
name
=
''
,
default
=
None
,
context
=
None
):
"""Look for the utility that provides interface
Returns the nearest utility to the context that implements
the specified interface. If one is not found, returns default.
"""
def
getUtilitiesFor
(
interface
,
context
=
None
):
"""Return the utilities that provide an interface
An iterable of utility name-value pairs is returned.
"""
def
getAllUtilitiesRegisteredFor
(
interface
,
context
=
None
):
"""Return all registered utilities for an interface
This includes overridden utilities.
An iterable of utility instances is returned. No names are
returned.
"""
class
IFiveSiteManager
(
ISiteManager
,
IRegisterUtilitySimply
):
"""Five site manager
For the sake of forward-portability, registering utilities can be
done directly on the site manager to cut out the middle man called
utility service (this corresponds to Zope 3.1's understanding of
site managers). An implementation of this interface will probably
delegate the work to an IFiveUtilityService component, though."""
# BBB 2005/11/01 -- gone in Five 1.5.
IFiveUtilityService
=
IFiveUtilityRegistry
import
zope.deprecation
zope
.
deprecation
.
deprecated
(
'IFiveUtilityService'
,
"'IFiveUtilityService' has been renamed to "
"'IFiveUtilityRegistry' and will disappear in Five 1.5."
)
lib/python/Products/Five/site/localsite.py
0 → 100644
View file @
528f46df
##############################################################################
#
# Copyright (c) 2005 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.
#
##############################################################################
"""Local sites
$Id$
"""
from
zope.event
import
notify
from
zope.interface
import
directlyProvides
,
directlyProvidedBy
from
zope.interface
import
implements
from
zope.component
import
getGlobalSiteManager
from
zope.component.exceptions
import
ComponentLookupError
from
zope.app.component.interfaces
import
ISite
,
IPossibleSite
from
zope.app.publication.zopepublication
import
BeforeTraverseEvent
from
ExtensionClass
import
Base
from
Acquisition
import
aq_base
,
aq_inner
,
aq_parent
from
Products.SiteAccess.AccessRule
import
AccessRule
from
ZPublisher.BeforeTraverse
import
registerBeforeTraverse
from
ZPublisher.BeforeTraverse
import
unregisterBeforeTraverse
from
Products.Five.site.interfaces
import
IFiveSiteManager
,
IFiveUtilityRegistry
# Hook up custom component architecture calls
import
zope.app.component.hooks
zope
.
app
.
component
.
hooks
.
setHooks
()
def
siteManagerAdapter
(
ob
):
"""An adapter * -> ISiteManager.
This is registered in place of the one in Zope 3 so that we lookup
using acquisition instead of ILocation.
"""
current
=
ob
while
True
:
if
ISite
.
providedBy
(
current
):
return
current
.
getSiteManager
()
current
=
getattr
(
current
,
'__parent__'
,
aq_parent
(
aq_inner
(
current
)))
if
current
is
None
:
# It does not support acquisition or has no parent, so we
# return the global site
return
getGlobalSiteManager
()
HOOK_NAME
=
'__local_site_hook__'
class
LocalSiteHook
(
Base
):
def
__call__
(
self
,
container
,
request
):
notify
(
BeforeTraverseEvent
(
container
,
request
))
def
enableLocalSiteHook
(
obj
):
"""Install __before_traverse__ hook for Local Site
"""
# We want the original object, not stuff in between, and no acquisition
obj
=
aq_base
(
obj
)
if
not
IPossibleSite
.
providedBy
(
obj
):
raise
TypeError
,
'Must provide IPossibleSite'
hook
=
AccessRule
(
HOOK_NAME
)
registerBeforeTraverse
(
obj
,
hook
,
HOOK_NAME
,
1
)
if
not
hasattr
(
obj
,
HOOK_NAME
):
setattr
(
obj
,
HOOK_NAME
,
LocalSiteHook
())
directlyProvides
(
obj
,
ISite
,
directlyProvidedBy
(
obj
))
def
disableLocalSiteHook
(
obj
):
"""Remove __before_traverse__ hook for Local Site
"""
# We want the original object, not stuff in between, and no acquisition
obj
=
aq_base
(
obj
)
if
not
ISite
.
providedBy
(
obj
):
raise
TypeError
,
'Must provide ISite'
unregisterBeforeTraverse
(
obj
,
HOOK_NAME
)
if
hasattr
(
obj
,
HOOK_NAME
):
delattr
(
obj
,
HOOK_NAME
)
directlyProvides
(
obj
,
directlyProvidedBy
(
obj
)
-
ISite
)
class
FiveSiteManager
(
object
):
implements
(
IFiveSiteManager
)
def
__init__
(
self
,
context
):
# make {get|query}NextSiteManager() work without having to
# resort to Zope 2 acquisition
self
.
context
=
self
.
__parent__
=
context
@
property
def
next
(
self
):
obj
=
self
.
context
while
obj
is
not
None
:
obj
=
aq_parent
(
aq_inner
(
obj
))
if
ISite
.
providedBy
(
obj
):
return
obj
.
getSiteManager
()
# In Zope 3.1+, returning None here is understood by
# getNextSiteManager as that our next site manager is the
# global one. If we returned the global one, it would be
# understood as a lookup error. Yeah, it's weird, tell me
# about it.
return
None
@
property
def
adapters
(
self
):
return
getGlobalSiteManager
().
adapters
#XXX wrong
@
property
def
utilities
(
self
):
return
IFiveUtilityRegistry
(
self
.
context
)
def
queryAdapter
(
self
,
object
,
interface
,
name
,
default
=
None
):
return
self
.
adapters
.
queryAdapter
(
object
,
interface
,
name
,
default
)
def
queryMultiAdapter
(
self
,
objects
,
interface
,
name
,
default
=
None
):
return
self
.
adapters
.
queryMultiAdapter
(
objects
,
interface
,
name
,
default
)
def
getAdapters
(
self
,
objects
,
provided
):
return
self
.
adapters
.
getAdapters
(
objects
,
provided
)
def
subscribers
(
self
,
required
,
provided
):
return
self
.
adapters
.
subscribers
(
required
,
provided
)
def
queryUtility
(
self
,
interface
,
name
=
''
,
default
=
None
):
return
self
.
utilities
.
queryUtility
(
interface
,
name
,
default
)
def
getUtilitiesFor
(
self
,
interface
):
return
self
.
utilities
.
getUtilitiesFor
(
interface
)
def
getAllUtilitiesRegisteredFor
(
self
,
interface
):
return
self
.
utilities
.
getAllUtilitiesRegisteredFor
(
interface
)
def
registerUtility
(
self
,
interface
,
utility
,
name
=
''
):
return
self
.
utilities
.
registerUtility
(
interface
,
utility
,
name
)
class
FiveSite
:
implements
(
IPossibleSite
)
def
getSiteManager
(
self
):
return
FiveSiteManager
(
self
)
def
setSiteManager
(
self
,
sm
):
raise
NotImplementedError
(
'This class has a fixed site manager'
)
lib/python/Products/Five/site/managesite.pt
0 → 100644
View file @
528f46df
<tal:tag
condition=
"view/update"
/>
<html
metal:use-macro=
"context/@@standard_macros/view"
i18n:domain=
"zope"
>
<body>
<div
metal:fill-slot=
"body"
>
<form
action=
"."
tal:attributes=
"action request/URL"
method=
"POST"
enctype=
"multipart/form-data"
>
<div
class=
"row"
>
<div
class=
"controls"
>
<input
type=
"submit"
value=
"Make site"
name=
"UPDATE_MAKESITE"
i18n:attributes=
"value"
tal:attributes=
"disabled view/isSite"
/>
<input
type=
"submit"
value=
"Unmake site"
name=
"UPDATE_UNMAKESITE"
i18n:attributes=
"value"
tal:attributes=
"disabled not:view/isSite"
/>
</div>
</div>
</form>
</div>
</body>
</html>
lib/python/Products/Five/site/meta.zcml
0 → 100644
View file @
528f46df
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:meta="http://namespaces.zope.org/meta">
<meta:directives namespace="http://namespaces.zope.org/five">
<meta:directive
name="localsite"
schema=".metadirectives.ILocalSiteDirective"
handler=".metaconfigure.installSiteHook"
/>
</meta:directives>
</configure>
lib/python/Products/Five/site/metaconfigure.py
0 → 100644
View file @
528f46df
##############################################################################
#
# Copyright (c) 2004, 2005 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.
#
##############################################################################
"""Five-specific directive handlers
These directives are specific to Five and have no equivalents in Zope 3.
$Id: fiveconfigure.py 18581 2005-10-14 16:54:25Z regebro $
"""
from
zope.interface
import
classImplements
,
classImplementsOnly
,
implementedBy
from
zope.interface.interface
import
InterfaceClass
from
zope.configuration.exceptions
import
ConfigurationError
from
zope.app.component.metaconfigure
import
adapter
from
zope.app.component.interfaces
import
IPossibleSite
from
Products.Five.site.localsite
import
FiveSite
def
classSiteHook
(
class_
,
site_class
):
setattr
(
class_
,
'getSiteManager'
,
site_class
.
getSiteManager
.
im_func
)
setattr
(
class_
,
'setSiteManager'
,
site_class
.
setSiteManager
.
im_func
)
_localsite_monkies
=
[]
def
installSiteHook
(
_context
,
class_
,
site_class
=
None
):
if
site_class
is
None
:
if
not
IPossibleSite
.
implementedBy
(
class_
):
# This is not a possible site, we need to monkey-patch it so that
# it is.
site_class
=
FiveSite
else
:
if
not
IPossibleSite
.
implementedBy
(
site_class
):
raise
ConfigurationError
(
'Site class does not implement '
'IPossibleClass: %s'
%
site_class
)
if
site_class
is
not
None
:
_context
.
action
(
discriminator
=
(
class_
,),
callable
=
classSiteHook
,
args
=
(
class_
,
site_class
)
)
_context
.
action
(
discriminator
=
(
class_
,
IPossibleSite
),
callable
=
classImplements
,
args
=
(
class_
,
IPossibleSite
)
)
_localsite_monkies
.
append
(
class_
)
# clean up code
def
uninstallSiteHooks
():
for
class_
in
_localsite_monkies
:
delattr
(
class_
,
'getSiteManager'
)
delattr
(
class_
,
'setSiteManager'
)
classImplementsOnly
(
class_
,
implementedBy
(
class_
)
-
IPossibleSite
)
_localsite_monkies
.
remove
(
class_
)
from
zope.testing.cleanup
import
addCleanUp
addCleanUp
(
uninstallSiteHooks
)
del
addCleanUp
lib/python/Products/Five/
tests/test_import_conflict
s.py
→
lib/python/Products/Five/
site/metadirective
s.py
View file @
528f46df
...
...
@@ -11,30 +11,26 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
Test import conflict
s
"""
Site support ZCML directive schema
s
$Id:
test_import_conflicts.py 18150 2005-10-04 16:19:49Z philikon
$
$Id:
fivedirectives.py 18581 2005-10-14 16:54:25Z regebro
$
"""
import
os
,
sys
if
__name__
==
'__main__'
:
execfile
(
os
.
path
.
join
(
sys
.
path
[
0
],
'framework.py'
))
from
zope.interface
import
Interface
from
zope.configuration.fields
import
GlobalObject
def
testImportConflicts
():
"""
In a Five environment, importing Zope 3 packages that would use
interfaces from the Zope 3 transaction module would lead to an
error, because of the monkey patching. The zope.app.mail package
makes use of transaction interfaces, for example the following
class:
>>> from zope.app.mail.delivery import QueueProcessorThread
class
ILocalSiteDirective
(
Interface
):
"""Make instances of class hookable for Site.
Note that this only concerns Zope 2.7 and Zope X3 3.0.
site_class is an implementation of ISite, which will have it's methods
monkey_patched into the the class. If not given a default implementation
will be used.
"""
class_
=
GlobalObject
(
title
=
u"Class"
,
required
=
True
)
def
test_suite
():
from
Testing.ZopeTestCase
import
ZopeDocTestSuite
return
ZopeDocTestSuite
()
if
__name__
==
'__main__'
:
framework
()
site_class
=
GlobalObject
(
title
=
u"Site Class"
,
required
=
False
)
lib/python/Products/Five/site/tests/__init__.py
0 → 100644
View file @
528f46df
# make this directory a package
lib/python/Products/Five/site/tests/dummy.py
0 → 100644
View file @
528f46df
##############################################################################
#
# Copyright (c) 2005 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.
#
##############################################################################
"""Dummy test fixtures
$Id$
"""
from
zope.interface
import
implements
,
Interface
from
OFS.SimpleItem
import
SimpleItem
from
Products.Five.tests.testing
import
FiveTraversableFolder
class
IDummySite
(
Interface
):
pass
class
DummySite
(
FiveTraversableFolder
):
"""A very dummy Site
"""
implements
(
IDummySite
)
def
manage_addDummySite
(
self
,
id
,
REQUEST
=
None
):
"""Add the dummy site."""
id
=
self
.
_setObject
(
id
,
DummySite
(
id
))
return
''
class
IDummyUtility
(
Interface
):
pass
class
ISuperDummyUtility
(
IDummyUtility
):
pass
class
DummyUtility
(
SimpleItem
):
implements
(
IDummyUtility
)
lib/python/Products/Five/site/tests/framework.py
0 → 100644
View file @
528f46df
##############################################################################
#
# ZopeTestCase
#
# COPY THIS FILE TO YOUR 'tests' DIRECTORY.
#
# This version of framework.py will use the SOFTWARE_HOME
# environment variable to locate Zope and the Testing package.
#
# If the tests are run in an INSTANCE_HOME installation of Zope,
# Products.__path__ and sys.path with be adjusted to include the
# instance's Products and lib/python directories respectively.
#
# If you explicitly set INSTANCE_HOME prior to running the tests,
# auto-detection is disabled and the specified path will be used
# instead.
#
# If the 'tests' directory contains a custom_zodb.py file, INSTANCE_HOME
# will be adjusted to use it.
#
# If you set the ZEO_INSTANCE_HOME environment variable a ZEO setup
# is assumed, and you can attach to a running ZEO server (via the
# instance's custom_zodb.py).
#
##############################################################################
#
# The following code should be at the top of every test module:
#
# import os, sys
# if __name__ == '__main__':
# execfile(os.path.join(sys.path[0], 'framework.py'))
#
# ...and the following at the bottom:
#
# if __name__ == '__main__':
# framework()
#
##############################################################################
__version__
=
'0.2.3'
# Save start state
#
__SOFTWARE_HOME
=
os
.
environ
.
get
(
'SOFTWARE_HOME'
,
''
)
__INSTANCE_HOME
=
os
.
environ
.
get
(
'INSTANCE_HOME'
,
''
)
if
__SOFTWARE_HOME
.
endswith
(
os
.
sep
):
__SOFTWARE_HOME
=
os
.
path
.
dirname
(
__SOFTWARE_HOME
)
if
__INSTANCE_HOME
.
endswith
(
os
.
sep
):
__INSTANCE_HOME
=
os
.
path
.
dirname
(
__INSTANCE_HOME
)
# Find and import the Testing package
#
if
not
sys
.
modules
.
has_key
(
'Testing'
):
p0
=
sys
.
path
[
0
]
if
p0
and
__name__
==
'__main__'
:
os
.
chdir
(
p0
)
p0
=
''
s
=
__SOFTWARE_HOME
p
=
d
=
s
and
s
or
os
.
getcwd
()
while
d
:
if
os
.
path
.
isdir
(
os
.
path
.
join
(
p
,
'Testing'
)):
zope_home
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
p
))
sys
.
path
[:
1
]
=
[
p0
,
p
,
zope_home
]
break
p
,
d
=
s
and
(
''
,
''
)
or
os
.
path
.
split
(
p
)
else
:
print
'Unable to locate Testing package.'
,
print
'You might need to set SOFTWARE_HOME.'
sys
.
exit
(
1
)
import
Testing
,
unittest
execfile
(
os
.
path
.
join
(
os
.
path
.
dirname
(
Testing
.
__file__
),
'common.py'
))
# Include ZopeTestCase support
#
if
1
:
# Create a new scope
p
=
os
.
path
.
join
(
os
.
path
.
dirname
(
Testing
.
__file__
),
'ZopeTestCase'
)
if
not
os
.
path
.
isdir
(
p
):
print
'Unable to locate ZopeTestCase package.'
,
print
'You might need to install ZopeTestCase.'
sys
.
exit
(
1
)
ztc_common
=
'ztc_common.py'
ztc_common_global
=
os
.
path
.
join
(
p
,
ztc_common
)
f
=
0
if
os
.
path
.
exists
(
ztc_common_global
):
execfile
(
ztc_common_global
)
f
=
1
if
os
.
path
.
exists
(
ztc_common
):
execfile
(
ztc_common
)
f
=
1
if
not
f
:
print
'Unable to locate %s.'
%
ztc_common
sys
.
exit
(
1
)
# Debug
#
print
'SOFTWARE_HOME: %s'
%
os
.
environ
.
get
(
'SOFTWARE_HOME'
,
'Not set'
)
print
'INSTANCE_HOME: %s'
%
os
.
environ
.
get
(
'INSTANCE_HOME'
,
'Not set'
)
sys
.
stdout
.
flush
()
lib/python/Products/Five/site/tests/functional.txt
0 → 100644
View file @
528f46df
Functional test for local sites
===============================
Set up all of Five:
>>> import Products.Five
>>> from Products.Five import zcml
>>> zcml.load_config("configure.zcml", Products.Five)
First we turn our DummySite class into a site in ZCML (and register
some views that will provide us with some test info),
>>> zcml_text = """
... <configure xmlns="http://namespaces.zope.org/zope"
... xmlns:meta="http://namespaces.zope.org/meta"
... xmlns:five="http://namespaces.zope.org/five"
... xmlns:browser="http://namespaces.zope.org/browser">
...
... <!-- make the zope2.Public permission work -->
... <meta:redefinePermission from="zope2.Public" to="zope.Public" />
...
... <five:localsite class="Products.Five.site.tests.dummy.DummySite" />
...
... <browser:page
... for="Products.Five.site.tests.dummy.IDummySite"
... name="checkSiteManager.html"
... class="Products.Five.site.tests.test_functional.CheckSiteManagerView"
... permission="zope2.Public"
... />
...
... <browser:page
... for="Products.Five.site.tests.dummy.IDummySite"
... name="lookupUtilities.html"
... class="Products.Five.site.tests.test_functional.LookupUtilitiesView"
... permission="zope2.Public"
... />
...
... </configure>"""
>>> zcml.load_string(zcml_text)
then we add an instance to our folder:
>>> from Products.Five.site.tests.dummy import manage_addDummySite
>>> nothing = manage_addDummySite(self.folder, 'site')
Now we check what the info view tells us about local component lookup:
>>> print http(r'''
... GET /test_folder_1_/site/@@checkSiteManager.html HTTP/1.1
... ''')
HTTP/1.1 200 OK
...
{'IFiveUtilityRegistry.providedBy(utility_service)': False,
'isinstance(zapi.getSiteManager(), FiveSiteManager)': False,
'zapi.getSiteManager() is zapi.getGlobalSiteManager()': True}
We see that we have no local component lookup yet, because we haven't
set the site. Therefore, enable the traversal hook by using the view
that's provided for this task (we first need to create a manager
account in order to be able to access it):
>>> uf = self.folder.acl_users
>>> uf._doAddUser('manager', 'r00t', ['Manager'], [])
>>> print http(r'''
... POST /test_folder_1_/site/@@manage_site.html HTTP/1.1
... Authorization: Basic manager:r00t
... Content-Length: 25
...
... UPDATE_MAKESITE=Make site''')
HTTP/1.1 200 OK
...
Now we call the info view again and find that local component lookup
is working:
>>> print http(r'''
... GET /test_folder_1_/site/@@checkSiteManager.html HTTP/1.1
... ''')
HTTP/1.1 200 OK
...
{'IFiveUtilityRegistry.providedBy(utility_service)': True,
'isinstance(zapi.getSiteManager(), FiveSiteManager)': True,
'zapi.getSiteManager() is zapi.getGlobalSiteManager()': False}
Of course, sites are only active *during* traversal; after traversal
they're gone:
>>> from zope.app.component.hooks import getSite
>>> getSite() is None
True
We can also register utilities now:
>>> from zope.app import zapi
>>> sm = self.folder.site.getSiteManager()
>>> from Products.Five.site.tests.dummy import IDummyUtility, DummyUtility
>>> dummy = DummyUtility()
>>> sm.registerUtility(IDummyUtility, dummy)
and find them being looked up just fine:
>>> print http(r'''
... GET /test_folder_1_/site/@@lookupUtilities.html HTTP/1.1
... ''')
HTTP/1.1 200 OK
...
zapi.getUtility(IDummyUtility) == dummy: True
Of course, we can't look it up once the request has ended, because we
lose the local site setup:
>>> zapi.getUtility(IDummyUtility)
Traceback (most recent call last):
...
ComponentLookupError: (<InterfaceClass Products.Five.site.tests.dummy.IDummyUtility>, '')
At last we can "unmake" the site using the browser view provided by
Five:
>>> print http(r'''
... POST /test_folder_1_/site/@@manage_site.html HTTP/1.1
... Authorization: Basic manager:r00t
... Content-Length: 29
...
... UPDATE_UNMAKESITE=Unmake site''')
HTTP/1.1 200 OK
...
And everything is back to normal with respect to local component
lookup:
>>> print http(r'''
... GET /test_folder_1_/site/@@checkSiteManager.html HTTP/1.1
... ''')
HTTP/1.1 200 OK
...
{'IFiveUtilityRegistry.providedBy(utility_service)': False,
'isinstance(zapi.getSiteManager(), FiveSiteManager)': False,
'zapi.getSiteManager() is zapi.getGlobalSiteManager()': True}
Finally, global services and the monkeys:
>>> from zope.app.testing.placelesssetup import tearDown
>>> tearDown()
lib/python/Products/Five/site/tests/sitemanager.txt
0 → 100644
View file @
528f46df
Five Site Manager
=================
In this test we want to test Five's implementation of a site manager.
First, we need to set a few things up...
>>> from zope.app.testing.placelesssetup import setUp, tearDown
>>> setUp()
>>> import Products.Five
>>> from Products.Five import zcml
>>> zcml.load_config("meta.zcml", Products.Five)
>>> zcml.load_config("permissions.zcml", Products.Five)
>>> zcml.load_config("configure.zcml", Products.Five.site)
>>> zcml_text = """\
... <five:localsite
... xmlns:five="http://namespaces.zope.org/five"
... class="Products.Five.site.tests.dummy.DummySite" />"""
>>> zcml.load_string(zcml_text)
...for example some sort of site object:
>>> from Products.Five.site.tests.dummy import manage_addDummySite
>>> nothing = manage_addDummySite(self.folder, 'dummysite')
>>> dummysite = self.folder.dummysite
Local vs. global sites
----------------------
Let's make the possible site a real site:
>>> from Products.Five.site.localsite import enableLocalSiteHook
>>> enableLocalSiteHook(dummysite)
and tell Zope 3 about it:
>>> from zope.app.component.hooks import setSite, setHooks
>>> setSite(dummysite)
Also hook up custom component architecture calls; we need to do this
here because zope.app.component.hooks registers a cleanup with the
testing cleanup framework, so the hooks get torn down by
placelesssetup each time.
>>> setHooks()
That seems to have worked (we test this by using the context property
of FiveSiteManager):
>>> from zope.app import zapi
>>> zapi.getSiteManager().context == dummysite
True
Since there's no other local site in between this one and the global
one, the next one should be the global one. FiveSiteManager indicates
that to us by return ``None``:
>>> from zope.app import zapi
>>> zapi.getSiteManager().next is None
True
To the the Zope 3 API, this means the next site manager should be the
global one:
>>> from zope.app.component import getNextSiteManager
>>> getNextSiteManager(dummysite.getSiteManager()) is zapi.getGlobalSiteManager()
True
ISiteManager API
----------------
Site managers are supposed to have an ``adapters`` and a ``utilities``
attribute. Five's site manager simply passes through the global
adapter registry:
>>> zapi.getSiteManager().adapters is zapi.getGlobalSiteManager().adapters
True
The utility registry, however, is an ``IFiveUtilityRegistry``:
>>> from Products.Five.site.interfaces import IFiveUtilityRegistry
>>> IFiveUtilityRegistry.providedBy(zapi.getSiteManager().utilities)
True
The methods on registering and looking up utilities are covered by the
utility tests in depth. The methods on adapter look up are indirectly
covered in the functional test; view look up, for example, is adapter
look up.
Nesting sites
-------------
Let's set up another site to test nested sites:
>>> nothing = manage_addDummySite(self.folder.dummysite, 'subsite')
>>> subsite = self.folder.dummysite.subsite
Now we set the current site to the ``subsite``:
>>> enableLocalSiteHook(subsite)
>>> setSite(subsite)
When we call getServices() now, we get the correct site manager:
>>> zapi.getSiteManager().context == subsite
True
The "next" site is the less local one:
>>> zapi.getSiteManager().next.context == dummysite
True
The Zope 3 API for this agrees with that:
>>> getNextSiteManager(subsite.getSiteManager()).context == dummysite
True
Finally, some clean up:
>>> tearDown()
lib/python/Products/Five/site/tests/test_functional.py
0 → 100644
View file @
528f46df
##############################################################################
#
# Copyright (c) 2005 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.
#
##############################################################################
"""Test local sites
$Id$
"""
import
os
,
sys
if
__name__
==
'__main__'
:
execfile
(
os
.
path
.
join
(
sys
.
path
[
0
],
'framework.py'
))
import
pprint
from
zope.app
import
zapi
from
Products.Five
import
BrowserView
from
Products.Five.site.interfaces
import
IFiveUtilityRegistry
from
Products.Five.site.localsite
import
FiveSiteManager
from
Products.Five.site.tests.dummy
import
IDummyUtility
class
CheckSiteManagerView
(
BrowserView
):
def
__call__
(
self
):
sm
=
zapi
.
getSiteManager
()
result
=
{
'zapi.getSiteManager() is zapi.getGlobalSiteManager()'
:
sm
is
zapi
.
getGlobalSiteManager
(),
'IFiveUtilityRegistry.providedBy(utility_service)'
:
IFiveUtilityRegistry
.
providedBy
(
sm
.
utilities
),
'isinstance(zapi.getSiteManager(), FiveSiteManager)'
:
isinstance
(
sm
,
FiveSiteManager
),
}
return
pprint
.
pformat
(
result
)
class
LookupUtilitiesView
(
BrowserView
):
def
__call__
(
self
):
dummy
=
getattr
(
self
.
context
.
utilities
,
IDummyUtility
.
getName
())
return
"zapi.getUtility(IDummyUtility) == dummy: %s"
%
\
(
zapi
.
getUtility
(
IDummyUtility
)
==
dummy
)
def
test_suite
():
from
Testing.ZopeTestCase
import
FunctionalDocFileSuite
suite
=
FunctionalDocFileSuite
(
'functional.txt'
,
package
=
'Products.Five.site.tests'
)
suite
.
level
=
2
return
suite
if
__name__
==
'__main__'
:
framework
()
lib/python/Products/Five/site/tests/test_localsite.py
0 → 100644
View file @
528f46df
##############################################################################
#
# Copyright (c) 2005 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.
#
##############################################################################
"""Test local sites
$Id$
"""
import
os
,
sys
if
__name__
==
'__main__'
:
execfile
(
os
.
path
.
join
(
sys
.
path
[
0
],
'framework.py'
))
import
unittest
from
Testing
import
ZopeTestCase
from
zope.interface
import
implements
from
zope.interface
import
directlyProvides
,
directlyProvidedBy
from
zope.component
import
getGlobalSiteManager
,
getSiteManager
from
zope.component.exceptions
import
ComponentLookupError
from
zope.component.interfaces
import
ISiteManager
from
zope.app.component.hooks
import
setSite
,
getSite
,
setHooks
from
zope.app.component.interfaces
import
IPossibleSite
,
ISite
from
zope.app.traversing.interfaces
import
IContainmentRoot
from
zope.app.testing.placelesssetup
import
PlacelessSetup
from
Acquisition
import
Implicit
from
OFS.ObjectManager
import
ObjectManager
import
Products.Five
from
Products.Five
import
zcml
class
SiteManager
(
Implicit
):
implements
(
ISiteManager
)
class
Folder
(
ObjectManager
):
implements
(
IPossibleSite
)
sm
=
None
def
getId
(
self
):
return
self
.
id
def
getSiteManager
(
self
,
default
=
None
):
return
self
.
sm
def
setSiteManager
(
self
,
sm
):
self
.
sm
=
sm
directlyProvides
(
self
,
ISite
,
directlyProvidedBy
(
self
))
class
Package
(
Implicit
):
pass
class
Root
(
Folder
):
implements
(
IContainmentRoot
,
ISite
)
def
getSiteManager
(
self
):
return
getGlobalSiteManager
()
class
SiteManagerStub
(
object
):
implements
(
ISiteManager
)
class
SiteManagerTest
(
PlacelessSetup
,
unittest
.
TestCase
):
def
setUp
(
self
):
super
(
SiteManagerTest
,
self
).
setUp
()
self
.
root
=
root
=
Root
()
self
.
f1
=
f1
=
Folder
().
__of__
(
root
)
self
.
sm1
=
sm1
=
SiteManager
()
f1
.
setSiteManager
(
sm1
)
self
.
p1
=
p1
=
Package
().
__of__
(
sm1
)
self
.
f2
=
f2
=
Folder
().
__of__
(
f1
)
self
.
sm2
=
sm2
=
SiteManager
()
f2
.
setSiteManager
(
sm2
)
self
.
p2
=
p2
=
Package
().
__of__
(
sm2
)
sm1
.
next
=
getGlobalSiteManager
()
sm2
.
next
=
sm1
self
.
unparented_folder
=
Folder
()
self
.
unrooted_subfolder
=
Folder
().
__of__
(
self
.
unparented_folder
)
zcml
.
load_config
(
"meta.zcml"
,
Products
.
Five
)
zcml
.
load_config
(
"permissions.zcml"
,
Products
.
Five
)
zcml
.
load_config
(
"configure.zcml"
,
Products
.
Five
.
site
)
zcml_text
=
"""
\
<five:localsite
xmlns:five="http://namespaces.zope.org/five"
class="Products.Five.site.tests.dummy.DummySite" />"""
zcml
.
load_string
(
zcml_text
)
# Hook up custom component architecture calls; we need to do
# this here because zope.app.component.hooks registers a
# cleanup with the testing cleanup framework, so the hooks get
# torn down by placelesssetup each time.
setHooks
()
def
test_getSiteManager
(
self
):
self
.
assertEqual
(
getSiteManager
(
None
),
getGlobalSiteManager
())
self
.
assertEqual
(
getSiteManager
(
self
.
root
),
getGlobalSiteManager
())
self
.
assertEqual
(
getSiteManager
(
self
.
f1
),
self
.
sm1
)
self
.
assertEqual
(
getSiteManager
(
self
.
f2
),
self
.
sm2
)
setSite
(
self
.
f2
)
self
.
assertEqual
(
getSiteManager
(
None
),
self
.
sm2
)
def
test_queryNextSiteManager
(
self
):
from
zope.app.component
import
queryNextSiteManager
marker
=
object
()
self
.
assert_
(
queryNextSiteManager
(
self
.
root
,
marker
)
is
marker
)
self
.
assert_
(
queryNextSiteManager
(
self
.
f1
,
marker
)
is
getGlobalSiteManager
())
#XXX the following used to be
#self.assertEqual(queryNextSiteManager(self.f2, marker), marker)
self
.
assertEqual
(
queryNextSiteManager
(
self
.
f2
,
marker
),
self
.
sm1
)
self
.
assertEqual
(
queryNextSiteManager
(
self
.
sm1
),
getGlobalSiteManager
())
self
.
assertEqual
(
queryNextSiteManager
(
self
.
sm2
),
self
.
sm1
)
#XXX the following used to be
#self.assert_(queryNextSiteManager(self.p1) is getGlobalSiteManager())
self
.
assert_
(
queryNextSiteManager
(
self
.
p1
,
marker
)
is
marker
)
#XXX the following used to be
#self.assertEqual(queryNextSiteManager(self.p2), self.sm1)
self
.
assert_
(
queryNextSiteManager
(
self
.
p2
,
marker
)
is
marker
)
self
.
assert_
(
queryNextSiteManager
(
self
.
unparented_folder
,
marker
)
is
marker
)
self
.
assert_
(
queryNextSiteManager
(
self
.
unrooted_subfolder
,
marker
)
is
marker
)
def
test_getNextSiteManager
(
self
):
from
zope.app.component
import
getNextSiteManager
self
.
assertRaises
(
ComponentLookupError
,
getNextSiteManager
,
self
.
root
)
self
.
assertEqual
(
getNextSiteManager
(
self
.
f1
),
getGlobalSiteManager
())
#XXX the following used to be
#self.assertRaises(ComponentLookupError, getNextSiteManager, self.f2)
self
.
assertEqual
(
getNextSiteManager
(
self
.
f2
),
self
.
sm1
)
self
.
assertEqual
(
getNextSiteManager
(
self
.
sm1
),
getGlobalSiteManager
())
self
.
assertEqual
(
getNextSiteManager
(
self
.
sm2
),
self
.
sm1
)
#XXX the following used to be
#self.assert_(getNextSiteManager(self.p1) is getGlobalSiteManager())
self
.
assertRaises
(
ComponentLookupError
,
getNextSiteManager
,
self
.
p1
)
#XXX the following used to be
#self.assertEqual(getNextSiteManager(self.p2), self.sm1)
self
.
assertRaises
(
ComponentLookupError
,
getNextSiteManager
,
self
.
p2
)
self
.
assertRaises
(
ComponentLookupError
,
getNextSiteManager
,
self
.
unparented_folder
)
self
.
assertRaises
(
ComponentLookupError
,
getNextSiteManager
,
self
.
unrooted_subfolder
)
# XXX Maybe we need to test this with RestrictedPython in the context
# of Zope2? Maybe we just don't care.
#
# def test_getNextSiteManager_security(self):
# from zope.app.component import getNextSiteManager
# from zope.security.checker import ProxyFactory, NamesChecker
# sm = ProxyFactory(self.sm1, NamesChecker(('next',)))
# # Check that getGlobalSiteManager() is not proxied
# self.assert_(getNextSiteManager(sm) is getGlobalSiteManager())
def
test_siteManagerAdapter
(
self
):
from
Products.Five.site.localsite
import
siteManagerAdapter
# If it is a site, return the service service.
sm
=
SiteManagerStub
()
site
=
Folder
()
site
.
setSiteManager
(
sm
)
self
.
assertEqual
(
siteManagerAdapter
(
site
),
sm
)
# If it has an acquisition context, "acquire" the site
# and return the service service
ob
=
Folder
()
ob
=
ob
.
__of__
(
site
)
self
.
assertEqual
(
siteManagerAdapter
(
ob
),
sm
)
ob2
=
Folder
()
ob2
=
ob2
.
__of__
(
ob
)
self
.
assertEqual
(
siteManagerAdapter
(
ob2
),
sm
)
# If it does we are unable to find a service service, raise
# ComponentLookupError
orphan
=
Folder
()
self
.
failUnless
(
siteManagerAdapter
(
orphan
)
is
getGlobalSiteManager
())
def
test_setThreadSite_clearThreadSite
(
self
):
from
zope.app.component.site
import
threadSiteSubscriber
,
clearSite
from
zope.app.publication.zopepublication
import
BeforeTraverseEvent
self
.
assertEqual
(
getSite
(),
None
)
# A site is traversed
sm
=
SiteManagerStub
()
site
=
Folder
()
site
.
setSiteManager
(
sm
)
ev
=
BeforeTraverseEvent
(
site
,
object
())
threadSiteSubscriber
(
site
,
ev
)
self
.
assertEqual
(
getSite
(),
site
)
clearSite
()
self
.
assertEqual
(
getSite
(),
None
)
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
SiteManagerTest
))
return
suite
if
__name__
==
'__main__'
:
framework
()
lib/python/Products/Five/
adding
.py
→
lib/python/Products/Five/
site/tests/test_sitemanager
.py
View file @
528f46df
##############################################################################
#
# Copyright (c) 200
4, 200
5 Zope Corporation and Contributors.
# Copyright (c) 2005 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
...
...
@@ -11,16 +11,18 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
Z2 -> Z3 bridge utilities.
"""
Test Five site manager
$Id
: adding.py 15515 2005-08-02 17:42:08Z yuppie
$
$Id$
"""
import
os
,
sys
# BBB: This file will be removed in future versions of Five.
from
browser.adding
import
ContentAdding
if
__name__
==
'__main__'
:
execfile
(
os
.
path
.
join
(
sys
.
path
[
0
],
'framework.py'
))
import
warnings
warnings
.
warn
(
"
\
n
The Products.Five.adding module has been renamed to "
"Products.Five.browser.adding
\
n
"
"and will be disabled starting in Five 1.2.
\
n
"
,
DeprecationWarning
,
stacklevel
=
2
)
def
test_suite
():
from
Testing.ZopeTestCase
import
ZopeDocFileSuite
return
ZopeDocFileSuite
(
'sitemanager.txt'
,
package
=
"Products.Five.site.tests"
)
if
__name__
==
'__main__'
:
framework
()
lib/python/Products/Five/site/tests/test_utility.py
0 → 100644
View file @
528f46df
##############################################################################
#
# Copyright (c) 2005 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.
#
##############################################################################
"""Test local sites
$Id$
"""
import
os
,
sys
if
__name__
==
'__main__'
:
execfile
(
os
.
path
.
join
(
sys
.
path
[
0
],
'framework.py'
))
import
unittest
import
sets
from
Testing
import
ZopeTestCase
from
zope.interface
import
directlyProvides
from
zope.component
import
provideUtility
from
zope.component.exceptions
import
ComponentLookupError
from
zope.app
import
zapi
from
zope.app.testing.placelesssetup
import
setUp
,
tearDown
from
zope.app.component
import
getNextUtility
from
zope.app.component.hooks
import
setSite
,
clearSite
,
setHooks
import
Products.Five
from
Products.Five
import
zcml
from
Products.Five.site.interfaces
import
IRegisterUtilitySimply
from
Products.Five.site.localsite
import
enableLocalSiteHook
from
Products.Five.site.tests.dummy
import
manage_addDummySite
,
\
IDummyUtility
,
ISuperDummyUtility
,
DummyUtility
class
LocalUtilityServiceTest
(
ZopeTestCase
.
ZopeTestCase
):
def
afterSetUp
(
self
):
setUp
()
zcml
.
load_config
(
"meta.zcml"
,
Products
.
Five
)
zcml
.
load_config
(
"permissions.zcml"
,
Products
.
Five
)
zcml
.
load_config
(
"configure.zcml"
,
Products
.
Five
.
site
)
zcml_text
=
"""
\
<five:localsite
xmlns:five="http://namespaces.zope.org/five"
class="Products.Five.site.tests.dummy.DummySite" />"""
zcml
.
load_string
(
zcml_text
)
manage_addDummySite
(
self
.
folder
,
'site'
)
enableLocalSiteHook
(
self
.
folder
.
site
)
setSite
(
self
.
folder
.
site
)
# Hook up custom component architecture calls; we need to do
# this here because zope.app.component.hooks registers a
# cleanup with the testing cleanup framework, so the hooks get
# torn down by placelesssetup each time.
setHooks
()
def
beforeTearDown
(
self
):
tearDown
()
def
test_getSiteManagerHook
(
self
):
from
Products.Five.site.localsite
import
FiveSiteManager
from
Products.Five.site.utility
import
SimpleLocalUtilityRegistry
local_sm
=
zapi
.
getSiteManager
(
None
)
self
.
failIf
(
local_sm
is
zapi
.
getGlobalSiteManager
())
self
.
failUnless
(
isinstance
(
local_sm
,
FiveSiteManager
))
local_sm
=
zapi
.
getSiteManager
(
self
.
folder
.
site
)
self
.
failIf
(
local_sm
is
zapi
.
getGlobalSiteManager
())
self
.
failUnless
(
isinstance
(
local_sm
,
FiveSiteManager
))
sm
=
zapi
.
getSiteManager
()
self
.
failUnless
(
isinstance
(
sm
.
utilities
,
SimpleLocalUtilityRegistry
))
def
test_getUtilitiesNoUtilitiesFolder
(
self
):
sm
=
zapi
.
getSiteManager
()
#XXX test whether sm really is a local site...
self
.
failUnless
(
sm
.
queryUtility
(
IDummyUtility
)
is
None
)
self
.
assertEquals
(
list
(
sm
.
getUtilitiesFor
(
IDummyUtility
)),
[])
self
.
assertEquals
(
list
(
sm
.
getAllUtilitiesRegisteredFor
(
IDummyUtility
)),
[])
def
test_registerUtilityOnUtilityRegistry
(
self
):
utils
=
zapi
.
getSiteManager
().
utilities
dummy
=
DummyUtility
()
utils
.
registerUtility
(
IDummyUtility
,
dummy
,
'dummy'
)
self
.
assertEquals
(
zapi
.
getUtility
(
IDummyUtility
,
name
=
'dummy'
),
dummy
)
self
.
assertEquals
(
list
(
zapi
.
getUtilitiesFor
(
IDummyUtility
)),
[(
'dummy'
,
dummy
)])
self
.
assertEquals
(
list
(
zapi
.
getAllUtilitiesRegisteredFor
(
IDummyUtility
)),
[
dummy
])
def
test_registerUtilityOnSiteManager
(
self
):
sm
=
zapi
.
getSiteManager
()
self
.
failUnless
(
IRegisterUtilitySimply
.
providedBy
(
sm
))
dummy
=
DummyUtility
()
sm
.
registerUtility
(
IDummyUtility
,
dummy
,
'dummy'
)
self
.
assertEquals
(
zapi
.
getUtility
(
IDummyUtility
,
name
=
'dummy'
),
dummy
)
self
.
assertEquals
(
list
(
zapi
.
getUtilitiesFor
(
IDummyUtility
)),
[(
'dummy'
,
dummy
)])
self
.
assertEquals
(
list
(
zapi
.
getAllUtilitiesRegisteredFor
(
IDummyUtility
)),
[
dummy
])
def
test_registerTwoUtilitiesWithSameNameDifferentInterface
(
self
):
sm
=
zapi
.
getSiteManager
()
self
.
failUnless
(
IRegisterUtilitySimply
.
providedBy
(
sm
))
dummy
=
DummyUtility
()
superdummy
=
DummyUtility
()
directlyProvides
(
superdummy
,
ISuperDummyUtility
)
sm
.
registerUtility
(
IDummyUtility
,
dummy
,
'dummy'
)
sm
.
registerUtility
(
ISuperDummyUtility
,
superdummy
,
'dummy'
)
self
.
assertEquals
(
zapi
.
getUtility
(
IDummyUtility
,
'dummy'
),
dummy
)
self
.
assertEquals
(
zapi
.
getUtility
(
ISuperDummyUtility
,
'dummy'
),
superdummy
)
def
test_nestedSitesDontConflictButStillAcquire
(
self
):
# let's register a dummy utility in the dummy site
dummy
=
DummyUtility
()
sm
=
zapi
.
getSiteManager
()
sm
.
registerUtility
(
IDummyUtility
,
dummy
)
# let's also create a subsite and make that our site
manage_addDummySite
(
self
.
folder
.
site
,
'subsite'
)
enableLocalSiteHook
(
self
.
folder
.
site
.
subsite
)
setSite
(
self
.
folder
.
site
.
subsite
)
# we should still be able to lookup the original utility from
# the site one level above
self
.
assertEqual
(
zapi
.
getUtility
(
IDummyUtility
),
dummy
)
# now we register a dummy utility in the subsite and see that
# its registration doesn't conflict
subdummy
=
DummyUtility
()
sm
=
zapi
.
getSiteManager
()
sm
.
registerUtility
(
IDummyUtility
,
subdummy
)
# when we look it up we get the more local one now because the
# more local one shadows the less local one
self
.
assertEqual
(
zapi
.
getUtility
(
IDummyUtility
),
subdummy
)
# getAllUtilitiesFor gives us both the more local and the less
# local utility (XXX not sure if this is the right semantics
# for getAllUtilitiesFor)
self
.
assertEqual
(
sets
.
Set
(
zapi
.
getAllUtilitiesRegisteredFor
(
IDummyUtility
)),
sets
.
Set
([
subdummy
,
dummy
]))
# getUtilitiesFor will only find one, because the more local
# one shadows the less local one
self
.
assertEqual
(
list
(
zapi
.
getUtilitiesFor
(
IDummyUtility
)),
[(
''
,
subdummy
)])
def
test_registeringTwiceIsConflict
(
self
):
dummy1
=
DummyUtility
()
dummy2
=
DummyUtility
()
sm
=
zapi
.
getSiteManager
()
sm
.
registerUtility
(
IDummyUtility
,
dummy1
)
self
.
assertRaises
(
ValueError
,
sm
.
registerUtility
,
IDummyUtility
,
dummy2
)
sm
.
registerUtility
(
IDummyUtility
,
dummy1
,
'dummy'
)
self
.
assertRaises
(
ValueError
,
sm
.
registerUtility
,
IDummyUtility
,
dummy2
,
'dummy'
)
def
test_utilitiesHaveProperAcquisitionContext
(
self
):
dummy
=
DummyUtility
()
sm
=
zapi
.
getSiteManager
()
sm
.
registerUtility
(
IDummyUtility
,
dummy
)
# let's see if we can acquire something all the way from the
# root (Application) object; we need to be careful to choose
# something that's only available from the root object
from
Acquisition
import
aq_acquire
dummy
=
zapi
.
getUtility
(
IDummyUtility
)
acquired
=
aq_acquire
(
dummy
,
'ZopeAttributionButton'
,
None
)
self
.
failUnless
(
acquired
is
not
None
)
name
,
dummy
=
zapi
.
getUtilitiesFor
(
IDummyUtility
).
next
()
acquired
=
aq_acquire
(
dummy
,
'ZopeAttributionButton'
,
None
)
self
.
failUnless
(
acquired
is
not
None
)
dummy
=
zapi
.
getAllUtilitiesRegisteredFor
(
IDummyUtility
).
next
()
acquired
=
aq_acquire
(
dummy
,
'ZopeAttributionButton'
,
None
)
self
.
failUnless
(
acquired
is
not
None
)
def
test_getNextUtility
(
self
):
# test local site vs. global site
global_dummy
=
DummyUtility
()
provideUtility
(
global_dummy
,
IDummyUtility
)
local_dummy
=
DummyUtility
()
sm
=
zapi
.
getSiteManager
()
sm
.
registerUtility
(
IDummyUtility
,
local_dummy
)
self
.
assertEquals
(
zapi
.
getUtility
(
IDummyUtility
),
local_dummy
)
self
.
assertEquals
(
getNextUtility
(
self
.
folder
.
site
,
IDummyUtility
),
global_dummy
)
# test local site vs. nested local site
manage_addDummySite
(
self
.
folder
.
site
,
'subsite'
)
enableLocalSiteHook
(
self
.
folder
.
site
.
subsite
)
setSite
(
self
.
folder
.
site
.
subsite
)
sublocal_dummy
=
DummyUtility
()
sm
=
zapi
.
getSiteManager
()
sm
.
registerUtility
(
IDummyUtility
,
sublocal_dummy
)
self
.
assertEquals
(
zapi
.
getUtility
(
IDummyUtility
),
sublocal_dummy
)
self
.
assertEquals
(
getNextUtility
(
self
.
folder
.
site
.
subsite
,
IDummyUtility
),
local_dummy
)
self
.
assertEquals
(
getNextUtility
(
self
.
folder
.
site
,
IDummyUtility
),
global_dummy
)
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
LocalUtilityServiceTest
))
return
suite
if
__name__
==
'__main__'
:
framework
()
lib/python/Products/Five/site/utility.py
0 → 100644
View file @
528f46df
##############################################################################
#
# Copyright (c) 2005 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.
#
##############################################################################
"""Local utility registration
$Id$
"""
from
zope.interface
import
implements
from
zope.component
import
getGlobalSiteManager
from
zope.component.exceptions
import
ComponentLookupError
from
zope.app.component
import
getNextSiteManager
from
Acquisition
import
aq_base
from
OFS.Folder
import
Folder
from
Products.Five.site.interfaces
import
IFiveUtilityRegistry
class
SimpleLocalUtilityRegistry
(
object
):
implements
(
IFiveUtilityRegistry
)
def
__init__
(
self
,
context
):
self
.
context
=
context
# make {get|query}NextSiteManager() work without having to
# resort to Zope 2 acquisition
self
.
__parent__
=
self
.
context
.
getSiteManager
()
@
property
def
next
(
self
):
try
:
return
getNextSiteManager
(
self
)
except
ComponentLookupError
:
return
getGlobalSiteManager
()
def
getUtility
(
self
,
interface
,
name
=
''
):
"""See IFiveUtilityRegistry interface
"""
c
=
self
.
queryUtility
(
interface
,
name
)
if
c
is
not
None
:
return
c
raise
ComponentLookupError
(
interface
,
name
)
def
queryUtility
(
self
,
interface
,
name
=
''
,
default
=
None
):
"""See IFiveUtilityRegistry interface
"""
if
name
==
''
:
# Singletons. Only one per interface allowed, so, let's call it
# by the interface.
id
=
interface
.
getName
()
else
:
id
=
interface
.
getName
()
+
'-'
+
name
if
getattr
(
aq_base
(
self
.
context
),
'utilities'
,
None
)
is
not
None
:
utility
=
self
.
context
.
utilities
.
_getOb
(
id
,
None
)
if
utility
is
not
None
:
return
utility
return
self
.
next
.
queryUtility
(
interface
,
name
,
default
)
def
getUtilitiesFor
(
self
,
interface
):
names
=
[]
prefix
=
interface
.
getName
()
+
'-'
if
getattr
(
aq_base
(
self
.
context
),
'utilities'
,
None
)
is
not
None
:
for
name
,
utility
in
self
.
context
.
utilities
.
objectItems
():
if
name
==
interface
.
getName
():
names
.
append
(
''
)
yield
''
,
utility
elif
name
.
startswith
(
prefix
):
name
=
name
[
len
(
prefix
):]
names
.
append
(
name
)
yield
(
name
,
utility
)
for
name
,
utility
in
self
.
next
.
getUtilitiesFor
(
interface
):
if
name
not
in
names
:
yield
name
,
utility
def
getAllUtilitiesRegisteredFor
(
self
,
interface
):
# This also supposedly returns "overridden" utilities, but we don't
# keep them around. It also does not return the name-value pair that
# getUtilitiesFor returns.
if
getattr
(
aq_base
(
self
.
context
),
'utilities'
,
None
)
is
not
None
:
for
utility
in
self
.
context
.
utilities
.
objectValues
():
if
interface
.
providedBy
(
utility
):
yield
utility
for
utility
in
self
.
next
.
getAllUtilitiesRegisteredFor
(
interface
):
yield
utility
def
registerUtility
(
self
,
interface
,
utility
,
name
=
''
):
# I think you are *really* supposed to:
# 1. Check if there is a "registrations" object for utilities.
# 2. If not create one.
# 3. Get it.
# 4. Create a registration object for the utility.
# 5. Rgister the registration object in the registrations.
# But that is quite complex, and Jim sais he wants to change that
# anyway, and in any case the way you would normally do this in Zope3
# and Five would probably differ anyway, so, here is this new
# Five-only, easy to use method!
if
getattr
(
aq_base
(
self
.
context
),
'utilities'
,
None
)
is
None
:
self
.
context
.
_setObject
(
'utilities'
,
Folder
(
'utilities'
))
utilities
=
self
.
context
.
utilities
if
name
==
''
:
# Singletons. Only one per interface allowed, so, let's call it
# by the interface.
id
=
interface
.
getName
()
else
:
id
=
interface
.
getName
()
+
'-'
+
name
if
id
in
utilities
.
objectIds
():
raise
ValueError
(
"There is already a utility registered for "
"%s with the name '%s'"
%
(
interface
.
getName
(),
name
))
utilities
.
_setObject
(
id
,
utility
)
# BBB 2005/11/01 -- gone in Five 1.5.
SimpleLocalUtilityService
=
SimpleLocalUtilityRegistry
import
zope.deprecation
zope
.
deprecation
.
deprecated
(
'SimpleLocalUtilityService'
,
"'SimpleLocalUtilityService' has been renamed to "
"'SimpleLocalUtilityRegistry' and will disappear in Five 1.5."
)
lib/python/Products/Five/skin/standardmacros.py
View file @
528f46df
...
...
@@ -13,17 +13,17 @@
##############################################################################
"""Mimick the Zope 3 skinning system in Five.
$Id: standardmacros.py 1
2884 2005-05-30 13:10:4
1Z philikon $
$Id: standardmacros.py 1
9283 2005-10-31 17:43:5
1Z philikon $
"""
from
zope.interface.common.mapping
import
IItemMapping
from
zope.interface
import
implements
from
zope.
component
import
getView
import
zope.interface
from
zope.
app
import
zapi
from
Products.Five.browser
import
BrowserView
# this is a verbatim copy of zope.app.basicskin except that it doesn't
# derive from ``object``
class
Macros
:
implements
(
IItemMapping
)
zope
.
interface
.
implements
(
zope
.
interface
.
common
.
mapping
.
IItemMapping
)
macro_pages
=
()
aliases
=
{
...
...
@@ -37,7 +37,7 @@ class Macros:
context
=
self
.
context
request
=
self
.
request
for
name
in
self
.
macro_pages
:
page
=
getView
(
context
,
name
,
request
)
page
=
zapi
.
getMultiAdapter
((
context
,
request
),
name
=
name
)
try
:
v
=
page
[
key
]
except
KeyError
:
...
...
lib/python/Products/Five/skin/tests/test_standardmacros.py
View file @
528f46df
...
...
@@ -26,7 +26,7 @@ def test_standard_macros():
>>> uf._doAddUser('manager', 'r00t', ['Manager'], [])
>>> self.login('manager')
>>> from Products.Five.testing import manage_addFiveTraversableFolder
>>> from Products.Five.test
s.test
ing import manage_addFiveTraversableFolder
>>> manage_addFiveTraversableFolder(self.folder, 'testoid', 'Testoid')
>>> import Products.Five.skin.tests
...
...
@@ -72,7 +72,7 @@ def test_standard_macros():
Clean up:
>>> from zope.app.test
s
.placelesssetup import tearDown
>>> from zope.app.test
ing
.placelesssetup import tearDown
>>> tearDown()
"""
...
...
lib/python/Products/Five/tests/README.txt
View file @
528f46df
Five tests
==========
The tests require ZopeTestCase to be installed. ZopeTestCase can be
downloaded from here:
All you have to do is type::
http://zope.org/Members/shh/ZopeTestCase
it needs to be installed in your Zope software's lib/python/Testing
directory.
Then, if you have Zope 2.7.3 or better all you have to do is type::
./bin/zopectl test --dir Products/Five
$ bin/zopectl test -s Products.Five
to run the Five tests.
lib/python/Products/Five/tests/boilerplate.py
View file @
528f46df
...
...
@@ -21,16 +21,16 @@ if __name__ == '__main__':
def
test_boilerplate
():
"""
>>> from zope.app.test
s
.placelesssetup import setUp, tearDown
>>> from zope.app.test
ing
.placelesssetup import setUp, tearDown
>>> setUp()
>>> import Products.Five.tests
>>> from Products.Five import zcml
>>> zcml.load_config('boilerplate.zcml', Products.Five.tests)
>>> from Products.Five.testing import manage_addFiveTraversableFolder
>>> from Products.Five.testing.simplecontent import manage_addSimpleContent
>>> from Products.Five.testing.fancycontent import manage_addFancyContent
>>> from Products.Five.test
s.test
ing import manage_addFiveTraversableFolder
>>> from Products.Five.test
s.test
ing.simplecontent import manage_addSimpleContent
>>> from Products.Five.test
s.test
ing.fancycontent import manage_addFancyContent
>>> tearDown()
"""
...
...
lib/python/Products/Five/tests/directives.zcml
View file @
528f46df
...
...
@@ -11,17 +11,17 @@
once on a class; SimpleContent inherits from Traversable, so
one directive suffices here -->
<five:traversable class="Products.Five.testing.simplecontent.SimpleContent" />
<five:traversable class="Products.Five.test
s.test
ing.simplecontent.SimpleContent" />
<!-- this is a test whether the *directive* can be called more than
once without raising a conflicting configuration exception -->
<five:traversable class="Products.Five.testing.simplecontent.SimpleContent" />
<five:traversable class="Products.Five.test
s.test
ing.simplecontent.SimpleContent" />
<!-- this tests whether five:traversable can be called on a class that
already provides __bobo_traverse__, such as our FancyContent -->
<five:traversable class="Products.Five.testing.fancycontent.FancyContent" />
<five:traversable class="Products.Five.test
s.test
ing.fancycontent.FancyContent" />
<!-- Testing the vocabulary directive -->
...
...
lib/python/Products/Five/tests/event.txt
View file @
528f46df
Test events
===========
================
Container events
================
Before we can start, we need to set up an event subscriber that allows
us to inspect events that will be thrown during the test:
Zope 3 container events are used to inform subscribers that an object is
about to be added/removed from a container, and also after it has been
done. This is used for bookkeeping and cleaning up in subobjects.
>>> from zope.app.tests.placelesssetup import setUp, tearDown
>>> setUp()
Add a folder that doesn't verify objects on paste. We use it as a
test sandbox:
>>> from Products.Five.testing import manage_addNoVerifyPasteFolder
>>> manage_addNoVerifyPasteFolder(self.folder, 'npvf')
>>> folder = self.folder.npvf
Finally add a manager user login, give it the right permissions and
log in using it:
>>> uf = self.folder.acl_users
>>> uf._doAddUser('manager', 'r00t', ['Manager'], [])
>>> self.setPermissions(standard_permissions + ['Copy or Move'], 'Manager')
>>> self.login('manager')
>>> from zope.app.event.tests.placelesssetup import getEvents, clearEvents
Sending events
--------------
Zope 2 classes need to be modified so that they send Zope 3 style
events. Our stub class here is such a case. We can add it to a
folder, for example, ...
>>> from Products.Five.testing.simplecontent import manage_addSimpleContent
>>> manage_addSimpleContent(folder, 'foo', 'Foo')
and no event will have been triggered:
>>> len(getEvents())
0
Clean up:
>>> folder.manage_delObjects(['foo'])
Now make the class send events:
>>> from Products.Five.eventconfigure import classSendEvents
>>> from Products.Five.testing.simplecontent import SimpleContent
>>> classSendEvents(SimpleContent)
Added event
------------
Let's add an object to a folder:
>>> manage_addSimpleContent(folder, 'foo', 'Foo')
These events replace the old Zope 2 manage_afterAdd, manage_beforeDelete
and manage_afterClone methods.
One object event should have been sent with the event's object being
our foo object
:
All standard Zope containers will only call manage_afterAdd & co on
classes specified with the directive:
:
>>> events = getEvents()
>>> len(events)
1
>>> foo = folder.foo
>>> events[0].object == foo
True
<five:deprecatedManageAddDelete class="some.content.class"/>
That object event should have been an object added event:
Classes that don't have this directive but still have manage_afterAdd &
co methods will trigger a warning when they are called (and this is
strictly a compatibility call, behavior may not be strictly equivalent
to the original one).
>>> from zope.app.container.interfaces import IObjectAddedEvent
>>> events = getEvents(IObjectAddedEvent)
>>> len(events)
1
>>> events[0].object == foo
True
>>> events[0].newParent == foo.aq_parent
True
Test setup
==========
Check that the object's original manage_afterAdd method was also called:
A bit of setup for the tests. Because we'll test copy/paste, we need to
work inside a database::
>>> foo.afterAdd_called
True
Now clean up:
>>> clearEvents()
Moved event (I) -- Renaming
--------------------------
>>> from zope.app.testing.placelesssetup import setUp, tearDown
>>> setUp()
Somehow we need to at least commit a subtransaction to make renaming
succeed:
>>> import ZODB.tests.util
>>> db = ZODB.tests.util.DB()
>>> connection = db.open()
>>> root = connection.root()
We'll use a few simple classes (defined in python code for picklability)
for our tests.
>>> from Products.Five.tests.test_event import MyApp, MyContent
>>> from Products.Five.tests.test_event import MyFolder, MyBTreeFolder
>>> from Products.Five.tests.test_event import MyOrderedFolder
>>> app = MyApp('')
>>> root['app'] = app
>>> folder = MyFolder('folder')
>>> app._setObject('folder', folder) # doctest: +NORMALIZE_WHITESPACE
old manage_afterAdd folder folder
'folder'
>>> folder = app.folder
>>> btfolder = MyBTreeFolder('btfolder')
>>> app._setObject('btfolder', btfolder) # doctest: +NORMALIZE_WHITESPACE
old manage_afterAdd btfolder btfolder
'btfolder'
To observe what object events are dispatched, we'll have some
subscribers print them. We'll actually do that for a specific interface,
not for (None, IObjectEvent), and register our subscribers before the
framework's ones, so ours will be called first. This has the effect that
printed events will be in their "natural" order::
>>> from zope.app.event.interfaces import IObjectEvent
>>> from zope.app.container.interfaces import IObjectMovedEvent
>>> from OFS.interfaces import IObjectWillBeMovedEvent
>>> from OFS.interfaces import IObjectClonedEvent
>>> from OFS.interfaces import IItem
>>> def printObjectEvent(object, event):
... print event.__class__.__name__, object.getId()
>>> def printObjectEventExceptSome(object, event):
... if (IObjectMovedEvent.providedBy(event) or
... IObjectWillBeMovedEvent.providedBy(event) or
... IObjectClonedEvent.providedBy(event)):
... return
... print event.__class__.__name__, object.getId()
>>> from zope.component import provideHandler
>>> provideHandler(printObjectEvent, (IItem, IObjectMovedEvent))
>>> provideHandler(printObjectEvent, (IItem, IObjectWillBeMovedEvent))
>>> provideHandler(printObjectEvent, (IItem, IObjectClonedEvent))
>>> provideHandler(printObjectEventExceptSome, (None, IObjectEvent))
Finally we need to load the subscribers configuration::
>>> from Products.Five import zcml
>>> import Products.Five
>>> import zope.app.component
>>> zcml.load_config('meta.zcml', zope.app.component)
>>> zcml.load_config('event.zcml', Products.Five)
Old class
=========
If we use an instance of an old class for which we haven't specified
anything, events are sent and the manage_afterAdd & co methods are
called but in a "compatibility" way.
Because the bases classes of Zope have been changed to not recurse
except through the event framework, unexpected behavior may happen
(however a warning will be sent)::
>>> ob = MyContent('dog')
>>> folder._setObject('dog', ob)
ObjectWillBeAddedEvent dog
ObjectAddedEvent dog
old manage_afterAdd dog dog folder
'dog'
And when we delete the object, manage_beforeDelete is also called and
events are sent::
>>> folder.manage_delObjects('dog')
old manage_beforeDelete dog dog folder
ObjectWillBeRemovedEvent dog
ObjectRemovedEvent dog
Old class with deprecatedManageAddDelete
========================================
We specifiy that our class is deprecated (using zcml in real life)::
>>> from Products.Five.eventconfigure import setDeprecatedManageAddDelete
>>> setDeprecatedManageAddDelete(MyContent)
>>> setDeprecatedManageAddDelete(MyFolder)
>>> setDeprecatedManageAddDelete(MyOrderedFolder)
Now some events are sent but the old manage_afterAdd method is also
called correctly::
>>> ob = MyContent('lassie')
>>> folder._setObject('lassie', ob)
ObjectWillBeAddedEvent lassie
ObjectAddedEvent lassie
old manage_afterAdd lassie lassie folder
'lassie'
And when we delete the object, manage_beforeDelete is also called and
events are sent::
>>> folder.manage_delObjects('lassie')
ObjectWillBeRemovedEvent lassie
old manage_beforeDelete lassie lassie folder
ObjectRemovedEvent lassie
The old behavior happens for a move or a copy, with events too.
For a move::
>>> ob = MyContent('blueberry')
>>> folder._setObject('blueberry', ob)
ObjectWillBeAddedEvent blueberry
ObjectAddedEvent blueberry
old manage_afterAdd blueberry blueberry folder
'blueberry'
>>> cp = folder.manage_cutObjects('blueberry')
>>> folder.manage_pasteObjects(cp)
ObjectWillBeMovedEvent blueberry
old manage_beforeDelete blueberry blueberry folder
ObjectMovedEvent blueberry
old manage_afterAdd blueberry blueberry folder
[{'new_id': 'blueberry', 'id': 'blueberry'}]
Old behavior with events for a copy::
>>> cp = folder.manage_copyObjects('blueberry')
>>> folder.manage_pasteObjects(cp)
ObjectCopiedEvent copy_of_blueberry
ObjectWillBeAddedEvent copy_of_blueberry
ObjectAddedEvent copy_of_blueberry
old manage_afterAdd copy_of_blueberry copy_of_blueberry folder
ObjectClonedEvent copy_of_blueberry
old manage_afterClone copy_of_blueberry copy_of_blueberry
[{'new_id': 'copy_of_blueberry', 'id': 'blueberry'}]
Old behavior with events for a renaming::
>>> folder.manage_renameObject('copy_of_blueberry', 'myrtille')
ObjectWillBeMovedEvent copy_of_blueberry
old manage_beforeDelete copy_of_blueberry copy_of_blueberry folder
ObjectMovedEvent myrtille
old manage_afterAdd myrtille myrtille folder
Old behavior with events for a clone::
>>> res = folder.manage_clone(folder.blueberry, 'strawberry')
ObjectCopiedEvent strawberry
ObjectWillBeAddedEvent strawberry
ObjectAddedEvent strawberry
old manage_afterAdd strawberry strawberry folder
ObjectClonedEvent strawberry
old manage_afterClone strawberry strawberry
>>> res.getId()
'strawberry'
Events are also sent when we work with a BTreeFolder::
>>> ob = MyContent('luckyluke')
>>> btfolder._setObject('luckyluke', ob)
ObjectWillBeAddedEvent luckyluke
ObjectAddedEvent luckyluke
old manage_afterAdd luckyluke luckyluke btfolder
'luckyluke'
>>> btfolder.manage_delObjects('luckyluke')
ObjectWillBeRemovedEvent luckyluke
old manage_beforeDelete luckyluke luckyluke btfolder
ObjectRemovedEvent luckyluke
Here is what happens for a tree of objects. Let's create a simple one::
>>> subfolder = MyFolder('subfolder')
>>> folder._setObject('subfolder', subfolder)
ObjectWillBeAddedEvent subfolder
ObjectAddedEvent subfolder
old manage_afterAdd subfolder subfolder folder
'subfolder'
>>> subfolder = folder.subfolder
>>> ob = MyContent('donald')
>>> subfolder._setObject('donald', ob)
ObjectWillBeAddedEvent donald
ObjectAddedEvent donald
old manage_afterAdd donald donald subfolder
'donald'
Renaming a tree of objects. Note that manage_beforeDelete is called
bottom-up::
>>> folder.manage_renameObject('subfolder', 'pluto')
ObjectWillBeMovedEvent subfolder
ObjectWillBeMovedEvent donald
old manage_beforeDelete donald subfolder folder
old manage_beforeDelete subfolder subfolder folder
ObjectMovedEvent pluto
old manage_afterAdd pluto pluto folder
ObjectMovedEvent donald
old manage_afterAdd donald pluto folder
Cloning a tree of objects::
>>> res = folder.manage_clone(folder.pluto, 'mickey')
ObjectCopiedEvent mickey
ObjectWillBeAddedEvent mickey
ObjectWillBeAddedEvent donald
ObjectAddedEvent mickey
old manage_afterAdd mickey mickey folder
ObjectAddedEvent donald
old manage_afterAdd donald mickey folder
ObjectClonedEvent mickey
old manage_afterClone mickey mickey
ObjectClonedEvent donald
old manage_afterClone donald mickey
>>> res.getId()
'mickey'
New class
=========
If we use classes that don't have any manage_afterAdd & co method,
everything happens correctly::
>>> from Products.Five.tests.test_event import MyNewFolder, MyNewContent
>>> app = MyApp('')
>>> root['app'] = app
>>> folder = MyNewFolder('folder')
>>> app._setObject('folder', folder)
ObjectWillBeAddedEvent folder
ObjectAddedEvent folder
'folder'
>>> folder = app.folder
>>> ob = MyNewContent('dogbert')
>>> folder._setObject('dogbert', ob)
ObjectWillBeAddedEvent dogbert
ObjectAddedEvent dogbert
'dogbert'
>>> folder.manage_delObjects('dogbert')
ObjectWillBeRemovedEvent dogbert
ObjectRemovedEvent dogbert
Now move::
>>> ob = MyNewContent('dilbert')
>>> folder._setObject('dilbert', ob)
ObjectWillBeAddedEvent dilbert
ObjectAddedEvent dilbert
'dilbert'
>>> cp = folder.manage_cutObjects('dilbert')
>>> folder.manage_pasteObjects(cp)
ObjectWillBeMovedEvent dilbert
ObjectMovedEvent dilbert
[{'new_id': 'dilbert', 'id': 'dilbert'}]
And copy::
>>> cp = folder.manage_copyObjects('dilbert')
>>> folder.manage_pasteObjects(cp)
ObjectCopiedEvent copy_of_dilbert
ObjectWillBeAddedEvent copy_of_dilbert
ObjectAddedEvent copy_of_dilbert
ObjectClonedEvent copy_of_dilbert
[{'new_id': 'copy_of_dilbert', 'id': 'dilbert'}]
Then rename::
>>> folder.manage_renameObject('copy_of_dilbert', 'wally')
ObjectWillBeMovedEvent copy_of_dilbert
ObjectMovedEvent wally
Or copy using manage_clone::
>>> res = folder.manage_clone(folder.dilbert, 'phb')
ObjectCopiedEvent phb
ObjectWillBeAddedEvent phb
ObjectAddedEvent phb
ObjectClonedEvent phb
>>> res.getId()
'phb'
Also on a BTreeFolder::
>>> ob = MyNewContent('alice')
>>> btfolder._setObject('alice', ob)
ObjectWillBeAddedEvent alice
ObjectAddedEvent alice
'alice'
>>> btfolder.manage_renameObject('alice', 'rabbit')
ObjectWillBeMovedEvent alice
ObjectMovedEvent rabbit
>>> btfolder.manage_delObjects('rabbit')
ObjectWillBeRemovedEvent rabbit
ObjectRemovedEvent rabbit
Now for a tree of objects. Let's create a simple one::
>>> subfolder = MyNewFolder('subfolder')
>>> folder._setObject('subfolder', subfolder)
ObjectWillBeAddedEvent subfolder
ObjectAddedEvent subfolder
'subfolder'
>>> subfolder = folder.subfolder
>>> ob = MyNewContent('mel')
>>> subfolder._setObject('mel', ob)
ObjectWillBeAddedEvent mel
ObjectAddedEvent mel
'mel'
Renaming a tree of objects::
>>> folder.manage_renameObject('subfolder', 'firefly')
ObjectWillBeMovedEvent subfolder
ObjectWillBeMovedEvent mel
ObjectMovedEvent firefly
ObjectMovedEvent mel
Cloning a tree of objects::
>>> res = folder.manage_clone(folder.firefly, 'serenity')
ObjectCopiedEvent serenity
ObjectWillBeAddedEvent serenity
ObjectWillBeAddedEvent mel
ObjectAddedEvent serenity
ObjectAddedEvent mel
ObjectClonedEvent serenity
ObjectClonedEvent mel
>>> res.getId()
'serenity'
OrderedFolder has the same renaming behavior than before::
>>> ofolder = MyOrderedFolder('ofolder')
>>> app._setObject('ofolder', ofolder) # doctest: +NORMALIZE_WHITESPACE
ObjectWillBeAddedEvent ofolder
ObjectAddedEvent ofolder
old manage_afterAdd ofolder ofolder
'ofolder'
>>> ob1 = MyNewContent('ob1')
>>> ofolder._setObject('ob1', ob1)
ObjectWillBeAddedEvent ob1
ObjectAddedEvent ob1
'ob1'
>>> ob2 = MyNewContent('ob2')
>>> ofolder._setObject('ob2', ob2)
ObjectWillBeAddedEvent ob2
ObjectAddedEvent ob2
'ob2'
>>> ofolder.manage_renameObject('ob1', 'ob4')
ObjectWillBeMovedEvent ob1
ObjectMovedEvent ob4
>>> ofolder.objectIds()
['ob4', 'ob2']
Now cleanup::
>>> import transaction
>>> transaction.commit(1)
Let's rename the object we created before:
>>> folder.manage_renameObject('foo', 'bar')
We should get two events...
>>> events = getEvents()
>>> len(events)
2
the removed event...
>>> event = events[0]
>>> from zope.app.container.interfaces import IObjectRemovedEvent
>>> IObjectRemovedEvent.providedBy(event)
True
>>> event.object == foo
True
>>> event.oldName, event.newName
('foo', None)
>>> event.oldParent == folder
True
>>> event.newParent is None
True
and the moved event:
>>> event = events[1]
>>> event.object == foo
True
>>> event.oldName, event.newName
('foo', 'bar')
>>> event.oldParent == folder
True
>>> event.newParent == folder
True
Now clean up:
>>> folder.manage_delObjects(['bar'])
>>> clearEvents()
We don't delete the stub object just yet because it's being used in
the next part of the test.
Moved event (II) -- Cut and paste
---------------------------------
Let's move from one folder to another:
>>> manage_addNoVerifyPasteFolder(folder, 'folder1', 'Folder1')
>>> folder1 = folder.folder1
>>> manage_addNoVerifyPasteFolder(folder, 'folder2', 'Folder2')
>>> folder2 = folder.folder2
>>> manage_addSimpleContent(folder1, 'foo', 'Foo')
>>> foo = folder1.foo
We need to trigger a subtransaction before cut/paste can work:
>>> transaction.commit(1)
>>> cb = folder1.manage_cutObjects(['foo'])
>>> info = folder2.manage_pasteObjects(cb)
Apart from the added event we triggerred when we added the stub object
to the folder, we expect two events...
>>> events = getEvents()
>>> len(events)
3
>>> len(getEvents(IObjectAddedEvent))
1
a removed event...
>>> event = events[1]
>>> from zope.app.container.interfaces import IObjectRemovedEvent
>>> IObjectRemovedEvent.providedBy(event)
True
>>> event.oldParent == folder1
True
>>> event.newParent is None
True
and a moved event:
>>> event = events[2]
>>> event.object == foo
True
>>> event.oldName, event.newName
('foo', 'foo')
>>> event.oldParent == folder1
True
>>> event.newParent == folder2
True
Now clean up:
>>> folder.manage_delObjects(['folder1'])
>>> folder.manage_delObjects(['folder2'])
>>> clearEvents()
Copied event
------------
>>> manage_addSimpleContent(folder, 'foo', 'Foo')
>>> manage_addNoVerifyPasteFolder(folder, 'folder1')
>>> folder1 = folder.folder1
We need to trigger subtransaction before copy/paste can work
>>> transaction.commit(1)
>>> cb = folder.manage_copyObjects(['foo'])
>>> info = folder1.manage_pasteObjects(cb)
>>> foo = folder1.foo
Apart from the added event we triggerred when we added the stub object
to the folder, we expect two events...
>>> events = getEvents()
>>> len(events)
3
a copied event...
>>> event = events[1]
>>> from zope.app.event.interfaces import IObjectCopiedEvent
>>> IObjectCopiedEvent.providedBy(event)
True
>>> events[1].object == foo
True
and an added event:
>>> event = events[2]
>>> IObjectAddedEvent.providedBy(event)
True
>>> event.object == foo
True
>>> event.newName
'foo'
>>> event.newParent == folder1
True
Now clean up:
>>> folder.manage_delObjects(['folder1'])
>>> folder.manage_delObjects(['foo'])
>>> clearEvents()
Removed event
-------------
>>> manage_addSimpleContent(folder, 'foo', 'Foo')
>>> foo = folder.foo
>>> foo.beforeDelete_called
False
>>> folder.manage_delObjects(['foo'])
>>> events = getEvents()
>>> len(events)
2
>>> events[1].object.id
'foo'
Check that the object's original manage_beforeDelete method was also called:
>>> foo.beforeDelete_called
True
>>> clearEvents()
Clean up
--------
Finally, we need to put our stub class back the way it was before we
monkeyed with it:
>>> from Products.Five.eventconfigure import cleanUp
>>> cleanUp()
Now adding an object won't trigger an event anymore:
>>> from Products.Five.testing.simplecontent import manage_addSimpleContent
>>> manage_addSimpleContent(folder, 'foo', 'Foo')
>>> len(getEvents())
0
Finally, we need to tear down everything else (services, etc.)
>>> transaction.abort()
>>> tearDown()
lib/python/Products/Five/tests/test_directives.py
View file @
528f46df
...
...
@@ -23,9 +23,6 @@ def test_directives():
"""
Test ZCML directives
>>> from zope.app.tests.placelesssetup import setUp, tearDown
>>> setUp()
There isn't much to test here since the actual directive handlers
are either tested in other, more specific tests, or they're
already tested in Zope 3. We'll just do a symbolic test of
...
...
@@ -62,9 +59,10 @@ def test_directives():
>>> dest.method()
'Overridden'
Clean up:
Clean up
adapter registry and others
:
>>> tearDown()
>>> from zope.testing.cleanup import cleanUp
>>> cleanUp()
"""
def
test_suite
():
...
...
lib/python/Products/Five/tests/test_event.py
View file @
528f46df
...
...
@@ -19,9 +19,64 @@ import os, sys
if
__name__
==
'__main__'
:
execfile
(
os
.
path
.
join
(
sys
.
path
[
0
],
'framework.py'
))
# These classes aren't defined in the doctest because otherwise
# they wouldn't be picklable, and we need that to test copy/paste.
from
OFS.SimpleItem
import
SimpleItem
from
OFS.Folder
import
Folder
from
OFS.OrderedFolder
import
OrderedFolder
from
Products.BTreeFolder2.BTreeFolder2
import
BTreeFolder2
class
DontComplain
(
object
):
def
_verifyObjectPaste
(
self
,
object
,
validate_src
=
1
):
pass
def
cb_isMoveable
(
self
):
return
True
def
cb_isCopyable
(
self
):
return
True
class
NotifyBase
(
DontComplain
):
def
manage_afterAdd
(
self
,
item
,
container
):
print
'old manage_afterAdd %s %s %s'
%
(
self
.
getId
(),
item
.
getId
(),
container
.
getId
())
def
manage_beforeDelete
(
self
,
item
,
container
):
print
'old manage_beforeDelete %s %s %s'
%
(
self
.
getId
(),
item
.
getId
(),
container
.
getId
())
def
manage_afterClone
(
self
,
item
):
print
'old manage_afterClone %s %s'
%
(
self
.
getId
(),
item
.
getId
())
class
MyApp
(
Folder
):
def
getPhysicalRoot
(
self
):
return
self
class
MyFolder
(
NotifyBase
,
Folder
):
pass
class
MyOrderedFolder
(
NotifyBase
,
OrderedFolder
):
pass
class
MyBTreeFolder
(
NotifyBase
,
BTreeFolder2
):
def
_verifyObjectPaste
(
self
,
object
,
validate_src
=
1
):
pass
class
MyContent
(
NotifyBase
,
SimpleItem
):
def
__init__
(
self
,
id
):
self
.
_setId
(
id
)
# These don't have manage_beforeDelete & co methods
class
MyNewContent
(
DontComplain
,
SimpleItem
):
def
__init__
(
self
,
id
):
self
.
_setId
(
id
)
class
MyNewFolder
(
DontComplain
,
Folder
):
pass
def
test_suite
():
from
Testing.ZopeTestCase
import
Zope
DocFileSuite
return
Zope
DocFileSuite
(
'event.txt'
,
package
=
"Products.Five.tests"
)
from
zope.testing.doctest
import
DocFileSuite
return
DocFileSuite
(
'event.txt'
,
package
=
"Products.Five.tests"
)
if
__name__
==
'__main__'
:
framework
()
lib/python/Products/Five/tests/test_i18n.py
View file @
528f46df
...
...
@@ -23,7 +23,7 @@ def test_directive():
"""
Test the i18n directive
>>> from zope.app.test
s
.placelesssetup import setUp, tearDown
>>> from zope.app.test
ing
.placelesssetup import setUp, tearDown
>>> setUp()
First, we need to register the ZCML directive:
...
...
@@ -44,9 +44,9 @@ def test_directive():
Now, take an arbitrary message id from that domain:
>>> from zope.i18nmessageid import Message
ID
Factory
>>> from zope.i18nmessageid import MessageFactory
>>> from zope.i18n import translate
>>> _ = Message
ID
Factory('fivetest')
>>> _ = MessageFactory('fivetest')
>>> msg = _(u'explicit-msg', u'This is an explicit message')
As you can see, both the default functionality and translation to
...
...
lib/python/Products/Five/tests/test_registerclass.py
0 → 100644
View file @
528f46df
##############################################################################
#
# Copyright (c) 2004, 2005 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.
#
##############################################################################
"""Unit tests for the registerClass directive.
$Id$
"""
import
os
,
sys
if
__name__
==
'__main__'
:
execfile
(
os
.
path
.
join
(
sys
.
path
[
0
],
'framework.py'
))
def
test_registerClass
():
"""
Testing registerClass
>>> from zope.app.testing.placelesssetup import setUp, tearDown
>>> setUp()
>>> import Products
>>> import Products.Five
>>> from Products.Five import zcml
>>> from Products.Five.tests.testing.simplecontent import SimpleContent
>>> from Products.Five.tests.testing.simplecontent import ISimpleContent
>>> from persistent.interfaces import IPersistent
Use the five:registerClass directive::
>>> configure_zcml = '''
... <configure
... xmlns="http://namespaces.zope.org/zope"
... xmlns:five="http://namespaces.zope.org/five"
... i18n_domain="foo">
... <permission id="foo.add" title="Add Foo"/>
... <five:registerClass
... class="Products.Five.tests.testing.simplecontent.SimpleContent"
... meta_type="Foo Type"
... permission="foo.add"
... addview="addfoo.html"
... icon="foo_icon.png"
... global="false"
... />
... </configure>'''
>>> zcml.load_config('meta.zcml', Products.Five)
>>> zcml.load_string(configure_zcml)
Make sure that the class attributes are set correctly::
>>> SimpleContent.meta_type
'Foo Type'
>>> SimpleContent.icon
'++resource++foo_icon.png'
And the meta_type is registered correctly::
>>> for info in Products.meta_types:
... if info['name'] == 'Foo Type':
... break
>>> info['product']
'Five'
>>> info['permission']
'Add Foo'
>>> ISimpleContent in info['interfaces']
True
>>> IPersistent in info['interfaces']
True
>>> info['visibility'] is None
True
>>> info['instance'] is SimpleContent
True
>>> info['action']
'+/addfoo.html'
>>> info['container_filter'] is None
True
Now reset everything and see what happens without optional parameters::
>>> tearDown()
>>> setUp()
Use the five:registerClass directive again::
>>> configure_zcml = '''
... <configure
... xmlns="http://namespaces.zope.org/zope"
... xmlns:five="http://namespaces.zope.org/five"
... i18n_domain="bar">
... <permission id="bar.add" title="Add Bar"/>
... <five:registerClass
... class="Products.Five.tests.testing.simplecontent.SimpleContent"
... meta_type="Bar Type"
... permission="bar.add"
... />
... </configure>'''
>>> zcml.load_config('meta.zcml', Products.Five)
>>> zcml.load_string(configure_zcml)
Make sure that the class attributes are set correctly::
>>> SimpleContent.meta_type
'Bar Type'
>>> SimpleContent.icon
''
And the meta_type is registered correctly::
>>> for info in Products.meta_types:
... if info['name'] == 'Bar Type':
... break
>>> info['product']
'Five'
>>> info['permission']
'Add Bar'
>>> ISimpleContent in info['interfaces']
True
>>> IPersistent in info['interfaces']
True
>>> info['visibility']
'Global'
>>> info['instance'] is SimpleContent
True
>>> info['action']
''
>>> info['container_filter'] is None
True
Clean up:
>>> tearDown()
>>> SimpleContent.meta_type
'simple item'
>>> SimpleContent.icon
''
>>> [info for info in Products.meta_types if info['name'] == 'Bar Type']
[]
"""
def
test_suite
():
from
Testing.ZopeTestCase
import
ZopeDocTestSuite
return
ZopeDocTestSuite
()
if
__name__
==
'__main__'
:
framework
()
lib/python/Products/Five/tests/test_security.py
View file @
528f46df
...
...
@@ -45,7 +45,7 @@ def test_security_equivalence():
Zope 2 can be replaced by ZCML statements without any loss of
information.
>>> from zope.app.test
s
.placelesssetup import setUp, tearDown
>>> from zope.app.test
ing
.placelesssetup import setUp, tearDown
>>> setUp()
We start out with two classes, ``Dummy1`` and ``Dummy2``. They
...
...
@@ -141,7 +141,7 @@ def test_checkPermission():
"""
Test checkPermission
>>> from zope.app.test
s
.placelesssetup import setUp, tearDown
>>> from zope.app.test
ing
.placelesssetup import setUp, tearDown
>>> setUp()
Zope 3 has a function zope.security.checkPermission which provides
...
...
lib/python/Products/Five/tests/test_size.py
View file @
528f46df
...
...
@@ -54,21 +54,21 @@ def test_size():
Set up:
>>> from zope.app.test
s
.placelesssetup import setUp, tearDown
>>> from zope.app.test
ing
.placelesssetup import setUp, tearDown
>>> setUp()
>>> configure_zcml = '''
... <configure xmlns="http://namespaces.zope.org/zope"
... xmlns:five="http://namespaces.zope.org/five">
... <five:sizable class="Products.Five.testing.simplecontent.SimpleContent" />
... <five:sizable class="Products.Five.testing.fancycontent.FancyContent" />
... <five:sizable class="Products.Five.test
s.test
ing.simplecontent.SimpleContent" />
... <five:sizable class="Products.Five.test
s.test
ing.fancycontent.FancyContent" />
... <adapter
... for="Products.Five.testing.simplecontent.ISimpleContent"
... for="Products.Five.test
s.test
ing.simplecontent.ISimpleContent"
... provides="zope.app.size.interfaces.ISized"
... factory="Products.Five.tests.test_size.SimpleContentSize"
... />
... <adapter
... for="Products.Five.testing.fancycontent.IFancyContent"
... for="Products.Five.test
s.test
ing.fancycontent.IFancyContent"
... provides="zope.app.size.interfaces.ISized"
... factory="Products.Five.tests.test_size.FancyContentSize"
... />
...
...
@@ -79,8 +79,8 @@ def test_size():
>>> zcml.load_config('meta.zcml', Products.Five)
>>> zcml.load_string(configure_zcml)
>>> from Products.Five.testing.simplecontent import manage_addSimpleContent
>>> from Products.Five.testing.fancycontent import manage_addFancyContent
>>> from Products.Five.test
s.test
ing.simplecontent import manage_addSimpleContent
>>> from Products.Five.test
s.test
ing.fancycontent import manage_addFancyContent
We have registered an ``ISized`` adapter for SimpleContent:
...
...
lib/python/Products/Five/tests/test_viewable.py
View file @
528f46df
...
...
@@ -23,9 +23,6 @@ def test_defaultView():
"""
Testing default view functionality
>>> from zope.app.tests.placelesssetup import setUp, tearDown
>>> setUp()
Take a class Foo and an interface IFoo:
>>> class Foo:
...
...
@@ -37,14 +34,14 @@ def test_defaultView():
Set up a default view for IFoo:
>>> from zope.
app import zapi
>>>
pres = zapi.getGlobalService('Presentation')
>>> from zope.
component import provideAdapter
>>>
from zope.component.interfaces import IDefaultViewName
>>> from zope.publisher.interfaces.browser import IBrowserRequest
and default view names for everything and IFoo objects in particular:
>>> pr
es.setDefaultViewName(None, IBrowserRequest, u'index.html'
)
>>> pr
es.setDefaultViewName(IFoo, IBrowserRequest, u'foo.html'
)
>>> pr
ovideAdapter(u'index.html', (None, IBrowserRequest), IDefaultViewName
)
>>> pr
ovideAdapter(u'foo.html', (IFoo, IBrowserRequest), IDefaultViewName
)
Now take a BrowserDefault for an instance of Foo::
...
...
@@ -73,10 +70,10 @@ def test_defaultView():
>>> path
[u'foo.html']
Clean up adapter registry:
Clean up:
>>> tearDown()
>>> from zope.testing.cleanup import cleanUp
>>> cleanUp()
"""
def
test_suite
():
...
...
lib/python/Products/Five/testing/__init__.py
→
lib/python/Products/Five/test
s/test
ing/__init__.py
View file @
528f46df
...
...
@@ -13,11 +13,11 @@
##############################################################################
"""Test helpers
$Id
: __init__.py 14470 2005-07-10 11:57:49Z philikon
$
$Id$
"""
from
Products.Five.testing.restricted
import
RestrictedPythonTestCase
from
Products.Five.test
s.test
ing.restricted
import
RestrictedPythonTestCase
from
Products.Five.testing.folder
import
FiveTraversableFolder
from
Products.Five.testing.folder
import
manage_addFiveTraversableFolder
from
Products.Five.testing.folder
import
NoVerifyPasteFolder
from
Products.Five.testing.folder
import
manage_addNoVerifyPasteFolder
from
Products.Five.test
s.test
ing.folder
import
FiveTraversableFolder
from
Products.Five.test
s.test
ing.folder
import
manage_addFiveTraversableFolder
from
Products.Five.test
s.test
ing.folder
import
NoVerifyPasteFolder
from
Products.Five.test
s.test
ing.folder
import
manage_addNoVerifyPasteFolder
lib/python/Products/Five/testing/fancycontent.py
→
lib/python/Products/Five/test
s/test
ing/fancycontent.py
View file @
528f46df
...
...
@@ -13,7 +13,7 @@
##############################################################################
"""Test content objects.
$Id
: fancycontent.py 14470 2005-07-10 11:57:49Z philikon
$
$Id$
"""
import
Acquisition
from
AccessControl
import
ClassSecurityInfo
...
...
lib/python/Products/Five/testing/folder.py
→
lib/python/Products/Five/test
s/test
ing/folder.py
View file @
528f46df
...
...
@@ -13,7 +13,7 @@
##############################################################################
"""Test folders
$Id
: folder.py 14468 2005-07-10 11:39:32Z philikon
$
$Id$
"""
from
OFS.Folder
import
Folder
from
OFS.interfaces
import
IFolder
...
...
lib/python/Products/Five/testing/restricted.py
→
lib/python/Products/Five/test
s/test
ing/restricted.py
View file @
528f46df
...
...
@@ -16,7 +16,7 @@
Based on Plone's RestrictedPythonTestCase, with kind permission by the
Plone developers.
$Id
: restricted.py 14473 2005-07-10 13:02:21Z philikon
$
$Id$
"""
from
AccessControl
import
Unauthorized
from
Testing.ZopeTestCase
import
ZopeTestCase
...
...
lib/python/Products/Five/testing/simplecontent.py
→
lib/python/Products/Five/test
s/test
ing/simplecontent.py
View file @
528f46df
...
...
@@ -13,7 +13,7 @@
##############################################################################
"""Simple content class(es) for browser tests
$Id
: simplecontent.py 17810 2005-09-24 09:12:59Z efge
$
$Id$
"""
from
OFS.SimpleItem
import
SimpleItem
from
Globals
import
InitializeClass
...
...
@@ -37,19 +37,10 @@ class SimpleContent(Traversable, SimpleItem):
meta_type
=
'Five SimpleContent'
security
=
ClassSecurityInfo
()
afterAdd_called
=
False
beforeDelete_called
=
False
def
__init__
(
self
,
id
,
title
):
self
.
id
=
id
self
.
title
=
title
def
manage_afterAdd
(
self
,
item
,
container
):
self
.
afterAdd_called
=
True
def
manage_beforeDelete
(
self
,
item
,
container
):
self
.
beforeDelete_called
=
True
security
.
declarePublic
(
'mymethod'
)
def
mymethod
(
self
):
return
"Hello world"
...
...
lib/python/Products/Five/traversable.py
View file @
528f46df
...
...
@@ -13,28 +13,29 @@
##############################################################################
"""Machinery for making things traversable through adaptation
$Id: traversable.py 1
8841 2005-10-23 09:57:38
Z philikon $
$Id: traversable.py 1
9283 2005-10-31 17:43:51
Z philikon $
"""
from
zExceptions
import
NotFound
from
zope.exceptions
import
NotFoundError
from
zope.component
import
getView
,
ComponentLookupError
from
zope.interface
import
implements
from
zope.component
import
getMultiAdapter
,
ComponentLookupError
from
zope.interface
import
implements
,
Interface
from
zope.publisher.interfaces
import
ILayer
from
zope.publisher.interfaces.browser
import
IBrowserRequest
from
zope.app.traversing.interfaces
import
ITraverser
,
ITraversable
from
zope.app.traversing.adapters
import
DefaultTraversable
from
zope.app.traversing.adapters
import
traversePathElement
from
zope.app.publication.browser
import
setDefaultSkin
from
zope.app.interface
import
queryType
from
AccessControl
import
getSecurityManager
from
Products.Five.security
import
newInteraction
_marker
=
object
class
FakeRequest
:
class
FakeRequest
(
dict
)
:
implements
(
IBrowserRequest
)
def
getPresentationSkin
(
self
):
return
None
def
has_key
(
self
,
key
):
return
False
...
...
@@ -69,16 +70,20 @@ class Traversable:
REQUEST
=
getattr
(
self
,
'REQUEST'
,
None
)
if
not
IBrowserRequest
.
providedBy
(
REQUEST
):
REQUEST
=
FakeRequest
()
# set the default skin on the request if it doesn't have any
# layers set on it yet
if
queryType
(
REQUEST
,
ILayer
)
is
None
:
setDefaultSkin
(
REQUEST
)
# con Zope 3 into using Zope 2's checkPermission
newInteraction
()
try
:
return
ITraverser
(
self
).
traverse
(
path
=
[
name
],
request
=
REQUEST
).
__of__
(
self
)
except
(
ComponentLookupError
,
NotFound
Error
,
except
(
ComponentLookupError
,
Lookup
Error
,
AttributeError
,
KeyError
,
NotFound
):
pass
try
:
return
getattr
(
self
,
name
)
except
AttributeError
:
...
...
@@ -100,8 +105,9 @@ class FiveTraversable(DefaultTraversable):
REQUEST
=
getattr
(
context
,
'REQUEST'
,
None
)
if
not
IBrowserRequest
.
providedBy
(
REQUEST
):
REQUEST
=
FakeRequest
()
# Try to lookup a view first
setDefaultSkin
(
REQUEST
)
# Try to lookup a view
try
:
return
get
View
(
context
,
name
,
REQUEST
)
return
get
MultiAdapter
((
context
,
REQUEST
),
Interface
,
name
)
except
ComponentLookupError
:
pass
lib/python/Products/Five/utilities/__init__.py
0 → 100644
View file @
528f46df
# make this directory a package
lib/python/Products/Five/utilities/browser/__init__.py
0 → 100644
View file @
528f46df
# make this directory a package
lib/python/Products/Five/utilities/browser/configure.zcml
0 → 100644
View file @
528f46df
<configure xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
<browser:page
for="*"
name="edit-markers.html"
template="edit_markers.pt"
class="Products.Five.utilities.browser.marker.EditView"
permission="zope2.ManageProperties"
/>
<browser:page
for="*"
name="manage_interfaces"
template="manage_interfaces.pt"
class="Products.Five.utilities.browser.marker.EditView"
permission="zope2.ManageProperties"
/>
</configure>
lib/python/Products/Five/utilities/browser/edit_markers.pt
0 → 100644
View file @
528f46df
<html
metal:use-macro=
"context/@@standard_macros/page"
>
<body>
<metal:slot
metal:fill-slot=
"body"
>
<metal:macro
metal:define-macro=
"heading"
>
<h1
i18n:translate=
"heading_edit_marker"
>
Assign Marker Interfaces
</h1>
</metal:macro>
<metal:macro
metal:define-macro=
"main"
>
<p
class=
"form-help formHelp"
i18n:translate=
""
>
Change the behavior of this
object by adding or removing marker interfaces. You can choose one or more
interfaces to be added to the list of provided interfaces for this
object.
</p>
<p
class=
"form-help formHelp"
i18n:translate=
""
>
A marker interface is used to
identify an instance of a piece of content. When in conjunction with Five,
this allows you to enable and disable views based on marker interfaces for
example.
</p>
<form
action=
"."
method=
"post"
tal:attributes=
"action request/ACTUAL_URL"
>
<fieldset>
<legend
i18n:translate=
"legend_provided"
>
Provided Interfaces
</legend>
<tal:loop
tal:repeat=
"interface view/getInterfaceNames"
>
<label
class=
"form-mono"
tal:content=
"interface/name"
i18n:translate=
""
>
INTERFACE
</label><br
/>
</tal:loop>
<tal:loop
tal:repeat=
"interface view/getDirectlyProvidedNames"
>
<input
type=
"checkbox"
id=
"INTERFACE"
name=
"remove:list"
tal:attributes=
"id interface/name; value interface/name"
/>
<label
class=
"form-mono"
for=
"INTERFACE"
tal:attributes=
"for interface/name"
tal:content=
"interface/name"
i18n:translate=
""
>
INTERFACE
</label><br
/>
</tal:loop>
<tal:case
tal:condition=
"view/getDirectlyProvidedNames"
>
<div
class=
"formControls FormButtons"
>
<input
class=
"form-element"
type=
"submit"
name=
"SAVE"
value=
"Remove"
i18n:attributes=
"value"
/>
</div>
</tal:case>
</fieldset>
<fieldset>
<legend
i18n:translate=
"legend_available_marker"
>
Available Marker
Interfaces
</legend>
<tal:loop
tal:repeat=
"interface view/getAvailableInterfaceNames"
>
<input
type=
"checkbox"
id=
"INTERFACE"
name=
"add:list"
tal:attributes=
"id interface/name; value interface/name"
/>
<label
class=
"form-mono"
for=
"INTERFACE"
tal:attributes=
"for interface/name"
tal:content=
"interface/name"
i18n:translate=
""
>
INTERFACE
</label><br
/>
</tal:loop>
<div
class=
"formControls FormButtons"
>
<input
class=
"form-element"
type=
"submit"
name=
"SAVE"
value=
"Add"
i18n:attributes=
"value"
/>
</div>
</fieldset>
</form>
</metal:macro>
</metal:slot>
</body>
</html>
lib/python/Products/Five/utilities/browser/manage_interfaces.pt
0 → 100644
View file @
528f46df
<h1 tal:replace="structure context/manage_page_header">PAGE HEADER</h1>
<h2 tal:replace="structure context/manage_tabs">TABS</h2>
<style type="text/css">
fieldset {width:auto; float:left}
</style>
<metal:macro metal:use-macro="context/@@edit-markers.html/main" />
<h1 tal:replace="structure context/manage_page_footer">PAGE FOOTER</h1>
lib/python/Products/Five/utilities/browser/marker.py
0 → 100644
View file @
528f46df
##############################################################################
#
# Copyright (c) 2004, 2005 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.
#
##############################################################################
"""Marker interfaces adapter views.
$Id$
"""
from
Products.Five.utilities.interfaces
import
IMarkerInterfaces
class
EditView
:
"""Marker interface edit view.
"""
def
__init__
(
self
,
context
,
request
):
self
.
context
=
context
self
.
request
=
request
self
.
adapted
=
IMarkerInterfaces
(
context
)
self
.
context_url
=
self
.
context
.
absolute_url
()
def
__call__
(
self
,
SAVE
=
None
,
add
=
(),
remove
=
()):
if
SAVE
:
self
.
update
(
add
,
remove
)
self
.
request
.
response
.
redirect
(
self
.
request
.
ACTUAL_URL
)
return
''
return
self
.
index
()
def
_getLinkToInterfaceDetailsView
(
self
,
interfaceName
):
return
(
self
.
context_url
+
'/views-details.html?iface=%s&type=zope.publisher.interfaces.browser.IBrowserRequest'
%
interfaceName
)
def
_getNameLinkDicts
(
self
,
interfaceNames
):
return
[
dict
(
name
=
name
,
link
=
self
.
_getLinkToInterfaceDetailsView
(
name
))
for
name
in
interfaceNames
]
def
getAvailableInterfaceNames
(
self
):
return
self
.
_getNameLinkDicts
(
self
.
adapted
.
getAvailableInterfaceNames
())
def
getDirectlyProvidedNames
(
self
):
return
self
.
_getNameLinkDicts
(
self
.
adapted
.
getDirectlyProvidedNames
())
def
getInterfaceNames
(
self
):
return
self
.
_getNameLinkDicts
(
self
.
adapted
.
getInterfaceNames
())
def
update
(
self
,
add
,
remove
):
# this could return errors
add
=
self
.
adapted
.
dottedToInterfaces
(
add
)
remove
=
self
.
adapted
.
dottedToInterfaces
(
remove
)
self
.
adapted
.
update
(
add
=
add
,
remove
=
remove
)
lib/python/Products/Five/utilities/browser/tests/__init__.py
0 → 100644
View file @
528f46df
# make this directory a package
lib/python/Products/Five/utilities/browser/tests/framework.py
0 → 100644
View file @
528f46df
##############################################################################
#
# ZopeTestCase
#
# COPY THIS FILE TO YOUR 'tests' DIRECTORY.
#
# This version of framework.py will use the SOFTWARE_HOME
# environment variable to locate Zope and the Testing package.
#
# If the tests are run in an INSTANCE_HOME installation of Zope,
# Products.__path__ and sys.path with be adjusted to include the
# instance's Products and lib/python directories respectively.
#
# If you explicitly set INSTANCE_HOME prior to running the tests,
# auto-detection is disabled and the specified path will be used
# instead.
#
# If the 'tests' directory contains a custom_zodb.py file, INSTANCE_HOME
# will be adjusted to use it.
#
# If you set the ZEO_INSTANCE_HOME environment variable a ZEO setup
# is assumed, and you can attach to a running ZEO server (via the
# instance's custom_zodb.py).
#
##############################################################################
#
# The following code should be at the top of every test module:
#
# import os, sys
# if __name__ == '__main__':
# execfile(os.path.join(sys.path[0], 'framework.py'))
#
# ...and the following at the bottom:
#
# if __name__ == '__main__':
# framework()
#
##############################################################################
__version__
=
'0.2.3'
# Save start state
#
__SOFTWARE_HOME
=
os
.
environ
.
get
(
'SOFTWARE_HOME'
,
''
)
__INSTANCE_HOME
=
os
.
environ
.
get
(
'INSTANCE_HOME'
,
''
)
if
__SOFTWARE_HOME
.
endswith
(
os
.
sep
):
__SOFTWARE_HOME
=
os
.
path
.
dirname
(
__SOFTWARE_HOME
)
if
__INSTANCE_HOME
.
endswith
(
os
.
sep
):
__INSTANCE_HOME
=
os
.
path
.
dirname
(
__INSTANCE_HOME
)
# Find and import the Testing package
#
if
not
sys
.
modules
.
has_key
(
'Testing'
):
p0
=
sys
.
path
[
0
]
if
p0
and
__name__
==
'__main__'
:
os
.
chdir
(
p0
)
p0
=
''
s
=
__SOFTWARE_HOME
p
=
d
=
s
and
s
or
os
.
getcwd
()
while
d
:
if
os
.
path
.
isdir
(
os
.
path
.
join
(
p
,
'Testing'
)):
zope_home
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
p
))
sys
.
path
[:
1
]
=
[
p0
,
p
,
zope_home
]
break
p
,
d
=
s
and
(
''
,
''
)
or
os
.
path
.
split
(
p
)
else
:
print
'Unable to locate Testing package.'
,
print
'You might need to set SOFTWARE_HOME.'
sys
.
exit
(
1
)
import
Testing
,
unittest
execfile
(
os
.
path
.
join
(
os
.
path
.
dirname
(
Testing
.
__file__
),
'common.py'
))
# Include ZopeTestCase support
#
if
1
:
# Create a new scope
p
=
os
.
path
.
join
(
os
.
path
.
dirname
(
Testing
.
__file__
),
'ZopeTestCase'
)
if
not
os
.
path
.
isdir
(
p
):
print
'Unable to locate ZopeTestCase package.'
,
print
'You might need to install ZopeTestCase.'
sys
.
exit
(
1
)
ztc_common
=
'ztc_common.py'
ztc_common_global
=
os
.
path
.
join
(
p
,
ztc_common
)
f
=
0
if
os
.
path
.
exists
(
ztc_common_global
):
execfile
(
ztc_common_global
)
f
=
1
if
os
.
path
.
exists
(
ztc_common
):
execfile
(
ztc_common
)
f
=
1
if
not
f
:
print
'Unable to locate %s.'
%
ztc_common
sys
.
exit
(
1
)
# Debug
#
print
'SOFTWARE_HOME: %s'
%
os
.
environ
.
get
(
'SOFTWARE_HOME'
,
'Not set'
)
print
'INSTANCE_HOME: %s'
%
os
.
environ
.
get
(
'INSTANCE_HOME'
,
'Not set'
)
sys
.
stdout
.
flush
()
lib/python/Products/Five/utilities/browser/tests/test_marker.py
0 → 100644
View file @
528f46df
##############################################################################
#
# Copyright (c) 2004, 2005 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.
#
##############################################################################
"""Unit tests for marker interface views.
$Id$
"""
import
os
,
sys
if
__name__
==
'__main__'
:
execfile
(
os
.
path
.
join
(
sys
.
path
[
0
],
'framework.py'
))
def
test_editview
():
"""
Set everything up:
>>> from zope.app.testing.placelesssetup import setUp, tearDown
>>> setUp()
>>> import Products.Five
>>> import Products.Five.utilities
>>> from Products.Five import zcml
>>> zcml.load_config('meta.zcml', Products.Five)
>>> zcml.load_config('permissions.zcml', Products.Five)
>>> zcml.load_config('configure.zcml', Products.Five.utilities)
>>> from Products.Five.utilities.browser.marker import EditView
>>> from Products.Five.tests.testing.simplecontent import SimpleContent
>>> obj = SimpleContent('foo', 'Foo').__of__(self.folder)
Create an EditView:
>>> view = EditView(obj, {})
>>> view.context.aq_inner is obj
True
>>> view.request
{}
>>> view.getAvailableInterfaceNames()
[]
>>> view.getDirectlyProvidedNames()
[]
>>> view.getInterfaceNames()
[...ISimpleContent...]
Try to add a marker interface that doesn't exist:
>>> view.update(('__builtin__.IFooMarker',), ())
Traceback (most recent call last):
...
ComponentLookupError...
Now create the marker interface:
>>> from Products.Five.tests.testing.simplecontent import ISimpleContent
>>> class IFooMarker(ISimpleContent): pass
>>> from zope.app.component.interface import provideInterface
>>> provideInterface('', IFooMarker)
>>> view.getAvailableInterfaceNames()
[...IFooMarker...]
>>> view.getDirectlyProvidedNames()
[]
And try again to add it to the object:
>>> view.update(('__builtin__.IFooMarker',), ())
>>> view.getAvailableInterfaceNames()
[]
>>> view.getDirectlyProvidedNames()
[...IFooMarker...]
And remove it again:
>>> view.update((), ('__builtin__.IFooMarker',))
>>> view.getAvailableInterfaceNames()
[...IFooMarker...]
>>> view.getDirectlyProvidedNames()
[]
Finally tear down:
>>> tearDown()
"""
def
test_suite
():
from
Testing.ZopeTestCase
import
ZopeDocTestSuite
return
ZopeDocTestSuite
()
if
__name__
==
'__main__'
:
framework
()
lib/python/Products/Five/utilities/configure.zcml
0 → 100644
View file @
528f46df
<configure xmlns="http://namespaces.zope.org/zope">
<include package=".browser"/>
<adapter
for="*"
provides=".interfaces.IMarkerInterfaces"
factory=".marker.MarkerInterfacesAdapter"
permission="zope2.ManageProperties"
/>
</configure>
lib/python/Products/Five/utilities/interfaces.py
0 → 100644
View file @
528f46df
##############################################################################
#
# Copyright (c) 2004, 2005 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.
#
##############################################################################
"""Utility Interface Definitions.
$Id$
"""
from
zope.interface
import
Interface
class
IReadInterface
(
Interface
):
def
getDirectlyProvided
():
"""List the interfaces directly implemented by the object.
"""
def
getDirectlyProvidedNames
():
"""List the names of interfaces directly implemented by the object.
"""
def
getAvailableInterfaces
():
"""List the marker interfaces available for the object.
"""
def
getAvailableInterfaceNames
():
"""List the names of marker interfaces available for the object.
"""
def
getInterfaces
():
"""List interfaces provided by the class of the object.
"""
def
getInterfaceNames
():
"""List the names of interfaces provided by the class of the object.
"""
def
getProvided
():
"""List interfaces provided by the object.
"""
def
getDirectlyProvidedNames
():
"""List the names of interfaces provided by the object.
"""
class
IWriteInterface
(
Interface
):
def
update
(
add
=
(),
remove
=
()):
"""Update directly provided interfaces of the object.
"""
def
mark
(
interface
):
"""Add interface to interfaces the object directly provides.
"""
def
erase
(
interface
):
"""Remove interfaces from interfaces the object directly provides.
"""
class
IMarkerInterfaces
(
IReadInterface
,
IWriteInterface
):
"""Provides methods for inspecting and assigning marker interfaces.
"""
lib/python/Products/Five/utilities/marker.py
0 → 100644
View file @
528f46df
##############################################################################
#
# Copyright (c) 2004, 2005 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.
#
##############################################################################
"""Marker interfaces adapter.
Allows for arbitrary application of marker interfaces to objects.
$Id$
"""
from
sets
import
Set
from
zope.interface
import
implements
from
zope.interface
import
implementedBy
from
zope.interface
import
directlyProvidedBy
from
zope.interface
import
directlyProvides
from
zope.interface
import
providedBy
from
zope.interface.interfaces
import
IInterface
from
zope.app.component.interface
import
getInterface
,
interfaceToName
from
zope.app.component.interface
import
searchInterface
from
interfaces
import
IMarkerInterfaces
def
interfaceStringCheck
(
f
):
def
wrapper
(
ob
,
interface
):
if
isinstance
(
interface
,
str
):
interface
=
getInterface
(
ob
,
interface
)
return
f
(
ob
,
interface
)
return
wrapper
def
mark
(
ob
,
interface
):
directlyProvides
(
ob
,
directlyProvidedBy
(
ob
),
interface
)
def
erase
(
ob
,
interface
):
directlyProvides
(
ob
,
directlyProvidedBy
(
ob
)
-
interface
)
mark
=
interfaceStringCheck
(
mark
)
erase
=
interfaceStringCheck
(
erase
)
class
MarkerInterfacesAdapter
(
object
):
implements
(
IMarkerInterfaces
)
mark
=
staticmethod
(
mark
)
erase
=
staticmethod
(
erase
)
def
__init__
(
self
,
context
):
self
.
context
=
context
def
dottedToInterfaces
(
self
,
seq
):
return
[
getInterface
(
self
.
context
,
dotted
)
for
dotted
in
seq
]
def
getDirectlyProvided
(
self
):
return
directlyProvidedBy
(
self
.
context
)
def
getDirectlyProvidedNames
(
self
):
return
self
.
_getInterfaceNames
(
self
.
getDirectlyProvided
())
def
getAvailableInterfaces
(
self
):
results
=
[]
todo
=
list
(
providedBy
(
self
.
context
))
done
=
[]
while
todo
:
interface
=
todo
.
pop
()
done
.
append
(
interface
)
for
base
in
interface
.
__bases__
:
if
base
not
in
todo
and
base
not
in
done
:
todo
.
append
(
base
)
markers
=
self
.
_getDirectMarkersOf
(
interface
)
for
interface
in
markers
:
if
(
interface
not
in
results
and
not
interface
.
providedBy
(
self
.
context
)):
results
.
append
(
interface
)
todo
+=
markers
return
tuple
(
results
)
def
getAvailableInterfaceNames
(
self
):
names
=
self
.
_getInterfaceNames
(
self
.
getAvailableInterfaces
())
names
.
sort
()
return
names
def
getInterfaces
(
self
):
return
tuple
(
implementedBy
(
self
.
context
.
__class__
))
def
getInterfaceNames
(
self
):
return
self
.
_getInterfaceNames
(
self
.
getInterfaces
())
def
getProvided
(
self
):
return
providedBy
(
self
.
context
)
def
getProvidedNames
(
self
):
return
self
.
_getInterfaceNames
(
self
.
getProvided
())
def
update
(
self
,
add
=
(),
remove
=
()):
"""Currently update adds and then removes, rendering duplicate null.
"""
marker_ifaces
=
self
.
getAvailableInterfaces
()
if
len
(
add
):
[
mark
(
self
.
context
,
interface
)
for
interface
in
Set
(
marker_ifaces
)
&
Set
(
add
)]
direct_ifaces
=
self
.
getDirectlyProvided
()
if
len
(
remove
):
[
erase
(
self
.
context
,
interface
)
for
interface
in
Set
(
direct_ifaces
)
&
Set
(
remove
)]
def
_getInterfaceNames
(
self
,
interfaces
):
return
[
interfaceToName
(
self
,
iface
)
for
iface
in
interfaces
]
def
_getDirectMarkersOf
(
self
,
base
):
"""Get empty interfaces directly inheriting from the given one.
"""
results
=
[]
interfaces
=
searchInterface
(
None
,
base
=
base
)
for
interface
in
interfaces
:
# There are things registered with the interface service
# that are not interfaces. Yay!
if
not
IInterface
.
providedBy
(
interface
):
continue
if
base
in
interface
.
__bases__
and
not
interface
.
names
():
results
.
append
(
interface
)
results
.
sort
()
return
tuple
(
results
)
lib/python/Products/Five/version.txt
View file @
528f46df
Five 1.
1
Five 1.
3b
lib/python/Products/Five/viewable.py
View file @
528f46df
...
...
@@ -17,10 +17,10 @@ $Id: viewable.py 14595 2005-07-12 21:26:12Z philikon $
"""
import
inspect
from
zExceptions
import
NotFound
from
zope.exceptions
import
NotFoundError
from
zope.component
import
getView
,
getDefaultViewName
,
ComponentLookupError
from
zope.component
import
ComponentLookupError
from
zope.interface
import
implements
from
zope.publisher.interfaces.browser
import
IBrowserRequest
from
zope.app.zapi
import
getDefaultViewName
from
Products.Five.traversable
import
FakeRequest
from
Products.Five.interfaces
import
IBrowserDefault
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment