Widgets

Widgets are small self-contained components that can be reused across the same web page or across multiple pages.

A widget typically has a state (its value) a configuration (its params) a template that describes what should be displayed, one ore more resources (javascript or CSS) needed during display and might have some logic that has to be executed every time the widget is displayed.

Using Widgets

A typical widget will look like:

class MyWidget(tw2.core.Widget):
    template = "mypackage.widgets.templates.mywidget"

Which will look for a template named mywidget.html into the templates python package within the widgets package of the mypackage application. The extension expected for the file depends on the template engine used:

  • mako: .mako
  • kajiki: .kajiki
  • jinja: .jinja
  • genshi: .genshi

The template engine used to render the provided template depends on the default_engine option provided when configuring tw2.core.middleware.TwMiddleware.

In case you don’t want to save the template into a separate file you can also set the inline_engine_name option to one of the template engines and provide the template as a string:

class HelloWidgetTemplate(tw2.core.Widget):
    inline_engine_name = "kajiki"
    template = """
        <i>Hello <span py:for="i in range(1, 4)">${i}, </span></i>
    """

Displaying a widget is as simple as calling the Widget.display():

HelloWidgetTemplate.display()

Widget value

Each Widget has a special paramter, which is value. This parameter contains the current state of the widget. Value will usually be a single value or a dictionary containing multiple values (in case of tw2.core.widgets.CompoundWidget).

You can use the value to drive what the widget should show once displayed:

class HelloWidgetValue(tw2.core.Widget):
    inline_engine_name = "kajiki"
    template = """
        <i>Hello ${w.value}</i>
    """

>>> HelloWidgetValue.display(value='World')
Markup('<i>Hello World</i>')

tw2.core.CompoundWidget can contain multiple subwidgets (children) and their value is typically a dict with values for each one of the children:

class CompoundHello(tw2.core.CompoundWidget):
    inline_engine_name = "kajiki"
    template = """
        <div py:for="c in w.children">
            ${c.display()}
        </div>
    """

    name = HelloWidgetValue()
    greeter = tw2.core.Widget(inline_engine_name="kajiki",
                              template="<span>From ${w.value}</span>")

>>> CompoundHello(value=dict(name="Mario", greeter="Luigi")).display()
Markup('<div><span>Hello Mario</span></div><div><span>From Luigi</span></div>')

Children of a compound widget (like Forms) can be accessed both as a list iterating over w.children or by name using w.children.childname.

Parameters

Widgets might require more information than just their value to display, or might allow more complex kind of configurations. The options required to configure the widget are provided through tw2.core.Param objects that define which options each widget supports.

If you want your widget to be configurable, you can make available one or more options to your Widget and allow any user to set them as they wish:

class HelloWidgetParam(tw2.core.Widget):
    inline_engine_name = "kajiki"
    template = """
        <i>Hello ${w.name}</i>
    """

    name = tw2.core.Param(description="Name of the greeted entity")

The parameters can be provided any time by changing configuration of a widget:

>>> w = HelloWidgetParam(name="Peach")
>>> w.display()
Markup('<i>Hello Peach</i>')
>>> w2 = w(name="Toad")
>>> w2.display()
Markup('<i>Hello Toad</i>')

Or can be provided at display time itself:

>>> HelloWidgetParam.display(name="Peach")
Markup('<i>Hello Peach</i>')

Deferred Parameters

When a widget requires a parameter that is not available before display time. That parameter can be set to a tw2.core.Deferred object.

Deferred objects will accept any callable and before the widget is displayed the callable will be executed to fetch the actual value for the widget:

>>> singleselect = SingleSelectField(options=tw2.core.Deferred(lambda: [1,2,3]))
>>> singleselect.options
<Deferred: <Deferred>>
>>> singleselect.display()
Markup('<select ><option value=""></option>\n <option value="1">1</option>\n <option value="2">2</option>\n <option value="3">3</option>\n</select>')

Deferred is typically used when loading data from the content of a database to ensure that the content is the one available at the time the widget is displayed and not the one that was available when the application started:

>>> userpicker = twf.SingleSelectField(
...     options=twc.Deferred(lambda: [(u.user_id, u.display_name) for u in model.DBSession.query(model.User)])
... )
>>> userpicker.display()
Markup('<select ><option value=""></option>\n <option value="1">Example manager</option>\n <option value="2">Example editor</option>\n</select>')

Builtin Widgets

The tw2.core packages comes with the basic buildin blocks needed to create your own custom widgets.

class tw2.core.widgets.Widget(**kw)[source]

Base class for all widgets.

classmethod req(**kw)[source]

Generate an instance of the widget.

Return the validated widget for this request if one exists.

classmethod post_define()[source]

This is a class method, that is called when a subclass of this Widget is created. Process static configuration here. Use it like this:

class MyWidget(LeafWidget):
    @classmethod
    def post_define(cls):
        id = getattr(cls,  'id', None)
        if id and not id.startswith('my'):
            raise pm.ParameterError("id must start with 'my'")

post_define should always cope with missing data - the class may be an abstract class. There is no need to call super(), the metaclass will do this automatically.

Get the URL to the controller . This is called at run time, not startup time, so we know the middleware if configured with the controller path. Note: this function is a temporary measure, a cleaner API for this is planned.

prepare()[source]

This is an instance method, that is called just before the Widget is displayed. Process request-local configuration here. For efficiency, widgets should do as little work as possible here. Use it like this:

class MyWidget(Widget):
    def prepare(self):
        super(MyWidget, self).prepare()
        self.value = 'My: ' + str(self.value)
iteritems()[source]

An iterator which will provide the params of the widget in key, value pairs.

controller_path = <functools.partial object>[source]
add_call = <functools.partial object>[source]
display = <functools.partial object>[source]
generate_output(displays_on)[source]

Generate the actual output text for this widget.

By default this renders the widget’s template. Subclasses can override this method for purely programmatic output.

displays_on
The name of the template engine this widget is being displayed inside.

Use it like this:

class MyWidget(LeafWidget):
    def generate_output(self, displays_on):
        return "<span {0}>{1}</span>".format(self.attrs, self.text)
classmethod validate(params, state=None)[source]

Validate form input. This should always be called on a class. It either returns the validated data, or raises a ValidationError exception.

class tw2.core.widgets.LeafWidget(**kw)[source]

A widget that has no children; this is the most common kind, e.g. form fields.

class tw2.core.widgets.CompoundWidget(**kw)[source]

A widget that has an arbitrary number of children, this is common for layout components, such as tw2.forms.TableLayout.

classmethod post_define()[source]

Check children are valid; update them to have a link to the parent.

prepare()[source]

Propagate the value for this widget to the children, based on their id.

class tw2.core.widgets.RepeatingWidget(**kw)[source]

A widget that has a single child, which is repeated an arbitrary number of times, such as tw2.forms.GridLayout.

classmethod post_define()[source]

Check child is valid; update with link to parent.

prepare()[source]

Propagate the value for this widget to the children, based on their index.

class tw2.core.widgets.DisplayOnlyWidget(**kw)[source]

A widget that has a single child. The parent widget is only used for display purposes; it does not affect value propagation or validation. This is used by widgets like tw2.forms.FieldSet.

classmethod post_define()[source]

This is a class method, that is called when a subclass of this Widget is created. Process static configuration here. Use it like this:

class MyWidget(LeafWidget):
    @classmethod
    def post_define(cls):
        id = getattr(cls,  'id', None)
        if id and not id.startswith('my'):
            raise pm.ParameterError("id must start with 'my'")

post_define should always cope with missing data - the class may be an abstract class. There is no need to call super(), the metaclass will do this automatically.

prepare()[source]

This is an instance method, that is called just before the Widget is displayed. Process request-local configuration here. For efficiency, widgets should do as little work as possible here. Use it like this:

class MyWidget(Widget):
    def prepare(self):
        super(MyWidget, self).prepare()
        self.value = 'My: ' + str(self.value)
class tw2.core.widgets.Page(**kw)[source]

An HTML page. This widget includes a request() method that serves the page.

classmethod post_define()[source]

This is a class method, that is called when a subclass of this Widget is created. Process static configuration here. Use it like this:

class MyWidget(LeafWidget):
    @classmethod
    def post_define(cls):
        id = getattr(cls,  'id', None)
        if id and not id.startswith('my'):
            raise pm.ParameterError("id must start with 'my'")

post_define should always cope with missing data - the class may be an abstract class. There is no need to call super(), the metaclass will do this automatically.

class tw2.core.Param(description=Default, default=Default, request_local=Default, attribute=Default, view_name=Default)[source]

A parameter for a widget.

description
A string to describe the parameter. When overriding a parameter description, the string can include $$ to insert the previous description.
default
The default value for the parameter. If no defalt is specified, the parameter is a required parameter. This can also be specified explicitly using tw.Required.
request_local
Can the parameter be overriden on a per-request basis? (default: True)
attribute
Should the parameter be automatically included as an attribute? (default: False)
view_name
The name used for the attribute. This is useful for attributes like class which are reserved names in Python. If this is None, the name is used. (default: None)

The class takes care to record which arguments have been explictly specifed, even if to their default value. If a parameter from a base class is updated in a subclass, arguments that have been explicitly specified will override the base class.

class tw2.core.Deferred(fn)[source]

This class is used as a wrapper around a parameter value. It takes a callable, which will be called every time the widget is displayed, with the returned value giving the parameter value.

Resources

ToscaWidgets comes with resources management for widgets too.

Some widgets might be complex enough that they need external resources to work properly. Typically those are CSS stylesheets or Javascript functions.

The need for those can be specified in the Widget.resources param, which is a list of resources the widget needs to work properly

The tw2.core.middleware.TwMiddleware takes care of serving all the resources needed by a widget through a tw2.core.resources.ResourcesApp. There is not need to setup such application manually, having a TwMiddleware in place will provide support for resources too.

When a widget is being prepared for display, all resources that it requires (as specified by tw2.core.Widget.resources) are registered into the current request and while the response page output goes through the middleware it will be edited to add the links (or content) of those resources as specified by their location.

Note

If a resource was already injected into the page during current request and another widget requires it, it won’t be injected twice. ToscaWidgets is able to detect that it’s the same resource (thanks to the resource id) and only inject that once.

To add resources to a widget simply specify them in tw2.core.Widget.resources:

class HelloWidgetClass(twc.Widget):
    inline_engine_name = "kajiki"
    template = """
        <i class="${w.css_class}">Hello ${w.name}</i>
    """

    name = twc.Param(description="Name of the greeted entity")
    css_class = twc.Param(description="Class used to display content", default="red")

    resources = [
        twc.CSSSource(src="""
            .red { color: red; }
            .green { color: green; }
            .blue { color: blue; }
        """)
    ]

Once the page where the widget is displayed is rendered, you will see that it begins with:

<!DOCTYPE html>
<html>
<head><style type="text/css">
            .red { color: red; }
            .green { color: green; }
            .blue { color: blue; }
        </style>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<meta charset="utf-8">

Which contains the CSS resource you specified as a dependency of your widget.

In case you are using a solution to package your resources into bundles like WebPack, WebAssets or similar, you might want to disable resources injection using inject_resoures=False option provided to tw2.core.middleware.TwMiddleware to avoid injecting resources that were already packed into your bundle.

Builtin Resource Types

class tw2.core.resources.ResourceBundle(**kw)[source]

Just a list of resources.

Use it as follows:

>>> jquery_ui = ResourceBundle(resources=[jquery_js, jquery_css])
>>> jquery_ui.inject()
class tw2.core.resources.Resource(**kw)[source]

A resource required by a widget being displayed.

location states where the resource should be injected into the page. Can be any of head, headbottom, bodytop or bodybottom or None.

A link to a file.

The link parameter can be used to specify the explicit link to a URL.

If omitted, the link will be built to serve filename from modname as a resource coming from a python distribution.

classmethod guess_modname()[source]

Try to guess my modname.

If I wasn’t supplied any modname, take a guess by stepping back up the frame stack until I find something not in tw2.core

classmethod post_define()[source]

This is a class method, that is called when a subclass of this Widget is created. Process static configuration here. Use it like this:

class MyWidget(LeafWidget):
    @classmethod
    def post_define(cls):
        id = getattr(cls,  'id', None)
        if id and not id.startswith('my'):
            raise pm.ParameterError("id must start with 'my'")

post_define should always cope with missing data - the class may be an abstract class. There is no need to call super(), the metaclass will do this automatically.

A whole directory as a resource.

Unlike JSLink and CSSLink, this resource doesn’t inject anything on the page.. but it does register all resources under the marked directory to be served by the middleware.

This is useful if you have a css file that pulls in a number of other static resources like icons and images.

A JavaScript source file.

By default is injected in whatever default place is specified by the middleware.

A CSS style sheet.

By default it’s injected at the top of the head node.

class tw2.core.resources.JSSource(**kw)[source]

Inline JavaScript source code.

By default is injected before the </body> is closed

class tw2.core.resources.CSSSource(**kw)[source]

Inline Cascading Style-Sheet code.

By default it’s injected at the top of the head node.