[Checkins] SVN: zope.contentprovider/tags/3.5.0/ Tag 3.5.0
Dan Korostelev
nadako at gmail.com
Tue Mar 17 17:06:32 EDT 2009
Log message for revision 98213:
Tag 3.5.0
Changed:
A zope.contentprovider/tags/3.5.0/
D zope.contentprovider/tags/3.5.0/CHANGES.txt
A zope.contentprovider/tags/3.5.0/CHANGES.txt
D zope.contentprovider/tags/3.5.0/README.txt
A zope.contentprovider/tags/3.5.0/README.txt
D zope.contentprovider/tags/3.5.0/setup.py
A zope.contentprovider/tags/3.5.0/setup.py
D zope.contentprovider/tags/3.5.0/src/zope/contentprovider/README.txt
A zope.contentprovider/tags/3.5.0/src/zope/contentprovider/README.txt
D zope.contentprovider/tags/3.5.0/src/zope/contentprovider/__init__.py
A zope.contentprovider/tags/3.5.0/src/zope/contentprovider/__init__.py
D zope.contentprovider/tags/3.5.0/src/zope/contentprovider/configure.zcml
A zope.contentprovider/tags/3.5.0/src/zope/contentprovider/configure.zcml
D zope.contentprovider/tags/3.5.0/src/zope/contentprovider/interfaces.py
A zope.contentprovider/tags/3.5.0/src/zope/contentprovider/interfaces.py
D zope.contentprovider/tags/3.5.0/src/zope/contentprovider/tales.py
A zope.contentprovider/tags/3.5.0/src/zope/contentprovider/tales.py
D zope.contentprovider/tags/3.5.0/src/zope/contentprovider/tests.py
A zope.contentprovider/tags/3.5.0/src/zope/contentprovider/tests.py
-=-
Deleted: zope.contentprovider/tags/3.5.0/CHANGES.txt
===================================================================
--- zope.contentprovider/trunk/CHANGES.txt 2009-03-17 17:31:53 UTC (rev 98210)
+++ zope.contentprovider/tags/3.5.0/CHANGES.txt 2009-03-17 21:06:31 UTC (rev 98213)
@@ -1,25 +0,0 @@
-=======
-CHANGES
-=======
-
-3.4.1 (unreleased)
-------------------
-
-- Add very simple, but useful base class for implementing content
- providers, see ``zope.contentprovider.provider.ContentProviderBase``.
-
-- Remove unneeded testing dependencies. We only need zope.testing and
- zope.app.pagetemplate.
-
-- Remove zcml slug and old zpkg-related files.
-
-- Added setuptools dependency to setup.py.
-
-- Change mailing list address to zope-dev at zope.org instead of retired one.
-
-- Change ``cheeseshop`` to ``pypi`` in the package url.
-
-3.4.0 (2007-10-02)
-------------------
-
-- Initial release independent of the main Zope tree.
Copied: zope.contentprovider/tags/3.5.0/CHANGES.txt (from rev 98211, zope.contentprovider/trunk/CHANGES.txt)
===================================================================
--- zope.contentprovider/tags/3.5.0/CHANGES.txt (rev 0)
+++ zope.contentprovider/tags/3.5.0/CHANGES.txt 2009-03-17 21:06:31 UTC (rev 98213)
@@ -0,0 +1,29 @@
+=======
+CHANGES
+=======
+
+3.5.0 (2009-03-18)
+------------------
+
+- Add very simple, but useful base class for implementing content
+ providers, see ``zope.contentprovider.provider.ContentProviderBase``.
+
+- Remove unneeded testing dependencies. We only need zope.testing and
+ zope.app.pagetemplate.
+
+- Remove zcml slug and old zpkg-related files.
+
+- Added setuptools dependency to setup.py.
+
+- Clean up package's description and documentation a bit. Remove
+ duplicate text in README.
+
+- Change mailing list address to zope-dev at zope.org instead of
+ retired one.
+
+- Change ``cheeseshop`` to ``pypi`` in the package url.
+
+3.4.0 (2007-10-02)
+------------------
+
+- Initial release independent of the main Zope tree.
Deleted: zope.contentprovider/tags/3.5.0/README.txt
===================================================================
--- zope.contentprovider/trunk/README.txt 2009-03-17 17:31:53 UTC (rev 98210)
+++ zope.contentprovider/tags/3.5.0/README.txt 2009-03-17 21:06:31 UTC (rev 98213)
@@ -1,12 +0,0 @@
-====================
-zope.contentprovider
-====================
-
-Overview
---------
-
-This package provides a framework to develop componentized Web GUI
-applications. Instead of describing the content of a page using a single
-template or static system of templates and METAL macros, content provider
-objects are dynamically looked up based on the setup/configuration of the
-application.
Copied: zope.contentprovider/tags/3.5.0/README.txt (from rev 98211, zope.contentprovider/trunk/README.txt)
===================================================================
--- zope.contentprovider/tags/3.5.0/README.txt (rev 0)
+++ zope.contentprovider/tags/3.5.0/README.txt 2009-03-17 21:06:31 UTC (rev 98213)
@@ -0,0 +1 @@
+See src/zope/contentprovider/README.txt.
Deleted: zope.contentprovider/tags/3.5.0/setup.py
===================================================================
--- zope.contentprovider/trunk/setup.py 2009-03-17 17:31:53 UTC (rev 98210)
+++ zope.contentprovider/tags/3.5.0/setup.py 2009-03-17 21:06:31 UTC (rev 98213)
@@ -1,67 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Setup for zope.contentprovider package
-
-$Id$
-"""
-import os
-from setuptools import setup, find_packages
-
-def read(*rnames):
- return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
-
-setup(name='zope.contentprovider',
- version = '3.4.1dev',
- author='Zope Corporation and Contributors',
- author_email='zope-dev at zope.org',
- description='Zope Content Providers',
- long_description=(
- read('README.txt')
- + '\n\n' +
- read('src', 'zope', 'contentprovider', 'README.txt')
- + '\n\n' +
- read('CHANGES.txt')
- ),
- keywords = "zope3 content provider",
- classifiers = [
- 'Development Status :: 5 - Production/Stable',
- 'Environment :: Web Environment',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: Zope Public License',
- 'Programming Language :: Python',
- 'Natural Language :: English',
- 'Operating System :: OS Independent',
- 'Topic :: Internet :: WWW/HTTP',
- 'Framework :: Zope3'],
- url='http://pypi.python.org/pypi/zope.contentprovider',
- license='ZPL 2.1',
- packages=find_packages('src'),
- package_dir = {'': 'src'},
- namespace_packages=['zope'],
- extras_require = dict(
- test=['zope.app.pagetemplate',
- 'zope.testing',
- ]),
- install_requires=['setuptools',
- 'zope.component',
- 'zope.event',
- 'zope.interface',
- 'zope.location',
- 'zope.publisher',
- 'zope.schema',
- 'zope.tales',
- ],
- include_package_data = True,
- zip_safe = False,
- )
Copied: zope.contentprovider/tags/3.5.0/setup.py (from rev 98211, zope.contentprovider/trunk/setup.py)
===================================================================
--- zope.contentprovider/tags/3.5.0/setup.py (rev 0)
+++ zope.contentprovider/tags/3.5.0/setup.py 2009-03-17 21:06:31 UTC (rev 98213)
@@ -0,0 +1,65 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Setup for zope.contentprovider package
+
+$Id$
+"""
+import os
+from setuptools import setup, find_packages
+
+def read(*rnames):
+ return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+setup(name='zope.contentprovider',
+ version = '3.5.0',
+ author='Zope Corporation and Contributors',
+ author_email='zope-dev at zope.org',
+ description='Content Provider Framework for Zope Templates',
+ long_description=(
+ read('src', 'zope', 'contentprovider', 'README.txt')
+ + '\n\n' +
+ read('CHANGES.txt')
+ ),
+ keywords = "zope3 content provider",
+ classifiers = [
+ 'Development Status :: 5 - Production/Stable',
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: Zope Public License',
+ 'Programming Language :: Python',
+ 'Natural Language :: English',
+ 'Operating System :: OS Independent',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Framework :: Zope3'],
+ url='http://pypi.python.org/pypi/zope.contentprovider',
+ license='ZPL 2.1',
+ packages=find_packages('src'),
+ package_dir = {'': 'src'},
+ namespace_packages=['zope'],
+ extras_require = dict(
+ test=['zope.app.pagetemplate',
+ 'zope.testing',
+ ]),
+ install_requires=['setuptools',
+ 'zope.component',
+ 'zope.event',
+ 'zope.interface',
+ 'zope.location',
+ 'zope.publisher',
+ 'zope.schema',
+ 'zope.tales',
+ ],
+ include_package_data = True,
+ zip_safe = False,
+ )
Deleted: zope.contentprovider/tags/3.5.0/src/zope/contentprovider/README.txt
===================================================================
--- zope.contentprovider/trunk/src/zope/contentprovider/README.txt 2009-03-17 17:31:53 UTC (rev 98210)
+++ zope.contentprovider/tags/3.5.0/src/zope/contentprovider/README.txt 2009-03-17 21:06:31 UTC (rev 98213)
@@ -1,574 +0,0 @@
-=================
-Content Providers
-=================
-
-This package provides a framework to develop componentized Web GUI
-applications. Instead of describing the content of a page using a single
-template or static system of templates and METAL macros, content provider
-objects are dynamically looked up based on the setup/configuration of the
-application.
-
- >>> from zope.contentprovider import interfaces
-
-
-Motivation and Design Goals
----------------------------
-
-Before diving into the features of this package let me take up a few bytes of
-text to explain the use cases that drove us to develop this package (also
-others) and how the API documented below fulfills/solves those use cases. When
-we started developing Zope 3, it was from a desire to decentralize
-functionality and thus the complexity of the Python code. And we were
-successful! The component architecture is a marvelous piece of software that
-hopefully will allow us to build scalable solutions for a very long
-time. However, when it comes to user interface design, in this case
-specifically HTML pages, we have failed to provide the features and patterns
-of assembeling a page from configured components.
-
-Looking up views for a particular content component and a request just simply
-does not work by itself. The content inside the page is still monolithic. One
-attempt to solve this problem are METAL macros, which allow you to insert
-other TAL snippets into your main template. But macros have two shortcomings.
-For one there is a "hard-coded" one-to-one mapping between a slot and the
-macro that fills that slot, which makes it impossible to register several
-macros for a given location. The second problem is that macros are not views
-in their own right; thus they cannot provide functionality that is independent
-of the main template's view.
-
-A second approach to modular UI design are rendering pipes. Rendering pipes
-have the great advantage that they can reach all regions of the page during
-every step of the rendering process. For example, if we have a widget in the
-middle of the page that requires some additional Javascript, then it is easy
-for a rendering unit to insert the Javascript file link in the HTML header of
-the page. This type of use case is very hard to solve using page
-templates. However, pipes are not the answer to componentized user interface,
-since they cannot simply deal with registering random content for a given page
-region. In fact, I propose that pipelines are orthogonal to content providers,
-the concept introducted below. A pipeline framework could easily use
-functionality provided by this and other packages to provide component-driven
-UI design.
-
-So our goal is clear: Bring the pluggability of the component architecture
-into page templates and user interface design. Zope is commonly known to
-reinvent the wheel, develop its own terminology and misuse other's terms. For
-example, the Plone community has a very different understanding of what a
-"portlet" is compared to the commonly accepted meaning in the corporate world,
-which derives its definition from JSR 168. Therefore an additional use case of
-the design of this package was to stick with common terms and use them in
-their original meaning -- well, given a little extra twist.
-
-The most basic user interface component in the Web application Java world is
-the "content provider" [1]_. A content provider is simply responsible for
-providing HTML content for a page. This is equivalent to a view that does not
-provide a full page, but just a snippet, much like widgets or macros. Once
-there is a way to configure those content providers, we need a way to
-inserting them into our page templates. In our implementation this is
-accomplished using a new TALES namespace that allows to insert content
-providers by name. But how, you might wonder, does this provide a
-componentized user interface? On the Zope 3 level, each content provider is
-registered as a presentation component discriminted by the context, request
-and view it will appear in. Thus different content providers will be picked
-for different configurations.
-
-Okay, that's pretty much everything there is to say about content
-providers. What, we are done? Hold on, what about defining regions of pages
-and filling them configured UI snippets. The short answer is: See the
-``zope.viewlet`` pacakge. But let me also give you the long answer. This and
-the other pacakges were developed using real world use cases. While doing
-this, we noticed that not every project would need, for example, all the
-features of a portlet, but would still profit from lower-level features. Thus
-we decided to declare clear boundaries of functionality and providing each
-level in a different package. This particualr package is only meant to provide
-the interface between the content provider world and page templates.
-
-.. [1] Note that this is a bit different from the role named content provider,
- which refers to a service that provides content; the content provider
- we are talking about here are the software components the service would
- provide to an application.
-
-
-Content Providers
------------------
-
-Content Provider is a term from the Java world that refers to components that
-can provide HTML content. It means nothing more! How the content is found and
-returned is totally up to the implementation. The Zope 3 touch to the concept
-is that content providers are multi-adapters that are looked up by the
-context, request (and thus the layer/skin), and view they are displayed in.
-
-The second important concept of content providers are their two-phase
-rendering design. In the first phase the state of the content provider is
-prepared and, if applicable, any data, the provider is responsible for, is
-updated.
-
-So let's create a simple content provider:
-
- >>> import zope.interface
- >>> import zope.component
- >>> from zope.publisher.interfaces import browser
-
- >>> class MessageBox(object):
- ... zope.interface.implements(interfaces.IContentProvider)
- ... zope.component.adapts(zope.interface.Interface,
- ... browser.IDefaultBrowserLayer,
- ... zope.interface.Interface)
- ... message = u'My Message'
- ...
- ... def __init__(self, context, request, view):
- ... self.__parent__ = view
- ...
- ... def update(self):
- ... pass
- ...
- ... def render(self):
- ... return u'<div class="box">%s</div>' %self.message
-
-The ``update()`` method is executed during phase one. Since no state needs to
-be calculated and no data is modified by this simple content provider, it is
-an empty implementation. The ``render()`` method implements phase 2 of the
-process. We can now instantiate the content provider (manually) and render it:
-
- >>> box = MessageBox(None, None, None)
- >>> box.render()
- u'<div class="box">My Message</div>'
-
-Since our content provider did not require the context, request or view to
-create its HTML content, we were able to pass trivial dummy values into the
-constructor. Also note that the provider must have a parent (using the
-``__parent__`` attribute) specified at all times. The parent must be the view
-the provider appears in.
-
-I agree, this functionally does not seem very useful now. The constructor and
-the ``update()`` method seem useless and the returned content is totally
-static. However, we implemented a contract for content providers that other
-code can rely on. Content providers are (commonly) instantiated using the
-context, request and view they appear in and are required to always generate
-its HTML using those three components.
-
-
-Two-Phased Content Providers
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Let's now have a look at a content provider that actively uses the two-phase
-rendering process. The simpler scenario is the case where the content provider
-updates a content component without affecting anything else. So let's create a
-content component to be updated,
-
- >>> class Article(object):
- ... title = u'initial'
- >>> article = Article()
-
-and the content provider that is updating the title:
-
- >>> class ChangeTitle(object):
- ... zope.interface.implements(interfaces.IContentProvider)
- ... zope.component.adapts(zope.interface.Interface,
- ... browser.IDefaultBrowserLayer,
- ... zope.interface.Interface)
- ... fieldName = 'ChangeTitle.title'
- ...
- ... def __init__(self, context, request, view):
- ... self.__parent__ = view
- ... self.context, self.request = context, request
- ...
- ... def update(self):
- ... if self.fieldName in self.request:
- ... self.context.title = self.request[self.fieldName]
- ...
- ... def render(self):
- ... return u'<input name="%s" value="%s" />' % (self.fieldName,
- ... self.context.title)
-
-Using a request, let's now instantiate the content provider and go through the
-two-phase rendering process:
-
- >>> from zope.publisher.browser import TestRequest
- >>> request = TestRequest()
- >>> changer = ChangeTitle(article, request, None)
- >>> changer.update()
- >>> changer.render()
- u'<input name="ChangeTitle.title" value="initial" />'
-
-Let's now enter a new title and render the provider:
-
- >>> request = TestRequest(form={'ChangeTitle.title': u'new title'})
- >>> changer = ChangeTitle(article, request, None)
- >>> changer.update()
- >>> changer.render()
- u'<input name="ChangeTitle.title" value="new title" />'
- >>> article.title
- u'new title'
-
-So this was easy. Let's now look at a case where one content provider's update
-influences the content of another. Let's say we have a content provider that
-displays the article's title:
-
- >>> class ViewTitle(object):
- ... zope.interface.implements(interfaces.IContentProvider)
- ... zope.component.adapts(zope.interface.Interface,
- ... browser.IDefaultBrowserLayer,
- ... zope.interface.Interface)
- ...
- ... def __init__(self, context, request, view):
- ... self.context, self.__parent__ = context, view
- ...
- ... def update(self):
- ... pass
- ...
- ... def render(self):
- ... return u'<h1>Title: %s</h1>' % self.context.title
-
-Let's now say that the `ShowTitle` content provider is shown on a page
-*before* the `ChangeTitle` content provider. If we do the full rendering
-process for each provider in sequence, we get the wrong result:
-
- >>> request = TestRequest(form={'ChangeTitle.title': u'newer title'})
-
- >>> viewer = ViewTitle(article, request, None)
- >>> viewer.update()
- >>> viewer.render()
- u'<h1>Title: new title</h1>'
-
- >>> changer = ChangeTitle(article, request, None)
- >>> changer.update()
- >>> changer.render()
- u'<input name="ChangeTitle.title" value="newer title" />'
-
-So the correct way of doing this is to first complete phase 1 (update) for all
-providers, before executing phase 2 (render):
-
- >>> request = TestRequest(form={'ChangeTitle.title': u'newest title'})
-
- >>> viewer = ViewTitle(article, request, None)
- >>> changer = ChangeTitle(article, request, None)
-
- >>> viewer.update()
- >>> changer.update()
-
- >>> viewer.render()
- u'<h1>Title: newest title</h1>'
-
- >>> changer.render()
- u'<input name="ChangeTitle.title" value="newest title" />'
-
-
-``UpdateNotCalled`` Errors
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Since calling ``update()`` before any other method that mutates the provider
-or any other data is so important to the correct functioning of the API, the
-developer has the choice to raise the ``UpdateNotCalled`` error, if any method
-is called before ``update()`` (with exception of the constructor):
-
- >>> class InfoBox(object):
- ... zope.interface.implements(interfaces.IContentProvider)
- ... zope.component.adapts(zope.interface.Interface,
- ... browser.IDefaultBrowserLayer,
- ... zope.interface.Interface)
- ...
- ... def __init__(self, context, request, view):
- ... self.__parent__ = view
- ... self.__updated = False
- ...
- ... def update(self):
- ... self.__updated = True
- ...
- ... def render(self):
- ... if not self.__updated:
- ... raise interfaces.UpdateNotCalled
- ... return u'<div>Some information</div>'
-
- >>> info = InfoBox(None, None, None)
-
- >>> info.render()
- Traceback (most recent call last):
- ...
- UpdateNotCalled: ``update()`` was not called yet.
-
- >>> info.update()
-
- >>> info.render()
- u'<div>Some information</div>'
-
-
-The TALES ``provider`` Expression
----------------------------------
-
-The ``provider`` expression will look up the name of the content provider,
-call it and return the HTML content. The first step, however, will be to
-register our content provider with the component architecture:
-
- >>> zope.component.provideAdapter(MessageBox, name='mypage.MessageBox')
-
-The content provider must be registered by name, since the TALES expression
-uses the name to look up the provider at run time.
-
-Let's now create a view using a page template:
-
- >>> import os, tempfile
- >>> temp_dir = tempfile.mkdtemp()
- >>> templateFileName = os.path.join(temp_dir, 'template.pt')
- >>> open(templateFileName, 'w').write('''
- ... <html>
- ... <body>
- ... <h1>My Web Page</h1>
- ... <div class="left-column">
- ... <tal:block replace="structure provider:mypage.MessageBox" />
- ... </div>
- ... <div class="main">
- ... Content here
- ... </div>
- ... </body>
- ... </html>
- ... ''')
-
-As you can see, we exprect the ``provider`` expression to simply look up the
-content provider and insert the HTML content at this place.
-
-Next we register the template as a view (browser page) for all objects:
-
- >>> from zope.app.pagetemplate.simpleviewclass import SimpleViewClass
- >>> FrontPage = SimpleViewClass(templateFileName, name='main.html')
-
- >>> zope.component.provideAdapter(
- ... FrontPage,
- ... (zope.interface.Interface, browser.IDefaultBrowserLayer),
- ... zope.interface.Interface,
- ... name='main.html')
-
-Let's create a content object that can be viewed:
-
- >>> class Content(object):
- ... zope.interface.implements(zope.interface.Interface)
-
- >>> content = Content()
-
-Finally we look up the view and render it. Note that a
-BeforeUpdateEvent is fired - this event should always be fired before
-any contentprovider is updated.
-
- >>> from zope.publisher.browser import TestRequest
- >>> events = []
- >>> zope.component.provideHandler(events.append, (None, ))
- >>> request = TestRequest()
-
- >>> view = zope.component.getMultiAdapter((content, request),
- ... name='main.html')
- >>> print view().strip()
- <html>
- <body>
- <h1>My Web Page</h1>
- <div class="left-column">
- <div class="box">My Message</div>
- </div>
- <div class="main">
- Content here
- </div>
- </body>
- </html>
-
- >>> events
- [<zope.contentprovider.interfaces.BeforeUpdateEvent object at ...>]
-
-The event holds the provider and the request.
-
- >>> events[0].request
- <zope.publisher.browser.TestRequest instance URL=http://127.0.0.1>
- >>> events[0].object
- <MessageBox object at ...>
-
-Failure to lookup a Content Provider
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If the name is not found, an error is raised. To demonstrate this behavior
-let's create another template:
-
- >>> errorFileName = os.path.join(temp_dir, 'error.pt')
- >>> open(errorFileName, 'w').write('''
- ... <html>
- ... <body>
- ... <tal:block replace="structure provider:mypage.UnknownName" />
- ... </body>
- ... </html>
- ... ''')
-
- >>> ErrorPage = SimpleViewClass(errorFileName, name='error.html')
- >>> zope.component.provideAdapter(
- ... ErrorPage,
- ... (zope.interface.Interface, browser.IDefaultBrowserLayer),
- ... zope.interface.Interface,
- ... name='main.html')
-
- >>> errorview = zope.component.getMultiAdapter((content, request),
- ... name='main.html')
- >>> print errorview()
- Traceback (most recent call last):
- ...
- ContentProviderLookupError: mypage.UnknownName
-
-
-Additional Data from TAL
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-The ``provider`` expression allows also for transferring data from the TAL
-context into the content provider. This is accomplished by having the content
-provider implement an interface that specifies the attributes and provides
-``ITALNamespaceData``:
-
- >>> import zope.schema
- >>> class IMessageText(zope.interface.Interface):
- ... message = zope.schema.Text(title=u'Text of the message box')
-
- >>> zope.interface.directlyProvides(IMessageText,
- ... interfaces.ITALNamespaceData)
-
-Now the message box can receive its text from the TAL environment:
-
- >>> class DynamicMessageBox(MessageBox):
- ... zope.interface.implements(IMessageText)
-
- >>> zope.component.provideAdapter(
- ... DynamicMessageBox, provides=interfaces.IContentProvider,
- ... name='mypage.DynamicMessageBox')
-
-We are now updating our original template to provide the message text:
-
- >>> open(templateFileName, 'w').write('''
- ... <html>
- ... <body>
- ... <h1>My Web Page</h1>
- ... <div class="left-column">
- ... <tal:block define="message string:Hello World!"
- ... replace="structure provider:mypage.DynamicMessageBox" />
- ... <tal:block define="message string:Hello World again!"
- ... replace="structure provider:mypage.DynamicMessageBox" />
- ... </div>
- ... <div class="main">
- ... Content here
- ... </div>
- ... </body>
- ... </html>
- ... ''')
-
-Now we should get two message boxes with different text:
-
- >>> print view().strip()
- <html>
- <body>
- <h1>My Web Page</h1>
- <div class="left-column">
- <div class="box">Hello World!</div>
- <div class="box">Hello World again!</div>
- </div>
- <div class="main">
- Content here
- </div>
- </body>
- </html>
-
-Finally, a content provider can also implement several ``ITALNamespaceData``:
-
- >>> class IMessageType(zope.interface.Interface):
- ... type = zope.schema.TextLine(title=u'The type of the message box')
-
- >>> zope.interface.directlyProvides(IMessageType,
- ... interfaces.ITALNamespaceData)
-
-We'll change our message box content provider implementation a bit, so the new
-information is used:
-
- >>> class BetterDynamicMessageBox(DynamicMessageBox):
- ... zope.interface.implements(IMessageType)
- ... type = None
- ...
- ... def render(self):
- ... return u'<div class="box,%s">%s</div>' %(self.type, self.message)
-
- >>> zope.component.provideAdapter(
- ... BetterDynamicMessageBox, provides=interfaces.IContentProvider,
- ... name='mypage.MessageBox')
-
-Of course, we also have to make our tempalte a little bit more dynamic as
-well:
-
- >>> open(templateFileName, 'w').write('''
- ... <html>
- ... <body>
- ... <h1>My Web Page</h1>
- ... <div class="left-column">
- ... <tal:block define="message string:Hello World!;
- ... type string:error"
- ... replace="structure provider:mypage.MessageBox" />
- ... <tal:block define="message string:Hello World again!;
- ... type string:warning"
- ... replace="structure provider:mypage.MessageBox" />
- ... </div>
- ... <div class="main">
- ... Content here
- ... </div>
- ... </body>
- ... </html>
- ... ''')
-
-Now we should get two message boxes with different text and types:
-
- >>> print view().strip()
- <html>
- <body>
- <h1>My Web Page</h1>
- <div class="left-column">
- <div class="box,error">Hello World!</div>
- <div class="box,warning">Hello World again!</div>
- </div>
- <div class="main">
- Content here
- </div>
- </body>
- </html>
-
-
-Base class
-----------
-
-The ``zope.contentprovider.provider`` module provides an useful base
-class for implementing content providers. It has all boilerplate code
-and it's only required to override the ``render`` method to make it
-work:
-
- >>> from zope.contentprovider.provider import ContentProviderBase
- >>> class MyProvider(ContentProviderBase):
- ... def render(self, *args, **kwargs):
- ... return 'Hi there'
-
- >>> provider = MyProvider(None, None, None)
- >>> interfaces.IContentProvider.providedBy(provider)
- True
-
- >>> provider.update()
- >>> print provider.render()
- Hi there
-
-Note, that it can't be used as is, without providing the ``render`` method:
-
- >>> bad = ContentProviderBase(None, None, None)
- >>> bad.update()
- >>> print bad.render()
- Traceback (most recent call last):
- ...
- NotImplementedError: ``render`` method must be implemented by subclass
-
-You can add the update logic into the ``update`` method as with any content
-provider and you can implement more complex rendering patterns, based on
-templates, using this ContentProviderBase class as a base.
-
-
-You might also want to look at the ``zope.viewlet`` package for a more
-featureful API.
-
-
-Cleanup
--------
-
- >>> import shutil
- >>> shutil.rmtree(temp_dir)
-
Copied: zope.contentprovider/tags/3.5.0/src/zope/contentprovider/README.txt (from rev 98211, zope.contentprovider/trunk/src/zope/contentprovider/README.txt)
===================================================================
--- zope.contentprovider/tags/3.5.0/src/zope/contentprovider/README.txt (rev 0)
+++ zope.contentprovider/tags/3.5.0/src/zope/contentprovider/README.txt 2009-03-17 21:06:31 UTC (rev 98213)
@@ -0,0 +1,572 @@
+=================
+Content Providers
+=================
+
+This package provides a framework to develop componentized Web GUI
+applications. Instead of describing the content of a page using a single
+template or static system of templates and METAL macros, content provider
+objects are dynamically looked up based on the setup/configuration of the
+application.
+
+.. contents::
+
+Motivation and Design Goals
+---------------------------
+
+Before diving into the features of this package let me take up a few bytes of
+text to explain the use cases that drove us to develop this package (also
+others) and how the API documented below fulfills/solves those use cases. When
+we started developing Zope 3, it was from a desire to decentralize
+functionality and thus the complexity of the Python code. And we were
+successful! The component architecture is a marvelous piece of software that
+hopefully will allow us to build scalable solutions for a very long
+time. However, when it comes to user interface design, in this case
+specifically HTML pages, we have failed to provide the features and patterns
+of assembeling a page from configured components.
+
+Looking up views for a particular content component and a request just simply
+does not work by itself. The content inside the page is still monolithic. One
+attempt to solve this problem are METAL macros, which allow you to insert
+other TAL snippets into your main template. But macros have two shortcomings.
+For one there is a "hard-coded" one-to-one mapping between a slot and the
+macro that fills that slot, which makes it impossible to register several
+macros for a given location. The second problem is that macros are not views
+in their own right; thus they cannot provide functionality that is independent
+of the main template's view.
+
+A second approach to modular UI design are rendering pipes. Rendering pipes
+have the great advantage that they can reach all regions of the page during
+every step of the rendering process. For example, if we have a widget in the
+middle of the page that requires some additional Javascript, then it is easy
+for a rendering unit to insert the Javascript file link in the HTML header of
+the page. This type of use case is very hard to solve using page
+templates. However, pipes are not the answer to componentized user interface,
+since they cannot simply deal with registering random content for a given page
+region. In fact, I propose that pipelines are orthogonal to content providers,
+the concept introducted below. A pipeline framework could easily use
+functionality provided by this and other packages to provide component-driven
+UI design.
+
+So our goal is clear: Bring the pluggability of the component architecture
+into page templates and user interface design. Zope is commonly known to
+reinvent the wheel, develop its own terminology and misuse other's terms. For
+example, the Plone community has a very different understanding of what a
+"portlet" is compared to the commonly accepted meaning in the corporate world,
+which derives its definition from JSR 168. Therefore an additional use case of
+the design of this package was to stick with common terms and use them in
+their original meaning -- well, given a little extra twist.
+
+The most basic user interface component in the Web application Java world is
+the "content provider" [1]_. A content provider is simply responsible for
+providing HTML content for a page. This is equivalent to a view that does not
+provide a full page, but just a snippet, much like widgets or macros. Once
+there is a way to configure those content providers, we need a way to
+inserting them into our page templates. In our implementation this is
+accomplished using a new TALES namespace that allows to insert content
+providers by name. But how, you might wonder, does this provide a
+componentized user interface? On the Zope 3 level, each content provider is
+registered as a presentation component discriminted by the context, request
+and view it will appear in. Thus different content providers will be picked
+for different configurations.
+
+Okay, that's pretty much everything there is to say about content
+providers. What, we are done? Hold on, what about defining regions of pages
+and filling them configured UI snippets. The short answer is: See the
+``zope.viewlet`` pacakge. But let me also give you the long answer. This and
+the other pacakges were developed using real world use cases. While doing
+this, we noticed that not every project would need, for example, all the
+features of a portlet, but would still profit from lower-level features. Thus
+we decided to declare clear boundaries of functionality and providing each
+level in a different package. This particualr package is only meant to provide
+the interface between the content provider world and page templates.
+
+.. [1] Note that this is a bit different from the role named content provider,
+ which refers to a service that provides content; the content provider
+ we are talking about here are the software components the service would
+ provide to an application.
+
+
+Content Providers
+-----------------
+
+Content Provider is a term from the Java world that refers to components that
+can provide HTML content. It means nothing more! How the content is found and
+returned is totally up to the implementation. The Zope 3 touch to the concept
+is that content providers are multi-adapters that are looked up by the
+context, request (and thus the layer/skin), and view they are displayed in.
+
+The second important concept of content providers are their two-phase
+rendering design. In the first phase the state of the content provider is
+prepared and, if applicable, any data, the provider is responsible for, is
+updated.
+
+ >>> from zope.contentprovider import interfaces
+
+So let's create a simple content provider:
+
+ >>> import zope.interface
+ >>> import zope.component
+ >>> from zope.publisher.interfaces import browser
+
+ >>> class MessageBox(object):
+ ... zope.interface.implements(interfaces.IContentProvider)
+ ... zope.component.adapts(zope.interface.Interface,
+ ... browser.IDefaultBrowserLayer,
+ ... zope.interface.Interface)
+ ... message = u'My Message'
+ ...
+ ... def __init__(self, context, request, view):
+ ... self.__parent__ = view
+ ...
+ ... def update(self):
+ ... pass
+ ...
+ ... def render(self):
+ ... return u'<div class="box">%s</div>' %self.message
+
+The ``update()`` method is executed during phase one. Since no state needs to
+be calculated and no data is modified by this simple content provider, it is
+an empty implementation. The ``render()`` method implements phase 2 of the
+process. We can now instantiate the content provider (manually) and render it:
+
+ >>> box = MessageBox(None, None, None)
+ >>> box.render()
+ u'<div class="box">My Message</div>'
+
+Since our content provider did not require the context, request or view to
+create its HTML content, we were able to pass trivial dummy values into the
+constructor. Also note that the provider must have a parent (using the
+``__parent__`` attribute) specified at all times. The parent must be the view
+the provider appears in.
+
+I agree, this functionally does not seem very useful now. The constructor and
+the ``update()`` method seem useless and the returned content is totally
+static. However, we implemented a contract for content providers that other
+code can rely on. Content providers are (commonly) instantiated using the
+context, request and view they appear in and are required to always generate
+its HTML using those three components.
+
+
+Two-Phased Content Providers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's now have a look at a content provider that actively uses the two-phase
+rendering process. The simpler scenario is the case where the content provider
+updates a content component without affecting anything else. So let's create a
+content component to be updated,
+
+ >>> class Article(object):
+ ... title = u'initial'
+ >>> article = Article()
+
+and the content provider that is updating the title:
+
+ >>> class ChangeTitle(object):
+ ... zope.interface.implements(interfaces.IContentProvider)
+ ... zope.component.adapts(zope.interface.Interface,
+ ... browser.IDefaultBrowserLayer,
+ ... zope.interface.Interface)
+ ... fieldName = 'ChangeTitle.title'
+ ...
+ ... def __init__(self, context, request, view):
+ ... self.__parent__ = view
+ ... self.context, self.request = context, request
+ ...
+ ... def update(self):
+ ... if self.fieldName in self.request:
+ ... self.context.title = self.request[self.fieldName]
+ ...
+ ... def render(self):
+ ... return u'<input name="%s" value="%s" />' % (self.fieldName,
+ ... self.context.title)
+
+Using a request, let's now instantiate the content provider and go through the
+two-phase rendering process:
+
+ >>> from zope.publisher.browser import TestRequest
+ >>> request = TestRequest()
+ >>> changer = ChangeTitle(article, request, None)
+ >>> changer.update()
+ >>> changer.render()
+ u'<input name="ChangeTitle.title" value="initial" />'
+
+Let's now enter a new title and render the provider:
+
+ >>> request = TestRequest(form={'ChangeTitle.title': u'new title'})
+ >>> changer = ChangeTitle(article, request, None)
+ >>> changer.update()
+ >>> changer.render()
+ u'<input name="ChangeTitle.title" value="new title" />'
+ >>> article.title
+ u'new title'
+
+So this was easy. Let's now look at a case where one content provider's update
+influences the content of another. Let's say we have a content provider that
+displays the article's title:
+
+ >>> class ViewTitle(object):
+ ... zope.interface.implements(interfaces.IContentProvider)
+ ... zope.component.adapts(zope.interface.Interface,
+ ... browser.IDefaultBrowserLayer,
+ ... zope.interface.Interface)
+ ...
+ ... def __init__(self, context, request, view):
+ ... self.context, self.__parent__ = context, view
+ ...
+ ... def update(self):
+ ... pass
+ ...
+ ... def render(self):
+ ... return u'<h1>Title: %s</h1>' % self.context.title
+
+Let's now say that the `ShowTitle` content provider is shown on a page
+*before* the `ChangeTitle` content provider. If we do the full rendering
+process for each provider in sequence, we get the wrong result:
+
+ >>> request = TestRequest(form={'ChangeTitle.title': u'newer title'})
+
+ >>> viewer = ViewTitle(article, request, None)
+ >>> viewer.update()
+ >>> viewer.render()
+ u'<h1>Title: new title</h1>'
+
+ >>> changer = ChangeTitle(article, request, None)
+ >>> changer.update()
+ >>> changer.render()
+ u'<input name="ChangeTitle.title" value="newer title" />'
+
+So the correct way of doing this is to first complete phase 1 (update) for all
+providers, before executing phase 2 (render):
+
+ >>> request = TestRequest(form={'ChangeTitle.title': u'newest title'})
+
+ >>> viewer = ViewTitle(article, request, None)
+ >>> changer = ChangeTitle(article, request, None)
+
+ >>> viewer.update()
+ >>> changer.update()
+
+ >>> viewer.render()
+ u'<h1>Title: newest title</h1>'
+
+ >>> changer.render()
+ u'<input name="ChangeTitle.title" value="newest title" />'
+
+
+``UpdateNotCalled`` Errors
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Since calling ``update()`` before any other method that mutates the provider
+or any other data is so important to the correct functioning of the API, the
+developer has the choice to raise the ``UpdateNotCalled`` error, if any method
+is called before ``update()`` (with exception of the constructor):
+
+ >>> class InfoBox(object):
+ ... zope.interface.implements(interfaces.IContentProvider)
+ ... zope.component.adapts(zope.interface.Interface,
+ ... browser.IDefaultBrowserLayer,
+ ... zope.interface.Interface)
+ ...
+ ... def __init__(self, context, request, view):
+ ... self.__parent__ = view
+ ... self.__updated = False
+ ...
+ ... def update(self):
+ ... self.__updated = True
+ ...
+ ... def render(self):
+ ... if not self.__updated:
+ ... raise interfaces.UpdateNotCalled
+ ... return u'<div>Some information</div>'
+
+ >>> info = InfoBox(None, None, None)
+
+ >>> info.render()
+ Traceback (most recent call last):
+ ...
+ UpdateNotCalled: ``update()`` was not called yet.
+
+ >>> info.update()
+
+ >>> info.render()
+ u'<div>Some information</div>'
+
+
+The TALES ``provider`` Expression
+---------------------------------
+
+The ``provider`` expression will look up the name of the content provider,
+call it and return the HTML content. The first step, however, will be to
+register our content provider with the component architecture:
+
+ >>> zope.component.provideAdapter(MessageBox, name='mypage.MessageBox')
+
+The content provider must be registered by name, since the TALES expression
+uses the name to look up the provider at run time.
+
+Let's now create a view using a page template:
+
+ >>> import os, tempfile
+ >>> temp_dir = tempfile.mkdtemp()
+ >>> templateFileName = os.path.join(temp_dir, 'template.pt')
+ >>> open(templateFileName, 'w').write('''
+ ... <html>
+ ... <body>
+ ... <h1>My Web Page</h1>
+ ... <div class="left-column">
+ ... <tal:block replace="structure provider:mypage.MessageBox" />
+ ... </div>
+ ... <div class="main">
+ ... Content here
+ ... </div>
+ ... </body>
+ ... </html>
+ ... ''')
+
+As you can see, we exprect the ``provider`` expression to simply look up the
+content provider and insert the HTML content at this place.
+
+Next we register the template as a view (browser page) for all objects:
+
+ >>> from zope.app.pagetemplate.simpleviewclass import SimpleViewClass
+ >>> FrontPage = SimpleViewClass(templateFileName, name='main.html')
+
+ >>> zope.component.provideAdapter(
+ ... FrontPage,
+ ... (zope.interface.Interface, browser.IDefaultBrowserLayer),
+ ... zope.interface.Interface,
+ ... name='main.html')
+
+Let's create a content object that can be viewed:
+
+ >>> class Content(object):
+ ... zope.interface.implements(zope.interface.Interface)
+
+ >>> content = Content()
+
+Finally we look up the view and render it. Note that a
+BeforeUpdateEvent is fired - this event should always be fired before
+any contentprovider is updated.
+
+ >>> from zope.publisher.browser import TestRequest
+ >>> events = []
+ >>> zope.component.provideHandler(events.append, (None, ))
+ >>> request = TestRequest()
+
+ >>> view = zope.component.getMultiAdapter((content, request),
+ ... name='main.html')
+ >>> print view().strip()
+ <html>
+ <body>
+ <h1>My Web Page</h1>
+ <div class="left-column">
+ <div class="box">My Message</div>
+ </div>
+ <div class="main">
+ Content here
+ </div>
+ </body>
+ </html>
+
+ >>> events
+ [<zope.contentprovider.interfaces.BeforeUpdateEvent object at ...>]
+
+The event holds the provider and the request.
+
+ >>> events[0].request
+ <zope.publisher.browser.TestRequest instance URL=http://127.0.0.1>
+ >>> events[0].object
+ <MessageBox object at ...>
+
+Failure to lookup a Content Provider
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If the name is not found, an error is raised. To demonstrate this behavior
+let's create another template:
+
+ >>> errorFileName = os.path.join(temp_dir, 'error.pt')
+ >>> open(errorFileName, 'w').write('''
+ ... <html>
+ ... <body>
+ ... <tal:block replace="structure provider:mypage.UnknownName" />
+ ... </body>
+ ... </html>
+ ... ''')
+
+ >>> ErrorPage = SimpleViewClass(errorFileName, name='error.html')
+ >>> zope.component.provideAdapter(
+ ... ErrorPage,
+ ... (zope.interface.Interface, browser.IDefaultBrowserLayer),
+ ... zope.interface.Interface,
+ ... name='main.html')
+
+ >>> errorview = zope.component.getMultiAdapter((content, request),
+ ... name='main.html')
+ >>> print errorview()
+ Traceback (most recent call last):
+ ...
+ ContentProviderLookupError: mypage.UnknownName
+
+
+Additional Data from TAL
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``provider`` expression allows also for transferring data from the TAL
+context into the content provider. This is accomplished by having the content
+provider implement an interface that specifies the attributes and provides
+``ITALNamespaceData``:
+
+ >>> import zope.schema
+ >>> class IMessageText(zope.interface.Interface):
+ ... message = zope.schema.Text(title=u'Text of the message box')
+
+ >>> zope.interface.directlyProvides(IMessageText,
+ ... interfaces.ITALNamespaceData)
+
+Now the message box can receive its text from the TAL environment:
+
+ >>> class DynamicMessageBox(MessageBox):
+ ... zope.interface.implements(IMessageText)
+
+ >>> zope.component.provideAdapter(
+ ... DynamicMessageBox, provides=interfaces.IContentProvider,
+ ... name='mypage.DynamicMessageBox')
+
+We are now updating our original template to provide the message text:
+
+ >>> open(templateFileName, 'w').write('''
+ ... <html>
+ ... <body>
+ ... <h1>My Web Page</h1>
+ ... <div class="left-column">
+ ... <tal:block define="message string:Hello World!"
+ ... replace="structure provider:mypage.DynamicMessageBox" />
+ ... <tal:block define="message string:Hello World again!"
+ ... replace="structure provider:mypage.DynamicMessageBox" />
+ ... </div>
+ ... <div class="main">
+ ... Content here
+ ... </div>
+ ... </body>
+ ... </html>
+ ... ''')
+
+Now we should get two message boxes with different text:
+
+ >>> print view().strip()
+ <html>
+ <body>
+ <h1>My Web Page</h1>
+ <div class="left-column">
+ <div class="box">Hello World!</div>
+ <div class="box">Hello World again!</div>
+ </div>
+ <div class="main">
+ Content here
+ </div>
+ </body>
+ </html>
+
+Finally, a content provider can also implement several ``ITALNamespaceData``:
+
+ >>> class IMessageType(zope.interface.Interface):
+ ... type = zope.schema.TextLine(title=u'The type of the message box')
+
+ >>> zope.interface.directlyProvides(IMessageType,
+ ... interfaces.ITALNamespaceData)
+
+We'll change our message box content provider implementation a bit, so the new
+information is used:
+
+ >>> class BetterDynamicMessageBox(DynamicMessageBox):
+ ... zope.interface.implements(IMessageType)
+ ... type = None
+ ...
+ ... def render(self):
+ ... return u'<div class="box,%s">%s</div>' %(self.type, self.message)
+
+ >>> zope.component.provideAdapter(
+ ... BetterDynamicMessageBox, provides=interfaces.IContentProvider,
+ ... name='mypage.MessageBox')
+
+Of course, we also have to make our tempalte a little bit more dynamic as
+well:
+
+ >>> open(templateFileName, 'w').write('''
+ ... <html>
+ ... <body>
+ ... <h1>My Web Page</h1>
+ ... <div class="left-column">
+ ... <tal:block define="message string:Hello World!;
+ ... type string:error"
+ ... replace="structure provider:mypage.MessageBox" />
+ ... <tal:block define="message string:Hello World again!;
+ ... type string:warning"
+ ... replace="structure provider:mypage.MessageBox" />
+ ... </div>
+ ... <div class="main">
+ ... Content here
+ ... </div>
+ ... </body>
+ ... </html>
+ ... ''')
+
+Now we should get two message boxes with different text and types:
+
+ >>> print view().strip()
+ <html>
+ <body>
+ <h1>My Web Page</h1>
+ <div class="left-column">
+ <div class="box,error">Hello World!</div>
+ <div class="box,warning">Hello World again!</div>
+ </div>
+ <div class="main">
+ Content here
+ </div>
+ </body>
+ </html>
+
+
+Base class
+----------
+
+The ``zope.contentprovider.provider`` module provides an useful base
+class for implementing content providers. It has all boilerplate code
+and it's only required to override the ``render`` method to make it
+work:
+
+ >>> from zope.contentprovider.provider import ContentProviderBase
+ >>> class MyProvider(ContentProviderBase):
+ ... def render(self, *args, **kwargs):
+ ... return 'Hi there'
+
+ >>> provider = MyProvider(None, None, None)
+ >>> interfaces.IContentProvider.providedBy(provider)
+ True
+
+ >>> provider.update()
+ >>> print provider.render()
+ Hi there
+
+Note, that it can't be used as is, without providing the ``render`` method:
+
+ >>> bad = ContentProviderBase(None, None, None)
+ >>> bad.update()
+ >>> print bad.render()
+ Traceback (most recent call last):
+ ...
+ NotImplementedError: ``render`` method must be implemented by subclass
+
+You can add the update logic into the ``update`` method as with any content
+provider and you can implement more complex rendering patterns, based on
+templates, using this ContentProviderBase class as a base.
+
+
+You might also want to look at the ``zope.viewlet`` package for a more
+featureful API.
+
+Let's remove all temporary data we created during this README.
+
+ >>> import shutil
+ >>> shutil.rmtree(temp_dir)
Deleted: zope.contentprovider/tags/3.5.0/src/zope/contentprovider/__init__.py
===================================================================
--- zope.contentprovider/trunk/src/zope/contentprovider/__init__.py 2009-03-17 17:31:53 UTC (rev 98210)
+++ zope.contentprovider/tags/3.5.0/src/zope/contentprovider/__init__.py 2009-03-17 21:06:31 UTC (rev 98213)
@@ -1,17 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Viewlet exceptions
-
-$Id$
-"""
Copied: zope.contentprovider/tags/3.5.0/src/zope/contentprovider/__init__.py (from rev 98212, zope.contentprovider/trunk/src/zope/contentprovider/__init__.py)
===================================================================
--- zope.contentprovider/tags/3.5.0/src/zope/contentprovider/__init__.py (rev 0)
+++ zope.contentprovider/tags/3.5.0/src/zope/contentprovider/__init__.py 2009-03-17 21:06:31 UTC (rev 98213)
@@ -0,0 +1,16 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
Deleted: zope.contentprovider/tags/3.5.0/src/zope/contentprovider/configure.zcml
===================================================================
--- zope.contentprovider/trunk/src/zope/contentprovider/configure.zcml 2009-03-17 17:31:53 UTC (rev 98210)
+++ zope.contentprovider/tags/3.5.0/src/zope/contentprovider/configure.zcml 2009-03-17 21:06:31 UTC (rev 98213)
@@ -1,21 +0,0 @@
-<configure
- xmlns="http://namespaces.zope.org/zope"
- xmlns:tales="http://namespaces.zope.org/tales"
- xmlns:apidoc="http://namespaces.zope.org/apidoc"
- xmlns:zcml="http://namespaces.zope.org/zcml"
- i18n_domain="zope">
-
- <interface interface=".interfaces.ITALESProviderExpression" />
- <tales:expressiontype
- name="provider"
- handler=".tales.TALESProviderExpression"
- />
-
- <apidoc:bookchapter
- id="contentprovider"
- title="Content Providers"
- doc_path="README.txt"
- zcml:condition="have apidoc"
- />
-
-</configure>
\ No newline at end of file
Copied: zope.contentprovider/tags/3.5.0/src/zope/contentprovider/configure.zcml (from rev 98212, zope.contentprovider/trunk/src/zope/contentprovider/configure.zcml)
===================================================================
--- zope.contentprovider/tags/3.5.0/src/zope/contentprovider/configure.zcml (rev 0)
+++ zope.contentprovider/tags/3.5.0/src/zope/contentprovider/configure.zcml 2009-03-17 21:06:31 UTC (rev 98213)
@@ -0,0 +1,22 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:tales="http://namespaces.zope.org/tales"
+ xmlns:apidoc="http://namespaces.zope.org/apidoc"
+ xmlns:zcml="http://namespaces.zope.org/zcml"
+ i18n_domain="zope">
+
+ <interface interface=".interfaces.ITALESProviderExpression" />
+
+ <tales:expressiontype
+ name="provider"
+ handler=".tales.TALESProviderExpression"
+ />
+
+ <apidoc:bookchapter
+ id="contentprovider"
+ title="Content Providers"
+ doc_path="README.txt"
+ zcml:condition="have apidoc"
+ />
+
+</configure>
Deleted: zope.contentprovider/tags/3.5.0/src/zope/contentprovider/interfaces.py
===================================================================
--- zope.contentprovider/trunk/src/zope/contentprovider/interfaces.py 2009-03-17 17:31:53 UTC (rev 98210)
+++ zope.contentprovider/tags/3.5.0/src/zope/contentprovider/interfaces.py 2009-03-17 21:06:31 UTC (rev 98213)
@@ -1,150 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Content provider interfaces
-
-$Id$
-"""
-__docformat__ = 'restructuredtext'
-
-import zope.component
-import zope.interface
-from zope.tales import interfaces
-from zope.publisher.interfaces import browser
-from zope.component.interfaces import ObjectEvent, IObjectEvent
-
-class IUpdateNotCalled(zope.interface.common.interfaces.IRuntimeError):
- """Update Not Called
-
- An error that is raised when any content provider method is called before
- the ``update()`` method.
- """
-
-class UpdateNotCalled(RuntimeError):
- pass
-
-# Make it a singelton
-UpdateNotCalled = UpdateNotCalled('``update()`` was not called yet.')
-
-class IBeforeUpdateEvent(IObjectEvent):
-
- """A Contentprovider will be updated"""
-
- request = zope.interface.Attribute(
- """The request in which the object is udpated, might also be
- None""")
-
-class BeforeUpdateEvent(ObjectEvent):
-
- """A Contentprovider will be updated"""
-
- zope.interface.implements(IBeforeUpdateEvent)
-
- def __init__(self, provider, request=None):
- super(BeforeUpdateEvent, self).__init__(provider)
- self.request = request
-
-class IContentProvider(browser.IBrowserView):
- """A piece of content to be shown on a page.
-
- Objects implementing this interface are providing HTML content when they
- are rendered. It is up to the implementation to decide how to lookup
- necessary data to complete the job.
-
- Content Providers use a two-stage process to fulfill their contract:
-
- (1) The first stage is responsible to calculate the state of the content
- provider and, if applicable, edit the data. This stage is executed
- using the ``update()`` method.
-
- (2) During the second stage the provider constructs/renders its HTML
- output based on the state that was calculated in the first stage. This
- stage is executed using the ``render()`` method.
-
- Content Providers are discriminated by three components: the context, the
- request and the view. This allows great control over the selection of the
- provider.
- """
-
- __parent__ = zope.interface.Attribute(
- """The view the provider appears in.
-
- The view is the third discriminator of the content provider. It allows
- that the content can be controlled for different views.
-
- Having it stored as the parent is also very important for the security
- context to be kept.
- """)
-
- def update():
- """Initialize the content provider.
-
- This method should perform all state calculation and *not* refer it to
- the rendering stage.
-
- In this method, all state must be calculated from the current
- interaction (e.g., the browser request); all contained or managed
- content providers must have ``update()`` be called as well; any
- additional stateful API for contained or managed content providers
- must be handled; and persistent objects should be modified, if the
- provider is going to do it.
-
- Do *not* store state about persistent objects: the rendering process
- should actually use the persistent objects for the data, in case other
- components modify the object between the update and render stages.
-
- This method *must* be called before any other method that mutates the
- instance (besides the class constructor). Non-mutating methods and
- attributes may raise an error if used before ``update()`` is
- called. The view may rely on this order but is *not required* to
- explicitly enforce this. Implementations *may* enforce it as a
- developer aid.
- """
-
- def render(*args, **kw):
- """Return the content provided by this content provider.
-
- Calling this method before ``update()`` *may* (but is not required to)
- raise an ``UpdateNotCalled`` error.
- """
-
-class IContentProviderType(zope.interface.interfaces.IInterface):
- """Type interface for content provider types (interfaces derived from
- IContentProvider).
- """
-
-
-class ITALNamespaceData(zope.interface.interfaces.IInterface):
- """A type interface that marks an interface as a TAL data specification.
-
- All fields specified in an interface that provides `ITALNamespaceData`
- will be looked up in the TAL context and stored on the content provider. A
- content provider can have multiple interfaces that are of this type.
- """
-
-
-class ContentProviderLookupError(zope.component.ComponentLookupError):
- """No content provider was found."""
-
-
-class ITALESProviderExpression(interfaces.ITALESExpression):
- """Return the HTML content of the named provider.
-
- To call a content provider in a view use the the following syntax in a page
- template::
-
- <tal:block replace="structure provider:provider.name">
-
- The content provider is looked up by the (context, request, view) objects
- and the name (`provider.name`).
- """
Copied: zope.contentprovider/tags/3.5.0/src/zope/contentprovider/interfaces.py (from rev 98212, zope.contentprovider/trunk/src/zope/contentprovider/interfaces.py)
===================================================================
--- zope.contentprovider/tags/3.5.0/src/zope/contentprovider/interfaces.py (rev 0)
+++ zope.contentprovider/tags/3.5.0/src/zope/contentprovider/interfaces.py 2009-03-17 21:06:31 UTC (rev 98213)
@@ -0,0 +1,150 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Content provider interfaces
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+
+import zope.component
+import zope.interface
+from zope.component.interfaces import ObjectEvent, IObjectEvent
+from zope.publisher.interfaces import browser
+from zope.tales import interfaces
+
+class IUpdateNotCalled(zope.interface.common.interfaces.IRuntimeError):
+ """Update Not Called
+
+ An error that is raised when any content provider method is called before
+ the ``update()`` method.
+ """
+
+class UpdateNotCalled(RuntimeError):
+ pass
+
+# Make it a singelton
+UpdateNotCalled = UpdateNotCalled('``update()`` was not called yet.')
+
+class IBeforeUpdateEvent(IObjectEvent):
+
+ """A Contentprovider will be updated"""
+
+ request = zope.interface.Attribute(
+ """The request in which the object is udpated, might also be
+ None""")
+
+class BeforeUpdateEvent(ObjectEvent):
+
+ """A Contentprovider will be updated"""
+
+ zope.interface.implements(IBeforeUpdateEvent)
+
+ def __init__(self, provider, request=None):
+ super(BeforeUpdateEvent, self).__init__(provider)
+ self.request = request
+
+class IContentProvider(browser.IBrowserView):
+ """A piece of content to be shown on a page.
+
+ Objects implementing this interface are providing HTML content when they
+ are rendered. It is up to the implementation to decide how to lookup
+ necessary data to complete the job.
+
+ Content Providers use a two-stage process to fulfill their contract:
+
+ (1) The first stage is responsible to calculate the state of the content
+ provider and, if applicable, edit the data. This stage is executed
+ using the ``update()`` method.
+
+ (2) During the second stage the provider constructs/renders its HTML
+ output based on the state that was calculated in the first stage. This
+ stage is executed using the ``render()`` method.
+
+ Content Providers are discriminated by three components: the context, the
+ request and the view. This allows great control over the selection of the
+ provider.
+ """
+
+ __parent__ = zope.interface.Attribute(
+ """The view the provider appears in.
+
+ The view is the third discriminator of the content provider. It allows
+ that the content can be controlled for different views.
+
+ Having it stored as the parent is also very important for the security
+ context to be kept.
+ """)
+
+ def update():
+ """Initialize the content provider.
+
+ This method should perform all state calculation and *not* refer it to
+ the rendering stage.
+
+ In this method, all state must be calculated from the current
+ interaction (e.g., the browser request); all contained or managed
+ content providers must have ``update()`` be called as well; any
+ additional stateful API for contained or managed content providers
+ must be handled; and persistent objects should be modified, if the
+ provider is going to do it.
+
+ Do *not* store state about persistent objects: the rendering process
+ should actually use the persistent objects for the data, in case other
+ components modify the object between the update and render stages.
+
+ This method *must* be called before any other method that mutates the
+ instance (besides the class constructor). Non-mutating methods and
+ attributes may raise an error if used before ``update()`` is
+ called. The view may rely on this order but is *not required* to
+ explicitly enforce this. Implementations *may* enforce it as a
+ developer aid.
+ """
+
+ def render(*args, **kw):
+ """Return the content provided by this content provider.
+
+ Calling this method before ``update()`` *may* (but is not required to)
+ raise an ``UpdateNotCalled`` error.
+ """
+
+class IContentProviderType(zope.interface.interfaces.IInterface):
+ """Type interface for content provider types (interfaces derived from
+ IContentProvider).
+ """
+
+
+class ITALNamespaceData(zope.interface.interfaces.IInterface):
+ """A type interface that marks an interface as a TAL data specification.
+
+ All fields specified in an interface that provides `ITALNamespaceData`
+ will be looked up in the TAL context and stored on the content provider. A
+ content provider can have multiple interfaces that are of this type.
+ """
+
+
+class ContentProviderLookupError(zope.component.ComponentLookupError):
+ """No content provider was found."""
+
+
+class ITALESProviderExpression(interfaces.ITALESExpression):
+ """Return the HTML content of the named provider.
+
+ To call a content provider in a view use the the following syntax in a page
+ template::
+
+ <tal:block replace="structure provider:provider.name">
+
+ The content provider is looked up by the (context, request, view) objects
+ and the name (`provider.name`).
+ """
Deleted: zope.contentprovider/tags/3.5.0/src/zope/contentprovider/tales.py
===================================================================
--- zope.contentprovider/trunk/src/zope/contentprovider/tales.py 2009-03-17 17:31:53 UTC (rev 98210)
+++ zope.contentprovider/tags/3.5.0/src/zope/contentprovider/tales.py 2009-03-17 21:06:31 UTC (rev 98213)
@@ -1,80 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Provider tales expression registrations
-
-$Id$
-"""
-__docformat__ = 'restructuredtext'
-
-import zope.component
-import zope.interface
-import zope.schema
-import zope.event
-from zope.tales import expressions
-
-from zope.contentprovider import interfaces
-from zope.location.interfaces import ILocation
-
-def addTALNamespaceData(provider, context):
- """Add the requested TAL attributes to the provider"""
- data = {}
-
- for interface in zope.interface.providedBy(provider):
- if interfaces.ITALNamespaceData.providedBy(interface):
- for name, field in zope.schema.getFields(interface).items():
- data[name] = context.vars.get(name, field.default)
-
- provider.__dict__.update(data)
-
-
-class TALESProviderExpression(expressions.StringExpr):
- """Collect content provider via a TAL namespace.
-
- Note that this implementation of the TALES `provider` namespace does not
- work with interdependent content providers, since each content-provider's
- stage one call is made just before the second stage is executed. If you
- want to implement interdependent content providers, you need to consider a
- TAL-independent view implementation that will complete all content
- providers' stage one before rendering any of them.
- """
-
- zope.interface.implements(interfaces.ITALESProviderExpression)
-
- def __call__(self, econtext):
- name = super(TALESProviderExpression, self).__call__(econtext)
- context = econtext.vars['context']
- request = econtext.vars['request']
- view = econtext.vars['view']
-
- # Try to look up the provider.
- provider = zope.component.queryMultiAdapter(
- (context, request, view), interfaces.IContentProvider, name)
-
- # Provide a useful error message, if the provider was not found.
- if provider is None:
- raise interfaces.ContentProviderLookupError(name)
-
- # add the __name__ attribute if it implements ILocation
- if ILocation.providedBy(provider):
- provider.__name__ = name
-
- # Insert the data gotten from the context
- addTALNamespaceData(provider, econtext)
-
- # Stage 1: Do the state update.
- zope.event.notify(interfaces.BeforeUpdateEvent(provider, request))
- provider.update()
-
- # Stage 2: Render the HTML content.
- return provider.render()
Copied: zope.contentprovider/tags/3.5.0/src/zope/contentprovider/tales.py (from rev 98212, zope.contentprovider/trunk/src/zope/contentprovider/tales.py)
===================================================================
--- zope.contentprovider/tags/3.5.0/src/zope/contentprovider/tales.py (rev 0)
+++ zope.contentprovider/tags/3.5.0/src/zope/contentprovider/tales.py 2009-03-17 21:06:31 UTC (rev 98213)
@@ -0,0 +1,80 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Provider TALES expression
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+
+import zope.component
+import zope.interface
+import zope.schema
+import zope.event
+from zope.location.interfaces import ILocation
+from zope.tales import expressions
+
+from zope.contentprovider import interfaces
+
+def addTALNamespaceData(provider, context):
+ """Add the requested TAL attributes to the provider"""
+ data = {}
+
+ for interface in zope.interface.providedBy(provider):
+ if interfaces.ITALNamespaceData.providedBy(interface):
+ for name, field in zope.schema.getFields(interface).items():
+ data[name] = context.vars.get(name, field.default)
+
+ provider.__dict__.update(data)
+
+
+class TALESProviderExpression(expressions.StringExpr):
+ """Collect content provider via a TAL namespace.
+
+ Note that this implementation of the TALES `provider` namespace does not
+ work with interdependent content providers, since each content-provider's
+ stage one call is made just before the second stage is executed. If you
+ want to implement interdependent content providers, you need to consider a
+ TAL-independent view implementation that will complete all content
+ providers' stage one before rendering any of them.
+ """
+
+ zope.interface.implements(interfaces.ITALESProviderExpression)
+
+ def __call__(self, econtext):
+ name = super(TALESProviderExpression, self).__call__(econtext)
+ context = econtext.vars['context']
+ request = econtext.vars['request']
+ view = econtext.vars['view']
+
+ # Try to look up the provider.
+ provider = zope.component.queryMultiAdapter(
+ (context, request, view), interfaces.IContentProvider, name)
+
+ # Provide a useful error message, if the provider was not found.
+ if provider is None:
+ raise interfaces.ContentProviderLookupError(name)
+
+ # add the __name__ attribute if it implements ILocation
+ if ILocation.providedBy(provider):
+ provider.__name__ = name
+
+ # Insert the data gotten from the context
+ addTALNamespaceData(provider, econtext)
+
+ # Stage 1: Do the state update.
+ zope.event.notify(interfaces.BeforeUpdateEvent(provider, request))
+ provider.update()
+
+ # Stage 2: Render the HTML content.
+ return provider.render()
Deleted: zope.contentprovider/tags/3.5.0/src/zope/contentprovider/tests.py
===================================================================
--- zope.contentprovider/trunk/src/zope/contentprovider/tests.py 2009-03-17 17:31:53 UTC (rev 98210)
+++ zope.contentprovider/tags/3.5.0/src/zope/contentprovider/tests.py 2009-03-17 21:06:31 UTC (rev 98213)
@@ -1,61 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Content provider tests
-
-$Id$
-"""
-__docformat__ = 'restructuredtext'
-import os.path
-import unittest
-from zope.component import eventtesting
-from zope.testing import doctest, cleanup
-from zope.testing.doctestunit import DocFileSuite
-
-counter = 0
-mtime_func = None
-
-def setUp(test):
- cleanup.setUp()
- eventtesting.setUp()
-
- from zope.app.pagetemplate import metaconfigure
- from zope.contentprovider import tales
- metaconfigure.registerType('provider', tales.TALESProviderExpression)
-
- # Make sure we are always reloading page template files ;-)
- global mtime_func
- mtime_func = os.path.getmtime
- def number(x):
- global counter
- counter += 1
- return counter
- os.path.getmtime = number
-
-
-def tearDown(test):
- cleanup.tearDown()
- os.path.getmtime = mtime_func
- global counter
- counter = 0
-
-def test_suite():
- return unittest.TestSuite((
- DocFileSuite('README.txt',
- setUp=setUp, tearDown=tearDown,
- optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
- ),
- ))
-
-if __name__ == '__main__':
- unittest.main(defaultTest='test_suite')
Copied: zope.contentprovider/tags/3.5.0/src/zope/contentprovider/tests.py (from rev 98212, zope.contentprovider/trunk/src/zope/contentprovider/tests.py)
===================================================================
--- zope.contentprovider/tags/3.5.0/src/zope/contentprovider/tests.py (rev 0)
+++ zope.contentprovider/tags/3.5.0/src/zope/contentprovider/tests.py 2009-03-17 21:06:31 UTC (rev 98213)
@@ -0,0 +1,61 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Content provider tests
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+import os.path
+import unittest
+from zope.component import eventtesting
+from zope.testing import doctest, cleanup
+from zope.testing.doctest import DocFileSuite
+
+counter = 0
+mtime_func = None
+
+def setUp(test):
+ cleanup.setUp()
+ eventtesting.setUp()
+
+ from zope.app.pagetemplate import metaconfigure
+ from zope.contentprovider import tales
+ metaconfigure.registerType('provider', tales.TALESProviderExpression)
+
+ # Make sure we are always reloading page template files ;-)
+ global mtime_func
+ mtime_func = os.path.getmtime
+ def number(x):
+ global counter
+ counter += 1
+ return counter
+ os.path.getmtime = number
+
+
+def tearDown(test):
+ cleanup.tearDown()
+ os.path.getmtime = mtime_func
+ global counter
+ counter = 0
+
+def test_suite():
+ return unittest.TestSuite((
+ DocFileSuite('README.txt',
+ setUp=setUp, tearDown=tearDown,
+ optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+ ),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
More information about the Checkins
mailing list