diff options
| author | Chris McDonough <chrism@agendaless.com> | 2010-08-13 09:56:20 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2010-08-13 09:56:20 +0000 |
| commit | 62b4794bb4c52080aaccc8058147f4ebe34caba6 (patch) | |
| tree | 40701910cd853c169fd4720e4fb974a9b72ce60b /repoze/bfg/renderers.py | |
| parent | ec55db55aba80618fb250aace0d22f0aa56cef1f (diff) | |
| download | pyramid-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.py | 301 |
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 |
