[Checkins] SVN: grokcore.view/trunk/ Merge shared_templates_userwarning branch

Sylvain Viollon sylvain at infrae.com
Tue Dec 7 09:57:43 EST 2010


Log message for revision 118742:
  Merge shared_templates_userwarning branch

Changed:
  U   grokcore.view/trunk/CHANGES.txt
  U   grokcore.view/trunk/src/grokcore/view/interfaces.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
  A   grokcore.view/trunk/src/grokcore/view/templatereg.txt
  U   grokcore.view/trunk/src/grokcore/view/tests/test_all.py
  U   grokcore.view/trunk/src/grokcore/view/tests/view/dirandinlinetemplate.py
  U   grokcore.view/trunk/src/grokcore/view/tests/view/dirtemplatesonly.py
  U   grokcore.view/trunk/src/grokcore/view/tests/view/inline_unassociated.py
  U   grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_dir.py
  D   grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_dir_fixture.py
  A   grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/
  A   grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/__init__.py
  A   grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/first_module.py
  A   grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/second_module.py
  A   grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/templates/
  A   grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/templates/cavepainting.pt
  A   grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/templates/food.pt
  A   grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/templates/unassociated.pt
  D   grokcore.view/trunk/src/grokcore/view/tests/view/shared_templates/
  U   grokcore.view/trunk/src/grokcore/view/tests/view/unassociated.py
  D   grokcore.view/trunk/src/grokcore/view/tests/view/warning_msgs.py

-=-
Modified: grokcore.view/trunk/CHANGES.txt
===================================================================
--- grokcore.view/trunk/CHANGES.txt	2010-12-07 14:47:19 UTC (rev 118741)
+++ grokcore.view/trunk/CHANGES.txt	2010-12-07 14:57:43 UTC (rev 118742)
@@ -4,7 +4,8 @@
 2.2 (unreleased)
 ----------------
 
-- Nothing changed yet.
+- Merge support for a global template registry that remove unnecessary
+  warnings about unassociated templates.
 
 
 2.1 (2010-11-03)

Modified: grokcore.view/trunk/src/grokcore/view/interfaces.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/interfaces.py	2010-12-07 14:47:19 UTC (rev 118741)
+++ grokcore.view/trunk/src/grokcore/view/interfaces.py	2010-12-07 14:57:43 UTC (rev 118742)
@@ -182,7 +182,35 @@
     def render(view):
         """Renders the template"""
 
+class TemplateLookupError(Exception):
+    pass
 
+class ITemplateRegAPI(Interface):
+    """Public API for the templatereg module.
+    """
+    def register_inline_template(module_info, template_name, template):
+        """Register an inline template with the template registry.
+
+        module_info - the module_info of the module the inline template is in
+        template_name - the name of the template
+        template - the template itself
+        """
+
+    def register_directory(module_info):
+        """Register a template directory for a module.
+
+        module_info - the module_info of the module
+        """
+
+    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
+        mark_as_associated - if a template is found, mark it as associated (disabled by default).
+        """
+
+
 class IGrokSecurityView(Interface):
     """A view treated special by the Grok publisher.
 

Modified: grokcore.view/trunk/src/grokcore/view/meta/templates.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/meta/templates.py	2010-12-07 14:47:19 UTC (rev 118741)
+++ grokcore.view/trunk/src/grokcore/view/meta/templates.py	2010-12-07 14:57:43 UTC (rev 118742)
@@ -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.TemplateRegistry()
-        return True
-
-
 class ModulePageTemplateGrokker(martian.InstanceGrokker):
     martian.component(components.BaseTemplate)
     # this needs to happen before any other grokkers execute that actually
@@ -36,18 +25,15 @@
     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,
             callable=instance._annotateGrokInfo,
-            args=(name, module_info.dotted_name),
+            args=(name, module_info.dotted_name)
             )
         return True
 
@@ -59,28 +45,28 @@
     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,
-            args=(module_info,),
+            callable=templatereg.register_directory,
+            args=(module_info,)
             )
         return True
 
 
 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,),
-            )
+        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/trunk/src/grokcore/view/meta/views.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/meta/views.py	2010-12-07 14:47:19 UTC (rev 118741)
+++ grokcore.view/trunk/src/grokcore/view/meta/views.py	2010-12-07 14:57:43 UTC (rev 118742)
@@ -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(component, module=None, **data):
     return component.__name__.lower()
@@ -43,13 +44,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.
@@ -72,7 +71,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)
@@ -82,8 +81,8 @@
         def has_no_render(factory):
             return not has_render(factory)
 
-        templates.checkTemplates(module_info, factory, 'view',
-                                 has_render, has_no_render)
+        templatereg.checkTemplates(
+            module_info, factory, 'view', has_render, has_no_render)
 
 
 class ViewSecurityGrokker(martian.ClassGrokker):

Modified: grokcore.view/trunk/src/grokcore/view/templatereg.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/templatereg.py	2010-12-07 14:47:19 UTC (rev 118741)
+++ grokcore.view/trunk/src/grokcore/view/templatereg.py	2010-12-07 14:57:43 UTC (rev 118742)
@@ -1,182 +1,262 @@
-##############################################################################
-#
-# Copyright (c) 2006-2010 Zope Foundation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Template registry
-"""
-import logging
 import os
+import warnings
 import zope.component
 import grokcore.component
 import grokcore.view
 from martian.error import GrokError
-from grokcore.view.interfaces import ITemplateFileFactory, ITemplate
+from grokcore.view.interfaces import ITemplate, ITemplateFileFactory, TemplateLookupError
 from grokcore.view.components import PageTemplate
 
-def get_logger():
-    """Setup a 'grokcore.view' logger if none is already defined.
 
-    Return the defined one else.
+class InlineTemplateRegistry(object):
+    def __init__(self):
+        self._reg = {}
+        self._unassociated = set()
 
-    We set the logger level to ``logging.ERROR``, which means that by
-    default warning messages will not be displayed.
 
-    Logger level is only set, if that not already happened
-    before. This way third-party components can determine the logging
-    options before grokking packages.
-    """
-    logger = logging.getLogger('grokcore.view')
-    if len(logger.handlers) > 0:
-        return logger
-    if logger.level == logging.NOTSET:
-        logger.setLevel(logging.ERROR)
-    handler = logging.StreamHandler()
-    formatter = logging.Formatter("%(levelname)s: %(message)s")
-    handler.setFormatter(formatter)
-    logger.addHandler(handler)
-    return logger
+    def register_inline_template(self, module_info, template_name, template):
+        # verify no file template got registered with the same name
+        try:
+            existing_template = file_template_registry.lookup(
+                module_info, template_name)
+        except TemplateLookupError:
+            pass
+        else:
+            template_dir = file_template_registry.get_template_dir(module_info)
+            raise GrokError("Conflicting templates found for name '%s': "
+                            "the inline template in module '%s' conflicts "
+                            "with the file template in directory '%s'" %
+                            (template_name, module_info.dotted_name,
+                             template_dir), None)
 
-class TemplateRegistry(object):
+        # register the inline template
+        self._reg[(module_info.dotted_name, template_name)] = template
+        self._unassociated.add((module_info.dotted_name, template_name))
 
+    def associate(self, module_info, 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, 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):
+        return self._unassociated
+
+class FileTemplateRegistry(object):
     def __init__(self):
         self._reg = {}
+        self._unassociated = set()
+        self._registered_directories = set()
 
-    def register(self, name, template):
-        self._reg[name] = dict(template=template, associated=False)
+    def register_directory(self, module_info):
+        # we cannot register a templates dir for a package
+        if module_info.isPackage():
+            return
 
-    def markAssociated(self, name):
-        self._reg[name]['associated'] = True
+        template_dir = self.get_template_dir(module_info)
+        # we can only register for directories
+        if not os.path.isdir(template_dir):
+            return
 
-    def get(self, name):
-        entry = self._reg.get(name)
-        if entry is None:
-            return None
-        return entry['template']
+        # we don't want associated templates become unassociated again
+        if template_dir in self._registered_directories:
+            return
 
-    def findFilesystem(self, module_info):
+        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)
+
+        if template_file.startswith('.') or template_file.endswith('~'):
+            return
+        if template_file.endswith('.cache'):
+            # chameleon creates '<tpl_name>.cache' files on the fly
+            return
+
+        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)
+        # verify no inline template exists with the same name
+        try:
+            inline_template_registry.lookup(module_info, template_name)
+        except TemplateLookupError:
+            pass
+        else:
+            raise GrokError("Conflicting templates found for name '%s': "
+                            "the inline template in module '%s' conflicts "
+                            "with the file template in directory '%s'" %
+                            (template_name, module_info.dotted_name,
+                             template_dir), None)
+
+        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)
+            return
+        template = template_factory(template_file, template_dir)
+        template._annotateGrokInfo(template_name, template_path)
+
+        self._reg[(template_dir, template_name)] = template
+        self._unassociated.add(template_path)
+
+    def associate(self, 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, 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):
+        return self._unassociated
+
+    def get_template_dir(self, module_info):
         template_dir_name = grokcore.view.templatedir.bind().get(
             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
 
-        if not os.path.isdir(template_dir):
-            return
+inline_template_registry = InlineTemplateRegistry()
+file_template_registry = FileTemplateRegistry()
 
-        if module_info.isPackage():
-            return
+def register_inline_template(module_info, template_name, template):
+    return inline_template_registry.register_inline_template(module_info, template_name, template)
 
-        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
+def register_directory(module_info):
+    return file_template_registry.register_directory(module_info)
 
-            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)
+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()
 
-            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.
-                logger = get_logger()
-                msg = ("File '%s' has an unrecognized extension in "
-                       "directory '%s'" %
-                       (template_file, template_dir))
-                logger.warn(msg)
-                continue
+try:
+    from zope.testing.cleanup import addCleanUp
+except ImportError:
+    # don't have that part of Zope
+    pass
+else:
+    addCleanUp(_clear)
+    del addCleanUp
 
-            inline_template = self.get(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)
+def lookup(module_info, template_name, mark_as_associated=False):
+    try:
+        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, mark_as_associated)
+        except TemplateLookupError, e2:
+            # re-raise first error again
+            raise e
 
-            template = template_factory(template_file, template_dir)
-            template_path = os.path.join(template_dir, template_file)
-            template._annotateGrokInfo(template_name, template_path)
-
-            self.register(template_name, template)
-
-    def listUnassociated(self):
-        for name, entry in self._reg.iteritems():
-            if not entry['associated']:
-                yield name
-
-    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)))
-            logger = get_logger()
-            logger.warn(msg)
+                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)
 
-    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
+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
 
-            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)
+    # We used grok.template. Check if there is no template with the
+    # same name as the view
+    if factory_name != template_name:
+        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:
+            pass
 
-        # Check if view already have a template
-        factory_have_template = (
-            getattr(factory, 'template', None) is not None and
-            ITemplate.providedBy(factory.template))
+    # Check if view already have a template set with template =
+    factory_have_template = (
+        getattr(factory, 'template', None) is not None and
+        ITemplate.providedBy(factory.template))
 
-        # Lookup a template in the registry
-        template = self.get(template_name)
-        if template is not None:
-            self.markAssociated(template_name)
-            factory.template = template
-            factory_have_template = True
+    # Lookup for a template in the registry
+    try:
+        factory.template = lookup(module_info, template_name, mark_as_associated=True)
+        factory_have_template = True
+    except TemplateLookupError:
+        pass
 
-        if factory_have_template and 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)
+    # Check for have both render and template
+    if factory_have_template and has_render(factory):
+        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)
 
-        if not factory_have_template and 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)
+    # Check for no render and no template
+    if not factory_have_template and has_no_render(factory):
+        raise GrokError("%s %r has no associated template or "
+                        "'render' method." %
+                        (component_name.title(), factory), factory)
 
-        if factory_have_template:
-            factory.template._initFactory(factory)
+    if factory_have_template:
+        factory.template._initFactory(factory)
 
 
 class PageTemplateFileFactory(grokcore.component.GlobalUtility):
@@ -185,3 +265,5 @@
 
     def __call__(self, filename, _prefix=None):
         return PageTemplate(filename=filename, _prefix=_prefix)
+
+

Added: grokcore.view/trunk/src/grokcore/view/templatereg.txt
===================================================================
--- grokcore.view/trunk/src/grokcore/view/templatereg.txt	                        (rev 0)
+++ grokcore.view/trunk/src/grokcore/view/templatereg.txt	2010-12-07 14:57:43 UTC (rev 118742)
@@ -0,0 +1,398 @@
+Template registry
+=================
+
+When grokking views, there is a single global template registry that:
+
+* the grokking process can issue actions to register templates into it.
+
+* the actions that set up views can quickly look up templates from it
+  to associate them with views.
+
+* the template registry keeps track of templates that are associated
+  with views, or not.
+
+* an action gets registered that gets executed late in configuration
+  process that reports on any unassociated templates that are left.
+
+Registration functions
+----------------------
+
+In a normal run of the application, the global registration functions
+are used to register templates. These are ``register_inline_template``
+for inline templates in Python code, and ``register_directory`` for
+templates in directories associated with a module::
+
+  >>> from grokcore.view.templatereg import (register_directory, 
+  ...                                        register_inline_template)
+
+Setup
+-----
+
+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):
+  ...    implements(ITemplate) # we lie for testing purposes
+  ...    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)
+  ...    def __cmp__(self, other):
+  ...        return cmp(self.filename, other.filename)
+  ...    def _annotateGrokInfo(self, template_name, template_path):
+  ...        pass # XXX why do we need to implement this?
+
+  >>> class TestTemplateFactory(object):
+  ...    implements(ITemplateFileFactory)
+  ...    def __call__(self, filename, _prefix=None):
+  ...        f = open(os.path.join(_prefix, filename), 'r')
+  ...        data = f.read()
+  ...        f.close()
+  ...        return TestTemplate(os.path.join(_prefix, filename), data)
+
+  >>> from zope import component
+  >>> component.provideUtility(TestTemplateFactory(), ITemplateFileFactory, 
+  ...   name='template')
+
+We create a way to create a fake module_info for a (actually
+nonexistent) module with a real directory that contains templates::
+
+   >>> class ModuleInfo(object):
+   ...     def __init__(self, name, dir):
+   ...         self.dotted_name = name
+   ...         self.name = name
+   ...         self.dir = dir
+   ...     def getModule(self):
+   ...         return None
+   ...     def getResourcePath(self, template_dir_name):
+   ...         return os.path.join(self.dir, template_dir_name)
+   ...     def isPackage(self):
+   ...         return False
+
+   >>> import os, tempfile
+   >>> def create_module_info(module_name):
+   ...     package_dir = tempfile.mkdtemp()
+   ...     return ModuleInfo(module_name, package_dir)
+   >>> def create_module_info_with_templates(module_name):
+   ...     package_dir = tempfile.mkdtemp()
+   ...     templates_dir = os.path.join(package_dir, module_name + '_templates')
+   ...     os.mkdir(templates_dir)
+   ...     return ModuleInfo(module_name, package_dir), templates_dir
+
+Registering a directory
+-----------------------
+
+We create a directory with two templates in it::
+
+  >>> module_info, template_dir = create_module_info_with_templates('fake')
+  >>> f = open(os.path.join(template_dir, 'foo.template'), 'w')
+  >>> f.write('foo')
+  >>> f.close()
+  >>> f = open(os.path.join(template_dir, 'bar.template'), 'w')
+  >>> f.write('bar')
+  >>> f.close()
+
+We can now register the filesystem templates associated with our
+module_info with the registry::
+
+  >>> register_directory(module_info)
+
+We'll also import the global template registry to do some checks::
+
+  >>> from grokcore.view.templatereg import file_template_registry as reg
+
+We can look up the templates in the registry now::
+
+  >>> reg.lookup(module_info, 'foo')
+  <Template 'foo.template' in '...'>
+  >>> reg.lookup(module_info, 'bar')
+  <Template 'bar.template' in '...'>
+
+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):
+    ...
+  TemplateLookupError: template 'foo' in '...' cannot be found
+
+We get this error for templates that do not exist as well::
+
+  >>> reg.lookup(module_info, 'doesntexist')
+  Traceback (most recent call last):
+    ...
+  TemplateLookupError: template 'doesntexist' in ... cannot be found
+
+Since no templates have yet been associated, retrieving the unassociated
+templates will get us all registered templates::
+
+  >>> sorted(reg.unassociated())
+  ['...bar.template', '...foo.template']
+
+Now we use a template, so we mark it as associated::
+
+  >>> reg.associate(os.path.join(template_dir, 'foo.template'))
+
+There is only a single unassociated template left now::
+
+  >>> 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
+---------------------------
+
+We set up a directory with a template language that is not recognized by
+the system::
+
+  >>> import os, tempfile
+  >>> module_info2, template_dir2 = create_module_info_with_templates('module2')
+  >>> f = open(os.path.join(template_dir2, 'foo.unknown'), 'w')
+  >>> f.write('unknown')
+  >>> f.close()
+
+We will now start recording all the warnings, as we will get one about the
+unknown template language when we register the directory later::
+
+  >>> from grokcore.view.testing import warn
+  >>> import warnings
+  >>> saved_warn = warnings.warn
+  >>> warnings.warn = warn
+
+We register the directory now, and we get the warning::
+
+  >>> reg.register_directory(module_info2)
+  From grok.testing's warn():
+  ... UserWarning: File 'foo.unknown' has an unrecognized extension in directory '...'
+  ...
+
+We restore the normal warnings mechanism::
+
+  >>> warnings.warn = saved_warn
+
+This file will not be loaded as a template::
+
+  >>> reg.lookup(module_info2, 'foo.unknown')
+  Traceback (most recent call last):
+    ...
+  TemplateLookupError: template 'foo.unknown' in '...' cannot be found
+
+Multiple templates with the same name
+-------------------------------------
+
+Let's make the template languages ``1`` and ``2`` known::
+
+  >>> component.provideUtility(TestTemplateFactory(), ITemplateFileFactory, 
+  ...   name='1')
+  >>> component.provideUtility(TestTemplateFactory(), ITemplateFileFactory, 
+  ...   name='2')
+
+We now set up a directory which contains 'foo.1' and 'foo.2'. These
+templates have the same name but use different template languages, and
+Grok won't know which one it should use::
+
+  >>> module_info3, template_dir3 = create_module_info_with_templates('module3')
+  >>> f = open(os.path.join(template_dir3, 'foo.1'), 'w')
+  >>> f.write('1')
+  >>> f.close()
+  >>> f = open(os.path.join(template_dir3, 'foo.2'), 'w')
+  >>> f.write('2')
+  >>> f.close()
+
+We expect an error when we register this directory::
+
+  >>> register_directory(module_info3)
+  Traceback (most recent call last):
+    ...
+  GrokError: Conflicting templates found for name 'foo' in directory '...': 
+  multiple templates with the same name and different extensions.
+
+Inline templates
+----------------
+
+Inline templates are defined in a Python module instead of on the
+filesystem.
+
+Let's create a class for inline template and create an instance::
+
+  >>> class InlineTemplate(object):
+  ...     def __init__(self, name):
+  ...         self.name = name
+  ...     def __repr__(self):
+  ...         return "<InlineTemplate '%s'>" % self.name
+  >>> cavepainting = InlineTemplate('cavepainting')
+
+Let's register an inline template with the registry::
+
+  >>> module_info4, template_dir4 = create_module_info_with_templates('module4')
+  >>> register_inline_template(module_info4, 'cavepainting', cavepainting)
+
+  >>> from grokcore.view.templatereg import inline_template_registry as inline_reg
+
+We can look it up now::
+
+  >>> inline_reg.lookup(module_info4, 'cavepainting')
+  <InlineTemplate 'cavepainting'>
+  
+If we cannot find the template we get an error::
+
+  >>> inline_reg.lookup(module_info4, 'unknown')
+  Traceback (most recent call last):
+    ...
+  TemplateLookupError: inline template 'unknown' in 'module4' cannot be found
+
+Since no templates have yet been associated, retrieving the
+unassociated templates will get us all registered inline templates::
+
+  >>> 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.
+
+  >>> lookuptest_info, lookuptest_template_dir = create_module_info_with_templates('lookuptest')
+  >>> f = open(os.path.join(lookuptest_template_dir, 'foo.template'), 'w')
+  >>> f.write('foo')
+  >>> f.close()
+  >>> register_directory(lookuptest_info)
+
+  >>> from grokcore.view.templatereg import lookup
+  >>> lookup(lookuptest_info, 'foo')
+  <Template 'foo.template' in '...'>
+
+This can also be used to look up inline templates::
+
+  >>> bar = InlineTemplate('bar')
+  >>> register_inline_template(lookuptest_info, 'bar', bar)
+  >>> lookup(lookuptest_info, 'bar')
+  <InlineTemplate 'bar'>
+
+If we look up a template that doesn't exist, we get an error (about it
+missing on the filesystem)::
+
+  >>> lookup(lookuptest_info, 'qux')
+  Traceback (most recent call last):
+    ...
+  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
+-----------------------------------------------------
+
+We construct a fake templates directory that's associated with the fictional
+``module`` module::
+
+  >>> import os, tempfile
+
+  >>> module_info5, template_dir5 = create_module_info_with_templates('module5')
+
+We create a template with the name ``foo`` in it::
+
+  >>> f = open(os.path.join(template_dir5, 'foo.template'), 'w')
+  >>> f.write('foo')
+  >>> f.close()
+
+We register this directory, using the global registration functionality::
+
+  >>> register_directory(module_info5)
+
+We now also try to register an inline template with the same name
+(``foo``), but this fails due to a conflict with the file template::
+
+  >>> 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 
+  '...module5_templates'
+
+Let's now demonstrate the same conflict, the other way around.
+
+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': 
+   the inline template in module 'module6' conflicts with the file template in directory '...'
+
+
+XXX use configuration action conflicts with module_info.dotted_name,
+    name to determine conflicts between registrations?
+


Property changes on: grokcore.view/trunk/src/grokcore/view/templatereg.txt
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision

Modified: grokcore.view/trunk/src/grokcore/view/tests/test_all.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/test_all.py	2010-12-07 14:47:19 UTC (rev 118741)
+++ grokcore.view/trunk/src/grokcore/view/tests/test_all.py	2010-12-07 14:57:43 UTC (rev 118742)
@@ -4,6 +4,8 @@
 from zope.testing import doctest, cleanup, renormalizing
 import zope.component.eventtesting
 
+optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
+
 def setUpZope(test):
     zope.component.eventtesting.setUp(test)
 
@@ -34,8 +36,7 @@
                                     setUp=setUpZope,
                                     tearDown=cleanUpZope,
                                     checker=checker,
-                                    optionflags=doctest.ELLIPSIS+
-                                    doctest.NORMALIZE_WHITESPACE)
+                                    optionflags=optionflags)
 
         suite.addTest(test)
     return suite
@@ -44,4 +45,9 @@
     suite = unittest.TestSuite()
     for name in ['view', 'static', 'skin', 'template', 'directoryresource']:
         suite.addTest(suiteFromPackage(name))
+    suite.addTest(doctest.DocFileSuite('../templatereg.txt',
+                                       optionflags=optionflags,
+                                       setUp=setUpZope,
+                                       tearDown=cleanUpZope,
+                                       ))
     return suite

Modified: grokcore.view/trunk/src/grokcore/view/tests/view/dirandinlinetemplate.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/dirandinlinetemplate.py	2010-12-07 14:47:19 UTC (rev 118741)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/dirandinlinetemplate.py	2010-12-07 14:57:43 UTC (rev 118742)
@@ -5,8 +5,11 @@
   >>> 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/trunk/src/grokcore/view/tests/view/dirtemplatesonly.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/dirtemplatesonly.py	2010-12-07 14:47:19 UTC (rev 118741)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/dirtemplatesonly.py	2010-12-07 14:57:43 UTC (rev 118742)
@@ -1,15 +1,15 @@
 """
 A template directory may only contain recognized template files::
 
-  >>> from zope.testing.loggingsupport import InstalledHandler
-  >>> handler = InstalledHandler('grokcore.view')
-  >>> handler.clear()
+  >>> from grokcore.view.testing import warn, lastwarning
+  >>> import warnings
+  >>> saved_warn = warnings.warn
+  >>> warnings.warn = warn
 
   >>> grok.testing.grok(__name__)
-  >>> print handler
-  grokcore.view WARNING
-      File 'invalid.txt' has an unrecognized extension in directory
-      '...dirtemplatesonly_templates'
+  From grok.testing's warn():
+  ... UserWarning: File 'invalid.txt' has an unrecognized extension in
+  directory '...dirtemplatesonly_templates'...
 
 Files ending with '.cache' are generated on the fly by some template
 engines. Although they provide no valid template filename extension,
@@ -18,16 +18,15 @@
 There is a 'template' ``ignored.cache`` in our template dir, which
 emits no warning::
 
-  >>> #'ignored.cache' in lastwarning
-  >>> 'ignored.cache' in handler.records[0].msg
+  >>> 'ignored.cache' in lastwarning
   False
 
 The same applies to files and directories ending with '~' or starting
 with a dot ('.').
 
-Restore the logging machinery::
+Restore the warning machinery::
 
-  >>> handler.uninstall()
+  >>> warnings.warn = saved_warn
 
 """
 import grokcore.view as grok

Modified: grokcore.view/trunk/src/grokcore/view/tests/view/inline_unassociated.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/inline_unassociated.py	2010-12-07 14:47:19 UTC (rev 118741)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/inline_unassociated.py	2010-12-07 14:57:43 UTC (rev 118742)
@@ -1,23 +1,20 @@
 """
 Inline templates that are not associated with a view class will
-provoke a log message on warning level to ``grokcore.view`` logger:
+provoke an error:
 
-  >>> from zope.testing.loggingsupport import InstalledHandler
-  >>> handler = InstalledHandler('grokcore.view')
-  >>> handler.clear() # Make sure there are no old msgs stored...
+  >>> from grokcore.view.testing import warn
+  >>> import warnings
+  >>> saved_warn = warnings.warn
+  >>> warnings.warn = warn
 
   >>> grok.testing.grok(__name__)
-  >>> print handler
-  grokcore.view WARNING
-      Found the following unassociated template(s) when grokking
-      'grokcore.view.tests.view.inline_unassociated': club.  Define
-      view classes inheriting from grok.View to enable the
-      template(s).
+  From grok.testing's warn():
+  ...UserWarning: Found the following unassociated template(s) when grokking
+  'grokcore.view.tests.view.inline_unassociated': club. Define view classes inheriting
+  from grok.View to enable the template(s)...
 
-Restore logging machinery:
+  >>> warnings.warn = saved_warn
 
-  >>> handler.uninstall()
-
 """
 import grokcore.view as grok
 

Modified: grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_dir.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_dir.py	2010-12-07 14:47:19 UTC (rev 118741)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_dir.py	2010-12-07 14:57:43 UTC (rev 118742)
@@ -1,41 +1,21 @@
 """
-When modules share a template directory, templates that have not been
-associated with any view class of a given module issue a log message
-with level ``logging.WARNING`` to a ``grokcore.view`` logger:
+When modules share a template directory, templates that have not been associated with any view class of a given module issue a UserWarning:
 
-  >>> from zope.testing.loggingsupport import InstalledHandler
-  >>> handler = InstalledHandler('grokcore.view')
+  >>> import grokcore.view as grok
+  >>> from grokcore.view.testing import warn
+  >>> import warnings
+  >>> saved_warn = warnings.warn
+  >>> warnings.warn = warn
 
-  >>> import shared_template_dir_fixture
+  >>> import shared_template_fixture 
 
-  >>> handler.clear()  # Make sure no old log msgs are stored...
-  >>> grok.testing.grok(__name__)
-  >>> print handler
-  grokcore.view WARNING
-      Found the following unassociated template(s) when grokking
-      'grokcore.view.tests.view.shared_template_dir': food,
-      unassociated.  Define view classes inheriting from grok.View to
-      enable the template(s).
-  
-  >>> handler.clear()  # Make sure no old log msgs are stored...
-  >>> grok.testing.grok(shared_template_dir_fixture.__name__)
-  >>> print handler
-  grokcore.view WARNING
-        Found the following unassociated template(s) when grokking
-      'grokcore.view.tests.view.shared_template_dir_fixture':
-      cavepainting, unassociated.  Define view classes inheriting from
-      grok.View to enable the template(s).
+  >>> grok.testing.grok(shared_template_fixture.__name__)
+  From grok.testing's warn():
+  ...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 views:
+  ...shared_template_fixture...templates...unassociated.pt.  Define view classes inheriting from
+  grok.View to enable the template(s)...
 
-  >>> handler.uninstall()
-
 """
-import grokcore.view as grok
-
-
-grok.templatedir("shared_templates")
-
-class Mammoth(grok.Context):
-    pass
-
-class CavePainting(grok.View):
-    pass

Deleted: grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_dir_fixture.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_dir_fixture.py	2010-12-07 14:47:19 UTC (rev 118741)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_dir_fixture.py	2010-12-07 14:57:43 UTC (rev 118742)
@@ -1,11 +0,0 @@
-"""
-This should issue a UserWarning.
-"""
-import grokcore.view as grok
-from shared_template_dir import Mammoth
-
-grok.templatedir("shared_templates")
-
-class Food(grok.View):
-    grok.context(Mammoth)
-


Property changes on: grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/__init__.py
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision

Added: grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/first_module.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/first_module.py	                        (rev 0)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/first_module.py	2010-12-07 14:57:43 UTC (rev 118742)
@@ -0,0 +1,14 @@
+import grokcore.view as grok
+
+
+grok.templatedir("templates")
+
+class Mammoth(grok.Context):
+    pass
+
+class CavePainting(grok.View):
+    pass
+
+unassociated_instance = grok.PageTemplate("""
+<html><body><h1>GROK PAINT MAMMOTH!</h1></body></html>
+""")


Property changes on: grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/first_module.py
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision

Added: grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/second_module.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/second_module.py	                        (rev 0)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/second_module.py	2010-12-07 14:57:43 UTC (rev 118742)
@@ -0,0 +1,11 @@
+"""
+This should issue a UserWarning.
+"""
+import grokcore.view as grok
+from first_module import Mammoth
+
+grok.templatedir("templates")
+
+class Food(grok.View):
+    grok.context(Mammoth)
+


Property changes on: grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/second_module.py
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision

Added: grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/templates/cavepainting.pt
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/templates/cavepainting.pt	                        (rev 0)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/templates/cavepainting.pt	2010-12-07 14:57:43 UTC (rev 118742)
@@ -0,0 +1,5 @@
+<html>
+<body>
+ME GROK PAINT CAVE!
+</body>
+</html>


Property changes on: grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/templates/cavepainting.pt
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision

Added: grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/templates/food.pt
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/templates/food.pt	                        (rev 0)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/templates/food.pt	2010-12-07 14:57:43 UTC (rev 118742)
@@ -0,0 +1,5 @@
+<html>
+<body>
+ME GROK EAT MAMMOTH!
+</body>
+</html>


Property changes on: grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/templates/food.pt
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision

Added: grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/templates/unassociated.pt
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/templates/unassociated.pt	                        (rev 0)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/templates/unassociated.pt	2010-12-07 14:57:43 UTC (rev 118742)
@@ -0,0 +1,3 @@
+This template does not have an associated view class (in other words,
+there's no grokcore.view.tests.view.shared_template_dir.Unassociated class), therefore it
+provokes a UserWarning.


Property changes on: grokcore.view/trunk/src/grokcore/view/tests/view/shared_template_fixture/templates/unassociated.pt
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision

Modified: grokcore.view/trunk/src/grokcore/view/tests/view/unassociated.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/unassociated.py	2010-12-07 14:47:19 UTC (rev 118741)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/unassociated.py	2010-12-07 14:57:43 UTC (rev 118742)
@@ -2,33 +2,29 @@
 Templates that are not associated with a view class will provoke an
 error:
 
-  >>> from zope.testing.loggingsupport import InstalledHandler
-  >>> handler = InstalledHandler('grokcore.view')
+  >>> from grokcore.view.testing import warn
+  >>> import warnings
+  >>> saved_warn = warnings.warn
+  >>> warnings.warn = warn
 
   >>> grok.testing.grok(__name__)
-  >>> print handler
-  grokcore.view WARNING
-      Found the following unassociated template(s) when grokking
-      'grokcore.view.tests.view.unassociated': index.  Define view
-      classes inheriting from grok.View to enable the template(s).
+  From grok.testing's warn():
+  ...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
 resides in, should be found without error or warning. We check this
 with the local package `modequalspkgname`::
 
-  >>> handler.clear() # Make sure no old log msgs are stored...
+  >>> warnings.warn = warn
 
   >>> pkg = __name__.rsplit('.', 1)[0] + '.modequalspkgname'
   >>> grok.testing.grok(pkg) is None
   True
 
-No log messages were emitted:
+  >>> warnings.warn = saved_warn
 
-  >>> handler.records
-  []
-
-  >>> handler.uninstall()
-
 """
 import grokcore.view as grok
 

Deleted: grokcore.view/trunk/src/grokcore/view/tests/view/warning_msgs.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/warning_msgs.py	2010-12-07 14:47:19 UTC (rev 118741)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/warning_msgs.py	2010-12-07 14:57:43 UTC (rev 118742)
@@ -1,54 +0,0 @@
-"""
-Warnings are sent on ``logging.WARNING`` level to a logger named
-``grokcore.view``. By default this messages will not be displayed, as
-the logger level is set to ``logging.ERROR`` immediately before the
-first warning happens (so apps have time to prepare the logger if they
-want to do so).
-
-The logger is initialized immediately before the first warning
-happens:
-
-  >>> import logging
-  >>> logger = logging.getLogger('grokcore.view')
-  >>> logger.level == logging.NOTSET
-  True
-
-  >>> grok.testing.grok(__name__)
-  >>> logger.level == logging.ERROR
-  True
-  
-If we set our own logging handler or tweak the logger level, this
-won't be overridden when the next warning happens:
-
-  >>> logger.level = logging.CRITICAL
-  >>> grok.testing.grok(__name__)
-  >>> logger.level == logging.CRITICAL
-  True
-
-The logger really gets messages:
-
-  >>> from zope.testing.loggingsupport import InstalledHandler
-  >>> handler = InstalledHandler('grokcore.view')
-  >>> handler.clear() # Make sure there are no old msgs stored...
-
-  >>> grok.testing.grok(__name__)
-  >>> print handler
-  grokcore.view WARNING
-      Found the following unassociated template(s) when grokking
-      'grokcore.view.tests.view.warning_msgs': club.  Define view
-      classes inheriting from grok.View to enable the template(s).
-
-Restore logging machinery:
-
-  >>> handler.uninstall()
-  >>> logger.level = logging.ERROR
-
-"""
-import grokcore.view as grok
-
-class Mammoth(grok.Context):
-    pass
-
-club = grok.PageTemplate("""\
-<html><body><h1>GROK CLUB MAMMOTH!</h1></body></html>
-""")



More information about the checkins mailing list