Source code for pyams_viewlet.provider

#
# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#

"""PyAMS_viewlet.provider module

This module provides the "provider:" TALES expression, which allows inclusion of any registered
content provider into a Chameleon or ZPT template.
"""

import re

from chameleon.astutil import Symbol
from chameleon.tales import StringExpr
from zope.contentprovider.interfaces import BeforeUpdateEvent, ContentProviderLookupError, \
    IContentProvider
from zope.contentprovider.tales import addTALNamespaceData
from zope.location.interfaces import ILocation

from pyams_utils.tales import ContextExprMixin


__docformat__ = 'restructuredtext'


FUNCTION_EXPRESSION = re.compile(r'(.+)\((.+)\)', re.MULTILINE | re.DOTALL)
ARGUMENTS_EXPRESSION = re.compile(r'[^(,)]+')

CONTENT_PROVIDER_NAME = re.compile(r'([A-Za-z0-9_\-\.]+)')


[docs]def render_content_provider(econtext, name): """TALES provider: content provider This TALES expression is used to render a registered "content provider", which is an adapter providing IContentProvider interface; adapter lookup is based on current context, request and view. The requested provider can be called with our without arguments, like in ${structure:provider:my_provider} or ${structure:provider:my_provider(arg1, arg2)}. In the second form, arguments will be passed to the "update" method; arguments can be static (like strings or integers), or can be variables defined into current template context; other Python expressions including computations or functions calls are actually not supported, but dotted syntax is supported to access inner attributes of variables. Provider arguments can be passed by position but can also be passed by name, using classic syntax as in ${structure:provider:my_provider(arg1, arg3=var3)} """ def get_value(econtext, arg): """Extract argument value from context Extension expression language is quite simple. Values can be given as positioned strings, integers or named arguments of the same types. """ arg = arg.strip() if arg.startswith('"') or arg.startswith("'"): # may be a quoted string... return arg[1:-1] if '=' in arg: key, value = arg.split('=', 1) value = get_value(econtext, value) return {key.strip(): value} try: arg = int(arg) # check integer value except ValueError: args = arg.split('.') result = econtext.get(args.pop(0)) for arg in args: # pylint: disable=redefined-argument-from-local result = getattr(result, arg) return result else: return arg name = name.strip() context = econtext.get('context') request = econtext.get('request') view = econtext.get('view') args, kwargs = [], {} func_match = FUNCTION_EXPRESSION.match(name) if func_match: name, arguments = func_match.groups() for arg in map(lambda x: get_value(econtext, x), ARGUMENTS_EXPRESSION.findall(arguments)): if isinstance(arg, dict): kwargs.update(arg) else: args.append(arg) else: match = CONTENT_PROVIDER_NAME.match(name) if match: name = match.groups()[0] else: raise ContentProviderLookupError(name) registry = request.registry provider = registry.queryMultiAdapter((context, request, view), IContentProvider, name=name) # raise an exception if the provider was not found. if provider is None: raise ContentProviderLookupError(name) # add the __name__ attribute if it implements ILocation if ILocation.providedBy(provider): provider.__name__ = name # Insert the data gotten from the context addTALNamespaceData(provider, econtext) # Stage 1: Do the state update registry.notify(BeforeUpdateEvent(provider, request)) provider.update(*args, **kwargs) # Stage 2: Render the HTML content return provider.render()
[docs]class ProviderExpr(ContextExprMixin, StringExpr): """provider: TALES expression""" transform = Symbol(render_content_provider)