[Checkins] SVN: grokcore.view/trunk/ svn merge -r 119971:120020 svn+ssh://svn.zope.org/repos/main/grokcore.view/branches/sylvain-template-inheritance-fix .
Jan-Wijbrand Kolman
janwijbrand at gmail.com
Tue Feb 8 08:58:34 EST 2011
Log message for revision 120209:
svn merge -r 119971:120020 svn+ssh://svn.zope.org/repos/main/grokcore.view/branches/sylvain-template-inheritance-fix .
Changed:
U grokcore.view/trunk/CHANGES.txt
U grokcore.view/trunk/src/grokcore/view/directive.py
U grokcore.view/trunk/src/grokcore/view/meta/templates.py
U grokcore.view/trunk/src/grokcore/view/meta/views.py
U grokcore.view/trunk/src/grokcore/view/templatereg.py
U grokcore.view/trunk/src/grokcore/view/templatereg.txt
A grokcore.view/trunk/src/grokcore/view/tests/view/cross_package.py
A grokcore.view/trunk/src/grokcore/view/tests/view/cross_package_fixture/
-=-
Modified: grokcore.view/trunk/CHANGES.txt
===================================================================
--- grokcore.view/trunk/CHANGES.txt 2011-02-08 13:24:20 UTC (rev 120208)
+++ grokcore.view/trunk/CHANGES.txt 2011-02-08 13:58:34 UTC (rev 120209)
@@ -4,8 +4,15 @@
2.4 (unreleased)
----------------
-- Nothing changed yet.
+- Use the zope configuration action ordering feature to have templates
+ registered for all packages and modules, before trying to associate the
+ templates. Checking for unassociated templates is done very very late in the
+ configuration action order.
+- Inherited grok.template() information is looked up against the module of
+ the view class that uses the grok.template() directive. This allows for
+ subclassing view components that use the grok.template() directive from other
+ packages.
2.3 (2011-01-04)
----------------
@@ -13,7 +20,6 @@
- Removed the static directory grokker in order to make way for using
fanstatic.
-
2.2 (2010-12-16)
----------------
Modified: grokcore.view/trunk/src/grokcore/view/directive.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/directive.py 2011-02-08 13:24:20 UTC (rev 120208)
+++ grokcore.view/trunk/src/grokcore/view/directive.py 2011-02-08 13:58:34 UTC (rev 120209)
@@ -14,6 +14,7 @@
"""Grok directives.
"""
import os.path
+import sys
import martian
from martian.error import GrokImportError
@@ -38,7 +39,13 @@
store = martian.ONCE
validate = martian.validateText
+ def factory(self, name):
+ # In combination of the name, store from which module the
+ # template is refered.
+ f_locals = sys._getframe(2).f_locals
+ return (f_locals['__module__'], name)
+
class templatedir(martian.Directive):
scope = martian.MODULE
store = martian.ONCE
Modified: grokcore.view/trunk/src/grokcore/view/meta/templates.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/meta/templates.py 2011-02-08 13:24:20 UTC (rev 120208)
+++ grokcore.view/trunk/src/grokcore/view/meta/templates.py 2011-02-08 13:58:34 UTC (rev 120209)
@@ -12,7 +12,7 @@
#
##############################################################################
"""Grokkers for templates."""
-
+import sys
import martian
from grokcore.view import components
@@ -25,31 +25,34 @@
martian.priority(1000)
def grok(self, name, instance, module_info, config, **kw):
+ # We set the configuration action order to 0, to be sure to
+ # register templates first.
config.action(
discriminator=None,
callable=templatereg.register_inline_template,
- args=(module_info, name, instance)
- )
+ args=(module_info, name, instance),
+ order=0)
config.action(
discriminator=None,
callable=instance._annotateGrokInfo,
- args=(name, module_info.dotted_name)
- )
+ args=(name, module_info.dotted_name))
return True
class FilesystemPageTemplateGrokker(martian.GlobalGrokker):
- # do this early on, but after ModulePageTemplateGrokker, as
- # findFilesystem depends on module-level templates to be
- # already grokked for error reporting
+ # Do this early on, but after ModulePageTemplateGrokker, as
+ # findFilesystem depends on module-level templates to be already
+ # grokked for error reporting.
martian.priority(999)
def grok(self, name, module, module_info, config, **kw):
+ # We set the configuration action order to 0, to be sure to
+ # register templates first.
config.action(
discriminator=None,
callable=templatereg.register_directory,
- args=(module_info,)
- )
+ args=(module_info,),
+ order=0)
return True
@@ -62,11 +65,13 @@
def grok(self, name, module, module_info, config, **kw):
if not self._action_registered:
self._action_registered = True
+ # We set the configuration action order to very very high
+ # to be sure to check unused template at the end only.
config.action(
discriminator=None,
callable=templatereg.check_unassociated,
args=(),
- order=10000
+ order=sys.maxint
)
return True
Modified: grokcore.view/trunk/src/grokcore/view/meta/views.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/meta/views.py 2011-02-08 13:24:20 UTC (rev 120208)
+++ grokcore.view/trunk/src/grokcore/view/meta/views.py 2011-02-08 13:58:34 UTC (rev 120209)
@@ -12,6 +12,7 @@
#
##############################################################################
"""Grokkers for the views code."""
+import sys
from zope import interface, component
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
@@ -34,22 +35,33 @@
class TemplateGrokker(martian.ClassGrokker):
martian.baseclass()
+ _template_order = sys.maxint/2
+
def grok(self, name, factory, module_info, **kw):
# Need to store the module info to look for a template
factory.module_info = module_info
return super(TemplateGrokker, self).grok(name, factory, module_info, **kw)
def execute(self, factory, config, **kw):
- # find templates
+ # Associate templates to a view or a component. We set the
+ # configuration action order to a number quite high, to do it
+ # after all templates have be registered to the shared template
+ # registry, and yet before unassociated templates are checked.
config.action(
discriminator=None,
- callable=self.check_templates,
- args=(factory.module_info, factory))
+ callable=self.associate_template,
+ args=(factory.module_info, factory),
+ order=self._template_order)
+ # We increase _template_order to maintain the relative order of
+ # template association between the different Grok extensions
+ # (like an implicit template can be inherited between two
+ # different Grok extensions).
+ self._template_order += 1
return True
- def check_templates(self, module_info, factory):
+ def associate_template(self, module_info, factory):
component_name = martian.component.bind().get(self).__name__.lower()
- templatereg.checkTemplates(
+ templatereg.associate_template(
module_info, factory, component_name, self.has_render, self.has_no_render)
def has_render(self, factory):
Modified: grokcore.view/trunk/src/grokcore/view/templatereg.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/templatereg.py 2011-02-08 13:24:20 UTC (rev 120208)
+++ grokcore.view/trunk/src/grokcore/view/templatereg.py 2011-02-08 13:58:34 UTC (rev 120209)
@@ -3,6 +3,7 @@
import zope.component
import grokcore.component
import grokcore.view
+from martian.scan import module_info_from_dotted_name
from martian.error import GrokError
from grokcore.view.interfaces import ITemplate, ITemplateFileFactory, TemplateLookupError
from grokcore.view.components import PageTemplate
@@ -207,15 +208,29 @@
warnings.warn(msg, UserWarning, 1)
-def checkTemplates(module_info, factory, component_name,
- has_render, has_no_render):
+def associate_template(module_info, factory, component_name,
+ has_render, has_no_render):
+ """Associate a template to a factory located in the module
+ described by module_info.
+ """
factory_name = factory.__name__.lower()
- template_name = grokcore.view.template.bind().get(factory)
+ module_name, template_name = grokcore.view.template.bind(
+ default=(None, None)).get(factory)
if template_name is None:
+ # We didn't used grok.template. Default the template name to
+ # the factory name.
template_name = factory_name
+ else:
+ # We used grok.template. Use the same module_info to fetch the
+ # template that the module in which the directive have been
+ # used (to get the grok.templatedir value).
+ assert module_name is not None, \
+ u"module_name cannot be None if template_name is specified."
+ module_info = module_info_from_dotted_name(module_name)
- # We used grok.template. Check if there is no template with the
- # same name as the view
+ # We used grok.template, to specify a template which is different
+ # than the class name. Check if there is no template with the same
+ # name as the view
if factory_name != template_name:
try:
lookup(module_info, factory_name)
Modified: grokcore.view/trunk/src/grokcore/view/templatereg.txt
===================================================================
--- grokcore.view/trunk/src/grokcore/view/templatereg.txt 2011-02-08 13:24:20 UTC (rev 120208)
+++ grokcore.view/trunk/src/grokcore/view/templatereg.txt 2011-02-08 13:58:34 UTC (rev 120209)
@@ -22,7 +22,7 @@
for inline templates in Python code, and ``register_directory`` for
templates in directories associated with a module::
- >>> from grokcore.view.templatereg import (register_directory,
+ >>> from grokcore.view.templatereg import (register_directory,
... register_inline_template)
Setup
@@ -31,7 +31,7 @@
Our templates are ``.template``, so we need to register a
``ITemplateFileFactory`` utility for them that knows how to make the
appropriate templates::
-
+
>>> from grokcore.view.interfaces import ITemplateFileFactory, ITemplate
>>> from zope.interface import implements
>>> class TestTemplate(object):
@@ -57,7 +57,7 @@
... return TestTemplate(os.path.join(_prefix, filename), data)
>>> from zope import component
- >>> component.provideUtility(TestTemplateFactory(), ITemplateFileFactory,
+ >>> component.provideUtility(TestTemplateFactory(), ITemplateFileFactory,
... name='template')
We create a way to create a fake module_info for a (actually
@@ -116,7 +116,7 @@
If we try to look up a template in a directory that doesn't exist, we get
a TemplateLookupError::
-
+
>>> nonexistent_module_info = create_module_info('nonexistent')
>>> reg.lookup(nonexistent_module_info, 'foo')
Traceback (most recent call last):
@@ -142,13 +142,13 @@
There is only a single unassociated template left now::
- >>> sorted(reg.unassociated())
+ >>> sorted(reg.unassociated())
['...bar.template']
Registering the templates directory again should do nothing and thus the unassociated list should be the same::
>>> register_directory(module_info)
- >>> sorted(reg.unassociated())
+ >>> sorted(reg.unassociated())
['...bar.template']
We can associate several times a template without error::
@@ -199,9 +199,9 @@
Let's make the template languages ``1`` and ``2`` known::
- >>> component.provideUtility(TestTemplateFactory(), ITemplateFileFactory,
+ >>> component.provideUtility(TestTemplateFactory(), ITemplateFileFactory,
... name='1')
- >>> component.provideUtility(TestTemplateFactory(), ITemplateFileFactory,
+ >>> component.provideUtility(TestTemplateFactory(), ITemplateFileFactory,
... name='2')
We now set up a directory which contains 'foo.1' and 'foo.2'. These
@@ -221,7 +221,7 @@
>>> register_directory(module_info3)
Traceback (most recent call last):
...
- GrokError: Conflicting templates found for name 'foo' in directory '...':
+ GrokError: Conflicting templates found for name 'foo' in directory '...':
multiple templates with the same name and different extensions.
Inline templates
@@ -250,7 +250,7 @@
>>> inline_reg.lookup(module_info4, 'cavepainting')
<InlineTemplate 'cavepainting'>
-
+
If we cannot find the template we get an error::
>>> inline_reg.lookup(module_info4, 'unknown')
@@ -272,9 +272,9 @@
>>> sorted(inline_reg.unassociated())
[]
-
+
We can associate several times an inline template without error::
-
+
>>> inline_reg.associate(module_info4, 'cavepainting')
@@ -361,35 +361,35 @@
>>> register_inline_template(module_info5, 'foo', InlineTemplate('foo'))
Traceback (most recent call last):
...
- GrokError: Conflicting templates found for name 'foo': the inline template
- in module 'module5' conflicts with the file template in directory
+ GrokError: Conflicting templates found for name 'foo': the inline template
+ in module 'module5' conflicts with the file template in directory
'...module5_templates'
Let's now demonstrate the same conflict, the other way around.
-First we set up a fictional filesystem structure surrounding a
+First we set up a fictional filesystem structure surrounding a
``module6``::
>>> module_info6, template_dir6 = create_module_info_with_templates('module6')
-
+
We add a template to it::
>>> f = open(os.path.join(template_dir6, 'bar.template'), 'w')
>>> f.write('bar')
>>> f.close()
-
+
Now we first register an inline template ``bar`` before loading up that
directory::
>>> register_inline_template(module_info6, 'bar', InlineTemplate('bar'))
-
+
When we now try to register the template ``bar`` in a directory, we'll
get an error::
>>> register_directory(module_info6)
Traceback (most recent call last):
...
- GrokError: Conflicting templates found for name 'bar':
+ GrokError: Conflicting templates found for name 'bar':
the inline template in module 'module6' conflicts with the file template in directory '...'
Copied: grokcore.view/trunk/src/grokcore/view/tests/view/cross_package.py (from rev 120020, grokcore.view/branches/sylvain-template-inheritance-fix/src/grokcore/view/tests/view/cross_package.py)
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/cross_package.py (rev 0)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/cross_package.py 2011-02-08 13:58:34 UTC (rev 120209)
@@ -0,0 +1,7 @@
+"""
+ >>> import cross_package_fixture
+
+ >>> grok.testing.grok(cross_package_fixture.__name__)
+
+"""
+import grokcore.view as grok
More information about the checkins
mailing list