[Checkins] SVN: grokcore.view/trunk/ Revert the CodeView split. Fix again the template = case.

Sylvain Viollon sylvain at infrae.com
Wed Sep 16 06:06:09 EDT 2009


Log message for revision 104134:
  Revert the CodeView split. Fix again the template = case.
  
  

Changed:
  U   grokcore.view/trunk/CHANGES.txt
  U   grokcore.view/trunk/src/grokcore/view/__init__.py
  U   grokcore.view/trunk/src/grokcore/view/components.py
  U   grokcore.view/trunk/src/grokcore/view/ftests/url/redirect.py
  U   grokcore.view/trunk/src/grokcore/view/ftests/url/url.py
  U   grokcore.view/trunk/src/grokcore/view/ftests/url/url_function.py
  U   grokcore.view/trunk/src/grokcore/view/ftests/view/argument.py
  U   grokcore.view/trunk/src/grokcore/view/ftests/view/macros.py
  U   grokcore.view/trunk/src/grokcore/view/ftests/view/require.py
  U   grokcore.view/trunk/src/grokcore/view/ftests/view/skindirective.py
  U   grokcore.view/trunk/src/grokcore/view/interfaces.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/tests/skin/conflict.py
  U   grokcore.view/trunk/src/grokcore/view/tests/template/pluggability.py
  D   grokcore.view/trunk/src/grokcore/view/tests/view/codeview.py
  D   grokcore.view/trunk/src/grokcore/view/tests/view/codeviewnorender.py
  U   grokcore.view/trunk/src/grokcore/view/tests/view/dirtemplateandrender.py
  D   grokcore.view/trunk/src/grokcore/view/tests/view/norenderinview.py
  D   grokcore.view/trunk/src/grokcore/view/tests/view/notemplate.py
  U   grokcore.view/trunk/src/grokcore/view/tests/view/templatenotfound.py
  A   grokcore.view/trunk/src/grokcore/view/tests/view/templates/
  U   grokcore.view/trunk/src/grokcore/view/tests/view/view.py
  U   grokcore.view/trunk/src/grokcore/view/tests/view/view_decorator.py
  D   grokcore.view/trunk/src/grokcore/view/tests/view/view_templates/
  D   grokcore.view/trunk/src/grokcore/view/tests/view/viewrenderbasemethod.py
  U   grokcore.view/trunk/src/grokcore/view/tests/view/viewtemplateequal.py
  D   grokcore.view/trunk/src/grokcore/view/tests/view/viewwithrender.py

-=-
Modified: grokcore.view/trunk/CHANGES.txt
===================================================================
--- grokcore.view/trunk/CHANGES.txt	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/CHANGES.txt	2009-09-16 10:06:08 UTC (rev 104134)
@@ -8,7 +8,7 @@
   copy; a local copy for all grokcore packages is just too hard to
   maintain.
 
-- Fix View and CodeView interfaces.
+- Revert the splitting CodeView/View.
 
 - Fix the template = way to associate a template to a view.
 

Modified: grokcore.view/trunk/src/grokcore/view/__init__.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/__init__.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/__init__.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -19,7 +19,7 @@
 from zope.publisher.interfaces.browser import IBrowserRequest
 from zope.publisher.interfaces.browser import IDefaultBrowserLayer
 
-from grokcore.view.components import View, CodeView
+from grokcore.view.components import View
 from grokcore.view.components import PageTemplate, PageTemplateFile
 from grokcore.view.components import DirectoryResource
 from grokcore.view.directive import layer, template, templatedir, skin, path

Modified: grokcore.view/trunk/src/grokcore/view/components.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/components.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/components.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -31,12 +31,13 @@
 from grokcore.view import interfaces, util
 
 
-class BaseView(BrowserPage):
-    interface.implements(interfaces.IGrokBaseView)
+class View(BrowserPage):
+    interface.implements(interfaces.IGrokView)
 
     def __init__(self, context, request):
-        super(BaseView, self).__init__(context, request)
+        super(View, self).__init__(context, request)
         self.__name__ = getattr(self, '__view_name__', None)
+
         if getattr(self, 'module_info', None) is not None:
             self.static = component.queryAdapter(
                 self.request,
@@ -46,12 +47,51 @@
         else:
             self.static = None
 
-    def update(self, **kwargs):
-        pass
+    @property
+    def response(self):
+        return self.request.response
 
-    def redirect(self, url):
-        return self.request.response.redirect(url)
+    def __call__(self):
+        mapply(self.update, (), self.request)
+        if self.request.response.getStatus() in (302, 303):
+            # A redirect was triggered somewhere in update().  Don't
+            # continue rendering the template or doing anything else.
+            return
 
+        template = getattr(self, 'template', None)
+        if template is not None:
+            return self._render_template()
+        return mapply(self.render, (), self.request)
+
+    def _render_template(self):
+        return self.template.render(self)
+
+    def default_namespace(self):
+        namespace = {}
+        namespace['context'] = self.context
+        namespace['request'] = self.request
+        namespace['static'] = self.static
+        namespace['view'] = self
+        return namespace
+
+    def namespace(self):
+        return {}
+
+    def __getitem__(self, key):
+        # This is BBB code for Zope page templates only:
+        if not isinstance(self.template, PageTemplate):
+            raise AttributeError("View has no item %s" % key)
+
+        value = self.template._template.macros[key]
+        # When this deprecation is done with, this whole __getitem__ can
+        # be removed.
+        warnings.warn("Calling macros directly on the view is deprecated. "
+                      "Please use context/@@viewname/macros/macroname\n"
+                      "View %r, macro %s" % (self, key),
+                      DeprecationWarning, 1)
+        return value
+
+
     def url(self, obj=None, name=None, data=None):
         """Return string for the URL based on the obj and name. The data
         argument is used to form a CGI query string.
@@ -79,70 +119,18 @@
 
         return util.url(self.request, obj, name, data=data)
 
-    @property
-    def response(self):
-        return self.request.response
+    def redirect(self, url):
+        return self.request.response.redirect(url)
 
-    def default_namespace(self):
-        namespace = {}
-        namespace['context'] = self.context
-        namespace['request'] = self.request
-        namespace['static'] = self.static
-        namespace['view'] = self
-        return namespace
+    def update(self, **kwargs):
+        pass
 
-    def namespace(self):
-        return {}
+    def render(self, **kwargs):
+        pass
 
+    render.base_method = True
 
-class CodeView(BaseView):
 
-    interface.implements(interfaces.IGrokCodeView)
-
-    def __init__(self, context, request):
-        super(CodeView, self).__init__(context, request)
-
-    def __call__(self, *args, **kwargs):
-        mapply(self.update, (), self.request)
-        if self.request.response.getStatus() in (302, 303):
-            # A redirect was triggered somewhere in update().  Don't
-            # continue rendering the template or doing anything else.
-            return
-
-        return mapply(self.render, (), self.request)
-
-
-class View(BaseView):
-
-    interface.implements(interfaces.IGrokView)
-
-    def __init__(self, context, request):
-        super(View, self).__init__(context, request)
-
-    def __call__(self, *args, **kwargs):
-        mapply(self.update, (), self.request)
-        if self.request.response.getStatus() in (302, 303):
-            # A redirect was triggered somewhere in update().  Don't
-            # continue rendering the template or doing anything else.
-            return
-
-        return self.template.render(self)
-
-    def __getitem__(self, key):
-        # This is BBB code for Zope page templates only:
-        if not isinstance(self.template, PageTemplate):
-            raise AttributeError("View has no item %s" % key)
-
-        value = self.template._template.macros[key]
-        # When this deprecation is done with, this whole __getitem__ can
-        # be removed.
-        warnings.warn("Calling macros directly on the view is deprecated. "
-                      "Please use context/@@viewname/macros/macroname\n"
-                      "View %r, macro %s" % (self, key),
-                      DeprecationWarning, 1)
-        return value
-
-
 class BaseTemplate(object):
     """Any sort of page template"""
 
@@ -211,12 +199,15 @@
         namespace.update(view.namespace())
         return namespace
 
+
 class TrustedPageTemplate(TrustedAppPT, pagetemplate.PageTemplate):
     pass
 
+
 class TrustedFilePageTemplate(TrustedAppPT, pagetemplatefile.PageTemplateFile):
     pass
 
+
 class PageTemplate(GrokTemplate):
 
     def setFromString(self, string):
@@ -239,7 +230,7 @@
         factory.macros = property(_get_macros)
 
     def render(self, view):
-        assert interfaces.IGrokBaseView.providedBy(view)
+        assert interfaces.IGrokView.providedBy(view)
         namespace = self.getNamespace(view)
         template = self._template
         namespace.update(template.pt_getContext())
@@ -254,6 +245,7 @@
             _prefix = os.path.dirname(module.__file__)
         self.setFromFilename(filename, _prefix)
 
+
 class DirectoryResource(directoryresource.DirectoryResource):
     # We subclass this, because we want to override factories for
     # .pt and .html file types, not creating pagetemplate resources.
@@ -268,8 +260,10 @@
     # having defined the DirectoryResourceFactory class.
     directory_factory = None
 
+
 class DirectoryResourceFactory(directoryresource.DirectoryResourceFactory):
     # We need this to allow hooking up our own DirectoryResource class.
     factoryClass = DirectoryResource
 
+
 DirectoryResource.directory_factory = DirectoryResourceFactory

Modified: grokcore.view/trunk/src/grokcore/view/ftests/url/redirect.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/ftests/url/redirect.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/ftests/url/redirect.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -12,18 +12,18 @@
   >>> browser.open('http://localhost/manfred')
   >>> browser.url
   'http://localhost/manfred/another'
-
+  
 """
 import grokcore.view as grok
 
 class Mammoth(grok.Context):
     pass
 
-class Index(grok.CodeView):
+class Index(grok.View):
     def render(self):
         self.redirect(self.url('another'))
 
-class Another(grok.CodeView):
+class Another(grok.View):
     def render(self):
         return "Another view"
 

Modified: grokcore.view/trunk/src/grokcore/view/ftests/url/url.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/ftests/url/url.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/ftests/url/url.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -180,18 +180,18 @@
 
 grok.context(Mammoth)
 
-class Index(grok.CodeView):
+class Index(grok.View):
     def render(self):
         return self.url()
 
-class Another(grok.CodeView):
+class Another(grok.View):
     def render(self):
         return self.url()
 
 class YetAnother(grok.View):
     pass
 
-class Multiplier(grok.CodeView):
+class Multiplier(grok.View):
     def update(self, age=0):
         self.age = age
 

Modified: grokcore.view/trunk/src/grokcore/view/ftests/url/url_function.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/ftests/url/url_function.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/ftests/url/url_function.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -61,26 +61,20 @@
   >>> expected = unicode('http://127.0.0.1/herd/árgh', 'UTF-8')
   >>> urllib.unquote(u).decode('utf-8') == expected
   True
-
 """
 import grokcore.view as grok
 from grokcore.view import url
 from zope.app.container.contained import Contained
 
-
 class Mammoth(Contained):
     pass
 
 grok.context(Mammoth)
 
-
-class Index(grok.CodeView):
+class Index(grok.View):
     def render(self):
         return url(self.request, self)
 
-
 class Another(grok.View):
-    pass
-
-
-another = grok.PageTemplate('<p tal:replace="view/url" />')
+    def render(self):
+        return url(self.request, self)

Modified: grokcore.view/trunk/src/grokcore/view/ftests/view/argument.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/ftests/view/argument.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/ftests/view/argument.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -49,18 +49,15 @@
 """
 import grokcore.view as grok
 
-
 class Mammoth(grok.Context):
     pass
 
-
-class RenderWithArguments(grok.CodeView):
+class RenderWithArguments(grok.View):
     grok.name('render')
 
     def render(self, message, another):
         return "Message: %s\nAnother: %s" % (message, another)
 
-
 class UpdateWithArguments(grok.View):
     grok.name('update')
     grok.template('update')
@@ -69,7 +66,6 @@
         self.message = message
         self.another = another
 
-
 update = grok.PageTemplate("""
 Coming to us from update():
 Message: <span tal:replace="view/message" />

Modified: grokcore.view/trunk/src/grokcore/view/ftests/view/macros.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/ftests/view/macros.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/ftests/view/macros.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -19,8 +19,7 @@
 
   >>> browser.open("http://localhost/manfred/@@dancing")
   Traceback (most recent call last):
-  ...
-  TraversalError: (<grokcore.view.ftests.view.macros.DancingHall object at ...>, 'macros')
+  AttributeError: 'DancingHall' object has no attribute 'template'
 
 If the view has an attribute with the same name as a macro, the macro
 shadows the view. XXX This should probably generate a warning at runtime.
@@ -72,36 +71,26 @@
   >>> open(template_file, 'w').write(before)
 
 
+
 """
 import grokcore.view as grok
 
-
 class Mammoth(grok.Context):
     pass
 
+class DancingHall(grok.View):
 
-class DancingHall(grok.CodeView):
-
     def render(self):
-	return "Bla Bla Dancing Hall"
+        return "A nice large dancing hall for mammoths."
 
-
 class Grilled(grok.View):
 
     def update(self):
         self.spices = "Pepper and salt"
 
-
-grilled = grok.PageTemplate("""\
-<html metal:define-macro="spices">
-Curry
-</html>""")
-
-
 class Painting(grok.View):
     pass
 
-
 painting = grok.PageTemplate("""\
 <html metal:use-macro="context/@@layout/macros/main">
 <div metal:fill-slot="slot">
@@ -110,40 +99,38 @@
 </html>
 """)
 
-
 class Layout(grok.View):
     # Layout template is in macros_templates/layout.pt for reload test
     # purposes.
     pass
 
-
 class Dancing(grok.View):
     pass
 
-
 dancing = grok.PageTemplate("""\
 <html metal:use-macro="context/@@dancinghall/macros/something">
 </html>
 """)
 
-
 class GrillDish(grok.View):
     pass
 
-
 grilldish = grok.PageTemplate("""
 <html metal:use-macro="context/@@grilled/macros/spices">
 </html>""")
 
-
-
 class Burnt(grok.View):
     pass
 
-
 burnt = grok.PageTemplate("""\
 <html metal:use-macro="context/@@grilled/spices">
 </html>""")
 
+class Grilled(grok.View):
+    pass
 
+grilled = grok.PageTemplate("""\
+<html metal:define-macro="spices">
+Curry
+</html>""")
 

Modified: grokcore.view/trunk/src/grokcore/view/ftests/view/require.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/ftests/view/require.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/ftests/view/require.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -27,20 +27,17 @@
 import grokcore.view as grok
 import zope.interface
 
-
 class ViewPainting(grok.Permission):
     grok.name('cave.ViewPainting')
 
-
-class Painting(grok.CodeView):
+class Painting(grok.View):
     grok.context(zope.interface.Interface)
     grok.require(ViewPainting)
 
     def render(self):
         return 'What a beautiful painting.'
 
-
-class PublicNudity(grok.CodeView):
+class PublicNudity(grok.View):
     grok.context(zope.interface.Interface)
     grok.require(grok.Public)
 

Modified: grokcore.view/trunk/src/grokcore/view/ftests/view/skindirective.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/ftests/view/skindirective.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/ftests/view/skindirective.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -47,14 +47,14 @@
 </html>
 """)
 
-class MoreDrawings(grok.CodeView):
+class MoreDrawings(grok.View):
     grok.layer(rotterdam)
 
     def render(self):
         return "Pretty"
 
 
-class EvenMoreDrawings(grok.CodeView):
+class EvenMoreDrawings(grok.View):
     grok.layer(MySkinLayer)
 
     def render(self):

Modified: grokcore.view/trunk/src/grokcore/view/interfaces.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/interfaces.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/interfaces.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -19,7 +19,6 @@
 
 class IBaseClasses(Interface):
     View = Attribute("Base class for browser views.")
-    CodeView = Attribute("Base class for browser views with render().")
     DirectoryResource = Attribute("Base class to create new "
                                   "directory resource.")
 
@@ -74,7 +73,7 @@
     IDefaultBrowserLayer = Attribute('Default layer for browser views.')
 
 
-class IGrokBaseView(IBrowserPage, IBrowserView):
+class IGrokView(IBrowserPage, IBrowserView):
     """Grok views all provide this interface."""
 
     context = Attribute('context', "Object that the view presents.")
@@ -84,6 +83,9 @@
     response = Attribute('response', "Response object that is "
                          "associated with the current request.")
 
+    static = Attribute('static', "Directory resource containing "
+                       "the static files of the view's package.")
+
     def redirect(url):
        """Redirect to given URL"""
 
@@ -104,19 +106,6 @@
         as a cgi query string.
         """
 
-    def update(**kw):
-        """This method is meant to be implemented by grok.View
-        subclasses.  It will be called *before* the view's associated
-        template is rendered and can be used to pre-compute values
-        for the template.
-
-        update() can take arbitrary keyword parameters which will be
-        filled in from the request (in that case they *must* be
-        present in the request)."""
-
-    static = Attribute('static', "Directory resource containing "
-                       "the static files of the view's package.")
-
     def default_namespace():
         """Returns a dictionary of namespaces that the template
         implementation expects to always be available.
@@ -133,8 +122,15 @@
         developer.
         """
 
+    def update(**kw):
+        """This method is meant to be implemented by grok.View
+        subclasses.  It will be called *before* the view's associated
+        template is rendered and can be used to pre-compute values
+        for the template.
 
-class IGrokCodeView(IGrokBaseView):
+        update() can take arbitrary keyword parameters which will be
+        filled in from the request (in that case they *must* be
+        present in the request)."""
 
     def render(**kw):
         """A view can either be rendered by an associated template, or
@@ -146,12 +142,12 @@
         filled in from the request (in that case they *must* be
         present in the request)."""
 
+    def __call__():
+        """This is the main method called by Zope to render the
+        view. You can use that method if you whish to render the
+        view."""
 
-class IGrokView(IGrokBaseView):
-    """Marker Interface for Views with a template
-    """
 
-
 class ITemplateFileFactory(Interface):
     """Utility that generates templates from files in template directories.
     """

Modified: grokcore.view/trunk/src/grokcore/view/meta/views.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/meta/views.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/meta/views.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -46,18 +46,14 @@
         return super(ViewGrokker, self).grok(name, factory, module_info, **kw)
 
     def execute(self, factory, config, context, layer, name, **kw):
-        # Make sure that we have a render Method
-        render = getattr(factory, 'render', None)
-        if render and not getattr(render, 'base_method', False):
-            raise GrokError("View Class '%s' has a render method, use CodeView instead" % factory, factory)
-
         # find templates
         templates = factory.module_info.getAnnotation('grok.templates', None)
-        config.action(
-            discriminator=None,
-            callable=self.checkTemplates,
-            args=(templates, factory.module_info, factory)
-            )
+        if templates is not None:
+            config.action(
+                discriminator=None,
+                callable=self.checkTemplates,
+                args=(templates, factory.module_info, factory)
+                )
 
         # safety belt: make sure that the programmer didn't use
         # @grok.require on any of the view's methods.
@@ -80,54 +76,21 @@
             )
         return True
 
-
     def checkTemplates(self, templates, module_info, factory):
-        templates.checkTemplates(module_info, factory, 'view')
 
+        def has_render(factory):
+            render = getattr(factory, 'render', None)
+            base_method = getattr(render, 'base_method', False)
+            return render and not base_method
 
-class CodeViewGrokker(martian.ClassGrokker):
-    martian.component(components.CodeView)
-    martian.directive(grokcore.component.context)
-    martian.directive(grokcore.view.layer, default=IDefaultBrowserLayer)
-    martian.directive(grokcore.component.name, get_default=default_view_name)
+        def has_no_render(factory):
+            return not getattr(factory, 'render', None)
+        templates.checkTemplates(module_info, factory, 'view',
+                                 has_render, has_no_render)
 
-    def grok(self, name, factory, module_info, **kw):
-        # Need to store the module info object on the view class so that it
-        # can look up the 'static' resource directory.
-        factory.module_info = module_info
-        return super(CodeViewGrokker, self).grok(name, factory, module_info, **kw)
 
-    def execute(self, factory, config, context, layer, name, **kw):
-
-        # Make sure that we have a render Method
-        render = getattr(factory, 'render', None)
-        if not render:
-            raise GrokError("CodeView Class '%s' without an render method" % factory, factory)
-
-        # safety belt: make sure that the programmer didn't use
-        # @grok.require on any of the view's methods.
-        methods = util.methods_from_class(factory)
-        for method in methods:
-            if grokcore.security.require.bind().get(method) is not None:
-                raise GrokError('The @grok.require decorator is used for '
-                                'method %r in view %r. It may only be used '
-                                'for XML-RPC methods.'
-                                % (method.__name__, factory), factory)
-
-        # __view_name__ is needed to support IAbsoluteURL on views
-        factory.__view_name__ = name
-        adapts = (context, layer)
-
-        config.action(
-            discriminator=('adapter', adapts, interface.Interface, name),
-            callable=component.provideAdapter,
-            args=(factory, adapts, interface.Interface, name),
-            )
-        return True
-
-
 class ViewSecurityGrokker(martian.ClassGrokker):
-    martian.component(components.BaseView)
+    martian.component(components.View)
     martian.directive(grokcore.security.require, name='permission')
 
     def execute(self, factory, config, permission, **kw):

Modified: grokcore.view/trunk/src/grokcore/view/templatereg.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/templatereg.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/templatereg.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -4,7 +4,7 @@
 import grokcore.component
 import grokcore.view
 from martian.error import GrokError
-from grokcore.view.interfaces import ITemplateFileFactory
+from grokcore.view.interfaces import ITemplateFileFactory, ITemplate
 from grokcore.view.components import PageTemplate
 
 class TemplateRegistry(object):
@@ -90,7 +90,9 @@
                 module_info.dotted_name, ', '.join(unassociated)))
             warnings.warn(msg, UserWarning, 1)
 
-    def checkTemplates(self, module_info, factory, component_name):
+    def checkTemplates(self, module_info, factory, component_name,
+                       has_render, has_no_render):
+        # TODO: remove has_no_render arg, it's not used anymore
         factory_name = factory.__name__.lower()
         template_name = grokcore.view.template.bind().get(factory)
         if template_name is None:
@@ -105,15 +107,38 @@
                                 "a template called '%s'."
                                 % (component_name, factory, template_name,
                                    factory_name), factory)
+
+        # Check if view already have a 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
-        elif getattr(factory, 'template', None) is None:
-            raise GrokError("%s %r has no associated template." %
+            factory_have_template = True
+
+        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)
+
+        if not factory_have_template and not has_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)
-        factory.template._initFactory(factory)
 
+        if factory_have_template:
+            factory.template._initFactory(factory)
+
+
 class PageTemplateFileFactory(grokcore.component.GlobalUtility):
     grokcore.component.implements(ITemplateFileFactory)
     grokcore.component.name('pt')

Modified: grokcore.view/trunk/src/grokcore/view/tests/skin/conflict.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/skin/conflict.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/tests/skin/conflict.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -10,10 +10,8 @@
 
 import grokcore.view as grok
 
-
 class Skin1(grok.IBrowserRequest):
     grok.skin('foo')
 
-
 class Skin2(grok.IBrowserRequest):
     grok.skin('foo')

Modified: grokcore.view/trunk/src/grokcore/view/tests/template/pluggability.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/template/pluggability.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/tests/template/pluggability.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -2,12 +2,12 @@
 Testing the plugging in of a template language
 
   >>> grok.testing.grok(__name__)
-
+  
   >>> cave = Cave()
   >>> from zope.publisher.browser import TestRequest
   >>> request = TestRequest()
   >>> from zope import component
-
+  
   # The inline template should work:
   >>> view = component.getMultiAdapter((cave, request), name='sebaayeni')
   >>> print view()
@@ -23,7 +23,7 @@
   >>> print view()
   <html><body>Kakadu is in Australia</body></html>
 
-  # We should be able to extend the namespac in the view and
+  # We should be able to extend the namespac in the view and 
   >>> view = component.getMultiAdapter((cave, request), name='sierra')
   >>> print view()
   <html><body>Sierra de San Fransisco is in Mexico</body></html>
@@ -33,15 +33,14 @@
 
 # Dummy template language:
 class MyTemplate(object):
-
+    
     def __init__(self, text):
         self._text = text
-
+            
     def render(self, **kw):
         # Silliest template language ever:
         return self._text % kw
 
-
 class MyPageTemplate(grok.components.GrokTemplate):
 
     def setFromString(self, string):
@@ -71,19 +70,19 @@
 
 class Sebaayeni(grok.View):
     pass
-
+    
 sebaayeni = MyPageTemplate('<html><body>Sebaayeni is in South Africa</body></html>')
 
 class Lascaux(grok.View):
     pass
-
+    
 lascaux = MyPageTemplate(filename='lascaux.html')
 
 class Kakadu(grok.View):
     pass
 
 class Sierra(grok.View):
-
+    
     def namespace(self):
         return {'cave': 'Sierra de San Fransisco',
                 'country': 'Mexico'}

Deleted: grokcore.view/trunk/src/grokcore/view/tests/view/codeview.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/codeview.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/codeview.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -1,29 +0,0 @@
-"""
-
-  >>> grok.testing.grok(__name__)
-
-  >>> from zope.publisher.browser import TestRequest
-  >>> from zope.interface.verify import verifyObject
-  >>> from zope.component import getMultiAdapter
-  >>> from grokcore.view.interfaces import IGrokCodeView
-
-  >>> mammoth = Mammoth()
-
-  >>> code_view = getMultiAdapter((mammoth, TestRequest()), name="cavepainting")
-  >>> print code_view()
-  A cave painting of a mammoth
-
-  >>> verifyObject(IGrokCodeView, code_view)
-  True
-
-"""
-
-import grokcore.view as grok
-
-class Mammoth(grok.Context):
-    pass
-
-class CavePainting(grok.CodeView):
-
-    def render(self, **kwargs):
-        return 'A cave painting of a mammoth'

Deleted: grokcore.view/trunk/src/grokcore/view/tests/view/codeviewnorender.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/codeviewnorender.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/codeviewnorender.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -1,16 +0,0 @@
-"""
-
-  >>> grok.testing.grok(__name__)
-  Traceback (most recent call last):
-  ...
-  GrokError: CodeView Class '<class 'grokcore.view.tests.view.codeviewnorender.CaveTiger'>' without an render method 
-
-"""
-
-import grokcore.view as grok
-
-class Mammoth(grok.Context):
-    pass
-
-class CaveTiger(grok.CodeView):
-    pass

Modified: grokcore.view/trunk/src/grokcore/view/tests/view/dirtemplateandrender.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/dirtemplateandrender.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/dirtemplateandrender.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -1,13 +1,15 @@
 """
-A View may only have an associated template.  Not a render-method, for that
-you must use CodeView.  Here we check that this also works for templates in a
-template-directory:
+A View may either have an associated template or a render-method. Here
+we check that this also works for templates in a template-directory:
 
-    >>> grok.testing.grok(__name__)
-    Traceback (most recent call last):
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
     ...
-    GrokError: View Class '<class 'grokcore.view.tests.view.dirtemplateandrender.CavePainting'>' has a render method, use CodeView instead
-
+  ConfigurationExecutionError: martian.error.GrokError: Multiple possible ways to render view
+  <class 'grokcore.view.tests.view.dirtemplateandrender.CavePainting'>.
+  It has both a 'render' method as well as an associated template.
+  in:
+  
 """
 import grokcore.view as grok
 

Deleted: grokcore.view/trunk/src/grokcore/view/tests/view/norenderinview.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/norenderinview.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/norenderinview.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -1,20 +0,0 @@
-"""
-Only a template may be specified, not a render() method.  Use CodeView if you
-want a render method.
-
-    >>> grok.testing.grok(__name__)
-    Traceback (most recent call last):
-    ...
-    GrokError: View Class '<class 'grokcore.view.tests.view.norenderinview.CavePainting'>' has a render method, use CodeView instead
-
-"""
-import grokcore.view as grok
-
-class Mammoth(grok.Context):
-    pass
-
-class CavePainting(grok.View):
-    def render(self):
-        pass
-
-cavepainting = grok.PageTemplate("nothing")

Deleted: grokcore.view/trunk/src/grokcore/view/tests/view/notemplate.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/notemplate.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/notemplate.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -1,19 +0,0 @@
-"""
-Views need an associated template.
-
-    >>> grok.testing.grok(__name__)
-    Traceback (most recent call last):
-    ...
-    ConfigurationExecutionError: <class 'martian.error.GrokError'>: View <class 'grokcore.view.tests.view.notemplate.CavePainting'> has no associated template.
-      in:
-    <BLANKLINE>    
-
-"""
-
-import grokcore.view as grok
-
-class Mammoth(grok.Context):
-    pass
-
-class CavePainting(grok.View):
-    pass

Modified: grokcore.view/trunk/src/grokcore/view/tests/view/templatenotfound.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/templatenotfound.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/templatenotfound.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -2,15 +2,13 @@
 This should fail because ``grok.template`` points to a non-existing
 template:
 
-    >>> grok.testing.grok(__name__)
-    Traceback (most recent call last):
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
     ...
-    ConfigurationExecutionError: <class 'martian.error.GrokError'>: View <class 'grokcore.view.tests.view.templatenotfound.Painting'> has no associated template.
-      in:
-      
-
+  ConfigurationExecutionError: martian.error.GrokError: View <class 'grokcore.view.tests.view.templatenotfound.Painting'>
+  has no associated template or 'render' method.
+  in:
 """
-
 import grokcore.view as grok
 
 class Mammoth(grok.Context):

Modified: grokcore.view/trunk/src/grokcore/view/tests/view/view.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/view.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/view.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -2,9 +2,6 @@
 
   >>> grok.testing.grok(__name__)
 
-  >>> from zope.interface.verify import verifyObject
-  >>> from grokcore.view.interfaces import IGrokView
-
 We should find the ``cavepainting`` view for a mammoth:
 
   >>> manfred = Mammoth()
@@ -12,23 +9,24 @@
   >>> request = TestRequest()
   >>> from zope import component
   >>> view = component.getMultiAdapter((manfred, request), name='cavepainting')
-  >>> print view()
-  A cave painting of a mammoth
+  >>> view()
+  'A cave painting of a mammoth'
 
   >>> view.context is manfred
   True
   >>> view.request is request
   True
+
+  >>> from zope.interface.verify import verifyObject
+  >>> from grokcore.view.interfaces import IGrokView
   >>> verifyObject(IGrokView, view)
   True
 
 Look up a view with a name explicitly set with ``grok.name``:
 
   >>> view = component.getMultiAdapter((manfred, request), name='meal')
-  >>> print view()
-  Mammoth burger
-  >>> verifyObject(IGrokView, view)
-  True
+  >>> view()
+  'Mammoth burger'
 
 There's no view 'food':
 
@@ -41,14 +39,20 @@
 
 import grokcore.view as grok
 
+
 class Mammoth(grok.Context):
     pass
 
+
 class CavePainting(grok.View):
-    pass
 
+    def render(self, **kwargs):
+        return 'A cave painting of a mammoth'
+
+
 class Food(grok.View):
     """Grok says: ME NO SEE MAMMOTH, ME SEE MEAL!"""
     grok.name('meal')
-    grok.template('meal')
 
+    def render(self):
+        return 'Mammoth burger'

Modified: grokcore.view/trunk/src/grokcore/view/tests/view/view_decorator.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/view_decorator.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/view_decorator.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -12,12 +12,10 @@
 import grokcore.view as grok
 import zope.interface
 
-
 class Bogus(grok.Permission):
     grok.name('bogus.perm')
 
-
-class BogusView(grok.CodeView):
+class BogusView(grok.View):
     grok.context(zope.interface.Interface)
 
     @grok.require(Bogus)

Deleted: grokcore.view/trunk/src/grokcore/view/tests/view/viewrenderbasemethod.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/viewrenderbasemethod.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/viewrenderbasemethod.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -1,28 +0,0 @@
-"""
-
-  >>> grok.testing.grok(__name__)
-
-  >>> from zope.publisher.browser import TestRequest
-  >>> from zope.component import getMultiAdapter
-
-  >>> mammoth = Mammoth()
-
-  >>> view = getMultiAdapter((mammoth, TestRequest()), name="cavepicture")
-  >>> print view()
-  <b> cave picture </b> 
-
-"""
-
-import grokcore.view as grok
-
-class Mammoth(grok.Context):
-    pass
-
-class CavePicture(grok.View):
-
-    def render(self):
-        return 'A cave painting of a mammoth'
-
-    render.base_method = True
-
-cavepicture = grok.PageTemplate('<b> cave picture </b>')	

Modified: grokcore.view/trunk/src/grokcore/view/tests/view/viewtemplateequal.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/viewtemplateequal.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/viewtemplateequal.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -30,5 +30,5 @@
     pass
 
 class CavePainting(grok.View):
-    template = grok.PageTemplate(filename='view_templates/cavepainting.pt')
+    template = grok.PageTemplate(filename='templates/cavepainting.pt')
 

Deleted: grokcore.view/trunk/src/grokcore/view/tests/view/viewwithrender.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/viewwithrender.py	2009-09-16 09:48:34 UTC (rev 104133)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/viewwithrender.py	2009-09-16 10:06:08 UTC (rev 104134)
@@ -1,18 +0,0 @@
-"""
-
-  >>> grok.testing.grok(__name__)
-  Traceback (most recent call last):
-  ...
-  GrokError: View Class '<class 'grokcore.view.tests.view.viewwithrender.CavePainting'>' has a render method, use CodeView instead
-
-"""
-
-import grokcore.view as grok
-
-class Mammoth(grok.Context):
-    pass
-
-class CavePainting(grok.View):
-
-    def render(self):
-        return 'A cave painting of a mammoth'



More information about the checkins mailing list