[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