[Checkins] SVN: grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/ Grokkers use now the new template registry
Vincent Fretin
vincent.fretin at gmail.com
Mon Aug 3 12:23:22 EDT 2009
Log message for revision 102456:
Grokkers use now the new template registry
Changed:
U grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/interfaces.py
U grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/meta/templates.py
U grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/meta/views.py
U grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/templatereg.py
U grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/templatereg.txt
U grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/tests/view/dirandinlinetemplate.py
U grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/tests/view/shared_template_dir.py
U grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/tests/view/unassociated.py
-=-
Modified: grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/interfaces.py
===================================================================
--- grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/interfaces.py 2009-08-03 13:08:38 UTC (rev 102455)
+++ grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/interfaces.py 2009-08-03 16:23:21 UTC (rev 102456)
@@ -183,9 +183,10 @@
module_info - the module_info of the module
"""
- def lookup(module_info, template_name):
+ def lookup(module_info, template_name, mark_as_associated=False):
"""Look up a template for a module.
module_info - the module info for which to look up the template
- template_name - the name of the template to look up.
+ template_name - the name of the template to look up
+ mark_as_associated - if a template is found, mark it as associated (disabled by default).
"""
Modified: grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/meta/templates.py
===================================================================
--- grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/meta/templates.py 2009-08-03 13:08:38 UTC (rev 102455)
+++ grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/meta/templates.py 2009-08-03 16:23:21 UTC (rev 102456)
@@ -18,17 +18,6 @@
from grokcore.view import components
from grokcore.view import templatereg
-
-class TemplateGrokker(martian.GlobalGrokker):
- # this needs to happen before any other grokkers execute that use
- # the template registry
- martian.priority(1001)
-
- def grok(self, name, module, module_info, config, **kw):
- module.__grok_templates__ = templatereg.ModuleTemplateRegistry()
- return True
-
-
class ModulePageTemplateGrokker(martian.InstanceGrokker):
martian.component(components.BaseTemplate)
# this needs to happen before any other grokkers execute that actually
@@ -36,13 +25,10 @@
martian.priority(1000)
def grok(self, name, instance, module_info, config, **kw):
- templates = module_info.getAnnotation('grok.templates', None)
- if templates is None:
- return False
config.action(
discriminator=None,
- callable=templates.register,
- args=(name, instance)
+ callable=templatereg.register_inline_template,
+ args=(module_info, name, instance)
)
config.action(
discriminator=None,
@@ -59,12 +45,9 @@
martian.priority(999)
def grok(self, name, module, module_info, config, **kw):
- templates = module_info.getAnnotation('grok.templates', None)
- if templates is None:
- return False
config.action(
discriminator=None,
- callable=templates.findFilesystem,
+ callable=templatereg.register_directory,
args=(module_info,)
)
return True
@@ -72,17 +55,18 @@
class UnassociatedTemplatesGrokker(martian.GlobalGrokker):
martian.priority(-1001)
+ # XXX: The action should be registered only once, not for each module.
+ # There should be a way to register the action without a module grokker...
+ _action_registered = False
def grok(self, name, module, module_info, config, **kw):
- templates = module_info.getAnnotation('grok.templates', None)
- if templates is None:
- return False
-
- config.action(
- discriminator=None,
- callable=templates.checkUnassociated,
- args=(module_info,),
- order=100
- )
+ if not self._action_registered:
+ self._action_registered = True
+ config.action(
+ discriminator=None,
+ callable=templatereg.check_unassociated,
+ args=(),
+ order=10000
+ )
return True
Modified: grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/meta/views.py
===================================================================
--- grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/meta/views.py 2009-08-03 13:08:38 UTC (rev 102455)
+++ grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/meta/views.py 2009-08-03 16:23:21 UTC (rev 102456)
@@ -25,6 +25,7 @@
import grokcore.view
from grokcore.security.util import protect_getattr
from grokcore.view import components
+from grokcore.view import templatereg
def default_view_name(factory, module=None, **data):
return factory.__name__.lower()
@@ -47,13 +48,11 @@
def execute(self, factory, config, context, layer, name, **kw):
# find templates
- templates = factory.module_info.getAnnotation('grok.templates', None)
- if templates is not None:
- config.action(
- discriminator=None,
- callable=self.checkTemplates,
- args=(templates, factory.module_info, factory)
- )
+ config.action(
+ discriminator=None,
+ callable=self.checkTemplates,
+ args=(factory.module_info, factory)
+ )
# safety belt: make sure that the programmer didn't use
# @grok.require on any of the view's methods.
@@ -76,7 +75,7 @@
)
return True
- def checkTemplates(self, templates, module_info, factory):
+ def checkTemplates(self, module_info, factory):
def has_render(factory):
render = getattr(factory, 'render', None)
@@ -85,7 +84,7 @@
def has_no_render(factory):
return not getattr(factory, 'render', None)
- templates.checkTemplates(module_info, factory, 'view',
+ templatereg.checkTemplates(module_info, factory, 'view',
has_render, has_no_render)
Modified: grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/templatereg.py
===================================================================
--- grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/templatereg.py 2009-08-03 13:08:38 UTC (rev 102455)
+++ grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/templatereg.py 2009-08-03 16:23:21 UTC (rev 102456)
@@ -34,13 +34,19 @@
self._unassociated.add((module_info.dotted_name, template_name))
def associate(self, module_info, template_name):
- self._unassociated.remove((module_info.dotted_name, template_name))
+ # Two views in the same module should be able to use the same inline template
+ try:
+ self._unassociated.remove((module_info.dotted_name, template_name))
+ except KeyError:
+ pass
- def lookup(self, module_info, template_name):
+ def lookup(self, module_info, template_name, mark_as_associated=False):
result = self._reg.get((module_info.dotted_name, template_name))
if result is None:
raise TemplateLookupError("inline template '%s' in '%s' cannot be found" % (
template_name, module_info.dotted_name))
+ if mark_as_associated:
+ self.associate(module_info, template_name)
return result
def unassociated(self):
@@ -50,6 +56,7 @@
def __init__(self):
self._reg = {}
self._unassociated = set()
+ self._registered_directories = set()
def register_directory(self, module_info):
# we cannot register a templates dir for a package
@@ -60,10 +67,16 @@
# we can only register for directories
if not os.path.isdir(template_dir):
return
+
+ # we don't want associated templates become unassociated again
+ if template_dir in self._registered_directories:
+ return
for template_file in os.listdir(template_dir):
template_path = os.path.join(template_dir, template_file)
self._register_template_file(module_info, template_path)
+
+ self._registered_directories.add(template_dir)
def _register_template_file(self, module_info, template_path):
template_dir, template_file = os.path.split(template_path)
@@ -76,10 +89,13 @@
template_name, extension = os.path.splitext(template_file)
if (template_dir, template_name) in self._reg:
- raise GrokError("Conflicting templates found for name '%s' "
- "in directory '%s': multiple templates with "
- "the same name and different extensions ." %
- (template_name, template_dir), None)
+ registered_template_path = self._reg.get((template_dir, template_name)).__grok_location__
+ # __grok_location__ is set by _annotateGrokInfo
+ if template_path != registered_template_path:
+ raise GrokError("Conflicting templates found for name '%s' "
+ "in directory '%s': multiple templates with "
+ "the same name and different extensions." %
+ (template_name, template_dir), None)
# verify no inline template exists with the same name
try:
inline_template_registry.lookup(module_info, template_name)
@@ -106,21 +122,27 @@
(template_file, template_dir), UserWarning, 2)
return
template = template_factory(template_file, template_dir)
- # XXX this isn't defined in the interface or anywhere...
template._annotateGrokInfo(template_name, template_path)
self._reg[(template_dir, template_name)] = template
self._unassociated.add(template_path)
def associate(self, template_path):
- self._unassociated.remove(template_path)
+ # Two views in different module should be able to use the same template
+ try:
+ self._unassociated.remove(template_path)
+ except KeyError:
+ pass
- def lookup(self, module_info, template_name):
+ def lookup(self, module_info, template_name, mark_as_associated=False):
template_dir = self.get_template_dir(module_info)
result = self._reg.get((template_dir, template_name))
if result is None:
raise TemplateLookupError("template '%s' in '%s' cannot be found" % (
template_name, template_dir))
+ if mark_as_associated:
+ registered_template_path = self._reg.get((template_dir, template_name)).__grok_location__
+ self.associate(registered_template_path)
return result
def unassociated(self):
@@ -138,205 +160,101 @@
inline_template_registry = InlineTemplateRegistry()
file_template_registry = FileTemplateRegistry()
-register_inline_template = inline_template_registry.register_inline_template
+def register_inline_template(module_info, template_name, template):
+ return inline_template_registry.register_inline_template(module_info, template_name, template)
-register_directory = file_template_registry.register_directory
-
-all_directory_templates_registries = {}
+def register_directory(module_info):
+ return file_template_registry.register_directory(module_info)
-def lookup(module_info, template_name):
+def _clear():
+ """Remove the registries (for use by tests)."""
+ global inline_template_registry
+ global file_template_registry
+ inline_template_registry = InlineTemplateRegistry()
+ file_template_registry = FileTemplateRegistry()
+
+try:
+ from zope.testing.cleanup import addCleanUp
+except ImportError:
+ # don't have that part of Zope
+ pass
+else:
+ addCleanUp(_clear)
+ del addCleanUp
+
+def lookup(module_info, template_name, mark_as_associated=False):
try:
- return file_template_registry.lookup(module_info, template_name)
+ return file_template_registry.lookup(module_info, template_name, mark_as_associated)
except TemplateLookupError, e:
try:
- return inline_template_registry.lookup(module_info, template_name)
+ return inline_template_registry.lookup(module_info, template_name, mark_as_associated)
except TemplateLookupError, e2:
# re-raise first error again
raise e
-class BaseTemplateRegistry(object):
-
- def __init__(self):
- self._reg = {}
-
- def register(self, name, template):
- self._reg[name] = dict(template=template, associated=False)
-
- def markAssociated(self, name):
- entry = self._getEntry(name)
- entry['associated'] = True
-
- def _getEntry(self, name):
- return self._reg.get(name)
-
- def get(self, name):
- entry = self._getEntry(name)
- if entry is None:
- return None
- return entry['template']
-
- def listUnassociated(self):
- for name, entry in self._reg.iteritems():
- if not entry['associated']:
- yield name
-
-
-class ModuleTemplateRegistry(BaseTemplateRegistry):
-
- _directory_registry = None
-
- def initializeDirectoryRegistry(self, template_dir):
- if template_dir is not None:
- if not template_dir in all_directory_templates_registries:
- all_directory_templates_registries[template_dir] = DirectoryTemplateRegistry(template_dir)
- self._directory_registry = all_directory_templates_registries[template_dir]
-
- def _getEntry(self, name):
- entry = super(ModuleTemplateRegistry, self)._getEntry(name)
- # self._directory_registry has not been instanciated when registering instance templates
- if entry is None and self._directory_registry is not None:
- entry = self._directory_registry._getEntry(name)
- return entry
-
- def getLocal(self, name):
- entry = self._reg.get(name)
- if entry is None:
- return None
- return entry['template']
-
- def _getTemplateDir(self, module_info):
- template_dir_name = grokcore.view.templatedir.bind().get(
- module=module_info.getModule())
- if template_dir_name is None:
- template_dir_name = module_info.name + '_templates'
-
- template_dir = module_info.getResourcePath(template_dir_name)
-
- return template_dir
-
- def findFilesystem(self, module_info):
- template_dir = self._getTemplateDir(module_info)
-
- if not os.path.isdir(template_dir):
- return
-
- self.initializeDirectoryRegistry(template_dir)
-
- if module_info.isPackage():
- return
-
- for template_file in os.listdir(template_dir):
- if template_file.startswith('.') or template_file.endswith('~'):
- continue
- if template_file.endswith('.cache'):
- # chameleon creates '<tpl_name>.cache' files on the fly
- continue
-
- template_name, extension = os.path.splitext(template_file)
- extension = extension[1:] # Get rid of the leading dot.
- template_factory = zope.component.queryUtility(
- grokcore.view.interfaces.ITemplateFileFactory,
- name=extension)
-
- if template_factory is None:
- # Warning when importing files. This should be
- # allowed because people may be using editors that generate
- # '.bak' files and such.
- warnings.warn("File '%s' has an unrecognized extension in "
- "directory '%s'" %
- (template_file, template_dir), UserWarning, 2)
- continue
-
- inline_template = self.getLocal(template_name)
- if inline_template:
- raise GrokError("Conflicting templates found for name '%s' "
- "in module %r, either inline and in template "
- "directory '%s', or two templates with the "
- "same name and different extensions."
- % (template_name, module_info.getModule(),
- template_dir), inline_template)
-
- if self._directory_registry._getEntry(template_name) is None:
- template = template_factory(template_file, template_dir)
- template_path = os.path.join(template_dir, template_file)
- template._annotateGrokInfo(template_name, template_path)
-
- self._directory_registry.register(template_name, template)
-
- def checkUnassociated(self, module_info):
- unassociated = list(self.listUnassociated())
- if unassociated:
+def check_unassociated():
+ unassociated = inline_template_registry.unassociated()
+ if unassociated:
+ for dotted_name, template_name in unassociated:
msg = (
"Found the following unassociated template(s) when "
"grokking %r: %s. Define view classes inheriting "
"from grok.View to enable the template(s)." % (
- module_info.dotted_name, ', '.join(unassociated)))
+ dotted_name, template_name))
warnings.warn(msg, UserWarning, 1)
+ unassociated = file_template_registry.unassociated()
+ if unassociated:
+ msg = (
+ "Found the following unassociated template(s) when "
+ "grokking views: %s. Define view classes inheriting "
+ "from grok.View to enable the template(s)." % (
+ ', '.join(unassociated)))
+ warnings.warn(msg, UserWarning, 1)
- if self._directory_registry is not None:
- self._directory_registry.checkUnassociated(module_info)
+def checkTemplates(module_info, factory, component_name,
+ has_render, has_no_render):
+ factory_name = factory.__name__.lower()
+ template_name = grokcore.view.template.bind().get(factory)
+ if template_name is None:
+ template_name = factory_name
- def checkTemplates(self, module_info, factory, component_name,
- has_render, has_no_render):
- factory_name = factory.__name__.lower()
- template_name = grokcore.view.template.bind().get(factory)
- if template_name is None:
- template_name = factory_name
+ if factory_name != template_name:
+ # grok.template is being used
- if factory_name != template_name:
- # grok.template is being used
+ try:
+ lookup(module_info, factory_name)
+ raise GrokError("Multiple possible templates for %s %r. It "
+ "uses grok.template('%s'), but there is also "
+ "a template called '%s'."
+ % (component_name, factory, template_name,
+ factory_name), factory)
+ except TemplateLookupError, e:
+ pass
+ try:
+ template = lookup(module_info, template_name, mark_as_associated=True)
+ 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 %s %r. "
+ "It has both a 'render' method as well as "
+ "an associated template." %
+ (component_name, factory), factory)
+ factory.template = template
+ template._initFactory(factory)
+ except TemplateLookupError, e:
+ if has_no_render(factory):
+ # we do not accept a view without any way to render it
+ raise GrokError("%s %r has no associated template or "
+ "'render' method." %
+ (component_name.title(), factory), factory)
- if self.get(factory_name):
- raise GrokError("Multiple possible templates for %s %r. It "
- "uses grok.template('%s'), but there is also "
- "a template called '%s'."
- % (component_name, factory, template_name,
- factory_name), factory)
- template = self.get(template_name)
- 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 %s %r. "
- "It has both a 'render' method as well as "
- "an associated template." %
- (component_name, factory), factory)
- self.markAssociated(template_name)
- factory.template = template
- template._initFactory(factory)
- else:
- if has_no_render(factory):
- # we do not accept a view without any way to render it
- raise GrokError("%s %r has no associated template or "
- "'render' method." %
- (component_name.title(), factory), factory)
-
-class DirectoryTemplateRegistry(BaseTemplateRegistry):
-
- _checked = False
-
- def __init__(self, template_dir):
- super(DirectoryTemplateRegistry, self).__init__()
- self.template_dir = template_dir
-
- def checkUnassociated(self, module_info):
- if not self._checked:
- self._checked = True
- unassociated = list(self.listUnassociated())
- if unassociated:
- msg = (
- "Found the following unassociated template(s) when "
- "grokking directory %r: %s. Define view classes inheriting "
- "from grok.View to enable the template(s)." % (
- self.template_dir, ', '.join(unassociated)))
- warnings.warn(msg, UserWarning, 1)
-
-
class PageTemplateFileFactory(grokcore.component.GlobalUtility):
grokcore.component.implements(ITemplateFileFactory)
grokcore.component.name('pt')
def __call__(self, filename, _prefix=None):
return PageTemplate(filename=filename, _prefix=_prefix)
+
+
Modified: grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/templatereg.txt
===================================================================
--- grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/templatereg.txt 2009-08-03 13:08:38 UTC (rev 102455)
+++ grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/templatereg.txt 2009-08-03 16:23:21 UTC (rev 102456)
@@ -39,6 +39,7 @@
... def __init__(self, filename, source):
... self.filename = filename
... self.source = source
+ ... self.__grok_location__ = filename
... def __repr__(self):
... path, filename = os.path.split(self.filename)
... return "<Template '%s' in '%s'>" % (filename, path)
@@ -144,6 +145,17 @@
>>> 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())
+ ['...bar.template']
+
+We can associate several times a template without error::
+
+ >>> reg.associate(os.path.join(template_dir, 'foo.template'))
+
+
Unknown template extensions
---------------------------
@@ -210,7 +222,7 @@
Traceback (most recent call last):
...
GrokError: Conflicting templates found for name 'foo' in directory '...':
- multiple templates with the same name and different extensions .
+ multiple templates with the same name and different extensions.
Inline templates
----------------
@@ -252,9 +264,29 @@
>>> sorted(inline_reg.unassociated())
[('module4', 'cavepainting')]
+Let's associate this template::
+
+ >>> inline_reg.associate(module_info4, 'cavepainting')
+
+Unassociated list is now empty::
+
+ >>> sorted(inline_reg.unassociated())
+ []
+
+We can associate several times an inline template without error::
+
+ >>> inline_reg.associate(module_info4, 'cavepainting')
+
+
A common template lookup function
---------------------------------
+First clean up the registries::
+ >>> from grokcore.view.templatereg import _clear
+ >>> _clear()
+ >>> from grokcore.view.templatereg import file_template_registry as reg
+ >>> from grokcore.view.templatereg import inline_template_registry as inline_reg
+
There is a single lookup function available that can used to look up
both filesystem templates as well as inline templates.
@@ -283,6 +315,26 @@
...
TemplateLookupError: template 'qux' in '...' cannot be found
+The file template and the inline template are unassociated::
+
+ >>> sorted(reg.unassociated())
+ ['...foo.template']
+ >>> sorted(inline_reg.unassociated())
+ [('lookuptest', 'bar')]
+
+We can give the parameter mark_as_associated=True to the lookup call to
+mark the returned template as associated::
+
+ >>> lookup(lookuptest_info, 'foo', mark_as_associated=True)
+ <Template 'foo.template' in '...'>
+ >>> sorted(reg.unassociated())
+ []
+ >>> lookup(lookuptest_info, 'bar', mark_as_associated=True)
+ <InlineTemplate 'bar'>
+ >>> sorted(inline_reg.unassociated())
+ []
+
+
Conflicts between inline templates and file templates
-----------------------------------------------------
@@ -341,9 +393,6 @@
the inline template in module 'module6' conflicts with the file template in directory '...'
-XXX a common lookup function that looks up both inline or filesystem that
- takes the module info
-
XXX use configuration action conflicts with module_info.dotted_name,
name to determine conflicts between registrations?
Modified: grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/tests/view/dirandinlinetemplate.py
===================================================================
--- grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/tests/view/dirandinlinetemplate.py 2009-08-03 13:08:38 UTC (rev 102455)
+++ grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/tests/view/dirandinlinetemplate.py 2009-08-03 16:23:21 UTC (rev 102456)
@@ -5,8 +5,8 @@
>>> grok.testing.grok(__name__)
Traceback (most recent call last):
...
- ConfigurationExecutionError: martian.error.GrokError: Conflicting templates found for name 'cavepainting' in module
- <module 'grokcore.view.tests.view.dirandinlinetemplate' from ...
+ ConfigurationExecutionError: martian.error.GrokError: Conflicting templates found for name 'cavepainting': the inline template in module 'grokcore.view.tests.view.dirandinlinetemplate' conflicts with the file template in directory '...dirandinlinetemplate_templates'
+ in:
"""
import grokcore.view as grok
Modified: grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/tests/view/shared_template_dir.py
===================================================================
--- grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/tests/view/shared_template_dir.py 2009-08-03 13:08:38 UTC (rev 102455)
+++ grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/tests/view/shared_template_dir.py 2009-08-03 16:23:21 UTC (rev 102456)
@@ -14,8 +14,8 @@
...UserWarning: Found the following unassociated template(s) when grokking
'grokcore.view.tests.view.shared_template_fixture.first_module': unassociated_instance. Define view classes inheriting from
grok.View to enable the template(s)...
- ...UserWarning: Found the following unassociated template(s) when grokking directory
- '...shared_template_fixture...templates': unassociated. Define view classes inheriting from
+ ...UserWarning: Found the following unassociated template(s) when grokking views:
+ ...shared_template_fixture...templates...unassociated.pt. Define view classes inheriting from
grok.View to enable the template(s)...
"""
Modified: grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/tests/view/unassociated.py
===================================================================
--- grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/tests/view/unassociated.py 2009-08-03 13:08:38 UTC (rev 102455)
+++ grokcore.view/branches/shared_templates_userwarning/src/grokcore/view/tests/view/unassociated.py 2009-08-03 16:23:21 UTC (rev 102456)
@@ -9,8 +9,8 @@
>>> grok.testing.grok(__name__)
From grok.testing's warn():
- ...UserWarning: Found the following unassociated template(s) when grokking directory
- '...unassociated_templates': index. Define view classes inheriting from
+ ...UserWarning: Found the following unassociated template(s) when grokking views:
+ ...unassociated_templates...index.pt. Define view classes inheriting from
grok.View to enable the template(s)...
Also templates of modules named equally as the package name the module
More information about the Checkins
mailing list