[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