[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