summaryrefslogtreecommitdiff
path: root/repoze/bfg/renderers.py
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2010-08-13 09:56:20 +0000
committerChris McDonough <chrism@agendaless.com>2010-08-13 09:56:20 +0000
commit62b4794bb4c52080aaccc8058147f4ebe34caba6 (patch)
tree40701910cd853c169fd4720e4fb974a9b72ce60b /repoze/bfg/renderers.py
parentec55db55aba80618fb250aace0d22f0aa56cef1f (diff)
downloadpyramid-62b4794bb4c52080aaccc8058147f4ebe34caba6.tar.gz
pyramid-62b4794bb4c52080aaccc8058147f4ebe34caba6.tar.bz2
pyramid-62b4794bb4c52080aaccc8058147f4ebe34caba6.zip
svn merge -r9909:HEAD $REPOZE_SVN/repoze.bfg/branches/rendererhelper
Diffstat (limited to 'repoze/bfg/renderers.py')
-rw-r--r--repoze/bfg/renderers.py301
1 files changed, 183 insertions, 118 deletions
diff --git a/repoze/bfg/renderers.py b/repoze/bfg/renderers.py
index 645284216..895debe2c 100644
--- a/repoze/bfg/renderers.py
+++ b/repoze/bfg/renderers.py
@@ -6,6 +6,7 @@ from webob import Response
from zope.deprecation import deprecated
from repoze.bfg.interfaces import IRendererGlobalsFactory
+from repoze.bfg.interfaces import IRendererFactory
from repoze.bfg.interfaces import IResponseFactory
from repoze.bfg.interfaces import ITemplateRenderer
@@ -13,77 +14,116 @@ from repoze.bfg.compat import json
from repoze.bfg.path import caller_package
from repoze.bfg.settings import get_settings
from repoze.bfg.threadlocal import get_current_registry
+from repoze.bfg.resource import resolve_resource_spec
+from repoze.bfg.decorator import reify
# API
-def render(_renderer_name, **values):
+def render(renderer_name, value, request=None, package=None):
""" Using the renderer specified as ``renderer_name`` (a template
- or a static renderer) render the set of values present in
- ``**values``. Return the result of the renderer's ``__call__``
+ or a static renderer) render the value (or set of values) present
+ in ``value``. Return the result of the renderer's ``__call__``
method (usually a string or Unicode).
If the renderer name refers to a file on disk (such as when the
renderer is a template), it's usually best to supply the name as a
- :term:`resource specification`. You may supply a relative
- filename as renderer name; it will be converted to a resource
- specification by combining the package name of the *caller* of
- this function with the relative filename.
-
- The ``values`` provided will be supplied as top-level names to the
- renderer. These will be augmented by a basic set of top-level
- system names, such as ``request``, ``context``, and
- ``renderer_name` unless any of these names is already provided
- within ``*values``. If :term:`renderer globals` have been
+ :term:`resource specification`.
+
+ You may supply a relative resource spec as ``renderer_name``. If
+ the ``package`` argument is supplied, a relative renderer name
+ will be converted to an absolute resource specification by
+ combining the package supplied as ``package`` with the relative
+ resource specification supplied as ``renderer_name``. If you do
+ not supply a ``package`` (or ``package`` is ``None``) the package
+ name of the *caller* of this function will be used as the package.
+
+ The ``value`` provided will be supplied as the input to the
+ renderer. Usually, for template renderings, this should be a
+ dictionary. For other renderers, this will need to be whatever
+ sort of value the renderer expects.
+
+ The 'system' values supplied to the renderer will include a basic
+ set of top-level system names, such as ``request``, ``context``,
+ and ``renderer_name`. If :term:`renderer globals` have been
specified, these will also be used to agument the value.
- Supply a ``request`` parameter containing the current
- :mod:`repoze.bfg` request as part of ``**values`` in order to
- provide the renderer with the most correct 'system' values
- (``request`` and ``context`` in particular).
+ Supply a ``request`` parameter in order to provide the renderer
+ with the most correct 'system' values (``request`` and ``context``
+ in particular).
.. note:: This API is new in :mod:`repoze.bfg` 1.3.
"""
- package = caller_package()
- request = values.pop('request', None)
- return _render(_renderer_name, request, values, None, None, package)
+ try:
+ registry = request.registry
+ except AttributeError:
+ registry = None
+ if package is None:
+ package = caller_package()
+ renderer = RendererHelper(renderer_name, package=package, registry=registry)
+ return renderer.render(value, None, request=request)
-def render_to_response(_renderer_name, **values):
+def render_to_response(renderer_name, value, request=None, package=None):
""" Using the renderer specified as ``renderer_name`` (a template
- or a static renderer) render the set of values present in
- ``**values``. Return a :term:`Response` object wrapping the result
- of of the renderer's ``__call__`` method.
+ or a static renderer) render the value (or set of values) using
+ the result of the renderer's ``__call__`` method (usually a string
+ or Unicode) as the response body.
If the renderer name refers to a file on disk (such as when the
renderer is a template), it's usually best to supply the name as a
- :term:`resource specification`. You may supply a relative
- filename as renderer name; it will be converted to a resource
- specification by combining the package name of the *caller* of
- this function with the relative filename.
-
- The ``values`` provided will be supplied as top-level names to the
- renderer. These will be augmented by a basic set of top-level
- system names, such as ``request``, ``context``, and
- ``renderer_name`` unless any of these names is already provided
- within ``*values``. If :term:`renderer globals` have been
+ :term:`resource specification`.
+
+ You may supply a relative resource spec as ``renderer_name``. If
+ the ``package`` argument is supplied, a relative renderer name
+ will be converted to an absolute resource specification by
+ combining the package supplied as ``package`` with the relative
+ resource specification supplied as ``renderer_name``. If you do
+ not supply a ``package`` (or ``package`` is ``None``) the package
+ name of the *caller* of this function will be used as the package.
+
+ The ``value`` provided will be supplied as the input to the
+ renderer. Usually, for template renderings, this should be a
+ dictionary. For other renderers, this will need to be whatever
+ sort of value the renderer expects.
+
+ The 'system' values supplied to the renderer will include a basic
+ set of top-level system names, such as ``request``, ``context``,
+ and ``renderer_name`. If :term:`renderer globals` have been
specified, these will also be used to agument the value.
- Supply a ``request`` parameter containing the current
- :mod:`repoze.bfg` request as part of ``**values`` in order to
- provide the renderer with the most correct 'system' values
- (``request`` and ``context`` in particular).
+ Supply a ``request`` parameter in order to provide the renderer
+ with the most correct 'system' values (``request`` and ``context``
+ in particular).
.. note:: This API is new in :mod:`repoze.bfg` 1.3.
+
+ """
+ try:
+ registry = request.registry
+ except AttributeError:
+ registry = None
+ if package is None:
+ package = caller_package()
+ renderer = RendererHelper(renderer_name, package=package, registry=registry)
+ return renderer.render_to_response(value, None, request=request)
+
+def get_renderer(renderer_name, package=None):
+ """ Return the renderer object for the renderer named as
+ ``renderer_name``.
+
+ You may supply a relative resource spec as ``renderer_name``. If
+ the ``package`` argument is supplied, a relative renderer name
+ will be converted to an absolute resource specification by
+ combining the package supplied as ``package`` with the relative
+ resource specification supplied as ``renderer_name``. If you do
+ not supply a ``package`` (or ``package`` is ``None``) the package
+ name of the *caller* of this function will be used as the package.
"""
- package = caller_package()
- request = values.pop('request', None)
- return _render_to_response(_renderer_name, request, values, None, None,
- package)
+ if package is None:
+ package = caller_package()
+ renderer = RendererHelper(renderer_name, package=package)
+ return renderer.get_renderer()
-def get_renderer(spec):
- """ Return the renderer object for the renderer named as ``spec`` """
- package = caller_package()
- return renderer_from_name(spec, package)
# concrete renderer factory implementations (also API)
@@ -146,45 +186,7 @@ def _reload_resources():
return settings and settings.get('reload_resources')
def renderer_from_name(path, package=None):
- from repoze.bfg.configuration import Configurator
- reg = get_current_registry()
- config = Configurator(reg, package=package)
- return config._renderer_from_name(path)
-
-def _render(renderer_name, request, values, system_values, renderer, package):
- try:
- registry = request.registry
- except AttributeError:
- registry = get_current_registry()
-
- if renderer is None:
- from repoze.bfg.configuration import Configurator
- config = Configurator(registry, package=package)
- renderer = config._renderer_from_name(renderer_name)
-
- if system_values is None:
- system_values = {
- 'view':None,
- 'renderer_name':renderer_name,
- 'context':getattr(request, 'context', None),
- 'request':request,
- }
-
- globals_factory = registry.queryUtility(IRendererGlobalsFactory)
-
- if globals_factory is not None:
- renderer_globals = globals_factory(system_values)
- if renderer_globals:
- system_values.update(renderer_globals)
-
- result = renderer(values, system_values)
- return result
-
-def _render_to_response(renderer_name, request, values, system_values,
- renderer, package):
- result = _render(renderer_name, request, values, system_values, renderer,
- package)
- return _make_response(request, result)
+ return RendererHelper(path, package=package).get_renderer()
def rendered_response(renderer, result, view, context, request, renderer_name):
# XXX: deprecated, left here only to not break old code; use
@@ -196,8 +198,9 @@ def rendered_response(renderer, result, view, context, request, renderer_name):
system = {'view':view, 'renderer_name':renderer_name,
'context':context, 'request':request}
- return _render_to_response(renderer_name, request, result, system, renderer,
- None)
+ helper = RendererHelper(renderer_name)
+ helper.renderer = renderer
+ return helper.render_to_response(result, system, request=request)
deprecated('rendered_response',
"('repoze.bfg.renderers.rendered_response' is not a public API; it is "
@@ -205,35 +208,97 @@ deprecated('rendered_response',
"use repoze.bfg.renderers.render_to_response instead')",
)
-def _make_response(request, result):
- try:
- registry = request.registry
- except AttributeError:
- registry = get_current_registry()
-
- response_factory = registry.queryUtility(IResponseFactory,
- default=Response)
-
- response = response_factory(result)
-
- if request is not None:
- attrs = request.__dict__
- content_type = attrs.get('response_content_type', None)
- if content_type is not None:
- response.content_type = content_type
- headerlist = attrs.get('response_headerlist', None)
- if headerlist is not None:
- for k, v in headerlist:
- response.headers.add(k, v)
- status = attrs.get('response_status', None)
- if status is not None:
- response.status = status
- charset = attrs.get('response_charset', None)
- if charset is not None:
- response.charset = charset
- cache_for = attrs.get('response_cache_for', None)
- if cache_for is not None:
- response.cache_expires = cache_for
-
- return response
+class RendererHelper(object):
+ def __init__(self, renderer_name, registry=None, package=None):
+ if registry is None:
+ registry = get_current_registry()
+ self.registry = registry
+ self.package = package
+ if renderer_name is None:
+ factory = registry.queryUtility(IRendererFactory)
+ renderer_type = None
+ else:
+ if '.' in renderer_name:
+ renderer_type = os.path.splitext(renderer_name)[1]
+ renderer_name = self.resolve_spec(renderer_name)
+ else:
+ renderer_type = renderer_name
+ renderer_name = renderer_name
+ factory = registry.queryUtility(IRendererFactory,
+ name=renderer_type)
+ self.renderer_name = renderer_name
+ self.renderer_type = renderer_type
+ self.factory = factory
+
+ @reify
+ def renderer(self):
+ if self.factory is None:
+ raise ValueError('No such renderer factory %s' % self.renderer_type)
+ return self.factory(self.renderer_name)
+
+ def resolve_spec(self, path_or_spec):
+ if path_or_spec is None:
+ return path_or_spec
+
+ package, filename = resolve_resource_spec(path_or_spec,
+ self.package)
+ if package is None:
+ return filename # absolute filename
+ return '%s:%s' % (package, filename)
+
+ def get_renderer(self):
+ return self.renderer
+
+ def render(self, value, system_values, request=None):
+ renderer = self.renderer
+ if system_values is None:
+ system_values = {
+ 'view':None,
+ 'renderer_name':self.renderer_name,
+ 'context':getattr(request, 'context', None),
+ 'request':request,
+ }
+
+ registry = self.registry
+ globals_factory = registry.queryUtility(IRendererGlobalsFactory)
+
+ if globals_factory is not None:
+ renderer_globals = globals_factory(system_values)
+ if renderer_globals:
+ system_values.update(renderer_globals)
+
+ result = renderer(value, system_values)
+ return result
+
+ def render_to_response(self, value, system_values, request=None):
+ result = self.render(value, system_values, request=request)
+ return self._make_response(result, request)
+
+ def _make_response(self, result, request):
+ registry = self.registry
+ response_factory = registry.queryUtility(IResponseFactory,
+ default=Response)
+
+ response = response_factory(result)
+
+ if request is not None:
+ attrs = request.__dict__
+ content_type = attrs.get('response_content_type', None)
+ if content_type is not None:
+ response.content_type = content_type
+ headerlist = attrs.get('response_headerlist', None)
+ if headerlist is not None:
+ for k, v in headerlist:
+ response.headers.add(k, v)
+ status = attrs.get('response_status', None)
+ if status is not None:
+ response.status = status
+ charset = attrs.get('response_charset', None)
+ if charset is not None:
+ response.charset = charset
+ cache_for = attrs.get('response_cache_for', None)
+ if cache_for is not None:
+ response.cache_expires = cache_for
+
+ return response