[Checkins] SVN: grokcore.view/trunk/ Merged r101414:101487 svn+ssh://reinout at svn.zope.org/repos/main/grokcore.view/branches/reinout-christian-codeview
Reinout van Rees
reinout at vanrees.org
Sat Jul 4 06:01:08 EDT 2009
Log message for revision 101488:
Merged r101414:101487 svn+ssh://reinout@svn.zope.org/repos/main/grokcore.view/branches/reinout-christian-codeview
Changed:
U grokcore.view/trunk/CHANGES.txt
U grokcore.view/trunk/README.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/directive.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/meta/views.py
U grokcore.view/trunk/src/grokcore/view/templatereg.py
U grokcore.view/trunk/src/grokcore/view/tests/skin/conflict.py
A grokcore.view/trunk/src/grokcore/view/tests/skin/nodouble.py
A grokcore.view/trunk/src/grokcore/view/tests/skin/nodouble_fixture.py
U grokcore.view/trunk/src/grokcore/view/tests/template/pluggability.py
A grokcore.view/trunk/src/grokcore/view/tests/view/codeview.py
A 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/eithertemplateorrender.py
A grokcore.view/trunk/src/grokcore/view/tests/view/norenderinview.py
A grokcore.view/trunk/src/grokcore/view/tests/view/notemplate.py
D grokcore.view/trunk/src/grokcore/view/tests/view/notemplateorrender.py
U grokcore.view/trunk/src/grokcore/view/tests/view/templatenotfound.py
U grokcore.view/trunk/src/grokcore/view/tests/view/view.py
U grokcore.view/trunk/src/grokcore/view/tests/view/view_decorator.py
A grokcore.view/trunk/src/grokcore/view/tests/view/viewwithrender.py
U grokcore.view/trunk/versions.cfg
-=-
Modified: grokcore.view/trunk/CHANGES.txt
===================================================================
--- grokcore.view/trunk/CHANGES.txt 2009-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/CHANGES.txt 2009-07-04 10:01:08 UTC (rev 101488)
@@ -6,6 +6,10 @@
- Add validator to templatedir directive to disallow path separator.
+- Splitted CodeView out of View. View only uses templates, CodeView only uses
+ a render() method. So views that have a render method must subclass from
+ CodeView instead of View (that should be the only change needed).
+
- Add grok.View permissions to functional tests (requires grokcore.security 1.1)
Modified: grokcore.view/trunk/README.txt
===================================================================
--- grokcore.view/trunk/README.txt 2009-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/README.txt 2009-07-04 10:01:08 UTC (rev 101488)
@@ -29,20 +29,32 @@
``grokcore.view.View`` baseclass. At a minimum, a browser page must
have
-1. either an associated template or a ``render()`` method
+1. an associated template (for a render() method, use CodeView)
2. a context that it's registered for as a view
3. a name (which is, if not specified explicitly, the class's name in
lower case characters).
+A browser page that does not use a template but just outputs some computed
+data should subclass ``grokcore.view.CodeView``. At a minimum, such a view
+must have
+
+1. a render() method
+
+2. a context that it's registered for as a view
+
+3. a name (which is, if not specified explicitly, the class's name in
+ lower case characters).
+
+
For example, the following class defines a view that's registered for
-all objects and simply prints "Hello World!"::
+all objects and simply prints "Hello World!". This is done with a CodeView::
import grokcore.view
import zope.interface
- class Hello(grokcore.view.View):
+ class Hello(grokcore.view.CodeView):
grokcore.view.context(zope.interface.Interface)
def render(self):
@@ -83,6 +95,15 @@
This will greet a logged in user with his or her actual name.
+Such a template-using page is a subclass of ``grokcore.view.View``.
+
+ import grokcore.view
+ import zope.interface
+
+ class Hello(grokcore.view.View):
+ grokcore.view.context(zope.interface.Interface)
+
+
To associate the template with the view, we have to put it in a
certain place. Let's say the ``Hello`` view class from above was in
an ``app.py`` module. Then we create an ``app_templates`` directory
@@ -174,6 +195,14 @@
associated with the view as well as the ``layer`` directive to
specify which layer it should be on if not the default layer.
+``CodeView``
+ Base class for browser pages. Use the ``context`` directive to specify
+ the view's context. Use the ``name`` directive to set the view's name; if
+ not used, the view's name will be the class's name in lower case
+ characters. The ``layer`` directive specifies which layer it should be on
+ if not the default layer.
+
+
View API
--------
@@ -214,7 +243,7 @@
Optionally, ``data`` can be a dictionary whose contents is added to
the URL as a query string.
-Methods for developers to implement:
+Method for developers to implement:
``update(**kw)``
This method will be called before the view's associated template
@@ -224,13 +253,15 @@
``view`` variable from the template. The method can take
arbitrary keyword parameters which are filled from request values.
-``render(**kw)``
- Implement this method if (and only if) there isn't a template that
- goes with the view class. Return either an encoded 8-bit string
- or a unicode string. The method can take arbitrary keyword
- parameters which are filled from request values.
+The CodeView class can have abovementioned ``update()`` method and
+additionally *has* to implement ``render()``
+``render(**kw)``
+ Return either an encoded 8-bit string or a unicode string. The method can
+ take arbitrary keyword parameters which are filled from request values.
+
+
Directives
----------
@@ -244,7 +275,7 @@
Class-level directive that specifies the name a template file
that's associated with a view class, *without* the file extension.
If not used, it defaults to the class's name in lower case
- characters.
+ characters. Only used for View, not CodeView.
``layer(layer_interface)``
Class-level directive that defines which layer the view is
@@ -288,3 +319,13 @@
.. _grokcore.component: http://pypi.python.org/pypi/grokcore.component
.. _grokcore.security: http://pypi.python.org/pypi/grokcore.security
.. _grokcore.view: http://pypi.python.org/pypi/grokcore.view
+
+
+Upgrade notice
+==============
+
+In grokcore.view 1.8, grokcore.view.View was splitted into View (that only
+works with templates) and CodeView (that only accepts a ``render()`` method).
+
+So views that have a render method must subclass from CodeView instead of
+View. That should be the only change needed.
Modified: grokcore.view/trunk/src/grokcore/view/__init__.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/__init__.py 2009-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/__init__.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -19,7 +19,7 @@
from zope.publisher.interfaces.browser import IBrowserRequest
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
-from grokcore.view.components import View
+from grokcore.view.components import View, CodeView
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-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/components.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -31,13 +31,67 @@
from grokcore.view import interfaces, util
-class View(BrowserPage):
+class BaseView(BrowserPage):
interface.implements(interfaces.IGrokView)
def __init__(self, context, request):
- super(View, self).__init__(context, request)
+ super(BaseView, self).__init__(context, request)
self.__name__ = getattr(self, '__view_name__', None)
+ def update(self):
+ pass
+
+ def redirect(self, url):
+ return self.request.response.redirect(url)
+
+ 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.
+ """
+ if isinstance(obj, basestring):
+ if name is not None:
+ raise TypeError(
+ 'url() takes either obj argument, obj, string arguments, '
+ 'or string argument')
+ name = obj
+ obj = None
+
+ if name is None and obj is None:
+ # create URL to view itself
+ obj = self
+ elif name is not None and obj is None:
+ # create URL to view on context
+ obj = self.context
+
+ if data is None:
+ data = {}
+ else:
+ if not isinstance(data, dict):
+ raise TypeError('url() data argument must be a dict.')
+
+ return util.url(self.request, obj, name, data=data)
+
+
+class CodeView(BaseView):
+
+ def __init__(self, context, request):
+ super(CodeView, self).__init__(context, request)
+
+ 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
+
+ return mapply(self.render, (), self.request)
+
+
+class View(BaseView):
+
+ def __init__(self, context, request):
+ super(View, self).__init__(context, request)
+
if getattr(self, 'module_info', None) is not None:
self.static = component.queryAdapter(
self.request,
@@ -47,6 +101,7 @@
else:
self.static = None
+ # Might be moved to BaseView currently only needed for PageTemplates CHECKTHIS
@property
def response(self):
return self.request.response
@@ -58,12 +113,6 @@
# 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):
@@ -92,40 +141,6 @@
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.
- """
- if isinstance(obj, basestring):
- if name is not None:
- raise TypeError(
- 'url() takes either obj argument, obj, string arguments, '
- 'or string argument')
- name = obj
- obj = None
-
- if name is None and obj is None:
- # create URL to view itself
- obj = self
- elif name is not None and obj is None:
- # create URL to view on context
- obj = self.context
-
- if data is None:
- data = {}
- else:
- if not isinstance(data, dict):
- raise TypeError('url() data argument must be a dict.')
-
- return util.url(self.request, obj, name, data=data)
-
- def redirect(self, url):
- return self.request.response.redirect(url)
-
- def update(self):
- pass
-
-
class BaseTemplate(object):
"""Any sort of page template"""
Modified: grokcore.view/trunk/src/grokcore/view/directive.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/directive.py 2009-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/directive.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -28,25 +28,30 @@
% directive.name)
# Define grok directives
+
class template(martian.Directive):
scope = martian.CLASS
store = martian.ONCE
validate = martian.validateText
+
class templatedir(martian.Directive):
scope = martian.MODULE
store = martian.ONCE
validate = validateLocalPath
+
class OneInterfaceOrClassOnClassOrModule(martian.Directive):
"""Convenience base class. Not for public use."""
scope = martian.CLASS_OR_MODULE
store = martian.ONCE
validate = martian.validateInterfaceOrClass
+
class layer(OneInterfaceOrClassOnClassOrModule):
pass
+
class TaggedValueStoreOnce(StoreOnce):
"""Stores the directive value in a interface tagged value.
"""
@@ -55,7 +60,8 @@
return component.queryTaggedValue(directive.dotted_name(), default)
def set(self, locals_, directive, value):
- if directive.dotted_name() in locals_:
+ already_set = locals_.get('__interface_tagged_values__', [])
+ if directive.dotted_name() in already_set:
raise GrokImportError(
"The '%s' directive can only be called once per %s." %
(directive.name, directive.scope.description))
@@ -70,6 +76,7 @@
def setattr(self, context, directive, value):
context.setTaggedValue(directive.dotted_name(), value)
+
class skin(martian.Directive):
# We cannot do any better than to check for a class scope. Ideally we
# would've checked whether the context is indeed an Interface class.
@@ -77,6 +84,7 @@
store = TaggedValueStoreOnce()
validate = martian.validateText
+
class path(martian.Directive):
scope = martian.CLASS
store = martian.ONCE
Modified: grokcore.view/trunk/src/grokcore/view/ftests/url/redirect.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/ftests/url/redirect.py 2009-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/ftests/url/redirect.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -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.View):
+class Index(grok.CodeView):
def render(self):
self.redirect(self.url('another'))
-class Another(grok.View):
+class Another(grok.CodeView):
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-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/ftests/url/url.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -180,18 +180,18 @@
grok.context(Mammoth)
-class Index(grok.View):
+class Index(grok.CodeView):
def render(self):
return self.url()
-class Another(grok.View):
+class Another(grok.CodeView):
def render(self):
return self.url()
class YetAnother(grok.View):
pass
-class Multiplier(grok.View):
+class Multiplier(grok.CodeView):
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-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/ftests/url/url_function.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -61,20 +61,26 @@
>>> 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.View):
+
+class Index(grok.CodeView):
def render(self):
return url(self.request, self)
+
class Another(grok.View):
- def render(self):
- return url(self.request, self)
+ pass
+
+
+another = grok.PageTemplate('<p tal:replace="view/url" />')
Modified: grokcore.view/trunk/src/grokcore/view/ftests/view/argument.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/ftests/view/argument.py 2009-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/ftests/view/argument.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -49,15 +49,18 @@
"""
import grokcore.view as grok
+
class Mammoth(grok.Context):
pass
-class RenderWithArguments(grok.View):
+
+class RenderWithArguments(grok.CodeView):
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')
@@ -66,6 +69,7 @@
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-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/ftests/view/macros.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -19,7 +19,8 @@
>>> browser.open("http://localhost/manfred/@@dancing")
Traceback (most recent call last):
- AttributeError: 'DancingHall' object has no attribute 'template'
+ ...
+ TraversalError: (<grokcore.view.ftests.view.macros.DancingHall object at ...>, 'macros')
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.
@@ -71,26 +72,36 @@
>>> 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 "A nice large dancing hall for mammoths."
+ return "Bla Bla Dancing Hall"
+
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">
@@ -99,38 +110,40 @@
</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-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/ftests/view/require.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -27,17 +27,20 @@
import grokcore.view as grok
import zope.interface
+
class ViewPainting(grok.Permission):
grok.name('cave.ViewPainting')
-class Painting(grok.View):
+
+class Painting(grok.CodeView):
grok.context(zope.interface.Interface)
grok.require(ViewPainting)
def render(self):
return 'What a beautiful painting.'
-class PublicNudity(grok.View):
+
+class PublicNudity(grok.CodeView):
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-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/ftests/view/skindirective.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -47,14 +47,14 @@
</html>
""")
-class MoreDrawings(grok.View):
+class MoreDrawings(grok.CodeView):
grok.layer(rotterdam)
def render(self):
return "Pretty"
-class EvenMoreDrawings(grok.View):
+class EvenMoreDrawings(grok.CodeView):
grok.layer(MySkinLayer)
def render(self):
Modified: grokcore.view/trunk/src/grokcore/view/meta/views.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/meta/views.py 2009-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/meta/views.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -46,14 +46,18 @@
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:
+ raise GrokError("View Class '%s' has a render method, use CodeView instead" % factory, factory)
+
# 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=(templates, factory.module_info, factory)
+ )
# safety belt: make sure that the programmer didn't use
# @grok.require on any of the view's methods.
@@ -76,21 +80,63 @@
)
return True
+
+ # CHECK THIS. There is no template/render checking anymore, so this is a bit
+ # elaborate.
def checkTemplates(self, templates, module_info, factory):
def has_render(factory):
- render = getattr(factory, 'render', None)
- base_method = getattr(render, 'base_method', False)
- return render and not base_method
+ return False
def has_no_render(factory):
- return not getattr(factory, 'render', None)
+ return True
templates.checkTemplates(module_info, factory, 'view',
has_render, has_no_render)
+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 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.View)
+ martian.component(components.BaseView)
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-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/templatereg.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -107,6 +107,7 @@
% (component_name, factory, template_name,
factory_name), factory)
template = self.get(template_name)
+ # TODO: strip render
if template is not None:
if has_render(factory):
# we do not accept render and template both for a view
@@ -122,8 +123,7 @@
else:
if has_no_render(factory):
# we do not accept a view without any way to render it
- raise GrokError("%s %r has no associated template or "
- "'render' method." %
+ raise GrokError("%s %r has no associated template." %
(component_name.title(), factory), factory)
class PageTemplateFileFactory(grokcore.component.GlobalUtility):
Modified: grokcore.view/trunk/src/grokcore/view/tests/skin/conflict.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/skin/conflict.py 2009-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/tests/skin/conflict.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -10,8 +10,10 @@
import grokcore.view as grok
+
class Skin1(grok.IBrowserRequest):
grok.skin('foo')
+
class Skin2(grok.IBrowserRequest):
grok.skin('foo')
Copied: grokcore.view/trunk/src/grokcore/view/tests/skin/nodouble.py (from rev 101487, grokcore.view/branches/reinout-christian-codeview/src/grokcore/view/tests/skin/nodouble.py)
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/skin/nodouble.py (rev 0)
+++ grokcore.view/trunk/src/grokcore/view/tests/skin/nodouble.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -0,0 +1,9 @@
+"""
+We cannot register two skins under the same name::
+
+ >>> from grokcore.view.tests.skin import nodouble_fixture
+ Traceback (most recent call last):
+ ...
+ GrokImportError: The 'skin' directive can only be called once per class.
+
+"""
Copied: grokcore.view/trunk/src/grokcore/view/tests/skin/nodouble_fixture.py (from rev 101487, grokcore.view/branches/reinout-christian-codeview/src/grokcore/view/tests/skin/nodouble_fixture.py)
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/skin/nodouble_fixture.py (rev 0)
+++ grokcore.view/trunk/src/grokcore/view/tests/skin/nodouble_fixture.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -0,0 +1,6 @@
+import grokcore.view as grok
+
+
+class Skin1(grok.IBrowserRequest):
+ grok.skin('foo')
+ grok.skin('bar')
Modified: grokcore.view/trunk/src/grokcore/view/tests/template/pluggability.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/template/pluggability.py 2009-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/tests/template/pluggability.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -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,14 +33,15 @@
# 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):
@@ -70,19 +71,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'}
Copied: grokcore.view/trunk/src/grokcore/view/tests/view/codeview.py (from rev 101487, grokcore.view/branches/reinout-christian-codeview/src/grokcore/view/tests/view/codeview.py)
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/codeview.py (rev 0)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/codeview.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -0,0 +1,24 @@
+"""
+
+ >>> grok.testing.grok(__name__)
+
+ >>> from zope.publisher.browser import TestRequest
+ >>> from zope.component import getMultiAdapter
+
+ >>> mammoth = Mammoth()
+
+ >>> code_view = getMultiAdapter((mammoth, TestRequest()), name="cavepainting")
+ >>> print code_view()
+ A cave painting of a mammoth
+
+"""
+
+import grokcore.view as grok
+
+class Mammoth(grok.Context):
+ pass
+
+class CavePainting(grok.CodeView):
+
+ def render(self):
+ return 'A cave painting of a mammoth'
Copied: grokcore.view/trunk/src/grokcore/view/tests/view/codeviewnorender.py (from rev 101487, grokcore.view/branches/reinout-christian-codeview/src/grokcore/view/tests/view/codeviewnorender.py)
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/codeviewnorender.py (rev 0)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/codeviewnorender.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -0,0 +1,16 @@
+"""
+
+ >>> 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-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/dirtemplateandrender.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -1,15 +1,13 @@
"""
-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:
+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:
- >>> grok.testing.grok(__name__)
- Traceback (most recent call last):
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
...
- 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:
-
+ GrokError: View Class '<class 'grokcore.view.tests.view.dirtemplateandrender.CavePainting'>' has a render method, use CodeView instead
+
"""
import grokcore.view as grok
Deleted: grokcore.view/trunk/src/grokcore/view/tests/view/eithertemplateorrender.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/eithertemplateorrender.py 2009-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/eithertemplateorrender.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -1,21 +0,0 @@
-"""
-Only one, either a template, or render() can be specified:
-
- >>> grok.testing.grok(__name__)
- Traceback (most recent call last):
- ...
- ConfigurationExecutionError: martian.error.GrokError: Multiple possible ways to render view
- <class 'grokcore.view.tests.view.eithertemplateorrender.CavePainting'>.
- It has both a 'render' method as well as an associated template.
- in:
-"""
-import grokcore.view as grok
-
-class Mammoth(grok.Context):
- pass
-
-class CavePainting(grok.View):
- def render(self):
- pass
-
-cavepainting = grok.PageTemplate("nothing")
Copied: grokcore.view/trunk/src/grokcore/view/tests/view/norenderinview.py (from rev 101487, grokcore.view/branches/reinout-christian-codeview/src/grokcore/view/tests/view/norenderinview.py)
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/norenderinview.py (rev 0)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/norenderinview.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -0,0 +1,20 @@
+"""
+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")
Copied: grokcore.view/trunk/src/grokcore/view/tests/view/notemplate.py (from rev 101487, grokcore.view/branches/reinout-christian-codeview/src/grokcore/view/tests/view/notemplate.py)
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/notemplate.py (rev 0)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/notemplate.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -0,0 +1,19 @@
+"""
+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
Deleted: grokcore.view/trunk/src/grokcore/view/tests/view/notemplateorrender.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/notemplateorrender.py 2009-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/notemplateorrender.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -1,19 +0,0 @@
-"""
-Views either need an associated template or a ``render`` method:
-
- >>> grok.testing.grok(__name__)
- Traceback (most recent call last):
- ...
- ConfigurationExecutionError: martian.error.GrokError: View <class 'grokcore.view.tests.view.notemplateorrender.CavePainting'>
- has no associated template or 'render' method.
- in:
-
-"""
-
-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-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/templatenotfound.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -2,13 +2,15 @@
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: martian.error.GrokError: View <class 'grokcore.view.tests.view.templatenotfound.Painting'>
- has no associated template or 'render' method.
- in:
+ ConfigurationExecutionError: <class 'martian.error.GrokError'>: View <class 'grokcore.view.tests.view.templatenotfound.Painting'> has no associated template.
+ 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-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/view.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -37,12 +37,12 @@
class Mammoth(grok.Context):
pass
-class CavePainting(grok.View):
+class CavePainting(grok.CodeView):
def render(self):
return 'A cave painting of a mammoth'
-class Food(grok.View):
+class Food(grok.CodeView):
"""Grok says: ME NO SEE MAMMOTH, ME SEE MEAL!"""
grok.name('meal')
Modified: grokcore.view/trunk/src/grokcore/view/tests/view/view_decorator.py
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/view_decorator.py 2009-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/view_decorator.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -12,10 +12,12 @@
import grokcore.view as grok
import zope.interface
+
class Bogus(grok.Permission):
grok.name('bogus.perm')
-class BogusView(grok.View):
+
+class BogusView(grok.CodeView):
grok.context(zope.interface.Interface)
@grok.require(Bogus)
Copied: grokcore.view/trunk/src/grokcore/view/tests/view/viewwithrender.py (from rev 101487, grokcore.view/branches/reinout-christian-codeview/src/grokcore/view/tests/view/viewwithrender.py)
===================================================================
--- grokcore.view/trunk/src/grokcore/view/tests/view/viewwithrender.py (rev 0)
+++ grokcore.view/trunk/src/grokcore/view/tests/view/viewwithrender.py 2009-07-04 10:01:08 UTC (rev 101488)
@@ -0,0 +1,18 @@
+"""
+
+ >>> 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'
Modified: grokcore.view/trunk/versions.cfg
===================================================================
--- grokcore.view/trunk/versions.cfg 2009-07-04 09:53:09 UTC (rev 101487)
+++ grokcore.view/trunk/versions.cfg 2009-07-04 10:01:08 UTC (rev 101488)
@@ -102,7 +102,7 @@
zope.tal = 3.4.1
zope.tales = 3.4.0
zope.testbrowser = 3.4.2
-zope.testing = 3.5.6
+zope.testing = 3.7.5
zope.thread = 3.4
zope.traversing = 3.4.1
zope.viewlet = 3.4.2
More information about the Checkins
mailing list