summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-09-20 22:13:11 +0000
committerChris McDonough <chrism@agendaless.com>2009-09-20 22:13:11 +0000
commite4610566d881f707c01d266a7e336084029c83e4 (patch)
tree0a2001361b14e5b0b7521164e67560e2763e4c3c
parent160f01439dc3e0d865b2e77bb4a9a7c9e7a16c1a (diff)
downloadpyramid-e4610566d881f707c01d266a7e336084029c83e4.tar.gz
pyramid-e4610566d881f707c01d266a7e336084029c83e4.tar.bz2
pyramid-e4610566d881f707c01d266a7e336084029c83e4.zip
- The way ``bfg_view`` declarations are scanned for has been modified.
This should have no external effects. - An object implementing the ``IRenderer`` interface (and ``ITemplateRenderer`, which is a subclass of ``IRenderer``) must now accept an extra ``system`` argument in its ``__call__`` method implementation. Values computed by the system (as opposed to by the view) are passed by the system in the ``system`` parameter, which will always be a dictionary. Keys in the dictionary include: ``view`` (the view object that returned the value), ``renderer_name`` (the template name or simple name of the renderer), ``context`` (the context object passed to the view), and ``request`` (the request object passed to the view). Previously only ITemplateRenderers received system arguments as elements inside the main ``value`` dictionary.
-rw-r--r--CHANGES.txt32
-rw-r--r--repoze/bfg/chameleon_text.py13
-rw-r--r--repoze/bfg/chameleon_zpt.py13
-rw-r--r--repoze/bfg/interfaces.py11
-rw-r--r--repoze/bfg/renderers.py12
-rw-r--r--repoze/bfg/testing.py2
-rw-r--r--repoze/bfg/tests/grokkedapp/__init__.py39
-rw-r--r--repoze/bfg/tests/grokkedapp/another.py39
-rw-r--r--repoze/bfg/tests/test_chameleon_text.py23
-rw-r--r--repoze/bfg/tests/test_chameleon_zpt.py19
-rw-r--r--repoze/bfg/tests/test_integration.py117
-rw-r--r--repoze/bfg/tests/test_renderers.py12
-rw-r--r--repoze/bfg/tests/test_testing.py2
-rw-r--r--repoze/bfg/tests/test_traversal.py5
-rw-r--r--repoze/bfg/tests/test_view.py152
-rw-r--r--repoze/bfg/tests/test_zcml.py19
-rw-r--r--repoze/bfg/traversal.py5
-rw-r--r--repoze/bfg/view.py70
-rw-r--r--repoze/bfg/zcml.py77
19 files changed, 394 insertions, 268 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 1de84f7d0..e6b44519c 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -31,6 +31,28 @@ Features
``view_renderer`` parameters (bring up to speed with 1.1a3
features). These can also be spelled as ``attr`` and ``renderer``.
+Backwards Incompatibilities
+---------------------------
+
+- An object implementing the ``IRenderer`` interface (and
+ ``ITemplateRenderer`, which is a subclass of ``IRenderer``) must now
+ accept an extra ``system`` argument in its ``__call__`` method
+ implementation. Values computed by the system (as opposed to by the
+ view) are passed by the system in the ``system`` parameter, which
+ will always be a dictionary. Keys in the dictionary include:
+ ``view`` (the view object that returned the value),
+ ``renderer_name`` (the template name or simple name of the
+ renderer), ``context`` (the context object passed to the view), and
+ ``request`` (the request object passed to the view). Previously
+ only ITemplateRenderers received system arguments as elements inside
+ the main ``value`` dictionary.
+
+Internal
+--------
+
+- The way ``bfg_view`` declarations are scanned for has been modified.
+ This should have no external effects.
+
- Speed: do not register an ITraverserFactory in configure.zcml;
instead rely on queryAdapter and a manual default to
ModelGraphTraverser.
@@ -41,6 +63,7 @@ Features
- General speed microimprovements for helloworld benchmark: replace
try/excepts with statements which use 'in' keyword.
+
1.1a3 (2009-09-16)
==================
@@ -115,12 +138,15 @@ Backwards Incompatibilities
- The ``ITemplateRenderer`` interface has been changed. Previously
its ``__call__`` method accepted ``**kw``. It now accepts a single
- positional parameter named ``kw``. This is mostly an internal
- change, but it was exposed in APIs in one place: if you've used the
+ positional parameter named ``kw`` (REVISED: it accepts two
+ positional parameters as of 1.1a4: ``value`` and ``system``). This
+ is mostly an internal change, but it was exposed in APIs in one
+ place: if you've used the
``repoze.bfg.testing.registerDummyRenderer`` API in your tests with
a custom "renderer" argument with your own renderer implementation,
you will need to change that renderer implementation to accept
- ``kw`` instead of ``**kw`` in its ``__call__`` method.
+ ``kw`` instead of ``**kw`` in its ``__call__`` method (REVISED: make
+ it accept ``value`` and ``system`` positional arguments as of 1.1a4).
- The ``ITemplateRendererFactory`` interface has been changed.
Previously its ``__call__`` method accepted an ``auto_reload``
diff --git a/repoze/bfg/chameleon_text.py b/repoze/bfg/chameleon_text.py
index 7910746ac..9b81c4469 100644
--- a/repoze/bfg/chameleon_text.py
+++ b/repoze/bfg/chameleon_text.py
@@ -35,8 +35,13 @@ class TextTemplateRenderer(object):
def implementation(self):
return self.template
- def __call__(self, kw):
- return self.template(**kw)
+ def __call__(self, value, system):
+ try:
+ system.update(value)
+ except TypeError:
+ raise ValueError('renderer was passed non-dictionary as value')
+ result = self.template(**system)
+ return result
def get_renderer(path):
""" Return a callable ``ITemplateRenderer`` object representing a
@@ -55,7 +60,7 @@ def render_template(path, **kw):
path (may also be absolute) using the kwargs in ``*kw`` as
top-level names and return a string."""
renderer = renderer_factory(path)
- return renderer(kw)
+ return renderer(kw, {})
def render_template_to_response(path, **kw):
""" Render a ``chameleon`` text template at the package-relative
@@ -63,6 +68,6 @@ def render_template_to_response(path, **kw):
top-level names and return a Response object with the body as the
template result."""
renderer = renderer_factory(path)
- result = renderer(kw)
+ result = renderer(kw, {})
response_factory = queryUtility(IResponseFactory, default=Response)
return response_factory(result)
diff --git a/repoze/bfg/chameleon_zpt.py b/repoze/bfg/chameleon_zpt.py
index 6fcdd9dad..ca9e743e0 100644
--- a/repoze/bfg/chameleon_zpt.py
+++ b/repoze/bfg/chameleon_zpt.py
@@ -24,8 +24,13 @@ class ZPTTemplateRenderer(object):
def implementation(self):
return self.template
- def __call__(self, kw):
- return self.template(**kw)
+ def __call__(self, value, system):
+ try:
+ system.update(value)
+ except TypeError:
+ raise ValueError('renderer was passed non-dictionary as value')
+ result = self.template(**system)
+ return result
def get_renderer(path):
""" Return a callable ``ITemplateRenderer`` object representing a
@@ -44,7 +49,7 @@ def render_template(path, **kw):
path (may also be absolute) using the kwargs in ``*kw`` as
top-level names and return a string."""
renderer = renderer_factory(path)
- return renderer(kw)
+ return renderer(kw, {})
def render_template_to_response(path, **kw):
""" Render a ``chameleon.zpt`` template at the package-relative
@@ -52,7 +57,7 @@ def render_template_to_response(path, **kw):
top-level names and return a Response object with the body as the
template result. """
renderer = renderer_factory(path)
- result = renderer(kw)
+ result = renderer(kw, {})
response_factory = queryUtility(IResponseFactory, default=Response)
return response_factory(result)
diff --git a/repoze/bfg/interfaces.py b/repoze/bfg/interfaces.py
index 928ee6c54..8896c883e 100644
--- a/repoze/bfg/interfaces.py
+++ b/repoze/bfg/interfaces.py
@@ -75,10 +75,17 @@ class ITraverserFactory(Interface):
""" Return an object that implements ITraverser """
class IRenderer(Interface):
- def __call__(value):
+ def __call__(value, system):
""" Call a the renderer implementation with the result of the
view (``value``) passed in and return a result (a string or
- unicode object useful as a response body)"""
+ unicode object useful as a response body). Values computed by
+ the system are passed by the system in the ``system``
+ parameter, which is a dictionary. Keys in the dictionary
+ include: ``view`` (the view object that returned the value),
+ ``renderer_name`` (the template name or simple name of the
+ renderer), ``context`` (the context object passed to the
+ view), and ``request`` (the request object passed to the
+ view)."""
class IRendererFactory(Interface):
def __call__(name):
diff --git a/repoze/bfg/renderers.py b/repoze/bfg/renderers.py
index 0d14279b0..1e7babcbc 100644
--- a/repoze/bfg/renderers.py
+++ b/repoze/bfg/renderers.py
@@ -19,12 +19,12 @@ except ImportError:
# concrete renderer factory implementations
def json_renderer_factory(name):
- def _render(value):
+ def _render(value, system):
return json.dumps(value)
return _render
def string_renderer_factory(name):
- def _render(value):
+ def _render(value, system):
if not isinstance(value, basestring):
value = str(value)
return value
@@ -49,11 +49,11 @@ def template_renderer_factory(path, impl, level=3):
spec = resource_spec(path, caller_package(level=level).__name__)
renderer = queryUtility(ITemplateRenderer, name=spec)
if renderer is None:
- # service unit tests here by trying the relative path
- # string as the utility name directly
+ # service unit tests by trying the relative path string as
+ # the utility name directly
renderer = queryUtility(ITemplateRenderer, name=path)
- pkg, path = spec.split(':', 1)
if renderer is None:
+ pkg, path = spec.split(':', 1)
if not pkg_resources.resource_exists(pkg, path):
raise ValueError('Missing template resource: %s' % spec)
abspath = pkg_resources.resource_filename(pkg, path)
@@ -66,7 +66,7 @@ def template_renderer_factory(path, impl, level=3):
return renderer
-def renderer_from_name(path, level=4):
+def renderer_from_name(path):
name = os.path.splitext(path)[1]
if not name:
name = path
diff --git a/repoze/bfg/testing.py b/repoze/bfg/testing.py
index d4aafa083..1c7693306 100644
--- a/repoze/bfg/testing.py
+++ b/repoze/bfg/testing.py
@@ -270,7 +270,7 @@ class DummyTemplateRenderer:
return self(kw)
return callit
- def __call__(self, kw):
+ def __call__(self, kw, system=None):
self._received.update(kw)
return self.string_response
diff --git a/repoze/bfg/tests/grokkedapp/__init__.py b/repoze/bfg/tests/grokkedapp/__init__.py
index 598d3be64..c58ee428a 100644
--- a/repoze/bfg/tests/grokkedapp/__init__.py
+++ b/repoze/bfg/tests/grokkedapp/__init__.py
@@ -2,25 +2,38 @@ from repoze.bfg.view import bfg_view
@bfg_view()
def grokked(context, request):
- """ """
+ return 'grokked'
-@bfg_view(request_type='POST')
+@bfg_view(request_method='POST')
def grokked_post(context, request):
- """ """
+ return 'grokked_post'
-class grokked_klass(object):
- """ """
+class oldstyle_grokked_class:
def __init__(self, context, request):
self.context = context
self.request = request
def __call__(self):
- """ """
+ return 'oldstyle_grokked_class'
+
+oldstyle_grokked_class = bfg_view(name='oldstyle_grokked_class')(
+ oldstyle_grokked_class)
+
+class grokked_class(object):
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def __call__(self):
+ return 'grokked_class'
-# in 2.6+ the below can be spelled as a class decorator:
-#
-# @bfg_view(for_=INothing, name='grokked_klass')
-# class grokked_class(object):
-# ....
-#
-grokked_klass = bfg_view(name='grokked_klass')(grokked_klass)
+grokked_class = bfg_view(name='grokked_class')(grokked_class)
+
+# ungrokkable
+
+A = 1
+B = {}
+
+def stuff():
+ """ """
+
diff --git a/repoze/bfg/tests/grokkedapp/another.py b/repoze/bfg/tests/grokkedapp/another.py
new file mode 100644
index 000000000..b97110ab0
--- /dev/null
+++ b/repoze/bfg/tests/grokkedapp/another.py
@@ -0,0 +1,39 @@
+from repoze.bfg.view import bfg_view
+
+@bfg_view(name='another')
+def grokked(context, request):
+ return 'another_grokked'
+
+@bfg_view(request_method='POST', name='another')
+def grokked_post(context, request):
+ return 'another_grokked_post'
+
+class oldstyle_grokked_class:
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def __call__(self):
+ return 'another_oldstyle_grokked_class'
+
+oldstyle_grokked_class = bfg_view(name='another_oldstyle_grokked_class')(
+ oldstyle_grokked_class)
+
+class grokked_class(object):
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def __call__(self):
+ return 'another_grokked_class'
+
+grokked_class = bfg_view(name='another_grokked_class')(grokked_class)
+
+# ungrokkable
+
+A = 1
+B = {}
+
+def stuff():
+ """ """
+
diff --git a/repoze/bfg/tests/test_chameleon_text.py b/repoze/bfg/tests/test_chameleon_text.py
index ddb6f717a..a6384887f 100644
--- a/repoze/bfg/tests/test_chameleon_text.py
+++ b/repoze/bfg/tests/test_chameleon_text.py
@@ -11,17 +11,10 @@ class Base:
os.unlink(self._getTemplatePath('minimal.txt.py'))
except:
pass
-
def tearDown(self):
cleanUp()
- def _zcmlConfigure(self):
- import repoze.bfg.includes
- import zope.configuration.xmlconfig
- zope.configuration.xmlconfig.file('configure.zcml',
- package=repoze.bfg.includes)
-
def _getTemplatePath(self, name):
import os
here = os.path.abspath(os.path.dirname(__file__))
@@ -48,23 +41,25 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
verifyClass(ITemplateRenderer, self._getTargetClass())
def test_call(self):
- self._zcmlConfigure()
minimal = self._getTemplatePath('minimal.txt')
instance = self._makeOne(minimal)
- result = instance({})
+ result = instance({}, {})
self.failUnless(isinstance(result, str))
self.assertEqual(result, 'Hello.\n')
+ def test_call_with_nondict_value(self):
+ minimal = self._getTemplatePath('minimal.txt')
+ instance = self._makeOne(minimal)
+ self.assertRaises(ValueError, instance, None, {})
+
def test_call_nonminimal(self):
- self._zcmlConfigure()
nonminimal = self._getTemplatePath('nonminimal.txt')
instance = self._makeOne(nonminimal)
- result = instance({'name':'Chris'})
+ result = instance({'name':'Chris'}, {})
self.failUnless(isinstance(result, str))
self.assertEqual(result, 'Hello, Chris!\n')
def test_implementation(self):
- self._zcmlConfigure()
minimal = self._getTemplatePath('minimal.txt')
instance = self._makeOne(minimal)
result = instance.implementation()()
@@ -77,7 +72,6 @@ class RenderTemplateTests(Base, unittest.TestCase):
return render_template(name, **kw)
def test_it(self):
- self._zcmlConfigure()
minimal = self._getTemplatePath('minimal.txt')
result = self._callFUT(minimal)
self.failUnless(isinstance(result, str))
@@ -89,7 +83,6 @@ class RenderTemplateToResponseTests(Base, unittest.TestCase):
return render_template_to_response(name, **kw)
def test_minimal(self):
- self._zcmlConfigure()
minimal = self._getTemplatePath('minimal.txt')
result = self._callFUT(minimal)
from webob import Response
@@ -165,7 +158,6 @@ class GetTemplateTests(unittest.TestCase, Base):
return get_template(name)
def test_nonabs_registered(self):
- self._zcmlConfigure()
from zope.component import getGlobalSiteManager
from zope.component import queryUtility
from repoze.bfg.chameleon_text import TextTemplateRenderer
@@ -179,7 +171,6 @@ class GetTemplateTests(unittest.TestCase, Base):
self.assertEqual(queryUtility(ITemplateRenderer, minimal), utility)
def test_nonabs_unregistered(self):
- self._zcmlConfigure()
from zope.component import getGlobalSiteManager
from zope.component import queryUtility
from repoze.bfg.chameleon_text import TextTemplateRenderer
diff --git a/repoze/bfg/tests/test_chameleon_zpt.py b/repoze/bfg/tests/test_chameleon_zpt.py
index f6d7c0da5..381a1d0bf 100644
--- a/repoze/bfg/tests/test_chameleon_zpt.py
+++ b/repoze/bfg/tests/test_chameleon_zpt.py
@@ -9,12 +9,6 @@ class Base(object):
def tearDown(self):
cleanUp()
- def _zcmlConfigure(self):
- import repoze.bfg.includes
- import zope.configuration.xmlconfig
- zope.configuration.xmlconfig.file('configure.zcml',
- package=repoze.bfg.includes)
-
def _getTemplatePath(self, name):
import os
here = os.path.abspath(os.path.dirname(__file__))
@@ -41,16 +35,19 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
verifyClass(ITemplateRenderer, self._getTargetClass())
def test_call(self):
- self._zcmlConfigure()
minimal = self._getTemplatePath('minimal.pt')
instance = self._makeOne(minimal)
- result = instance({})
+ result = instance({}, {})
self.failUnless(isinstance(result, unicode))
self.assertEqual(result,
'<div xmlns="http://www.w3.org/1999/xhtml">\n</div>')
+ def test_call_with_nondict_value(self):
+ minimal = self._getTemplatePath('minimal.pt')
+ instance = self._makeOne(minimal)
+ self.assertRaises(ValueError, instance, None, {})
+
def test_implementation(self):
- self._zcmlConfigure()
minimal = self._getTemplatePath('minimal.pt')
instance = self._makeOne(minimal)
result = instance.implementation()()
@@ -65,7 +62,6 @@ class RenderTemplateTests(Base, unittest.TestCase):
return render_template(name, **kw)
def test_it(self):
- self._zcmlConfigure()
minimal = self._getTemplatePath('minimal.pt')
result = self._callFUT(minimal)
self.failUnless(isinstance(result, unicode))
@@ -78,7 +74,6 @@ class RenderTemplateToResponseTests(Base, unittest.TestCase):
return render_template_to_response(name, **kw)
def test_it(self):
- self._zcmlConfigure()
minimal = self._getTemplatePath('minimal.pt')
result = self._callFUT(minimal)
from webob import Response
@@ -149,7 +144,6 @@ class GetTemplateTests(Base, unittest.TestCase):
return get_template(name)
def test_nonabs_registered(self):
- self._zcmlConfigure()
from zope.component import getGlobalSiteManager
from zope.component import queryUtility
from repoze.bfg.chameleon_zpt import ZPTTemplateRenderer
@@ -163,7 +157,6 @@ class GetTemplateTests(Base, unittest.TestCase):
self.assertEqual(queryUtility(ITemplateRenderer, minimal), utility)
def test_nonabs_unregistered(self):
- self._zcmlConfigure()
from zope.component import getGlobalSiteManager
from zope.component import queryUtility
from repoze.bfg.chameleon_zpt import ZPTTemplateRenderer
diff --git a/repoze/bfg/tests/test_integration.py b/repoze/bfg/tests/test_integration.py
index 681dcf043..bcd29d294 100644
--- a/repoze/bfg/tests/test_integration.py
+++ b/repoze/bfg/tests/test_integration.py
@@ -39,7 +39,7 @@ class WGSIAppPlusBFGViewTests(unittest.TestCase):
from repoze.bfg.interfaces import IRequest
from repoze.bfg.interfaces import IView
from repoze.bfg.zcml import scan
- context = DummyContext()
+ context = DummyZCMLContext()
from repoze.bfg.tests import test_integration
scan(context, test_integration)
actions = context.actions
@@ -99,39 +99,96 @@ class TestGrokkedApp(unittest.TestCase):
cleanUp()
def test_it(self):
- import inspect
+ from repoze.bfg.view import render_view_to_response
+ from zope.interface import directlyProvides
+ from repoze.bfg.zcml import zcml_configure
from repoze.bfg.interfaces import IView
from repoze.bfg.interfaces import IRequest
import repoze.bfg.tests.grokkedapp as package
- from zope.configuration import config
- from zope.configuration import xmlconfig
- context = config.ConfigurationMachine()
- xmlconfig.registerCommonDirectives(context)
- context.package = package
- xmlconfig.include(context, 'configure.zcml', package)
- actions = context.actions
+ actions = zcml_configure('configure.zcml', package)
- postview = actions[-1]
- self.assertEqual(postview[0][1], None)
- self.assertEqual(postview[0][2], '')
- self.assertEqual(postview[0][3], IRequest)
- self.assertEqual(postview[0][4], IView)
+ action = actions[-1]
+ self.assertEqual(action[0][1], None)
+ self.assertEqual(action[0][2], 'another_oldstyle_grokked_class')
+ self.assertEqual(action[0][3], IRequest)
+ self.assertEqual(action[0][4], IView)
+
+ action = actions[-2]
+ self.assertEqual(action[0][1], None)
+ self.assertEqual(action[0][2], 'another')
+ self.assertEqual(action[0][3], IRequest)
+ self.assertEqual(action[0][4], IView)
+
+ action = actions[-3]
+ self.assertEqual(action[0][1], None)
+ self.assertEqual(action[0][2], 'another_grokked_class')
+ self.assertEqual(action[0][3], IRequest)
+ self.assertEqual(action[0][4], IView)
+
+ action = actions[-4]
+ self.assertEqual(action[0][1], None)
+ self.assertEqual(action[0][2], 'another')
+ self.assertEqual(action[0][3], IRequest)
+ self.assertEqual(action[0][4], IView)
+
+ action = actions[-5]
+ self.assertEqual(action[0][1], None)
+ self.assertEqual(action[0][2], 'oldstyle_grokked_class')
+ self.assertEqual(action[0][3], IRequest)
+ self.assertEqual(action[0][4], IView)
- klassview = actions[-2]
- self.assertEqual(klassview[0][1], None)
- self.assertEqual(klassview[0][2], 'grokked_klass')
- self.assertEqual(klassview[0][3], IRequest)
- self.assertEqual(klassview[0][4], IView)
- self.failUnless(inspect.isfunction(package.grokked_klass))
- self.assertEqual(package.grokked_klass(None, None), None)
-
- funcview = actions[-3]
- self.assertEqual(funcview[0][1], None)
- self.assertEqual(funcview[0][2], '')
- self.assertEqual(funcview[0][3], IRequest)
- self.assertEqual(funcview[0][4], IView)
-
-class DummyContext:
+ action = actions[-6]
+ self.assertEqual(action[0][1], None)
+ self.assertEqual(action[0][2], '')
+ self.assertEqual(action[0][3], IRequest)
+ self.assertEqual(action[0][4], IView)
+
+ action = actions[-7]
+ self.assertEqual(action[0][1], None)
+ self.assertEqual(action[0][2], 'grokked_class')
+ self.assertEqual(action[0][3], IRequest)
+ self.assertEqual(action[0][4], IView)
+
+ action = actions[-8]
+ self.assertEqual(action[0][1], None)
+ self.assertEqual(action[0][2], '')
+ self.assertEqual(action[0][3], IRequest)
+ self.assertEqual(action[0][4], IView)
+
+ ctx = DummyContext()
+ req = DummyRequest()
+ directlyProvides(req, IRequest)
+
+ req.method = 'GET'
+ result = render_view_to_response(ctx, req, '')
+ self.assertEqual(result, 'grokked')
+
+ req.method = 'POST'
+ result = render_view_to_response(ctx, req, '')
+ self.assertEqual(result, 'grokked_post')
+
+ result= render_view_to_response(ctx, req, 'grokked_class')
+ self.assertEqual(result, 'grokked_class')
+
+ result= render_view_to_response(ctx, req, 'oldstyle_grokked_class')
+ self.assertEqual(result, 'oldstyle_grokked_class')
+
+ req.method = 'GET'
+ result = render_view_to_response(ctx, req, 'another')
+ self.assertEqual(result, 'another_grokked')
+
+ req.method = 'POST'
+ result = render_view_to_response(ctx, req, 'another')
+ self.assertEqual(result, 'another_grokked_post')
+
+ result= render_view_to_response(ctx, req, 'another_grokked_class')
+ self.assertEqual(result, 'another_grokked_class')
+
+ result= render_view_to_response(ctx, req,
+ 'another_oldstyle_grokked_class')
+ self.assertEqual(result, 'another_oldstyle_grokked_class')
+
+class DummyContext(object):
pass
class DummyRequest:
@@ -141,7 +198,7 @@ class DummyRequest:
def get_response(self, application):
return application(None, None)
-class DummyContext:
+class DummyZCMLContext:
def __init__(self):
self.actions = []
self.info = None
diff --git a/repoze/bfg/tests/test_renderers.py b/repoze/bfg/tests/test_renderers.py
index d1acc0285..a330d19da 100644
--- a/repoze/bfg/tests/test_renderers.py
+++ b/repoze/bfg/tests/test_renderers.py
@@ -149,9 +149,9 @@ class TestRendererFromName(unittest.TestCase):
def tearDown(self):
cleanUp()
- def _callFUT(self, path, level=4):
+ def _callFUT(self, path):
from repoze.bfg.renderers import renderer_from_name
- return renderer_from_name(path, level)
+ return renderer_from_name(path)
def test_it(self):
from repoze.bfg.interfaces import ITemplateRendererFactory
@@ -176,7 +176,7 @@ class Test_json_renderer_factory(unittest.TestCase):
def test_it(self):
renderer = self._callFUT(None)
- result = renderer({'a':1})
+ result = renderer({'a':1}, {})
self.assertEqual(result, '{"a": 1}')
class Test_string_renderer_factory(unittest.TestCase):
@@ -187,19 +187,19 @@ class Test_string_renderer_factory(unittest.TestCase):
def test_it_unicode(self):
renderer = self._callFUT(None)
value = unicode('La Pe\xc3\xb1a', 'utf-8')
- result = renderer(value)
+ result = renderer(value, {})
self.assertEqual(result, value)
def test_it_str(self):
renderer = self._callFUT(None)
value = 'La Pe\xc3\xb1a'
- result = renderer(value)
+ result = renderer(value, {})
self.assertEqual(result, value)
def test_it_other(self):
renderer = self._callFUT(None)
value = None
- result = renderer(value)
+ result = renderer(value, {})
self.assertEqual(result, 'None')
class DummyFactory:
diff --git a/repoze/bfg/tests/test_testing.py b/repoze/bfg/tests/test_testing.py
index 6c6b55337..c302bd9f5 100644
--- a/repoze/bfg/tests/test_testing.py
+++ b/repoze/bfg/tests/test_testing.py
@@ -65,7 +65,7 @@ class TestTestingFunctions(unittest.TestCase):
def test_registerTemplateRenderer_explicitrenderer(self):
from repoze.bfg import testing
- def renderer(kw):
+ def renderer(kw, system):
raise ValueError
renderer = testing.registerTemplateRenderer('templates/foo', renderer)
from repoze.bfg.chameleon_zpt import render_template_to_response
diff --git a/repoze/bfg/tests/test_traversal.py b/repoze/bfg/tests/test_traversal.py
index 0fb0becfd..3f347dc22 100644
--- a/repoze/bfg/tests/test_traversal.py
+++ b/repoze/bfg/tests/test_traversal.py
@@ -971,6 +971,11 @@ class UnderTraverseTests(unittest.TestCase):
from zope.interface import Interface
gsm.registerAdapter(traverser, (Interface,), ITraverserFactory)
+ def test_default_traverser_factory(self):
+ context = DummyContext()
+ result = self._callFUT(context, {})
+ self.assertEqual(result['view_name'], '')
+
def test_isdict(self):
traverser = make_traverser({})
self._registerTraverserFactory(traverser)
diff --git a/repoze/bfg/tests/test_view.py b/repoze/bfg/tests/test_view.py
index 959ad939b..42d14f83a 100644
--- a/repoze/bfg/tests/test_view.py
+++ b/repoze/bfg/tests/test_view.py
@@ -382,52 +382,26 @@ class TestBFGViewDecorator(unittest.TestCase):
self.assertEqual(wrapped.__request_type__, None)
def test_call_oldstyle_class(self):
- import inspect
decorator = self._makeOne()
class foo:
""" docstring """
- def __init__(self, context, request):
- self.context = context
- self.request = request
- def __call__(self):
- return self
wrapped = decorator(foo)
- self.failIf(wrapped is foo)
- self.failUnless(inspect.isfunction(wrapped))
+ self.failUnless(wrapped is foo)
self.assertEqual(wrapped.__is_bfg_view__, True)
self.assertEqual(wrapped.__permission__, None)
self.assertEqual(wrapped.__for__, None)
self.assertEqual(wrapped.__request_type__, None)
- self.assertEqual(wrapped.__module__, foo.__module__)
- self.assertEqual(wrapped.__name__, foo.__name__)
- self.assertEqual(wrapped.__doc__, foo.__doc__)
- result = wrapped(None, None)
- self.assertEqual(result.context, None)
- self.assertEqual(result.request, None)
def test_call_newstyle_class(self):
- import inspect
decorator = self._makeOne()
class foo(object):
""" docstring """
- def __init__(self, context, request):
- self.context = context
- self.request = request
- def __call__(self):
- return self
wrapped = decorator(foo)
- self.failIf(wrapped is foo)
- self.failUnless(inspect.isfunction(wrapped))
+ self.failUnless(wrapped is foo)
self.assertEqual(wrapped.__is_bfg_view__, True)
self.assertEqual(wrapped.__permission__, None)
self.assertEqual(wrapped.__for__, None)
self.assertEqual(wrapped.__request_type__, None)
- self.assertEqual(wrapped.__module__, foo.__module__)
- self.assertEqual(wrapped.__name__, foo.__name__)
- self.assertEqual(wrapped.__doc__, foo.__doc__)
- result = wrapped(None, None)
- self.assertEqual(result.context, None)
- self.assertEqual(result.request, None)
class TestDefaultForbiddenView(unittest.TestCase):
def _callFUT(self, context, request):
@@ -638,17 +612,12 @@ class Test_map_view(unittest.TestCase):
from zope.component import getSiteManager
class Renderer:
implements(ITemplateRenderer)
+ def __init__(self, path):
+ pass
def __call__(self, *arg):
return 'Hello!'
-
- class RendererFactory:
- def __call__(self, path):
- self.path = path
- return Renderer()
-
- factory = RendererFactory()
sm = getSiteManager()
- sm.registerUtility(factory, IRendererFactory, name=name)
+ sm.registerUtility(Renderer, IRendererFactory, name=name)
def test_view_as_function_context_and_request(self):
def view(context, request):
@@ -669,7 +638,7 @@ class Test_map_view(unittest.TestCase):
def view(context, request):
""" """
result = self._callFUT(view, attr='__name__',
- renderer='fixtures/minimal.txt')
+ renderer_name='fixtures/minimal.txt')
self.failIf(result is view)
self.assertRaises(TypeError, result, None, None)
@@ -727,8 +696,9 @@ class Test_map_view(unittest.TestCase):
pass
def index(self):
return {'a':'1'}
- result = self._callFUT(view, attr='index',
- renderer='repoze.bfg.tests:fixtures/minimal.txt')
+ result = self._callFUT(
+ view, attr='index',
+ renderer_name='repoze.bfg.tests:fixtures/minimal.txt')
self.failIf(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
@@ -769,8 +739,9 @@ class Test_map_view(unittest.TestCase):
pass
def index(self):
return {'a':'1'}
- result = self._callFUT(view, attr='index',
- renderer='repoze.bfg.tests:fixtures/minimal.txt')
+ result = self._callFUT(
+ view, attr='index',
+ renderer_name='repoze.bfg.tests:fixtures/minimal.txt')
self.failIf(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
@@ -812,8 +783,9 @@ class Test_map_view(unittest.TestCase):
pass
def index(self):
return {'a':'1'}
- result = self._callFUT(view, attr='index',
- renderer='repoze.bfg.tests:fixtures/minimal.txt')
+ result = self._callFUT(
+ view, attr='index',
+ renderer_name='repoze.bfg.tests:fixtures/minimal.txt')
self.failIf(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
@@ -854,8 +826,9 @@ class Test_map_view(unittest.TestCase):
pass
def index(self):
return {'a':'1'}
- result = self._callFUT(view, attr='index',
- renderer='repoze.bfg.tests:fixtures/minimal.txt')
+ result = self._callFUT(
+ view, attr='index',
+ renderer_name='repoze.bfg.tests:fixtures/minimal.txt')
self.failIf(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
@@ -887,8 +860,9 @@ class Test_map_view(unittest.TestCase):
def index(self, context, request):
return {'a':'1'}
view = View()
- result = self._callFUT(view, attr='index',
- renderer='repoze.bfg.tests:fixtures/minimal.txt')
+ result = self._callFUT(
+ view, attr='index',
+ renderer_name='repoze.bfg.tests:fixtures/minimal.txt')
self.failIf(result is view)
request = DummyRequest()
self.assertEqual(result(None, request).body, 'Hello!')
@@ -923,8 +897,9 @@ class Test_map_view(unittest.TestCase):
def index(self, request):
return {'a':'1'}
view = View()
- result = self._callFUT(view, attr='index',
- renderer='repoze.bfg.tests:fixtures/minimal.txt')
+ result = self._callFUT(
+ view, attr='index',
+ renderer_name='repoze.bfg.tests:fixtures/minimal.txt')
self.failIf(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
@@ -936,8 +911,9 @@ class Test_map_view(unittest.TestCase):
self._registerRenderer()
def view(context, request):
return {'a':'1'}
- result = self._callFUT(view,
- renderer='repoze.bfg.tests:fixtures/minimal.txt')
+ result = self._callFUT(
+ view,
+ renderer_name='repoze.bfg.tests:fixtures/minimal.txt')
self.failIf(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
@@ -1164,72 +1140,47 @@ class Test_rendered_response(unittest.TestCase):
def tearDown(self):
cleanUp()
- def _callFUT(self, renderer_name, response, view=None,
- context=None, request=None):
+ def _callFUT(self, renderer, response, view=None,
+ context=None, request=None, renderer_name=None):
from repoze.bfg.view import rendered_response
if request is None:
request = DummyRequest()
- return rendered_response(renderer_name, response, view, context,
- request)
-
- def _registerRenderer(self):
- from repoze.bfg.interfaces import IRendererFactory
- from repoze.bfg.interfaces import ITemplateRenderer
- from zope.interface import implements
- from zope.component import getSiteManager
- class Renderer:
- implements(ITemplateRenderer)
- def __call__(self, *arg):
- return 'Hello!'
-
- class RendererFactory:
- def __call__(self, path):
- self.path = path
- return Renderer()
+ return rendered_response(renderer, response, view,
+ context, request, renderer_name)
- factory = RendererFactory()
- sm = getSiteManager()
- sm.registerUtility(factory, IRendererFactory, name='.txt')
+ def _makeRenderer(self):
+ def renderer(*arg):
+ return 'Hello!'
+ return renderer
def test_is_response(self):
- self._registerRenderer()
+ renderer = self._makeRenderer()
response = DummyResponse()
- result = self._callFUT(
- 'repoze.bfg.tests:fixtures/minimal.txt', response)
+ result = self._callFUT(renderer, response)
self.assertEqual(result, response)
- def test_is_not_valid_dict(self):
- self._registerRenderer()
- response = None
- result = self._callFUT(
- 'repoze.bfg.tests:fixtures/minimal.txt', response)
- self.assertEqual(result, response)
-
- def test_valid_dict(self):
- self._registerRenderer()
+ def test_calls_renderer(self):
+ renderer = self._makeRenderer()
response = {'a':'1'}
- result = self._callFUT(
- 'repoze.bfg.tests:fixtures/minimal.txt', response)
+ result = self._callFUT(renderer, response)
self.assertEqual(result.body, 'Hello!')
def test_with_content_type(self):
- self._registerRenderer()
+ renderer = self._makeRenderer()
response = {'a':'1'}
request = DummyRequest()
attrs = {'response_content_type':'text/nonsense'}
request.environ['webob.adhoc_attrs'] = attrs
- result = self._callFUT(
- 'repoze.bfg.tests:fixtures/minimal.txt', response, request=request)
+ result = self._callFUT(renderer, response, request=request)
self.assertEqual(result.content_type, 'text/nonsense')
def test_with_headerlist(self):
- self._registerRenderer()
+ renderer = self._makeRenderer()
response = {'a':'1'}
request = DummyRequest()
attrs = {'response_headerlist':[('a', '1'), ('b', '2')]}
request.environ['webob.adhoc_attrs'] = attrs
- result = self._callFUT(
- 'repoze.bfg.tests:fixtures/minimal.txt', response, request=request)
+ result = self._callFUT(renderer, response, request=request)
self.assertEqual(result.headerlist,
[('Content-Type', 'text/html; charset=UTF-8'),
('Content-Length', '6'),
@@ -1237,33 +1188,30 @@ class Test_rendered_response(unittest.TestCase):
('b', '2')])
def test_with_status(self):
- self._registerRenderer()
+ renderer = self._makeRenderer()
response = {'a':'1'}
request = DummyRequest()
attrs = {'response_status':'406 You Lose'}
request.environ['webob.adhoc_attrs'] = attrs
- result = self._callFUT(
- 'repoze.bfg.tests:fixtures/minimal.txt', response, request=request)
+ result = self._callFUT(renderer, response, request=request)
self.assertEqual(result.status, '406 You Lose')
def test_with_charset(self):
- self._registerRenderer()
+ renderer = self._makeRenderer()
response = {'a':'1'}
request = DummyRequest()
attrs = {'response_charset':'UTF-16'}
request.environ['webob.adhoc_attrs'] = attrs
- result = self._callFUT(
- 'repoze.bfg.tests:fixtures/minimal.txt', response, request=request)
+ result = self._callFUT(renderer, response, request=request)
self.assertEqual(result.charset, 'UTF-16')
def test_with_cache_for(self):
- self._registerRenderer()
+ renderer = self._makeRenderer()
response = {'a':'1'}
request = DummyRequest()
attrs = {'response_cache_for':100}
request.environ['webob.adhoc_attrs'] = attrs
- result = self._callFUT(
- 'repoze.bfg.tests:fixtures/minimal.txt', response, request=request)
+ result = self._callFUT(renderer, response, request=request)
self.assertEqual(result.cache_control.max_age, 100)
class TestDeriveView(unittest.TestCase):
diff --git a/repoze/bfg/tests/test_zcml.py b/repoze/bfg/tests/test_zcml.py
index 0dcda485f..79354417f 100644
--- a/repoze/bfg/tests/test_zcml.py
+++ b/repoze/bfg/tests/test_zcml.py
@@ -1845,6 +1845,8 @@ class TestBFGViewFunctionGrokker(unittest.TestCase):
obj.__attr__ = None
obj.__template__ = None
obj.__wrapper_viewname__ = None
+ obj.__renderer__ = None
+ obj.__attr__ = None
context = DummyContext()
result = grokker.grok('name', obj, context=context)
self.assertEqual(result, True)
@@ -1879,13 +1881,15 @@ class TestZCMLScanDirective(unittest.TestCase):
return scan(context, package, martian)
def test_it(self):
+ from repoze.bfg.zcml import SimpleMultiGrokker
+ from repoze.bfg.zcml import exclude
martian = DummyMartianModule()
module_grokker = DummyModuleGrokker()
dummy_module = DummyModule()
- from repoze.bfg.zcml import exclude
self._callFUT(None, dummy_module, martian)
self.assertEqual(martian.name, 'dummy')
- self.assertEqual(len(martian.module_grokker.registered), 1)
+ multi_grokker = martian.module_grokker.multi_grokker
+ self.assertEqual(multi_grokker.__class__, SimpleMultiGrokker)
self.assertEqual(martian.context, None)
self.assertEqual(martian.exclude_filter, exclude)
@@ -1910,11 +1914,8 @@ class DummyModule:
__file__ = ''
class DummyModuleGrokker:
- def __init__(self):
- self.registered = []
-
- def register(self, other):
- self.registered.append(other)
+ def __init__(self, grokker=None):
+ self.multi_grokker = grokker
class DummyMartianModule:
def grok_dotted_name(self, name, grokker, context, exclude_filter=None):
@@ -1923,8 +1924,8 @@ class DummyMartianModule:
self.exclude_filter = exclude_filter
return True
- def ModuleGrokker(self):
- self.module_grokker = DummyModuleGrokker()
+ def ModuleGrokker(self, grokker=None):
+ self.module_grokker = DummyModuleGrokker(grokker)
return self.module_grokker
class DummyContext:
diff --git a/repoze/bfg/traversal.py b/repoze/bfg/traversal.py
index 16c1cc764..cec87ebc8 100644
--- a/repoze/bfg/traversal.py
+++ b/repoze/bfg/traversal.py
@@ -2,6 +2,7 @@ import re
import urllib
from zope.component import queryMultiAdapter
+from zope.component import queryAdapter
from zope.interface import classProvides
from zope.interface import implements
@@ -272,7 +273,9 @@ def traverse(model, path):
def _traverse(model, environ, traverser=None):
if traverser is None:
- traverser = ITraverserFactory(model)
+ traverser = queryAdapter(model, ITraverserFactory)
+ if traverser is None:
+ traverser = ModelGraphTraverser(model)
result = traverser(environ)
diff --git a/repoze/bfg/view.py b/repoze/bfg/view.py
index 1e25755b4..c710829ca 100644
--- a/repoze/bfg/view.py
+++ b/repoze/bfg/view.py
@@ -357,7 +357,7 @@ class bfg_view(object):
self.wrapper_viewname = wrapper
def __call__(self, wrapped):
- _bfg_view = map_view(wrapped, self.attr, self.renderer)
+ _bfg_view = wrapped #map_view(wrapped, self.attr, self.renderer)
_bfg_view.__is_bfg_view__ = True
_bfg_view.__permission__ = self.permission
_bfg_view.__for__ = self.for_
@@ -368,6 +368,8 @@ class bfg_view(object):
_bfg_view.__request_param__ = self.request_param
_bfg_view.__containment__ = self.containment
_bfg_view.__wrapper_viewname__ = self.wrapper_viewname
+ _bfg_view.__attr__ = self.attr
+ _bfg_view.__renderer__ = self.renderer
return _bfg_view
def default_view(context, request, status):
@@ -438,20 +440,12 @@ class MultiView(object):
continue
raise NotFound(self.name)
-def rendered_response(renderer_name, response, view, context, request):
- if is_response(response):
+def rendered_response(renderer, response, view, context,request, renderer_name):
+ if ( hasattr(response, 'app_iter') and hasattr(response, 'headerlist') and
+ hasattr(response, 'status') ):
return response
- renderer = renderer_from_name(renderer_name)
- if ITemplateRenderer.providedBy(renderer):
- kw = {'view':view, 'template_name':renderer_name, 'context':context,
- 'request':request}
- try:
- kw.update(response)
- except TypeError:
- return response
- result = renderer(kw)
- else:
- result = renderer(response)
+ result = renderer(response, {'view':view, 'renderer_name':renderer_name,
+ 'context':context, 'request':request})
response_factory = queryUtility(IResponseFactory, default=Response)
response = response_factory(result)
attrs = request.environ.get('webob.adhoc_attrs', {})
@@ -473,12 +467,18 @@ def rendered_response(renderer_name, response, view, context, request):
response.cache_expires = cache_for
return response
-def map_view(view, attr=None, renderer=None):
+def map_view(view, attr=None, renderer_name=None):
wrapped_view = view
- if renderer is None:
- if queryUtility(IRendererFactory) is not None: # default renderer
- renderer = ''
+ renderer = None
+
+ if renderer_name is None:
+ factory = queryUtility(IRendererFactory) # global default renderer
+ if factory is not None:
+ renderer_name = ''
+ renderer = factory(renderer_name)
+ else:
+ renderer = renderer_from_name(renderer_name)
if inspect.isclass(view):
# If the object we've located is a class, turn it into a
@@ -497,8 +497,10 @@ def map_view(view, attr=None, renderer=None):
else:
response = getattr(inst, attr)()
if renderer is not None:
- response = rendered_response(renderer, response, inst,
- context, request)
+ response = rendered_response(renderer,
+ response, inst,
+ context, request,
+ renderer_name)
return response
wrapped_view = _bfg_class_requestonly_view
else:
@@ -510,8 +512,10 @@ def map_view(view, attr=None, renderer=None):
else:
response = getattr(inst, attr)()
if renderer is not None:
- response = rendered_response(renderer, response, inst,
- context, request)
+ response = rendered_response(renderer,
+ response, inst,
+ context, request,
+ renderer_name)
return response
wrapped_view = _bfg_class_view
@@ -525,8 +529,10 @@ def map_view(view, attr=None, renderer=None):
response = getattr(view, attr)(request)
if renderer is not None:
- response = rendered_response(renderer, response, view,
- context, request)
+ response = rendered_response(renderer,
+ response, view,
+ context, request,
+ renderer_name)
return response
wrapped_view = _bfg_requestonly_view
@@ -534,16 +540,20 @@ def map_view(view, attr=None, renderer=None):
def _bfg_attr_view(context, request):
response = getattr(view, attr)(context, request)
if renderer is not None:
- response = rendered_response(renderer, response, view,
- context, request)
+ response = rendered_response(renderer,
+ response, view,
+ context, request,
+ renderer_name)
return response
wrapped_view = _bfg_attr_view
elif renderer is not None:
def _rendered_view(context, request):
response = view(context, request)
- response = rendered_response(renderer, response, view,
- context, request)
+ response = rendered_response(renderer,
+ response, view,
+ context, request,
+ renderer_name)
return response
wrapped_view = _rendered_view
@@ -617,8 +627,8 @@ def decorate_view(wrapped_view, original_view):
return False
def derive_view(original_view, permission=None, predicates=(), attr=None,
- renderer=None, wrapper_viewname=None, viewname=None):
- mapped_view = map_view(original_view, attr, renderer)
+ renderer_name=None, wrapper_viewname=None, viewname=None):
+ mapped_view = map_view(original_view, attr, renderer_name)
owrapped_view = owrap_view(mapped_view, viewname, wrapper_viewname)
secured_view = secure_view(owrapped_view, permission)
debug_view = authdebug_view(secured_view, permission)
diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py
index a3ddd8527..d5e7ffd67 100644
--- a/repoze/bfg/zcml.py
+++ b/repoze/bfg/zcml.py
@@ -1,3 +1,4 @@
+import inspect
import sys
import types
@@ -20,6 +21,7 @@ from zope.schema import Int
from zope.schema import TextLine
import martian
+import martian.core
from repoze.bfg.interfaces import IAuthenticationPolicy
from repoze.bfg.interfaces import IAuthorizationPolicy
@@ -557,20 +559,6 @@ def renderer(_context, factory, name=''):
sm.registerUtility(factory, IRendererFactory, name=name)
_context.action(discriminator=(IRendererFactory, name))
-class IScanDirective(Interface):
- package = GlobalObject(
- title=u"The package we'd like to scan.",
- required=True,
- )
-
-def scan(_context, package, martian=martian):
- # martian overrideable only for unit tests
- module_grokker = martian.ModuleGrokker()
- module_grokker.register(BFGViewFunctionGrokker())
- martian.grok_dotted_name(package.__name__, grokker=module_grokker,
- context=_context, exclude_filter=exclude)
-
-
class IStaticDirective(Interface):
name = TextLine(
title=u"The URL prefix of the static view",
@@ -598,21 +586,25 @@ def static(_context, name, path, cache_max_age=3600):
route(_context, name, "%s*subpath" % name, view=view,
view_for=StaticRootFactory, factory=StaticRootFactory(path))
-################# utility stuff ####################
-
-def zcml_configure(name, package):
- context = zope.configuration.config.ConfigurationMachine()
- xmlconfig.registerCommonDirectives(context)
- context.package = package
- xmlconfig.include(context, name, package)
- context.execute_actions(clear=False)
- return context.actions
+class IScanDirective(Interface):
+ package = GlobalObject(
+ title=u"The package we'd like to scan.",
+ required=True,
+ )
-file_configure = zcml_configure # backwards compat (>0.8.1)
+def scan(_context, package, martian=martian):
+ # martian overrideable only for unit tests
+ multi_grokker = SimpleMultiGrokker()
+ multi_grokker.register(BFGViewFunctionGrokker())
+ multi_grokker.register(BFGViewNewStyleClassGrokker())
+ multi_grokker.register(BFGViewOldStyleClassGrokker())
+ module_grokker = martian.ModuleGrokker(grokker=multi_grokker)
+ martian.grok_dotted_name(package.__name__, grokker=module_grokker,
+ context=_context, exclude_filter=exclude)
-class BFGViewFunctionGrokker(martian.InstanceGrokker):
- martian.component(types.FunctionType)
+################# utility stuff ####################
+class BFGViewGrokker(object):
def grok(self, name, obj, **kw):
if hasattr(obj, '__is_bfg_view__'):
permission = obj.__permission__
@@ -624,21 +616,52 @@ class BFGViewFunctionGrokker(martian.InstanceGrokker):
request_param = obj.__request_param__
containment = obj.__containment__
wrapper = obj.__wrapper_viewname__
+ attr = obj.__attr__
+ renderer = obj.__renderer__
context = kw['context']
view(context, permission=permission, for_=for_,
view=obj, name=name, request_type=request_type,
route_name=route_name, request_method=request_method,
request_param=request_param, containment=containment,
- wrapper=wrapper)
+ attr=attr, renderer=renderer, wrapper=wrapper)
return True
return False
+class BFGViewFunctionGrokker(BFGViewGrokker, martian.InstanceGrokker):
+ martian.component(types.FunctionType)
+
+class BFGViewOldStyleClassGrokker(BFGViewGrokker, martian.InstanceGrokker):
+ martian.component(types.ClassType)
+
+class BFGViewNewStyleClassGrokker(BFGViewGrokker, martian.InstanceGrokker):
+ martian.component(type)
+
def exclude(name):
if name.startswith('.'):
return True
return False
+class SimpleMultiGrokker(martian.core.MultiInstanceOrClassGrokkerBase):
+ # this is an amalgam of martian.core.MultiInstanceGrokker and
+ # martian.core.MultiClassGrokker.
+ def get_bases(self, obj):
+ if type(obj) is types.ModuleType:
+ return []
+ if hasattr(obj, '__class__'):
+ return inspect.getmro(obj.__class__)
+ return [types.ClassType]
+
class Uncacheable(object):
""" Include in discriminators of actions which are not cacheable;
this class only exists for backwards compatibility (<0.8.1)"""
+def zcml_configure(name, package):
+ context = zope.configuration.config.ConfigurationMachine()
+ xmlconfig.registerCommonDirectives(context)
+ context.package = package
+ xmlconfig.include(context, name, package)
+ context.execute_actions(clear=False)
+ return context.actions
+
+file_configure = zcml_configure # backwards compat (>0.8.1)
+