[Checkins] SVN: grok/branches/darrylcousins-martian-layers/ Making
a start working on viewlet/layer pattern used by form demo
Darryl Cousins
darryl at darrylcousins.net.nz
Sat Jun 30 08:37:37 EDT 2007
Log message for revision 77268:
Making a start working on viewlet/layer pattern used by form demo
Changed:
U grok/branches/darrylcousins-martian-layers/buildout.cfg
U grok/branches/darrylcousins-martian-layers/ftesting.zcml
U grok/branches/darrylcousins-martian-layers/martian/src/martian/directive.py
U grok/branches/darrylcousins-martian-layers/martian/src/martian/directive.txt
U grok/branches/darrylcousins-martian-layers/setup.py
U grok/branches/darrylcousins-martian-layers/src/grok/__init__.py
U grok/branches/darrylcousins-martian-layers/src/grok/components.py
U grok/branches/darrylcousins-martian-layers/src/grok/directive.py
U grok/branches/darrylcousins-martian-layers/src/grok/ftests/test_grok_functional.py
U grok/branches/darrylcousins-martian-layers/src/grok/meta.py
-=-
Modified: grok/branches/darrylcousins-martian-layers/buildout.cfg
===================================================================
--- grok/branches/darrylcousins-martian-layers/buildout.cfg 2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/buildout.cfg 2007-06-30 12:37:37 UTC (rev 77268)
@@ -1,5 +1,5 @@
[buildout]
-develop = . grokwiki ldapaddressbook martian
+develop = . grokwiki ldapaddressbook martian demo
parts = app data instance test devpython
find-links = http://download.zope.org/distribution/
@@ -11,15 +11,18 @@
eggs = grok
grokwiki
martian
+ demo
recipe = zc.zope3recipes:app
site.zcml = <include package="zope.security" file="meta.zcml" />
<include package="zope.i18n" file="meta.zcml" />
<include package="zope.app.securitypolicy" file="meta.zcml" />
<include package="zope.app.zcmlfiles" file="meta.zcml" />
+ <include package="zope.viewlet" file="meta.zcml" />
<include package="grok" file="meta.zcml" />
<include package="zope.annotation" />
<include package="zope.copypastemove" />
+ <include package="zope.contentprovider" />
<include package="zope.formlib" />
<include package="zope.i18n.locales" />
<include package="zope.publisher" />
@@ -27,6 +30,7 @@
<include package="zope.traversing" />
<include package="zope.traversing.browser" />
<include package="zope.publisher" />
+ <include package="zope.viewlet" />
<include package="zope.app.zcmlfiles" />
<include package="zope.app.securitypolicy" />
<include package="zope.app.authentication" />
@@ -34,9 +38,9 @@
<include package="zope.app.intid" />
<include package="zope.app.keyreference" />
<include package="zope.app.twisted" />
- <include package="martian" />
<include package="grok" />
<include package="grokwiki" />
+ <include package="demo" />
<securityPolicy
component="zope.app.securitypolicy.zopepolicy.ZopeSecurityPolicy" />
@@ -81,6 +85,7 @@
recipe = zc.recipe.testrunner
eggs = grok
martian
+ demo
defaults = ['--tests-pattern', '^f?tests$', '-v']
# installs bin/devpython to do simple interpreter tests
Modified: grok/branches/darrylcousins-martian-layers/ftesting.zcml
===================================================================
--- grok/branches/darrylcousins-martian-layers/ftesting.zcml 2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/ftesting.zcml 2007-06-30 12:37:37 UTC (rev 77268)
@@ -8,12 +8,14 @@
<!-- used for functional testing setup -->
<include package="zope.security" file="meta.zcml" />
<include package="zope.i18n" file="meta.zcml" />
+ <include package="zope.viewlet" file="meta.zcml" />
<include package="zope.app.securitypolicy" file="meta.zcml" />
<include package="zope.app.zcmlfiles" file="meta.zcml" />
<include package="grok" file="meta.zcml" />
<include package="zope.annotation" />
<include package="zope.copypastemove" />
+ <include package="zope.contentprovider" />
<include package="zope.formlib" />
<include package="zope.i18n.locales" />
<include package="zope.publisher" />
@@ -21,6 +23,7 @@
<include package="zope.traversing" />
<include package="zope.traversing.browser" />
<include package="zope.publisher" />
+ <include package="zope.viewlet" />
<include package="zope.app.zcmlfiles" />
<include package="zope.app.securitypolicy" />
<include package="zope.app.authentication" />
Modified: grok/branches/darrylcousins-martian-layers/martian/src/martian/directive.py
===================================================================
--- grok/branches/darrylcousins-martian-layers/martian/src/martian/directive.py 2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/martian/src/martian/directive.py 2007-06-30 12:37:37 UTC (rev 77268)
@@ -161,7 +161,17 @@
Directive that accepts a single unicode/ASCII value, only once.
"""
+class SingleIntegerDirective(SingleValue, OnceDirective):
+ """
+ Directive that accepts a single integer value, only once.
+ """
+ def check_arguments(self, value):
+ if not int(value) == value:
+ raise GrokImportError("You can only pass an integer to "
+ "%s." % self.name)
+
+
class MultipleTextDirective(BaseTextDirective, SingleValue,
MultipleTimesDirective):
"""
Modified: grok/branches/darrylcousins-martian-layers/martian/src/martian/directive.txt
===================================================================
--- grok/branches/darrylcousins-martian-layers/martian/src/martian/directive.txt 2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/martian/src/martian/directive.txt 2007-06-30 12:37:37 UTC (rev 77268)
@@ -80,6 +80,23 @@
>>> classormodulecontext.__grok_qux__
'hello world'
+Now let's define an integer directive::
+
+ >>> from martian.directive import SingleIntegerDirective
+ >>> weight = SingleIntegerDirective('grok.weight', ClassDirectiveContext())
+ >>> class Test(object):
+ ... weight('2')
+ Traceback (most recent call last):
+ ...
+ GrokImportError: You can only pass an integer to grok.weight.
+
+Integers only are allowed::
+
+ >>> class Test(object):
+ ... weight(2)
+ >>> Test.__grok_weight__
+ 2
+
Calling a directive once or multiple times
------------------------------------------
Modified: grok/branches/darrylcousins-martian-layers/setup.py
===================================================================
--- grok/branches/darrylcousins-martian-layers/setup.py 2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/setup.py 2007-06-30 12:37:37 UTC (rev 77268)
@@ -30,6 +30,7 @@
'zope.app.publisher',
'zope.app.testing',
'zope.component',
+ 'zope.contentprovider',
'zope.configuration',
'zope.dottedname',
'zope.event',
@@ -42,10 +43,14 @@
'zope.security',
'zope.testing',
'zope.traversing',
+ 'zope.viewlet',
+ 'z3c.viewlet',
+
# needed for ftests and typical deployments
'zope.testbrowser',
'zope.app.twisted',
'zope.app.securitypolicy',
- 'zope.app.zcmlfiles'],
+ 'zope.app.zcmlfiles',
+ ],
)
Modified: grok/branches/darrylcousins-martian-layers/src/grok/__init__.py
===================================================================
--- grok/branches/darrylcousins-martian-layers/src/grok/__init__.py 2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/src/grok/__init__.py 2007-06-30 12:37:37 UTC (rev 77268)
@@ -35,9 +35,11 @@
from grok.components import Site, GlobalUtility, LocalUtility, Annotation
from grok.components import Application, Form, AddForm, EditForm, DisplayForm
from grok.components import Indexes, Skin, ILayer
+from grok.components import Viewlet, ViewletManager, ContentProvider
from grok.directive import (context, name, template, templatedir, provides,
baseclass, global_utility, local_utility,
- define_permission, require, site, layer)
+ define_permission, require, site, layer,
+ viewletmanager, talnamespace, weight)
from grok._grok import do_grok as grok # Avoid name clash within _grok
from grok._grok import grok_component
from grok._grok import SubscribeDecorator as subscribe
Modified: grok/branches/darrylcousins-martian-layers/src/grok/components.py
===================================================================
--- grok/branches/darrylcousins-martian-layers/src/grok/components.py 2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/src/grok/components.py 2007-06-30 12:37:37 UTC (rev 77268)
@@ -51,6 +51,11 @@
from zope.app.container.interfaces import IReadContainer
from zope.app.component.site import SiteManagerContainer
+from zope.viewlet.manager import ViewletManagerBase
+from zope.viewlet.viewlet import ViewletBase
+
+from z3c.viewlet.manager import WeightOrderedViewletManager
+
from martian import util
from grok import interfaces, formlib
@@ -97,46 +102,40 @@
pass
-class View(BrowserPage):
- interface.implements(interfaces.IGrokView)
+class ViewBase(object):
- def __init__(self, context, request):
- super(View, self).__init__(context, request)
- self.static = component.queryAdapter(
- self.request,
- interface.Interface,
- name=self.module_info.package_dotted_name
- )
-
- @property
- def response(self):
- return self.request.response
-
- 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):
namespace = self.template.pt_getContext()
namespace['request'] = self.request
namespace['view'] = self
namespace['context'] = self.context
- # XXX need to check whether we really want to put None here if missing
namespace['static'] = self.static
return self.template.pt_render(namespace)
- def __getitem__(self, key):
- # XXX give nice error message if template is None
- return self.template.macros[key]
+ def application(self):
+ obj = self.context
+ while obj is not None:
+ if isinstance(obj, Application):
+ return obj
+ obj = obj.__parent__
+ raise ValueErrror("No application found.")
+ def site(self):
+ obj = self.context
+ while obj is not None:
+ if isinstance(obj, grok.Site):
+ return obj
+ obj = obj.__parent__
+ raise ValueErrror("No site found.")
+
+ def application_url(self, name=None):
+ obj = self.context
+ while obj is not None:
+ if isinstance(obj, Application):
+ return self.url(obj, name)
+ obj = obj.__parent__
+ raise ValueErrror("No application found.")
+
def url(self, obj=None, name=None):
# if the first argument is a string, that's the name. There should
# be no second argument
@@ -155,18 +154,42 @@
# create URL to view on context
obj = self.context
return url(self.request, obj, name)
-
- def application_url(self, name=None):
- obj = self.context
- while obj is not None:
- if isinstance(obj, Application):
- return self.url(obj, name)
- obj = obj.__parent__
- raise ValueError("No application found.")
-
+
def redirect(self, url):
return self.request.response.redirect(url)
+
+ @property
+ def response(self):
+ return self.request.response
+
+class View(BrowserPage, ViewBase):
+ interface.implements(interfaces.IGrokView)
+
+ def __init__(self, context, request):
+ super(View, self).__init__(context, request)
+ self.static = component.queryAdapter(
+ self.request,
+ interface.Interface,
+ name=self.module_info.package_dotted_name
+ )
+
+ 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 __getitem__(self, key):
+ # XXX give nice error message if template is None
+ return self.template.macros[key]
+
def update(self):
pass
@@ -472,3 +495,69 @@
class Skin(object):
pass
+class TemplateContentBase(object):
+ """Mixin class to provide render method using given template"""
+
+ def render(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()
+
+
+class ContentProvider(ViewBase, TemplateContentBase):
+
+ def __init__(self, context, request, view):
+ self.__parent__ = view
+ self.context = context
+ self.request = request
+ self.static = component.queryAdapter(
+ self.request,
+ interface.Interface,
+ name=self.module_info.package_dotted_name
+ )
+ return self.request.response
+
+# use z3c orderedviewletmanager
+class ViewletManager(WeightOrderedViewletManager, ViewBase):
+ """ A grok.View-like ViewletManager
+ """
+ template = None
+
+ def __init__(self, context, request, view):
+ super(ViewletManager, self).__init__(context, request, view)
+ self.static = component.queryAdapter(
+ self.request,
+ interface.Interface,
+ name=self.module_info.package_dotted_name
+ )
+
+ def update(self):
+ super(WeightOrderedViewletManager, self).update()
+
+ def render(self):
+ # Now render the view
+ template = getattr(self, 'template', None)
+ if template is not None:
+ return self._render_template()
+ else:
+ return u'\n'.join([viewlet.render() for viewlet in self.viewlets])
+
+
+class Viewlet(ViewletBase, ViewBase, TemplateContentBase):
+ """ A grok.View-like viewlet
+ """
+
+ def __init__(self, context, request, view, manager):
+ super(Viewlet, self).__init__(context, request, view, manager)
+ self.static = component.queryAdapter(
+ self.request,
+ interface.Interface,
+ name=self.module_info.package_dotted_name
+ )
+
Modified: grok/branches/darrylcousins-martian-layers/src/grok/directive.py
===================================================================
--- grok/branches/darrylcousins-martian-layers/src/grok/directive.py 2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/src/grok/directive.py 2007-06-30 12:37:37 UTC (rev 77268)
@@ -19,6 +19,7 @@
from martian.error import GrokImportError
from martian.directive import (MultipleTimesDirective, BaseTextDirective,
SingleValue, SingleTextDirective,
+ SingleIntegerDirective,
MultipleTextDirective,
MarkerDirective,
InterfaceDirective,
@@ -112,3 +113,8 @@
ClassDirectiveContext())
layer = InterfaceOrClassDirective('grok.layer',
ClassOrModuleDirectiveContext())
+viewletmanager = InterfaceOrClassDirective('grok.viewletmanager',
+ ClassDirectiveContext())
+talnamespace = InterfaceDirective('grok.talnamespace',
+ ClassDirectiveContext())
+weight = SingleIntegerDirective('grok.weight', ClassDirectiveContext())
Modified: grok/branches/darrylcousins-martian-layers/src/grok/ftests/test_grok_functional.py
===================================================================
--- grok/branches/darrylcousins-martian-layers/src/grok/ftests/test_grok_functional.py 2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/src/grok/ftests/test_grok_functional.py 2007-06-30 12:37:37 UTC (rev 77268)
@@ -42,6 +42,7 @@
def suiteFromPackage(name):
files = resource_listdir(__name__, name)
+ files = ['viewletmanager.py']
suite = unittest.TestSuite()
for filename in files:
if not filename.endswith('.py'):
@@ -55,10 +56,12 @@
suite.addTest(test)
return suite
+all = ['view', 'static', 'xmlrpc', 'traversal', 'form', 'url',
+ 'security', 'utility', 'catalog', 'admin']
+all = ['view']
def test_suite():
suite = unittest.TestSuite()
- for name in ['view', 'static', 'xmlrpc', 'traversal', 'form', 'url',
- 'security', 'utility', 'catalog', 'admin']:
+ for name in all:
suite.addTest(suiteFromPackage(name))
return suite
Modified: grok/branches/darrylcousins-martian-layers/src/grok/meta.py
===================================================================
--- grok/branches/darrylcousins-martian-layers/src/grok/meta.py 2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/src/grok/meta.py 2007-06-30 12:37:37 UTC (rev 77268)
@@ -4,6 +4,7 @@
from zope import interface, component
from zope.publisher.interfaces.browser import (IDefaultBrowserLayer,
IBrowserRequest,
+ IBrowserView,
IBrowserPublisher,
IBrowserSkinType)
from zope.publisher.interfaces.xmlrpc import IXMLRPCRequest
@@ -22,6 +23,7 @@
from zope.app.catalog.interfaces import ICatalog
from zope.exceptions.interfaces import DuplicationError
+from zope.contentprovider.interfaces import IContentProvider
import martian
from martian.error import GrokError
@@ -196,7 +198,62 @@
% (method.__name__, factory), factory)
return True
+class ContentProviderGrokker(martian.ClassGrokker):
+ component_class = grok.ContentProvider
+ def grok(self, name, factory, context, module_info, templates):
+ view_context = util.determine_class_context(factory, context)
+
+ factory.module_info = module_info
+ factory_name = factory.__name__.lower()
+
+ # find templates
+ template_name = util.class_annotation(factory, 'grok.template',
+ factory_name)
+ template = templates.get(template_name)
+
+ if factory_name != template_name:
+ # grok.template is being used
+ if templates.get(factory_name):
+ raise GrokError("Multiple possible templates for view %r. It "
+ "uses grok.template('%s'), but there is also "
+ "a template called '%s'."
+ % (factory, template_name, factory_name),
+ factory)
+
+ if template:
+ templates.markAssociated(template_name)
+ factory.template = template
+
+ view_layer = util.class_annotation(factory, 'grok.layer',
+ None) or module_info.getAnnotation('grok.layer',
+ None) or IDefaultBrowserLayer
+
+ view_name = util.class_annotation(factory, 'grok.name',
+ factory_name)
+ # __view_name__ is needed to support IAbsoluteURL on views
+ factory.__view_name__ = view_name
+ component.provideAdapter(factory,
+ adapts=(view_context, view_layer, IBrowserView),
+ provides=IContentProvider,
+ name=view_name)
+
+ # protect view, public by default
+ default_permission = get_default_permission(factory)
+ make_checker(factory, factory, default_permission)
+
+ # 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 getattr(method, '__grok_require__', None) 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)
+ return True
+
+
class JSONGrokker(martian.ClassGrokker):
component_class = grok.JSON
@@ -614,3 +671,4 @@
zope.component.interface.provideInterface(name, layer, IBrowserSkinType)
return True
+
More information about the Checkins
mailing list