core.widgets

Provides widgets.

Widgets are small rendered pieces such as news messages or upcoming events. They are defined with XLS and can be combinded with simple XML.

A widget is simply a class with a tag and template attribute and optionally a get_variables method:

class MyWidget:
    tag = 'my-widget'
    template = (
        '<xsl:template match="my-widget">'
        '    <div tal:attributes="class foo">'
        '        <xsl:apply-templates select="node()"/>'
        '    </div>'
        '</xsl:template>'
    )

    def get_variables(self, layout):
        return {'foo': 'bar'}

XML using the widget tags can then be transformed to chameleon HTML/XML. The widget variables need to be injected before rendering:

from onegov.core.templates import PageTemplate
widgets = [MyWidget()]
structure = '<my-widget>Hello world!</my-widget>'
template = PageTemplate(transform_structure(widgets, structure))
layout = None
template.render(**inject_variables(widgets, layout, structure))

Module Contents

Classes

Widget

Base class for protocol classes.

Functions

parse_structure(→ lxml.etree._Element)

Takes the XML structure and returns the parsed etree xml.

transform_structure(→ str)

Takes the XML structure and transforms it into a chameleon template.

inject_variables(…)

Takes the widgets, layout, structure and a dict of variables meant

Attributes

XSLT_BASE

XML_BASE

XML_LINE_OFFSET

class core.widgets.Widget[source]

Bases: Protocol

Base class for protocol classes.

Protocol classes are defined as:

class Proto(Protocol):
    def meth(self) -> int:
        ...

Such classes are primarily used with static type checkers that recognize structural subtyping (static duck-typing), for example:

class C:
    def meth(self) -> int:
        return 0

def func(x: Proto) -> int:
    return x.meth()

func(C())  # Passes static type check

See PEP 544 for details. Protocol classes decorated with @typing.runtime_checkable act as simple-minded runtime protocols that check only the presence of given attributes, ignoring their type signatures. Protocol classes can be generic, they are defined as:

class GenProto(Protocol[T]):
    def meth(self) -> T:
        ...
property tag: str[source]
property template: str[source]
core.widgets.XSLT_BASE = Multiline-String[source]
Show Value
"""<?xml version="1.0" encoding="UTF-8"?>

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:i18n="http://xml.zope.org/namespaces/i18n"
    xmlns:metal="http://xml.zope.org/namespaces/metal"
    xmlns:tal="http://xml.zope.org/namespaces/tal">

    <xsl:template match="@*|node()" name="identity">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
    </xsl:template>

    <xsl:template match="page">
      <div class="homepage">
        <xsl:apply-templates select="@*|node()"/>
      </div>
    </xsl:template>

    {}

    </xsl:stylesheet>

"""
core.widgets.XML_BASE = Multiline-String[source]
Show Value
"""<?xml version="1.0" encoding="UTF-8"?>

    <page xmlns:i18n="http://xml.zope.org/namespaces/i18n"
          xmlns:metal="http://xml.zope.org/namespaces/metal"
          xmlns:tal="http://xml.zope.org/namespaces/tal">

          {}

    </page>
"""
core.widgets.XML_LINE_OFFSET = 6[source]
core.widgets.parse_structure(widgets: Collection[Widget], structure: str) lxml.etree._Element[source]

Takes the XML structure and returns the parsed etree xml.

Raises a wtforms.ValidationError if there’s an element which is not supported.

We could do this with DTDs but we don’t actually need to, since we only care to not include any unknown tags.

Note that we try to make sure that this is no vector for remote code execution, but we ultimately do not guarantee it can’t happen.

This xml structure is meant to be static or possibly changeable by admins. Ordinary users should not be able to influence this structure.

core.widgets.transform_structure(widgets: Collection[Widget], structure: str) str[source]

Takes the XML structure and transforms it into a chameleon template.

The app is required as it contains the available widgets.

core.widgets.inject_variables(widgets: Collection[Widget], layout: core.layout.Layout, structure: Literal[] | None, variables: None = None, unique_variable_names: bool = True) None[source]
core.widgets.inject_variables(widgets: Collection[Widget], layout: core.layout.Layout, structure: Literal[] | None, variables: core.types.RenderData, unique_variable_names: bool = True) core.types.RenderData
core.widgets.inject_variables(widgets: Collection[Widget], layout: core.layout.Layout, structure: str, variables: None = None, unique_variable_names: bool = True) RenderData | None
core.widgets.inject_variables(widgets: Collection[Widget], layout: core.layout.Layout, structure: str | None, variables: core.types.RenderData, unique_variable_names: bool = True) core.types.RenderData

Takes the widgets, layout, structure and a dict of variables meant for the template engine and injects the variables required by the widgets, if the widgets are indeed in use.