[Checkins] SVN: grok/branches/ulif-testsetup/ Sync branch with changes from trunk.

Uli Fouquet uli at gnufix.de
Wed Mar 26 08:55:15 EDT 2008


Log message for revision 84953:
  Sync branch with changes from trunk.

Changed:
  U   grok/branches/ulif-testsetup/CHANGES.txt
  U   grok/branches/ulif-testsetup/COPYRIGHT.txt
  U   grok/branches/ulif-testsetup/doc/about.txt
  U   grok/branches/ulif-testsetup/doc/tutorial.txt
  U   grok/branches/ulif-testsetup/doc/upgrade.txt
  U   grok/branches/ulif-testsetup/setup.py
  U   grok/branches/ulif-testsetup/src/grok/__init__.py
  U   grok/branches/ulif-testsetup/src/grok/components.py
  U   grok/branches/ulif-testsetup/src/grok/configure.zcml
  U   grok/branches/ulif-testsetup/src/grok/directive.py
  U   grok/branches/ulif-testsetup/src/grok/ftests/test_grok_functional.py
  A   grok/branches/ulif-testsetup/src/grok/ftests/viewlet/
  U   grok/branches/ulif-testsetup/src/grok/interfaces.py
  U   grok/branches/ulif-testsetup/src/grok/meta.py
  U   grok/branches/ulif-testsetup/src/grok/meta.zcml
  U   grok/branches/ulif-testsetup/src/grok/templatereg.py
  U   grok/branches/ulif-testsetup/src/grok/tests/test_grok.py
  A   grok/branches/ulif-testsetup/src/grok/tests/viewlet/
  U   grok/branches/ulif-testsetup/src/grok/util.py
  U   grok/branches/ulif-testsetup/versions.cfg

-=-
Modified: grok/branches/ulif-testsetup/CHANGES.txt
===================================================================
--- grok/branches/ulif-testsetup/CHANGES.txt	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/CHANGES.txt	2008-03-26 12:55:14 UTC (rev 84953)
@@ -10,12 +10,33 @@
 * Added testsetup classes in grok.testing to improve easy setup of
   unit- and functional tests.
 
+* Add support for viewlets and viewlet managers, ``grok.Viewlet``
+  and ``grok.ViewletManager``.
+
 * Add a new directive, ``grok.order()``, which can be used to help
   sort components. At the time it is not used yet, but we intend to
   use it for the viewlets support. Note that this means Grok now
   requires Martian 0.9.3 or higher. See ``grok.interfaces`` for more
   documentation on this directive.
+
+* Now depend on ``z3c.autoinclude``. This allows the use of the
+  ``<autoinclude package="."/>`` directive, which automatically loads
+  up ZCML needed for the dependencies listed in your project's
+  ``setup.py``. The new release of grokproject adds this line
+  automatically. Upgrade ``grokproject`` to make use of this
+  functionality in new projects::
+
+    $ easy_install -U grokproject
+
+* Classes that end with "-Base" are no longer implicitly considered base
+  classes. These classes need to have the grok.baseclass() directive added to
+  them explicitly.
+
+  See also the ``upgrade notes``_ for information on how to update
+  your existing projects.
  
+.. _``upgrade notes``: http://grok.zope.org/project/upgrade-notes
+
 Bug fixes
 ---------
 

Modified: grok/branches/ulif-testsetup/COPYRIGHT.txt
===================================================================
--- grok/branches/ulif-testsetup/COPYRIGHT.txt	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/COPYRIGHT.txt	2008-03-26 12:55:14 UTC (rev 84953)
@@ -1,5 +1,4 @@
-Copyright (c) 2006 gocept gmbh & co. kg, Martijn Faassen and Philipp von
-Weitershausen
+Copyright (c) 2006-2008 Zope Corporation and contributors
 All Rights Reserved.
 
 This software is subject to the provisions of the Zope Public License,

Modified: grok/branches/ulif-testsetup/doc/about.txt
===================================================================
--- grok/branches/ulif-testsetup/doc/about.txt	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/doc/about.txt	2008-03-26 12:55:14 UTC (rev 84953)
@@ -134,4 +134,4 @@
 
 During the development of Grok we have taken a careful look at common
 patterns in Zope 3 code and configuration. Grok aims to make these
-patterns more easy to use and succinct.
+patterns easier to use and more succinct.

Modified: grok/branches/ulif-testsetup/doc/tutorial.txt
===================================================================
--- grok/branches/ulif-testsetup/doc/tutorial.txt	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/doc/tutorial.txt	2008-03-26 12:55:14 UTC (rev 84953)
@@ -38,7 +38,7 @@
 examples should be fairly obvious if you are already familiar with
 another templating language.
 
-We recommend beginners to follow the tutorial from top to bottom. The
+We recommend that beginners follow the tutorial from top to bottom. The
 tutorial is designed to explain important concepts in order and slowly
 builds up from there.
 
@@ -91,7 +91,9 @@
 
 Let's go through the prerequisites first. You need a computer
 connected to the internet, as Grok installs itself over the
-network. You also need Python 2.4 installed.
+network. You also need Python 2.4 installed (Python 2.5 is not
+yet supported, and does not pass all unit tests, though some
+have reported success using it with Grok.)
 
 Because Grok uses a source distribution of Zope 3, you may need to
 install your operating system's Python "dev" package. You also need a
@@ -120,39 +122,6 @@
 and set up the project in there. grokproject will automatically
 download and install Zope 3 and Grok into the project area.
 
-.. XXX when grokproject gains a switch for pointing to a shared egg
-       directory, mention this here.
-
-grokproject will tell you what it will be creating::
-
-  Selected and implied templates:
-    grokproject#grokproject  A grok project
-
-  Variables:
-    egg:      Sample
-    package:  sample
-    project:  Sample
-
-The "Selected and implied templates" line is something reported by
-Paste, which is the Python project generation software which
-grokproject is using. After this, it reports three names. 
-
-First, it reports the name this project will have if in the project's
-``setup.py``::
-
-    egg:      Sample
-
-Next, it specifies the name of the Python package that you will be
-developing with. The package will be placed under the project's ``src``
-directory::
-
-    package:  sample
-
-Finally, it gives the name of the project directory that it will
-create (under the current directory)::
-
-    project:  Sample
-
 You will be asked a number of questions now. First you need to supply
 the name of the initial module that your package will contain. We'll
 stick with the default ``app.py``::
@@ -164,8 +133,12 @@
 
   Enter user (Name of an initial administrator user): grok
   Enter passwd (Password for the initial administrator user): grok
+  Enter eggs_dir (Location where zc.buildout will look for and place packages) ['/home/<user>/buildout-eggs']:
 
-Now you have to wait a while as grokproject downloads `zc.buildout`_
+For the last question, we'll stick with the default path which will be
+a directory called 'buildout-eggs' in your home directory.
+
+Now you have to wait while grokproject downloads `zc.buildout`_
 (the system that's used to build the project area), Grok and the Zope
 3 libraries.
 
@@ -1275,8 +1248,9 @@
 ``grok.name``. We can use it on both view classes
 (``grok.name('index')``) to explicitly explain to Grok what we want.
 
-You can now try to restart Zope and create both applications. They
-should display the correct index pages when you look at them.
+You can now try to restart Zope and create both applications in the
+Grok Admin interface. They should display the correct index pages
+when you look at them.
 
 We can see that the introduction of a second model has complicated our
 code a bit, though you will hopefully agree with us that it is still
@@ -1295,7 +1269,7 @@
 subclasses ``grok.Container``. What we will do in this section is
 build an application that actually puts something into that container.
 
-Grok applications ar typically composed of containers and
+Grok applications are typically composed of containers and
 models. Containers are objects that can contain models. This includes
 other containers, as a container is just a special kind of model.
 

Modified: grok/branches/ulif-testsetup/doc/upgrade.txt
===================================================================
--- grok/branches/ulif-testsetup/doc/upgrade.txt	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/doc/upgrade.txt	2008-03-26 12:55:14 UTC (rev 84953)
@@ -6,7 +6,32 @@
 describes changes involving incompatibilities or deprecations, not new
 features (please refer to ``CHANGES.txt`` for those).
 
+Upgrading to 0.12
+-----------------
 
+* If you have existing Grok projects and you want to make use of 
+  Grok's new autoinclusion functionality in them, you can place
+  the following line in your project's ``configure.zcml``:
+
+    <autoinclude package="." />
+
+  This will cause the ZCML for ``setup.py`` dependencies of your
+  package to be loaded automatically. You can now get rid of any
+  manual ``include`` statements (except the one that includes ``grok``
+  itself).
+
+  For new projects created by ``grokproject``, this line will be
+  automatically be added for you and you don't have to do anything except
+  to upgrade ``grokproject``::
+
+    $ easy_install -U grokproject
+
+* The convention that classes ending with -Base automatically become base
+  classes has been removed with martian 0.9.4. Please add the grok.baseclass()
+  directive to these classes explicitly where the 'Base' class convention was
+  relied upon to preserve existing functionality.
+
+
 Upgrading to 0.11
 -----------------
 

Modified: grok/branches/ulif-testsetup/setup.py
===================================================================
--- grok/branches/ulif-testsetup/setup.py	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/setup.py	2008-03-26 12:55:14 UTC (rev 84953)
@@ -77,8 +77,10 @@
                       'zope.testing',
                       'zope.traversing',
                       'zope.testbrowser',
+                      'zope.viewlet',
                       'zc.catalog',
                       'z3c.flashmessage',
                       'z3c.testsetup',
+                      'z3c.autoinclude',
                       ],
 )

Modified: grok/branches/ulif-testsetup/src/grok/__init__.py
===================================================================
--- grok/branches/ulif-testsetup/src/grok/__init__.py	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/src/grok/__init__.py	2008-03-26 12:55:14 UTC (rev 84953)
@@ -40,9 +40,12 @@
 from grok.components import Skin, IGrokLayer
 from grok.components import RESTProtocol, IRESTLayer
 from grok.interfaces import IRESTSkinType
+from grok.components import ViewletManager, Viewlet
+
 from grok.directive import (context, name, title, template, templatedir,
                             provides, baseclass, global_utility, local_utility,
-                            permissions, require, site, layer, direct, order)
+                            permissions, require, site, layer, direct, viewletmanager,
+                            view, order)
 from grok.decorators import subscribe, adapter, implementer
 from martian.error import GrokError, GrokImportError
 

Modified: grok/branches/ulif-testsetup/src/grok/components.py
===================================================================
--- grok/branches/ulif-testsetup/src/grok/components.py	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/src/grok/components.py	2008-03-26 12:55:14 UTC (rev 84953)
@@ -16,7 +16,6 @@
 import sys
 import os
 import persistent
-import urllib
 import datetime
 import warnings
 import pytz
@@ -47,6 +46,9 @@
 from zope.app.component.site import SiteManagerContainer
 from zope.app.component.site import LocalSiteManager
 
+from zope.viewlet.manager import ViewletManagerBase
+from zope.viewlet.viewlet import ViewletBase
+
 import z3c.flashmessage.interfaces
 
 import martian.util
@@ -608,3 +610,104 @@
 
 class RESTProtocol(object):
     pass
+
+class ViewletManager(ViewletManagerBase):
+    template = None
+
+    def __init__(self, context, request, view):
+        super(ViewletManager, self).__init__(context, request, view)
+        self.__name__ = util.class_annotation(self.__class__,
+                                              'grok.name',
+                                              self.__class__.__name__.lower())
+        self.static = component.queryAdapter(
+            self.request,
+            interface.Interface,
+            name=self.module_info.package_dotted_name
+            )
+
+    def render(self):
+        """See zope.contentprovider.interfaces.IContentProvider"""
+        # Now render the view
+        if self.template:
+            return self.template.render(self) 
+        else:
+            viewlets = util.sort_components(self.viewlets)
+            return u'\n'.join([viewlet.render() for viewlet in viewlets])
+
+    def namespace(self):
+        return {}
+
+    @property
+    def response(self):
+        return self.request.response
+
+    def url(self, obj=None, name=None):
+        # if the first argument is a string, that's the name. There should
+        # be no second argument
+        if isinstance(obj, basestring):
+            if name is not None:
+                raise TypeError(
+                    'url() takes either obj argument, obj, string arguments, '
+                    'or string argument')
+            name = obj
+            obj = None
+
+        if name is None and obj is None:
+            # create URL to view itself
+            obj = self
+        elif name is not None and obj is None:
+            # create URL to view on context
+            obj = self.context
+        return util.url(self.request, obj, name)
+
+    def redirect(self, url):
+        return self.request.response.redirect(url)
+
+class Viewlet(ViewletBase):
+    """ Batteries included viewlet """
+
+
+    def __init__(self, context, request, view, manager):
+        super(Viewlet, self).__init__(context, request, view, manager)
+        # would be nice to move this to the ViewletGrokker but
+        # new objects don't have __name__ of their class
+        self.__name__ = util.class_annotation(self.__class__,
+                                             'grok.name',
+                                              self.__class__.__name__.lower())
+        self.static = component.queryAdapter(
+            self.request,
+            interface.Interface,
+            name=self.module_info.package_dotted_name
+            )
+
+    @property
+    def response(self):
+        return self.request.response
+
+    def render(self):
+        return self.template.render(self)
+
+    def namespace(self):
+        return {}
+
+    def url(self, obj=None, name=None):
+        # if the first argument is a string, that's the name. There should
+        # be no second argument
+        if isinstance(obj, basestring):
+            if name is not None:
+                raise TypeError(
+                    'url() takes either obj argument, obj, string arguments, '
+                    'or string argument')
+            name = obj
+            obj = None
+
+        if name is None and obj is None:
+            # create URL to view itself
+            obj = self
+        elif name is not None and obj is None:
+            # create URL to view on context
+            obj = self.context
+        return util.url(self.request, obj, name)
+
+    def update(self):
+        pass

Modified: grok/branches/ulif-testsetup/src/grok/configure.zcml
===================================================================
--- grok/branches/ulif-testsetup/src/grok/configure.zcml	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/src/grok/configure.zcml	2008-03-26 12:55:14 UTC (rev 84953)
@@ -11,6 +11,7 @@
 
   <include package="zope.annotation" />
   <include package="zope.copypastemove" />
+  <include package="zope.contentprovider" />
   <include package="zope.formlib" />
   <include package="zope.i18n.locales" />
   <include package="zope.publisher" />

Modified: grok/branches/ulif-testsetup/src/grok/directive.py
===================================================================
--- grok/branches/ulif-testsetup/src/grok/directive.py	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/src/grok/directive.py	2008-03-26 12:55:14 UTC (rev 84953)
@@ -138,5 +138,9 @@
     'grok.permissions', ClassDirectiveContext())
 layer = InterfaceOrClassDirective('grok.layer',
                            ClassOrModuleDirectiveContext())
+order = OrderDirective('grok.order', ClassDirectiveContext())
 direct = MarkerDirective('grok.direct', ClassDirectiveContext())
-order = OrderDirective('grok.order', ClassDirectiveContext())
+viewletmanager = InterfaceOrClassDirective('grok.viewletmanager',
+                                           ClassOrModuleDirectiveContext())
+view = InterfaceOrClassDirective('grok.view',
+                                 ClassOrModuleDirectiveContext())

Modified: grok/branches/ulif-testsetup/src/grok/ftests/test_grok_functional.py
===================================================================
--- grok/branches/ulif-testsetup/src/grok/ftests/test_grok_functional.py	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/src/grok/ftests/test_grok_functional.py	2008-03-26 12:55:14 UTC (rev 84953)
@@ -70,7 +70,8 @@
 def test_suite():
     suite = unittest.TestSuite()
     for name in ['view', 'staticdir', 'xmlrpc', 'traversal', 'form', 'url',
-                 'security', 'utility', 'catalog', 'admin', 'site', 'rest']:
+                 'security', 'utility', 'catalog', 'admin', 'site', 'rest',
+                 'viewlet']:
         suite.addTest(suiteFromPackage(name))
 
     # this test cannot follow the normal testing pattern, as the

Copied: grok/branches/ulif-testsetup/src/grok/ftests/viewlet (from rev 84952, grok/trunk/src/grok/ftests/viewlet)

Modified: grok/branches/ulif-testsetup/src/grok/interfaces.py
===================================================================
--- grok/branches/ulif-testsetup/src/grok/interfaces.py	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/src/grok/interfaces.py	2008-03-26 12:55:14 UTC (rev 84953)
@@ -47,6 +47,8 @@
     Indexes = interface.Attribute("Base class for catalog index definitions.")
     Layer = interface.Attribute("Base interface for layers.")
     Skin = interface.Attribute("Base class for skin.")
+    ViewletManager = interface.Attribute("Base class for viewletmanager.")
+    Viewlet = interface.Attribute("Base class for viewlet.")
 
 
 class IGrokErrors(interface.Interface):

Modified: grok/branches/ulif-testsetup/src/grok/meta.py
===================================================================
--- grok/branches/ulif-testsetup/src/grok/meta.py	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/src/grok/meta.py	2008-03-26 12:55:14 UTC (rev 84953)
@@ -17,11 +17,13 @@
 
 import zope.component.interface
 from zope import interface, component
+from zope.publisher.browser import IBrowserView
 from zope.publisher.interfaces.browser import (IDefaultBrowserLayer,
                                                IBrowserRequest,
                                                IBrowserPublisher,
                                                IBrowserSkinType)
 from zope.publisher.interfaces.xmlrpc import IXMLRPCRequest
+from zope.viewlet.interfaces import IViewletManager, IViewlet
 from zope.security.interfaces import IPermission
 from zope.securitypolicy.interfaces import IRole
 from zope.securitypolicy.rolepermission import rolePermissionManager
@@ -47,16 +49,20 @@
 import grok
 from grok import components, formlib, templatereg
 from grok.util import check_adapts, get_default_permission, make_checker
+from grok.util import check_module_component, determine_module_component
+from grok.util import determine_class_component
 from grok.util import determine_class_directive, public_methods_from_class
-from grok.util import determine_module_context, determine_class_context
-from grok.util import check_context
 from grok.rest import RestPublisher
 from grok.interfaces import IRESTSkinType
 
 def get_context(module_info, factory):
-    context = module_info.getAnnotation('grok.context', None)
-    return determine_class_context(factory, context)
+    return determine_class_component(module_info, factory,
+                                     'context', 'grok.context')
 
+def get_viewletmanager(module_info, factory):
+    return determine_class_component(module_info, factory,
+                                     'viewletmanager', 'grok.viewletmanager')
+
 def get_name_classname(factory):
     return get_name(factory, factory.__name__.lower())
 
@@ -74,13 +80,23 @@
     priority = 1001
 
     def grok(self, name, module, module_info, config, **kw):
-        possible_contexts = martian.scan_for_classes(module, [grok.Model,
-                                                              grok.Container])
-        context = determine_module_context(module_info, possible_contexts)
+        context = determine_module_component(module_info, 'grok.context',
+                                             [grok.Model, grok.Container])
         module.__grok_context__ = context
         return True
 
 
+class ViewletManagerContextGrokker(martian.GlobalGrokker):
+
+    priority = 1001
+
+    def grok(self, name, module, module_info, config, **kw):
+        viewletmanager = determine_module_component(module_info,
+                                                    'grok.viewletmanager',
+                                                    [grok.ViewletManager])
+        module.__grok_viewletmanager__ = viewletmanager
+        return True
+    
 class AdapterGrokker(martian.ClassGrokker):
     component_class = grok.Adapter
 
@@ -247,8 +263,8 @@
         if templates is not None:
             config.action(
                 discriminator=None,
-                callable=templates.checkTemplates,
-                args=(module_info, factory, factory.__name__.lower())
+                callable=self.checkTemplates,
+                args=(templates, module_info, factory)
             )
 
         # safety belt: make sure that the programmer didn't use
@@ -286,8 +302,14 @@
 
         return True
 
-def view__getitem__(self, key):
-    return self.template.macros[key]
+    def checkTemplates(self, templates, module_info, factory):
+        def has_render(factory):
+            return (getattr(factory, 'render', None) and
+                    not util.check_subclass(factory, grok.components.GrokForm))
+        def has_no_render(factory):
+            return not getattr(factory, 'render', None)
+        templates.checkTemplates(module_info, factory, 'view',
+                                 has_render, has_no_render)
 
 
 class JSONGrokker(martian.ClassGrokker):
@@ -452,7 +474,8 @@
             if interfaces is None:
                 # There's no explicit interfaces defined, so we assume the
                 # module context to be the thing adapted.
-                check_context(module_info.getModule(), context)
+                check_module_component(module_info.getModule(), context,
+                                       'context', 'grok.context')
                 interfaces = (context, )
 
             config.action(
@@ -873,3 +896,96 @@
             args=(name, layer, IRESTSkinType)
             )
         return True
+
+class ViewletManagerGrokker(martian.ClassGrokker):
+    component_class = grok.ViewletManager
+
+    def grok(self, name, factory, module_info, config, **kw):
+        factory.module_info = module_info
+
+        # find templates
+        templates = module_info.getAnnotation('grok.templates', None)
+        if templates is not None:
+            config.action(
+                discriminator=None,
+                callable=self.checkTemplates,
+                args=(templates, module_info, factory)
+                )
+
+        name = get_name(factory)
+        view_context = get_context(module_info, factory)
+
+        view = determine_class_directive('grok.view', factory,
+                                         module_info, default=IBrowserView)
+        viewlet_layer = determine_class_directive('grok.layer', factory,
+                                                  module_info,
+                                                  default=IDefaultBrowserLayer)
+
+        config.action(
+            discriminator = ('viewletManager', view_context, viewlet_layer,
+                             view, name),
+            callable = component.provideAdapter,
+            args = (factory, (view_context, viewlet_layer, view),
+                    IViewletManager, name)
+            )
+
+        return True
+
+    def checkTemplates(self, templates, module_info, factory):
+        def has_render(factory):
+            return factory.render != grok.components.ViewletManager.render
+        def has_no_render(factory):
+            # always has a render method
+            return False
+        templates.checkTemplates(module_info, factory, 'viewlet manager',
+                                 has_render, has_no_render)
+
+class ViewletGrokker(martian.ClassGrokker):
+    component_class = grok.Viewlet
+
+    def grok(self, name, factory, module_info, config, **kw):
+        viewlet_name = get_name_classname(factory)
+        viewlet_context = get_context(module_info, factory)
+
+        factory.module_info = module_info # to make /static available
+
+        # find templates
+        templates = module_info.getAnnotation('grok.templates', None)
+        if templates is not None:
+            config.action(
+                discriminator=None,
+                callable=self.checkTemplates,
+                args=(templates, module_info, factory)
+                )
+
+        view = determine_class_directive('grok.view', factory,
+                                         module_info, default=IBrowserView)
+        viewlet_layer = determine_class_directive('grok.layer', factory,
+                                                  module_info,
+                                                  default=IDefaultBrowserLayer)
+        viewletmanager = get_viewletmanager(module_info, factory)
+
+        config.action(
+            discriminator = ('viewlet', viewlet_context, viewlet_layer,
+                             view, viewletmanager, viewlet_name),
+            callable = component.provideAdapter,
+            args = (factory, (viewlet_context, viewlet_layer, view,
+                    viewletmanager), IViewlet, viewlet_name)
+            )
+
+        permission = get_default_permission(factory)
+        config.action(
+            discriminator=('protectName', factory, '__call__'),
+            callable=make_checker,
+            args=(factory, factory, permission, ['update', 'render']),
+            )
+
+        return True
+
+    def checkTemplates(self, templates, module_info, factory):
+        def has_render(factory):
+            return factory.render != grok.components.Viewlet.render
+        def has_no_render(factory):
+            return not has_render(factory)
+        templates.checkTemplates(module_info, factory, 'viewlet',
+                                 has_render, has_no_render)

Modified: grok/branches/ulif-testsetup/src/grok/meta.zcml
===================================================================
--- grok/branches/ulif-testsetup/src/grok/meta.zcml	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/src/grok/meta.zcml	2008-03-26 12:55:14 UTC (rev 84953)
@@ -3,6 +3,8 @@
     xmlns:meta="http://namespaces.zope.org/meta"
     xmlns:grok="http://namespaces.zope.org/grok">
 
+  <include package="z3c.autoinclude" file="meta.zcml" />
+
   <meta:directives namespace="http://namespaces.zope.org/grok">
     <meta:directive
         name="grok"

Modified: grok/branches/ulif-testsetup/src/grok/templatereg.py
===================================================================
--- grok/branches/ulif-testsetup/src/grok/templatereg.py	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/src/grok/templatereg.py	2008-03-26 12:55:14 UTC (rev 84953)
@@ -81,7 +81,9 @@
                 module_info.dotted_name, ', '.join(unassociated)))
             warnings.warn(msg, UserWarning, 2)
 
-    def checkTemplates(self, module_info, factory, factory_name):
+    def checkTemplates(self, module_info, factory, component_name,
+                       has_render, has_no_render):
+        factory_name = factory.__name__.lower()
         template_name = util.class_annotation(factory, 'grok.template',
                                               factory_name)
 
@@ -89,29 +91,30 @@
             # grok.template is being used
 
             if self.get(factory_name):
-                raise GrokError("Multiple possible templates for view %r. It "
+                raise GrokError("Multiple possible templates for %s %r. It "
                                 "uses grok.template('%s'), but there is also "
                                 "a template called '%s'."
-                                % (factory, template_name, factory_name),
-                                factory)
+                                % (component_name, factory, template_name,
+                                   factory_name), factory)
         template = self.get(template_name)
-        if template:
-            if (getattr(factory, 'render', None) and not
-                util.check_subclass(factory, grok.components.GrokForm)):
+        if template is not None:
+            if has_render(factory):
                 # we do not accept render and template both for a view
                 # (unless it's a form, they happen to have render.
                 raise GrokError(
-                    "Multiple possible ways to render view %r. "
+                    "Multiple possible ways to render %s %r. "
                     "It has both a 'render' method as well as "
-                    "an associated template." % factory, factory)
+                    "an associated template." %
+                    (component_name, factory), factory)
             self.markAssociated(template_name)
             factory.template = template
             template._initFactory(factory)
         else:
-            if not getattr(factory, 'render', None):
+            if has_no_render(factory):
                 # we do not accept a view without any way to render it
-                raise GrokError("View %r has no associated template or "
-                                "'render' method." % factory, factory)
+                raise GrokError("%s %r has no associated template or "
+                                "'render' method." %
+                                (component_name.title(), factory), factory)
 
 class PageTemplateFileFactory(grok.GlobalUtility):
 

Modified: grok/branches/ulif-testsetup/src/grok/tests/test_grok.py
===================================================================
--- grok/branches/ulif-testsetup/src/grok/tests/test_grok.py	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/src/grok/tests/test_grok.py	2008-03-26 12:55:14 UTC (rev 84953)
@@ -46,7 +46,7 @@
                  'zcml', 'static', 'utility', 'xmlrpc', 'json', 'container',
                  'traversal', 'form', 'grokker', 'directive', 'util',
                  'baseclass', 'annotation', 'application', 'template', 'order',
-                 'testsetup']:
+                 'viewlet', 'testsetup']:
         suite.addTest(suiteFromPackage(name))
     return suite
 

Copied: grok/branches/ulif-testsetup/src/grok/tests/viewlet (from rev 84952, grok/trunk/src/grok/tests/viewlet)

Modified: grok/branches/ulif-testsetup/src/grok/util.py
===================================================================
--- grok/branches/ulif-testsetup/src/grok/util.py	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/src/grok/util.py	2008-03-26 12:55:14 UTC (rev 84953)
@@ -25,7 +25,7 @@
 from zope.security.interfaces import IPermission
 
 from martian.error import GrokError, GrokImportError
-from martian.util import class_annotation, methods_from_class
+from martian.util import class_annotation, methods_from_class, scan_for_classes
 
 def check_adapts(class_):
     if component.adaptedBy(class_) is None:
@@ -33,18 +33,20 @@
                         "(use grok.adapts to specify)."
                         % class_, class_)
 
-def make_checker(factory, view_factory, permission):
+def make_checker(factory, view_factory, permission, method_names=None):
     """Make a checker for a view_factory associated with factory.
 
     These could be one and the same for normal views, or different
     in case we make method-based views such as for JSON and XMLRPC.
     """
+    if method_names is None:
+        method_names = ['__call__']
     if permission is not None:
         check_permission(factory, permission)
     if permission is None or permission == 'zope.Public':
-        checker = NamesChecker(['__call__'])
+        checker = NamesChecker(method_names)
     else:
-        checker = NamesChecker(['__call__'], permission)
+        checker = NamesChecker(method_names, permission)
     defineChecker(view_factory, checker)
 
 def check_permission(factory, permission):
@@ -123,31 +125,66 @@
     # if components have a grok.order directive, sort by that
     return sorted(components, key=_sort_key)
 
-AMBIGUOUS_CONTEXT = object()
-def check_context(component, context):
-    if context is None:
-        raise GrokError("No module-level context for %r, please use "
-                        "grok.context." % component, component)
-    elif context is AMBIGUOUS_CONTEXT:
-        raise GrokError("Multiple possible contexts for %r, please use "
-                        "grok.context." % component, component)
+AMBIGUOUS_COMPONENT = object()
+def check_module_component(factory, component,
+                           component_name, component_directive):
+    """Raise error if module-level component cannot be determined.
 
-def determine_module_context(module_info, models):
-    if len(models) == 0:
-        context = None
-    elif len(models) == 1:
-        context = models[0]
+    If the module-level component is None, it's never been specified;
+    raise error telling developer to specify.
+
+    if the module-level component is AMBIGUOUS_COMPONENT, raise
+    an error telling developer to specify which one to use.
+    """
+    if component is None:
+        raise GrokError("No module-level %s for %r, please use "
+                        "%s." % (component_name, factory, component_directive),
+                        factory)
+    elif component is AMBIGUOUS_COMPONENT:
+        raise GrokError("Multiple possible %ss for %r, please use "
+                        "%s." % (component_name, factory, component_directive),
+                        factory)
+    
+def determine_module_component(module_info, annotation, classes):
+    """Determine module-level component.
+
+    The module-level component can be set explicitly using the
+    annotation (such as grok.context).
+
+    If there is no annotation, the module-level component is determined
+    by scanning for subclasses of any in the list of classes.
+
+    If there is no module-level component, the module-level component is
+    None.
+
+    If there is one module-level component, it is returned.
+
+    If there are more than one module-level component, AMBIGUOUS_COMPONENT
+    is returned.
+    """
+    components = scan_for_classes(module_info.getModule(), classes)
+    if len(components) == 0:
+        component = None
+    elif len(components) == 1:
+        component = components[0]
     else:
-        context = AMBIGUOUS_CONTEXT
+        component= AMBIGUOUS_COMPONENT
+        
+    module_component = module_info.getAnnotation(annotation, None)
+    if module_component:
+        component = module_component
+    return component
 
-    module_context = module_info.getAnnotation('grok.context', None)
-    if module_context:
-        context = module_context
 
-    return context
+def determine_class_component(module_info, class_,
+                              component_name, component_directive):
+    """Determine component for a class.
 
-
-def determine_class_context(class_, module_context):
-    context = class_annotation(class_, 'grok.context', module_context)
-    check_context(class_, context)
-    return context
+    Determine a component for a class. If no class-specific component exists,
+    try falling back on module-level component.
+    """
+    module_component = module_info.getAnnotation(component_directive, None)
+    component = class_annotation(class_, component_directive, module_component)
+    check_module_component(class_, component,
+                           component_name, component_directive)
+    return component

Modified: grok/branches/ulif-testsetup/versions.cfg
===================================================================
--- grok/branches/ulif-testsetup/versions.cfg	2008-03-26 05:00:12 UTC (rev 84952)
+++ grok/branches/ulif-testsetup/versions.cfg	2008-03-26 12:55:14 UTC (rev 84953)
@@ -7,6 +7,7 @@
 pytz = 2007g
 RestrictedPython = 3.4.2
 simplejson = 1.7.1
+z3c.autoinclude = 0.1
 z3c.flashmessage = 1.0b2
 z3c.testsetup = 0.2.1
 zc.catalog = 1.2b
@@ -62,6 +63,7 @@
 zope.cachedescriptors = 3.4.0
 zope.component = 3.4.0
 zope.configuration = 3.4.0
+zope.contentprovider = 3.4.0
 zope.contenttype = 3.4.0
 zope.copypastemove = 3.4.0
 zope.datetime = 3.4.0
@@ -99,3 +101,4 @@
 zope.testing = 3.5.1
 zope.thread = 3.4
 zope.traversing = 3.5.0a1.dev-r78730
+zope.viewlet = 3.4.1



More information about the Checkins mailing list