Source code for hyperpython.html

from functools import wraps

from sidekick import import_later, Proxy

from .core import Text, Element, Block
from .utils.role_dispatch import role_singledispatch, error

django_loader = import_later('django.template.loader')


[docs]def render(obj, role=None, **kwargs): """ Like :func:`render`, but return a string of HTML code instead of a Hyperpython object. """ return html(obj, role=role, **kwargs).__html__()
[docs]@role_singledispatch def html(obj, role=None, **kwargs): """ Convert object into a hyperpython structure. Args: obj: Input object. role: Optional description Additional context variables for the rendering process can be passed as keyword arguments. Returns: A hyperpython object. """ # Try the html_role interface. try: method = obj.html_role except AttributeError: pass else: return method(role=role, **kwargs) # If role is given, we adopt a more strict behavior if role is not None: raise error(type(obj), role) # Fallback to __html__ or string renderers for role-less calls try: raw = obj.__html__() except AttributeError: return Text(str(obj)) else: return Text(raw, escape=False)
# # Auxiliary functions # def register_template(cls, template, role=None): """ Decorator that registers a template-based renderer. (Currently, only Django is supported). Args: cls: Type of input object. template: Template name or list of template names. role: Optional role for the template. Examples: The decorated function must receive an instance of `cls` as first argument and any number of keyword arguments. It should return a context dictionary that is passed to the template to render the final HTML string. @render.register_template(User, 'users/user-contact.html', 'contact') def user_contact(user, **kwargs): return { 'name': user.name, 'email': user.get_public_email(), # ... } The role can be omitted to register a fallback implementation for the given model. The fallback receives the passed role as a keyword argument. @render.register_template(User, 'users/user-generic.html') def user_contact(user, role=None, **kwargs): return { 'user': user, 'role': role, } """ template = django_loader.get_template(template) renderer = template.render def decorator(func): @html.register(cls, role) def wrapped(obj, **kwargs): ctx = func(obj, **kwargs) request = ctx.get('request') data = renderer(context=ctx, request=request) return Text(data, escape=False) return wrapped return decorator html.register_template = register_template # # Register default renderers # def no_role(func): @wraps(func) def wrapped(x, role=None, **kwargs): if role is None: return func(x, **kwargs) raise error(type(x), role) return wrapped html.register(str)(no_role(lambda x: Text(x))) html.register(Proxy)(lambda x, **kwargs: html(x._obj__, **kwargs)) for _cls in (Element, Text, Block): html.register(_cls)(no_role(lambda x: x))