Template helpers (bottle_utils.html)

Contents of this module are mostly meant to be used inside the view templates, but their usage is not limited to templates by any means. bottle_utils.html contains a few data-formatting functions as well as shortcuts for generating HTML snippets and binding data to form fields.

Basic usage

One way to make the module contents available to templates is to add the module itself as a default template variable.:

import bottle
from bottle_utils import html
bottle.BaseTemplate.defaults['h'] = html

This allows you to use the module members by access the h variable in templates:

<html {{! h.attr('lang', request.locale }}>

Note

If your tempate engine auto-escapes HTML, you need to instruct it to unescape strings gneerated by some of the helper functions. For instance, in Bottle’s SimpleTemplate engine, you need to enclose the strings in {{! }}.

Data formatting

bottle_utils.html.hsize(size, unit=u'B', step=1024, rounding=2, sep=u' ')[source]

Given size in unit produce size with human-friendly units. This is a simple formatting function that takes a value, a unit in which the value is expressed, and the size of multiple (kilo, mega, giga, etc).

This function rounds values to 2 decimal places and does not handle fractions. It also uses metric prefixes (K, M, G, etc) and only goes up to Peta (P, quadrillion) prefix. The number of decimal places can be customized using the rounding argument.

The size multiple (step parameter) is 1024 by default, suitable for expressing values related to size of data on disk.

The sep argument represents a separator between values and units.

Example:

>>> hsize(12)
'12.00 B'
>>> hsize(1030)
'1.01 KB'
>>> hsize(1536)
'1.50 KB'
>>> hsize(2097152)
'2.00 MB'
>>> hsize(12, sep='')
'12.00B'
bottle_utils.html.plur(word, n, plural=<function <lambda>>, convert=<function <lambda>>)[source]

Pluralize word based on number of items. This function provides rudimentary pluralization support. It is quite flexible, but not a replacement for functions like ngettext.

This function takes two optional arguments, plural() and convert(), which can be customized to change the way plural form is derived from the original string. The default implementation is a naive version of English language plural, which uses plural form if number is not 1, and derives the plural form by simply adding ‘s’ to the word. While this works in most cases, it doesn’t always work even for English.

The plural(n) function takes the value of the n argument and its return value is fed into the convert() function. The latter takes the source word as first argument, and return value of plural() call as second argument, and returns a string representing the pluralized word. Return value of the convert(w, p) call is returned from this function.

Here are some simple examples:

>>> plur('book', 1)
'book'
>>> plur('book', 2)
'books'

# But it's a bit naive
>>> plur('box', 2)
'boxs'

The latter can be fixed like this:

>>> exceptions = ['box']
>>> def pluralize(word, is_plural):
...    if not is_plural:
...        return word
...    if word in exceptions:
...        return word + 'es'
...    return word + 's'
>>> plur('book', 2)
'books'
>>> plur('box', 2, convert=pluralize)
'boxes'
bottle_utils.html.strft(ts, fmt)[source]

Reformat string datestamp/timestamp. This function parses a string representation of a date and/or time and reformats it using specified format.

The format is standard strftime format used in Python’s datetime.datetime.strftime() call.

Actual parsing of the input is delegated to python-dateutil library.

bottle_utils.html.trunc(s, chars)[source]

Trucante string at n characters. This function hard-trucates a string at specified number of characters and appends an elipsis to the end.

The truncating does not take into account words or markup. Elipsis is not appended if the string is shorter than the specified number of characters.

>>> trunc('foobarbaz', 6)
'foobar...'

Note

Keep in mind that the trucated string is always 3 characters longer than n because of the appended elipsis.

bottle_utils.html.yesno(val, yes=u'yes', no=u'no')[source]

Return yes or no depending on value. This function takes the value and returns either yes or no depending on whether the value evaluates to True.

Examples:

>>> yesno(True)
'yes'
>>> yesno(False)
'no'
>>> yesno(True, 'available', 'not available')
'available'

HTML rendering

bottle_utils.html.tag(name, content=u'', nonclosing=False, **attrs)[source]

Wraps content in a HTML tag with optional attributes. This function provides a Pythonic interface for writing HTML tags with a few bells and whistles.

The basic usage looks like this:

>>> tag('p', 'content', _class="note", _id="note1")
'<p class="note" id="note1">content</p>'

Any attribute names with any number of leading underscores (e.g., ‘_class’) will have the underscores strpped away.

If content is an iterable, the tag will be generated once per each member.

>>> tag('span', ['a', 'b', 'c'])
'<span>a</span><span>b</span><span>c</span>'

It does not sanitize the tag names, though, so it is possible to specify invalid tag names:

>>> tag('not valid')
'<not valid></not valid>

Warning

Please ensure that name argument does not come from user-specified data, or, if it does, that it is properly sanitized (best way is to use a whitelist of allowed names).

Because attributes are specified using keyword arguments, which are then treated as a dictionary, there is no guarantee of attribute order. If attribute order is important, don’t use this function.

This module contains a few partially applied aliases for this function. These mostly have hard-wired first argument (tag name), and are all uppercase:

  • A - alias for <a> tag
  • BUTTON - alias for <button> tag
  • HIDDEN - alias for <input> tag with type="hidden" attribute
  • INPUT - alias for <input> tag with nonclosing set to True
  • LI - alias for <li> tag
  • OPTION - alias for <option> tag
  • P - alias for <p> tag
  • SELECT - alias for <select> tag
  • SPAN - alias for <span> tag
  • SUBMIT - alias for <button> tag with type="submit" attribute
  • TEXTAREA - alias for <textarea> tag
  • UL - alias for <ul> tag

Only wrap label in anchor if given target URL, url, does not match the path. Given a label, this function will match the page URL against the path to which the anchor should point, and generate the anchor element markup as necessary. If the paths, match, wrapper will be used to generate the markup around the label.

Any additional keyword arguments are passed to the function that generates the anchor markup, which is A() alias of the tag() function.

If the URLs match (meaning the page URL matches the target path), the label will be passed to the wrapper function. The default wrapper function is SPAN(), so the label is wrapped in SPAN tag when the URLs matches.:

>>> link_other('foo', '/here', '/there')
'<a href="/target">foo</a>'
>>> link_other('foo', '/there', '/there')
'<span>foo</span>'

You can customize the appearance of the label in the case URLs match by customizing the wrapper:

>>> link_other('foo', '/there', '/there',
...            wrapper=lambda l, **kw: l + 'bar')
'foobar'

Note that the wrapper lambda function has wild-card keyword arguments. The wrapper function accepts the same extra keyword arguments that the anchor function does, so if you have common classes and similar attributes, you can specify them as extra keyword arguments and use any of the helper functions in this module.:

>>> link_other('foo', '/here', '/there', wrapper=BUTTON, _class='cls')
'<a class="cls" href="/target">foo</a>'
>>> link_other('foo', '/there', '/there', wrapper=BUTTON, _class='cls')
'<button class="cls">foo</button>'
bottle_utils.html.vinput(name, values, **attrs)[source]

Render input with bound value. This function can be used to bind values to form inputs. By default it will result in HTML markup for a generic input. The generated input has a name attribute set to specified name, and an id attribute that has the same value.

>>> vinput('foo', {})
'<input name="foo" id="foo">'

If the supplied dictionary of field values contains a key that matches the specified name (case-sensitive), the value of that key will be used as the value of the input:

>>> vinput('foo', {'foo': 'bar'})
'<input name="foo" id="foo" value="bar">'

All values are properly sanitized before they are added to the markup.

Any additional keyword arguments that are passed to this function are passed on the tag() function. Since the generated input markup is for generic text input, some of the other usual input types can be specified using _type parameter:

>>> input('foo', {}, _type='email')
'<input name="foo" id="foo" type="email">'
bottle_utils.html.varea(name, values, **attrs)[source]

Render textarea with bound value. Textareas use a somewhat different markup to that of regular inputs, so a separate function is used for binding values to this form control.:

>>> varea('foo', {'foo': 'bar'})
'<textarea name="foo" id="foo">bar</textarea>'

This function works the same way as vinput() function, so please look at it for more information. The primary difference is in the generated markup.

bottle_utils.html.vcheckbox(name, value, values, default=False, **attrs)[source]

Render checkbox with bound value. This function renders a checkbox which is checked or unchecked depending on whether its own name-value combination appears in the provided form values dictionary.

Because there are many ways to think about checkboxes in general, this particular function may or may not work for you. It treats checkboxes as a list of alues which are all named the same.

Let’s say we have markup that looks like this:

<input type="checkbox" name="foo" value="1">
<input type="checkbox" name="foo" value="2">
<input type="checkbox" name="foo" value="3">

If user checks all of them, we consider it a list foo=['1', '2', '3']. If user checks only the first and last, we have foo=['1', '3']. And so on.

This function assumes that you are using this pattern.

The values map can either map the checkbox name to a single value, or a list of multiple values. In the former case, if the single value matches the value of the checkbox, the checkbox is checked. In the latter case, if value of the checkbox is found in the list of values, the checkbox is checked.:

>>> vcheckbox('foo', 'bar', {'foo': 'bar'})
'<input type="checkbox" name="foo" id="foo" value="bar" checked>'
>>> vcheckbox('foo', 'bar', {'foo': ['foo', 'bar', 'baz']})
'<input type="checkbox" name="foo" id="foo" value="bar" checked>'
>>> vcheckbox('foo', 'bar', {'foo': ['foo', 'baz']})
'<input type="checkbox" name="foo" id="foo" value="bar">'

When the field values dictionary doesn’t contain a key that matches the checkbox name, the value of default keyword argument determines whether the checkbox should be checked:

>>> vcheckbox('foo', 'bar', {}, default=True)
'<input type="checkbox" name="foo" id="foo" value="bar" checked>'
bottle_utils.html.vselect(name, choices, values, empty=None, **attrs)[source]

Render select list with bound value. This function renders the select list with option elements with appropriate element selected based on field values that are passed.

The values and labels for option elemnets are specified using an iterable of two-tuples:

>>> vselect('foo', ((1, 'one'), (2, 'two'),), {})
'<select name="foo" id="foo"><option value="1">one</option><option...'

There is no mechanism for default value past what browsers support, so you should generally assume that most browsers will render the select with frist value preselected. Using an empty string or None as option value will render an option element without value:

>>> vselect('foo', ((None, '---'), (1, 'one'),), {})
'<select name="foo" id="foo"><option value>---</option><option val...'
>>> vselect('foo', (('', '---'), (1, 'one'),), {})
'<select name="foo" id="foo"><option value="">---</option><option ...'

When specifying values, keep in mind that only None is special, in that it will crete a value attribute without any value. All other Python types become strings in the HTML markup, and are submitted as such. You will need to convert the values back to their appropriate Python type manually.

If the choices iterable does not contain an element representing the empty value (None), you can specify it using the empty parameter. The argument for empty should be a label, and the matching value is None. The emtpy value is always inseted at the beginning of the list.

bottle_utils.html.form(method=None, action=None, csrf=False, multipart=False, **attrs)[source]

Render open form tag. This function renders the open form tag with additional features, such as faux HTTP methods, CSRF token, and multipart support.

All parameters are optional. Using this function without any argument has the same effect as naked form tag without any attributes.

Method names can be either lowercase or uppercase.

The methods other than GET and POST are faked using a hidden input with _method name and uppercase name of the HTTP method. The form will use POST method in this case. Server-side support is required for this feature to work.

Any additional keyword arguments will be used as attributes for the form tag.

URL handling

class bottle_utils.html.QueryDict(qs=u'')[source]

Represents a query string in bottle.MultiDict format.

This class differs from the base bottle.MultiDict class in two ways. First, it is instantiated with raw query string, rather than a list of two-tuples:

>>> q = QueryDict('a=1&b=2')

The query string is parsed and converted to MultiDict format. This works exactly the same way as request.query.

Second difference is the way string coercion is handled. QueryDict instances can be converted back into a query string by coercing them into string or bytestring:

>>> str(q)
'a=1&b=2'

The coercion also happens when using the + operator to concatenate with other strings:

>>> 'foo' + q
'foo?a=1&b=2'

Notice that the ‘?’ character is inserted when using the + operator.

Note

When converting back to string, the order of parameters in the resulting query string may differ from the original.

Furthermore, additional methods have been added to provide chaining capability in conjunction with *_qparam() functions in this module.

For instance:

>>> q = QueryDict('a=1&b=2')
>>> q.del_qparam('a').set_qparam(b=3).add_qparam(d=2, k=12)
>>> str(s)
'b=3&d=2&k=12'

When used with functions like add_qparam(), this provides a more intuitive API:

>>> qs = 'a=1&b=2'
>>> q = add_qparam(qs, c=2).set_qparam(a=2)
>>> str(q)
'a=2&b=2&c=2'

Since this class is a bottle.MultiDict subclass, you can expect it to behave the same way as a regular MultiDict object. You can assign values to keys, get values by key, get all items as a list of key-value tuples, and so on. Please consult the Bottle documentation for more information on how MultiDict objects work.

add_qparam(**params)[source]

Add query parameter. Any keyword arguments passed to this function will be converted to query parameters.

Returns the instance for further chaining.

del_qparam(*params)[source]

Remove a query parameter. Takes any number of parameter names to be removed.

Returns the instance for further chaining.

set_qparam(**params)[source]

Replace or add parameter. Any keyword arguments passed to this function will be converted to query parameters.

Returns the instance for further chaining.

to_qs()[source]

Return the string representation of the query string with prepended ‘?’ character.

bottle_utils.html.add_qparam(qs=None, **params)[source]

Add parameter to query string

If query string is omitted request.query_string is used.

Any keyword arguments passed to this function will be converted to query parameters.

The returned object is a QueryDict instance, which is a bottle.MultiDict subclass.

Example:

>>> q = add_qparam('a=1', b=2)
>>> str(q)
'a=1&b=2'
>> q = add_qparam('a=1', a=2)
>>> str(q)
'a=1&a=2'
bottle_utils.html.set_qparam(qs=None, **params)[source]

Replace or add parameters to query string

If query string is omitted request.query_string is used.

Any keyword arguments passed to this function will be converted to query parameters.

The returned object is a QueryDict instance, which is a bottle.MultiDict subclass.

bottle_utils.html.del_qparam(qs=None, *params)[source]

Remove query string parameters

If query string is None or empty, request.query_string is used.

Second and subsequent positional arguments are query parameter names to be removed from the query string.

The returned object is a QueryDict instance, which is a bottle.MultiDict subclass.

bottle_utils.html.urlquote(value)
bottle_utils.html.urlunquote(value)
bottle_utils.html.quote_dict(mapping)[source]

URL quote keys and values of the passed in dict-like object.

Parameters:mappingbottle.MultiDict or dict-like object
Returns:dict with url quoted values
bottle_utils.html.quoted_url(route, **params)[source]

Return matching URL with it’s query parameters quoted.