[Zope3-checkins]
SVN: Zope3/branches/roger-contentprovider/src/zope/viewlet/
Started implemeting ZCML directive
Roger Ineichen
roger at projekt01.ch
Sun Oct 9 04:30:11 EDT 2005
Log message for revision 38987:
Started implemeting ZCML directive
Started refactoring tests for ZCML directives
Changed:
U Zope3/branches/roger-contentprovider/src/zope/viewlet/directives.txt
U Zope3/branches/roger-contentprovider/src/zope/viewlet/metaconfigure.py
U Zope3/branches/roger-contentprovider/src/zope/viewlet/metadirectives.py
U Zope3/branches/roger-contentprovider/src/zope/viewlet/tests.py
-=-
Modified: Zope3/branches/roger-contentprovider/src/zope/viewlet/directives.txt
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/viewlet/directives.txt 2005-10-09 08:28:18 UTC (rev 38986)
+++ Zope3/branches/roger-contentprovider/src/zope/viewlet/directives.txt 2005-10-09 08:30:11 UTC (rev 38987)
@@ -6,6 +6,7 @@
hassle, like it was shown in the `README.txt` file. Here is a sample
directive::
+ >>> from zope.viewlet.tests import ILeftViewlet
>>> from zope.configuration import xmlconfig
>>> context = xmlconfig.string('''
... <configure i18n_domain="zope">
@@ -13,18 +14,25 @@
... </configure>
... ''')
+ >>> import os, tempfile
+ >>> temp_dir = tempfile.mkdtemp()
+ >>> testViewlet = os.path.join(temp_dir, 'testviewlet.pt')
+ >>> open(testViewlet, 'w').write('''
+ ... <div>testviewlet content</div>
+ ... ''')
+
>>> context = xmlconfig.string('''
... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
... package="zope.viewlet.tests">
... <viewlet
... name="testviewlet"
... for="*"
- ... region=".test_doc.ITestRegion"
- ... template="test_viewlet.pt"
+ ... providerType="zope.viewlet.tests.ILeftViewlet"
+ ... template="%s"
... permission="zope.Public"
... />
... </configure>
- ... ''', context=context)
+ ... ''' % testViewlet, context=context)
As you can see, the directive looks very similar to the page directive and you
are right. The viewlet directive does not permit you to specify a `menu` and
@@ -48,14 +56,13 @@
>>> view = BrowserView(content, request)
>>> import zope.interface
- >>> from zope.viewlet.tests.test_doc import ITestRegion
-
+ >>> from zope.viewlet.interfaces import IViewlet
+
>>> import zope.component
- >>> from zope.viewlet.interfaces import IViewlet
>>> viewlet = zope.component.getMultiAdapter(
- ... (content, request, view), ITestRegion, name='testviewlet')
- >>> viewlet()
- u'<div>testviewlet macro content</div>\n'
+ ... (content, request, view), ILeftViewlet, name='testviewlet')
+ >>> viewlet().strip()
+ u'<div>testviewlet content</div>'
Let's now ensure that we can also specify a viewlet class:
@@ -65,119 +72,127 @@
... <viewlet
... name="testviewlet2"
... for="*"
- ... region=".test_doc.ITestRegion"
- ... template="test_viewlet.pt"
- ... class=".test_doc.TestViewlet"
+ ... providerType="zope.viewlet.tests.ILeftViewlet"
+ ... template="%s"
+ ... class=".TestViewlet"
... permission="zope.Public"
... />
... </configure>
- ... ''', context=context)
+ ... ''' % testViewlet, context=context)
>>> viewlet = zope.component.getMultiAdapter(
- ... (content, request, view), ITestRegion, name='testviewlet2')
- >>> viewlet()
- u'<div>testviewlet macro content</div>\n'
+ ... (content, request, view), ILeftViewlet, name='testviewlet2')
+ >>> viewlet().strip()
+ u'<div>testviewlet content</div>'
-Okay, so the template-driven cases wrok. But just specifying a class should
-also work:
+#Okay, so the template-driven cases wrok. But just specifying a class should
+#also work:
+#
+# >>> context = xmlconfig.string('''
+# ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
+# ... package="zope.viewlet.tests">
+# ... <viewlet
+# ... name="testviewlet3"
+# ... for="*"
+# ... providerType="zope.viewlet.tests.ILeftViewlet"
+# ... class=".tests.TestViewlet2"
+# ... permission="zope.Public"
+# ... />
+# ... </configure>
+# ... ''', context=context)
+#
+# >>> viewlet = zope.component.getMultiAdapter(
+# ... (content, request, view), ILeftViewlet, name='testviewlet3')
+# >>> viewlet()
+# u'called'
+#
+#It should also be possible to specify an alternative attribute of the class to
+#be rendered upon calling the viewlet:
+#
+# >>> context = xmlconfig.string('''
+# ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
+# ... package="zope.viewlet.tests">
+# ... <viewlet
+# ... name="testviewlet4"
+# ... for="*"
+# ... providerType="zope.viewlet.tests.ILeftViewlet"
+# ... class=".tests.TestViewlet"
+# ... attribute="doSomething"
+# ... permission="zope.Public"
+# ... />
+# ... </configure>
+# ... ''', context=context)
+#
+# >>> viewlet = zope.component.getMultiAdapter(
+# ... (content, request, view), ILeftViewlet, name='testviewlet4')
+# >>> viewlet()
+# u'something'
+#
+#
+#Error Scenarios
+#---------------
+#
+#Neither the class or template have been specified:
+#
+# >>> context = xmlconfig.string('''
+# ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
+# ... package="zope.viewlet.tests">
+# ... <viewlet
+# ... name="testviewlet"
+# ... providerType="zope.viewlet.tests.ILeftViewlet"
+# ... permission="zope.Public"
+# ... />
+# ... </configure>
+# ... ''', context=context)
+# Traceback (most recent call last):
+# ...
+# ZopeXMLConfigurationError: File "<string>", line 4.2-8.8
+# ConfigurationError: Must specify a class or template
+#
+#The specified attribute is not ``__call__``, but also a template has been
+#specified:
+#
+# >>> context = xmlconfig.string('''
+# ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
+# ... package="zope.viewlet.tests">
+# ... <viewlet
+# ... name="testviewlet"
+# ... providerType="zope.viewlet.tests.ILeftViewlet"
+# ... template="test_viewlet.pt"
+# ... attribute="faux"
+# ... permission="zope.Public"
+# ... />
+# ... </configure>
+# ... ''', context=context)
+# Traceback (most recent call last):
+# ...
+# ZopeXMLConfigurationError: File "<string>", line 4.2-10.8
+# ConfigurationError: Attribute and template cannot be used together.
+#
+#Now, we are not specifying a template, but a class that does not have the
+#specified attribute:
+#
+# >>> context = xmlconfig.string('''
+# ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
+# ... package="zope.viewlet.tests">
+# ... <viewlet
+# ... name="testviewlet"
+# ... providerType="zope.viewlet.tests.ILeftViewlet"
+# ... class=".TestViewlet"
+# ... attribute="faux"
+# ... permission="zope.Public"
+# ... />
+# ... </configure>
+# ... ''', context=context)
+# Traceback (most recent call last):
+# ...
+# ZopeXMLConfigurationError: File "<string>", line 4.2-10.8
+# ConfigurationError: The provided class doesn't have the specified attribute
- >>> context = xmlconfig.string('''
- ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
- ... package="zope.viewlet.tests">
- ... <viewlet
- ... name="testviewlet3"
- ... for="*"
- ... region=".test_doc.ITestRegion"
- ... class=".test_doc.TestViewlet2"
- ... permission="zope.Public"
- ... />
- ... </configure>
- ... ''', context=context)
- >>> viewlet = zope.component.getMultiAdapter(
- ... (content, request, view), ITestRegion, name='testviewlet3')
- >>> viewlet()
- u'called'
-It should also be possible to specify an alternative attribute of the class to
-be rendered upon calling the viewlet:
+Cleanup
+-------
- >>> context = xmlconfig.string('''
- ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
- ... package="zope.viewlet.tests">
- ... <viewlet
- ... name="testviewlet4"
- ... for="*"
- ... region=".test_doc.ITestRegion"
- ... class=".test_doc.TestViewlet"
- ... attribute="doSomething"
- ... permission="zope.Public"
- ... />
- ... </configure>
- ... ''', context=context)
-
- >>> viewlet = zope.component.getMultiAdapter(
- ... (content, request, view), ITestRegion, name='testviewlet4')
- >>> viewlet()
- u'something'
-
-
-Error Scenarios
----------------
-
-Neither the class or template have been specified:
-
- >>> context = xmlconfig.string('''
- ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
- ... package="zope.viewlet.tests">
- ... <viewlet
- ... name="testviewlet"
- ... region=".test_doc.ITestRegion"
- ... permission="zope.Public"
- ... />
- ... </configure>
- ... ''', context=context)
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-8.8
- ConfigurationError: Must specify a class or template
-
-The specified attribute is not ``__call__``, but also a template has been
-specified:
-
- >>> context = xmlconfig.string('''
- ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
- ... package="zope.viewlet.tests">
- ... <viewlet
- ... name="testviewlet"
- ... region=".test_doc.ITestRegion"
- ... template="test_viewlet.pt"
- ... attribute="faux"
- ... permission="zope.Public"
- ... />
- ... </configure>
- ... ''', context=context)
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-10.8
- ConfigurationError: Attribute and template cannot be used together.
-
-Now, we are not specifying a template, but a class that does not have the
-specified attribute:
-
- >>> context = xmlconfig.string('''
- ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"
- ... package="zope.viewlet.tests">
- ... <viewlet
- ... name="testviewlet"
- ... region=".test_doc.ITestRegion"
- ... class=".test_doc.TestViewlet"
- ... attribute="faux"
- ... permission="zope.Public"
- ... />
- ... </configure>
- ... ''', context=context)
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-10.8
- ConfigurationError: The provided class doesn't have the specified attribute
+ >>> import shutil
+ >>> shutil.rmtree(temp_dir)
Modified: Zope3/branches/roger-contentprovider/src/zope/viewlet/metaconfigure.py
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/viewlet/metaconfigure.py 2005-10-09 08:28:18 UTC (rev 38986)
+++ Zope3/branches/roger-contentprovider/src/zope/viewlet/metaconfigure.py 2005-10-09 08:30:11 UTC (rev 38987)
@@ -30,27 +30,27 @@
from zope.app.publisher.browser import viewmeta
from zope.app.publisher.interfaces.browser import IBrowserView
-from zope.contentprovider.interfaces import IRegion
+#from zope.contentprovider.interfaces import IWeightSupport
from zope.viewlet import viewlet
from zope.viewlet import manager
from zope.viewlet import interfaces
-def viewletManagerDirective(_context, name, permission, viewletType,
+# TODO: remove weight out of viewlet manager directive
+# TODO: support default class_
+# TODO: do we need a allowed_interface ?
+# TODO:
+def viewletManagerDirective(_context, name, permission, providerType,
for_=Interface, layer=IDefaultBrowserLayer,
- class_=None, template=None, weight=0,
- allowed_interface=None):
+ class_=None, template=None, allowed_interface=None):
required = {}
# Get the permission; mainly to correctly handle CheckerPublic.
permission = viewmeta._handle_permission(_context, permission)
- # Either the class or template must be specified.
- if not (class_ or template):
- raise ConfigurationError("Must specify a class or template")
-
- if not class_:
+ # If class is not given we use the default viewlet manager.
+ if class_ is None:
class_ = manager.ViewletManager
# Make sure that the template exists and that all low-level API methods
@@ -61,35 +61,17 @@
raise ConfigurationError("No such file", template)
required['__getitem__'] = permission
- if template:
- # Create a new class for the viewlet manager template and class.
+ # Create a new class based on the template and class.
new_class = viewlet.SimpleViewletClass(
template, bases=(class_, ), weight=weight)
- else:
- if not hasattr(class_, 'browserDefault'):
- cdict = {
- 'browserDefault':
- lambda self, request: (getattr(self, attribute), ())
- }
- else:
- cdict = {}
- cdict['_weight'] = weight
- cdict['__name__'] = name
- cdict['__page_attribute__'] = attribute
- new_class = type(class_.__name__,
- (class_, viewlet.SimpleAttributeViewlet), cdict)
-
- if hasattr(class_, '__implements__'):
+ if hasattr(new_class, '__implements__'):
classImplements(new_class, IBrowserPublisher)
- # set type if not None
- if getattr(class_, 'viewletType'):
- classImplements(new_class, IBrowserPublisher)
+ # set providerType if the class_ defines the global attribute
+ if hasattr(class_, 'providerType'):
+ classImplements(new_class, providerType)
- # Make sure the new class implements the region
- classImplements(new_class, region)
-
for attr_name in (attribute, 'browserDefault', '__call__',
'publishTraverse', 'weight'):
required[attr_name] = permission
@@ -99,28 +81,32 @@
viewmeta._handle_for(_context, for_)
metaconfigure.interface(_context, view)
- metaconfigure.interface(_context, region, IRegion)
checker.defineChecker(new_class, checker.Checker(required))
# register viewlet
_context.action(
- discriminator = ('viewletManager', for_, layer, view, region, name),
+ discriminator = ('viewletManager', for_, layer, view, name),
callable = metaconfigure.handler,
args = ('provideAdapter',
- (for_, layer, view), region, name, new_class,
+ (for_, layer, view), IViewletManager, name, new_class,
_context.info),)
-def viewletDirective(_context, name, permission, region,
- for_=Interface, layer=IDefaultBrowserLayer,
- view=IBrowserView,
- class_=None, template=None, attribute='__call__', weight=0,
- allowed_interface=None, allowed_attributes=None):
+# TODO: support None for weight
+def viewletDirective(_context, name, permission, providerType, for_=Interface,
+ layer=IDefaultBrowserLayer, view=IBrowserView,
+ class_=None, template=None, attribute='__call__',
+ weight=None, allowed_interface=None,
+ allowed_attributes=None):
required = {}
+ if interfaces.IWeightSupport.implementedBy(class_) and weight == None:
+ msg = "Must specify a weight if IWeightSupport is implemented"
+ raise ConfigurationError(msg)
+
# Get the permission; mainly to correctly handle CheckerPublic.
permission = viewmeta._handle_permission(_context, permission)
@@ -181,8 +167,9 @@
new_class = viewlet.SimpleViewletClass(
template, name=name, weight=weight)
- # Make sure the new class implements the region
- classImplements(new_class, region)
+ # set providerType if the class_ defines the global attribute
+ if hasattr(new_class, 'providerType'):
+ classImplements(new_class, providerType)
for attr_name in (attribute, 'browserDefault', '__call__',
'publishTraverse', 'weight'):
@@ -195,14 +182,13 @@
viewmeta._handle_for(_context, for_)
metaconfigure.interface(_context, view)
- metaconfigure.interface(_context, region, IRegion)
checker.defineChecker(new_class, checker.Checker(required))
# register viewlet
_context.action(
- discriminator = ('viewlet', for_, layer, view, region, name),
+ discriminator = ('viewlet', for_, layer, view, name),
callable = metaconfigure.handler,
args = ('provideAdapter',
- (for_, layer, view), region, name, new_class,
+ (for_, layer, view), providerType, name, new_class,
_context.info),)
Modified: Zope3/branches/roger-contentprovider/src/zope/viewlet/metadirectives.py
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/viewlet/metadirectives.py 2005-10-09 08:28:18 UTC (rev 38986)
+++ Zope3/branches/roger-contentprovider/src/zope/viewlet/metadirectives.py 2005-10-09 08:30:11 UTC (rev 38987)
@@ -17,8 +17,8 @@
"""
__docformat__ = 'restructuredtext'
-from zope.configuration.fields import GlobalInterface
-from zope.schema import Int
+import zope.configuration.fields
+import zope.schema
from zope.app.publisher.browser import metadirectives
@@ -31,17 +31,12 @@
lookup viewlets of this type.
"""
- viewletType = GlobalInterface(
+ providerType = zope.configuration.fields.GlobalInterface(
title=u"Viewlet type",
description=u"The type interface for viewlets.",
required=True)
- weight = Int(
- title=u"weight",
- description=u"Integer key for sorting viewlets in the same region.",
- required=False)
-
- name = TextLine(
+ name = zope.schema.TextLine(
title=u"The name of the page (view)",
description=u"""
The name shows up in URLs/paths. For example 'foo' or
@@ -50,19 +45,19 @@
sub pages, it is common to use an extension for the view name
such as '.html'. If you do have sub pages and you want to
provide a view name, you shouldn't use extensions.""",
- required=True
- )
- template = Path(
+ required=True)
+
+ template = zope.configuration.fields.Path(
title=u"The name of a template that implements the page.",
description=u"""
Refers to a file containing a page template (should end in
extension '.pt' or '.html').""",
- required=False
- )
+ required=False)
class IViewletDirective(metadirectives.IPagesDirective,
- metadirectives.IViewPageSubdirective):
+ metadirectives.IViewPageSubdirective,
+ IViewletManagerDirective):
"""A directive to register a new viewlet.
Viewlet registrations are very similar to page registrations, except that
@@ -71,18 +66,13 @@
control the order of the viewlets.
"""
- region = GlobalInterface(
- title=u"region",
- description=u"The region interface this viewlet is for.",
- required=True)
-
- view = GlobalInterface(
+ view = zope.configuration.fields.GlobalInterface(
title=u"view",
description=u"The interface of the view this viewlet is for. "
u"(default IBrowserView)""",
required=False)
- weight = Int(
+ weight = zope.schema.Int(
title=u"weight",
description=u"Integer key for sorting viewlets in the same region.",
required=False)
Modified: Zope3/branches/roger-contentprovider/src/zope/viewlet/tests.py
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/viewlet/tests.py 2005-10-09 08:28:18 UTC (rev 38986)
+++ Zope3/branches/roger-contentprovider/src/zope/viewlet/tests.py 2005-10-09 08:30:11 UTC (rev 38987)
@@ -32,6 +32,22 @@
interaction = None
+class ILeftViewlet(interfaces.IViewlet):
+ """Test viewlet type."""
+
+
+class TestViewlet(object):
+
+ def doSomething(self):
+ return u'something'
+
+
+class TestViewlet2(object):
+
+ def __call__(self):
+ return u'called'
+
+
def setUp(test):
setup.placefulSetUp()
More information about the Zope3-Checkins
mailing list