Bottle Utils documentation¶
Bottle Utils (package name bottle-utils
) is a collection of decorators,
functions and classes that address typical problems developing web sites and
applications using Bottle framework. This package is created based on code
we use at Outernet for various user-facing interfaces as well as our own
sites.
Bottle Utils are compatible with Python 2.7, 3.3, and 3.4. Compatibility with other versions of Python is possible, but not tested. It targets latest stable release of Bottle.
Installation¶
Use one of the following commands to install Bottle Utils:
pip install bottle-utils
easy_install bottle-utils
Note
Between versions 0.3 and 0.5, bottle-utils package was split into multiple packages. Packages were structured in a way that allowed the API prior to version 0.3 to work without issues. However, this has caused various problems with deployment and development, and the approach was subsequently abandoned. Starting with version 0.5, Bottle Utils is again a monolithic package.
Source code¶
The complete source code is licensed under BSD license (see LICENSE
file in
the source package), and available on GitHub.
Package contents¶
The following functionality is available:
Common utilities (bottle_utils.common
)¶
The bottle_utils.common
module contains functions and constants that are
used in other modules.
This module also contains a few constants and variables that improve code that targets both Python 2.x and Python 3.x. Note, though, that this mostly works in the context of Bottle Utils and hasn’t been tested in too many different versions of Python. If you want a more comprehensive solution, you should look at six.
This module also contains names unicode
and basestring
, which work as
expected in both Python 2.x and Python 3.x.
Module contents¶
-
bottle_utils.common.
PY3
= False¶ Whether Python version is 3.x
-
bottle_utils.common.
PY2
= True¶ Whether Python version is 2.x
-
bottle_utils.common.
to_unicode
(v, encoding=u'utf8')[source]¶ Convert a value to Unicode string (or just string in Py3). This function can be used to ensure string is a unicode string. This may be useful when input can be of different types (but meant to be used when input can be either bytestring or Unicode string), and desired output is always Unicode string.
The
encoding
argument is used to specify the encoding for bytestrings.
-
bottle_utils.common.
to_bytes
(v, encoding=u'utf8')[source]¶ Convert a value to bytestring (or just string in Py2). This function is useful when desired output is always a bytestring, and input can be any type (although it is intended to be used with strings and bytestrings).
The
encoding
argument is used to specify the encoding of the resulting bytestring.
-
bottle_utils.common.
attr_escape
(attr)[source]¶ Escape
attr
string containing HTML attribute value. This function escapes certain characters that are undesirable in HTML attribute values. Functions that construct attribute values using user-supplied data should escape the values using this function.
-
bottle_utils.common.
html_escape
(html)[source]¶ Escape
html
strning containing HTML. This function escapes characters that are not desirable in HTML markup, when the source string should represent text content only. User-supplied data that should appar in markup should be escaped using this function.
-
bottle_utils.common.
full_url
(path=u'/')[source]¶ Convert a specified path to full URL based on request data. This function uses the current request context information about the request URL to construct a full URL using specified path. In particular it uses
bottle.request.urlparts
to obtain information about scheme, hostname, and port (if any).Because it uses the request context, it cannot be called outside a request.
AJAX (bottle_utils.ajax
)¶
The bottle_utils.ajax
module provides decorators for working with AJAX
requests.
Decorators¶
-
bottle_utils.ajax.
ajax_only
(func)[source]¶ Return HTTP 400 response for all non-XHR requests.
Warning
AJAX header (‘X-Requested-With’) can be faked, so don’t use this decorator as a security measure of any kind.
Example:
@ajax_only def hidden_from_non_xhr(): return "Foo!"
-
bottle_utils.ajax.
roca_view
(full, partial, **defaults)[source]¶ Render
partal
for XHR requests andfull
template otherwise. Iftemplate_func
keyword argument is found, it is assumed to be a function that renders the template, and is used instead of the default one, which isbottle.template()
.Note
To work around issues with Chrome browser (all platforms) when using this decorator in conjunction with HTML5 pushState, the decorator always adds a
Cache-Control: no-store
header to partial responses.Example:
@roca_view('page.html', 'fragment.html') def my_roca_handler(): return dict()
CSRF protection (bottle_utils.csrf
)¶
This module contains decorators and functions for facilitating CSRF protection.
App configuration¶
Functions in this module require the Bottle application to be configured with CSRF-specific options.
Here is an example of file-based configuration:
[csrf]
secret = SomeSecretValue
token_name = _csrf_token
path = /
expires = 600
secret
setting is the only setting you really must override. Not having
this setting set will result in KeyError
exception.
When using dict-based configuration, prefix each key with csrf.
.
The keys have following meaning:
csrf.secret
setting is a secret key used for setting cookies; it should be fairly random and difficult to guesscsrf.token_name
setting is the name of the cookie and form field that contain the tokencsrf.path
setting is the path of the cookiecsrf.expires
setting is in seconds and sets the cookie’s max-age
Caveat¶
As with most common CSRF protection schemes, decorators in this module will prevent the user from opening two forms and submitting them one after the other. This also applies to cases where forms are fetched from server side using XHR.
Every form must have a token, and a token must match the one in the cookie. However, there is only one cookie for the whole site. When you submit a form, the token in the cookie is replaced with a new one, making tokens in any of the previously opened forms invalid. The result is that form submission results in a HTTP 403 response (not authorized).
You need to decide whether you can live with this behavior before using this module. In case of XHR, consolidating different forms into a single form or fetching tokens separately may be viable solutions.
Note
A possible workaround for applications loading forms (and tokens) using XHR would be to reload all tokens on the page whenever one of the forms is submitted.
Functions and decorators¶
-
bottle_utils.csrf.
csrf_protect
(func)[source]¶ Perform CSRF protection checks. Performs checks to determine if submitted form data matches the token in the cookie. It is assumed that the GET request handler successfully set the token for the request and that the form was instrumented with a CSRF token field. Use the
csrf_token()
decorator to do this.If the handler function returns (i.e., it is not interrupted with
bottle.abort()
,bottle.redirect()
, and similar functions that throw an exception, a new token is set and response is returned to the requester. It is therefore recommended to perform a reidrect on successful POST.Generally, the handler does not need to do anything CSRF-protection-specific. All it needs is the decorator:
@app.post('/') @bottle.view('myform') @csrf_protect def protected_post_handler(): if successful: redirect('/someplace') return dict(errors="There were some errors")
-
bottle_utils.csrf.
csrf_tag
()[source]¶ Generte HTML for hidden form field. This is a convenience function to generate a simple hidden input field. It does not accept any arguments since it uses the
bottle.request
object to obtain the token.If the handler in which this function is invoked is not decorated with
csrf_token()
, anAttributeError
will be raised.Returns: HTML markup for hidden CSRF token field
-
bottle_utils.csrf.
csrf_token
(func)[source]¶ Create and set CSRF token in preparation for subsequent POST request. This decorator is used to set the token. It also sets the
'Cache-Control'
header in order to prevent caching of the page on which the token appears.When an existing token cookie is found, it is reused. The existing token is reset so that the expiration time is extended each time it is reused.
The POST handler must use the
csrf_protect()
decotrator for the token to be used in any way.The token is available in the
bottle.request
object ascsrf_token
attribute:@app.get('/') @bottle.view('myform') @csrf_token def put_token_in_form(): return dict(token=request.csrf_token)
In a view, you can render this token as a hidden field inside the form. The hidden field must have a name
_csrf_token
:<form method="POST"> <input type="hidden" name="_csrf_token" value="{{ token }}"> .... </form>
-
bottle_utils.csrf.
generate_csrf_token
()[source]¶ Generate and set new CSRF token in cookie. The generated token is set to
request.csrf_token
attribute for easier access by other functions.It is generally not necessary to use this function directly.
Warning
This function uses
os.urandom()
call to obtain 8 random bytes when generating the token. It is possible to deplete the randomness pool and make the random token predictable.
Flash messages (bottle_utils.flash
)¶
Flash messages are messages that are generated in one handler and displayed to the user in another. Commonly, this is done when you want to redirect to another path and still show the results of an operation performed in another. One example would be “You have logged out” message after logging the user out.
There are several ways to do this, but storing the message in a cookie is the most straightforward. This module provides methods for doing just that.
Unicode strings are fully supported.
Basic usage¶
In order to make flash messaging available to your app, install the
message_plugin()
plugin.
bottle.install(message_plugin)
This makes bottle.request.message
object and bottle.response.flash()
method available to all request handlers. To set a message, use
response.flash()
:
response.flash('This is my message')
To show the message in the interface, make the request.message
object
available to your template’s context and simply output it in your template:
<p class="flash">{{ message }}</p>
How it works¶
When a message is set, it is stored in a cookie in the user’s browser. The
bottle.request.message
is a lazy object (see
Lazy
), and does not do anything until you
actually use the message. When you access the message object, it retrieves
the text from the cookie and clears the cookie.
Warning
There is no mechanism for automatically clearing messages if they are not consumed. Therefore, it is important to consume it at the very next step user takes in your app. Otherwise, the message may appear on an unpexpected page at unexpected time, taken out of context, and confuse the user.
Functions and plugins¶
-
bottle_utils.flash.
get_message
()[source]¶ Return currently set message and delete the cookie. This function is lazily evaluated so it’s side effect of removing the cookie will only become effective when you actually use the message it returns.
-
bottle_utils.flash.
message_plugin
(func)[source]¶ Manages flash messages. This is a Bottle plugin that adds attributes to
bottle.request
andbottle.response
objects for setting and consuming the flash messages.See Basic usage.
Example:
bottle.install(message_plugin)
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()
andconvert()
, 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 then
argument and its return value is fed into theconvert()
function. The latter takes the source word as first argument, and return value ofplural()
call as second argument, and returns a string representing the pluralized word. Return value of theconvert(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
orno
depending on value. This function takes the value and returns either yes or no depending on whether the value evaluates toTrue
.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>
tagBUTTON
- alias for<button>
tagHIDDEN
- alias for<input>
tag withtype="hidden"
attributeINPUT
- alias for<input>
tag withnonclosing
set toTrue
LI
- alias for<li>
tagOPTION
- alias for<option>
tagP
- alias for<p>
tagSELECT
- alias for<select>
tagSPAN
- alias for<span>
tagSUBMIT
- alias for<button>
tag withtype="submit"
attributeTEXTAREA
- alias for<textarea>
tagUL
- alias for<ul>
tag
-
bottle_utils.html.
link_other
(label, url, path, wrapper=lambda l, *kw: l, **kwargs)[source]¶ Only wrap label in anchor if given target URL,
url
, does not match thepath
. 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 thetag()
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 anid
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 havefoo=['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 avalue
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 theempty
parameter. The argument forempty
should be a label, and the matching value isNone
. 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 asrequest.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 regularMultiDict
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 howMultiDict
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.
-
-
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 abottle.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 abottle.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 abottle.MultiDict
subclass.
-
bottle_utils.html.
urlquote
(value)¶
-
bottle_utils.html.
urlunquote
(value)¶
Form handling and validation (bottle_utils.form
)¶
Validation¶
-
class
bottle_utils.form.validators.
Validator
(messages={})[source]¶ Base validator class. This calss does not do much on its own. It is used primarily to build other validators.
The
validate()
method in the subclass performs the validation and raises aValidationError
exception when the data is invalid.The
messages
argument is used to override the error messages for the validators. This argument should be a dictionary that maps the error names used by individual validators to the new messages. The error names used by validators is documented for each class. You can also dynamically obtain the names by inspecting themessages
property on each of the validator classes.-
messages
= {}¶ Mapping between errors and their human-readabile messages
-
validate
(data)[source]¶ Perform actual validation over data. Should raise
ValidationError
if data does not pass the validation.Two arguments are passed to the validation error, the error name and a dictionary with extra parameters (usually with
value
key that points to the value).Error message is constructed based on the arguments, passed to the exception by looking up the key in the
messages
property to obtain the message, and then interpolating any extra parameters into the message.This method does not need to return anything.
-
-
class
bottle_utils.form.validators.
DateValidator
(messages={})[source]¶ Validates date fields. This validator attempts to parse the data as date (or date/time) data. When the data cannot be parsed, it fails.
Error name(s): date
-
class
bottle_utils.form.validators.
InRangeValidator
(min_value=None, max_value=None, **kwargs)[source]¶ Validates that value is within a range between two values. This validator works with any objects that support
>
and<
operators.The
min_value
andmax_value
arguments are used to set the lower and upper bounds respectively. The check for those bounds are only done when the arguments are supplied so, when both arguments are omitted, this validator is effectively pass-through.Error name(s): min_val, max_val
-
class
bottle_utils.form.validators.
LengthValidator
(min_len=None, max_len=None, **kwargs)[source]¶ Validates that value’s length is within specified range. This validator works with any objects that support the
len()
function.The
min_len
andmax_len
arguments are used to set the lower and upper bounds respectively. The check for those bounds are only done when the arguments are supplied so, when both arguments are omitted, this validator is effectively pass-through.Error name(s): min_len, max_len
-
class
bottle_utils.form.validators.
Required
(messages={})[source]¶ Validates the presence of data. Technically, this validator fails for any data that is an empty string, a string that only contains whitespace, or data that is not a string and evaluates to
False
when coerced into boolean (e.g., 0, empty arrays and dicts, etc).Error name(s): required
-
class
bottle_utils.form.exceptions.
ValidationError
(message, params=None, is_form=False)[source]¶ Error raised during field and form validation. The erorr object can be initialized using a message string, and two optional parameters,
params
andis_form
.The
params
is a dictionary of key-value pairs that are used to fill the message in with values that are only known at runtime. For example, if the message is'{value} is invalid for this field'
, we can pass aparams
argument that looks like{'value': foo}
. Theformat()
method is called on the message.Note that
message
is a key pointing to a value in themessages
dictionary on the form and field objects, not the actual message.
Fields¶
-
class
bottle_utils.form.fields.
DormantField
(field_cls, args, kwargs)[source]¶ Proxy for unbound fields. This class holds the the field constructor arguments until the data can be bound to it.
You never need to use this class directly.
-
class
bottle_utils.form.fields.
Field
(label=None, validators=None, value=None, name=None, messages={}, **options)[source]¶ Form field base class. This class provides the base functionality for all form fields.
The
label
argument is used to specify the field’s label.The
validators
argument is used to specify the validators that will be used on the field data.If any data should be bound to a field, the
value
argument can be used to specify it. Value can be a callable, in which case it is called and its return value used asvalue
.The
name
argument is used to specify the field name.The
messages
argument is used to customize the validation error messages. These override any messages found in themessages
attribute.Any extra keyword attributes passed to the constructor are stored as
options
property on the instance.-
exception
ValidationError
(message, params=None, is_form=False)¶ Error raised during field and form validation. The erorr object can be initialized using a message string, and two optional parameters,
params
andis_form
.The
params
is a dictionary of key-value pairs that are used to fill the message in with values that are only known at runtime. For example, if the message is'{value} is invalid for this field'
, we can pass aparams
argument that looks like{'value': foo}
. Theformat()
method is called on the message.Note that
message
is a key pointing to a value in themessages
dictionary on the form and field objects, not the actual message.
-
Field.
bind_value
(value)[source]¶ Binds a value. This method also sets the
is_value_bound
property toTrue
.
-
Field.
generic_error
¶ Generic error message to be used when no messages match the validation error.
-
Field.
is_valid
()[source]¶ Validate form field and return
True
is data is valid. If there is an error during Validation, the error object is stored in the_error
property. Before validation, the raw value is processed using theparse()
method, and stored inprocessed_value
attribute.When parsing fails with
ValueError
exception, a ‘generic’ error is stored. The default message for this error is stored in thegeneric_error
property, and can be customized by passing a'generic'
message as part of themessages
constructor argument.
-
Field.
is_value_bound
= None¶ Whether value is bound to this field
-
Field.
label
= None¶ Field label
-
Field.
messages
= {}¶ Validation error messages.
-
Field.
name
= None¶ Field name
-
Field.
options
= None¶ Extra keyword argument passed to the constructor
-
Field.
parse
(value)[source]¶ Parse the raw value and convert to Python object. Subclasses should return the value in it’s correct type. In case the passed in value cannot be cast into it’s correct type, the method should raise a
ValueError
exception with an appropriate error message.
-
Field.
processed_value
= None¶ Processed value of the field
-
Field.
type
= 'text'¶ Field markup type. This is arbitrary and normally used in the templates to differentiate between field types. It is up to the template author to decide how this should be treated.
-
Field.
validators
= None¶ Field validators
-
Field.
value
= None¶ Raw value of the field
-
exception
-
class
bottle_utils.form.fields.
BooleanField
(label=None, validators=None, value=None, default=False, **options)[source]¶ Field for working with boolean values.
Two additional constructor arguments are added. The
default
argument is used to specify the default state of the field, which can be used in the template to, for instance, check or uncheck a checkbox or radio button. Theexpected_value
is the base value of the field against which the bound value is checked: if they match, the Python value of the field isTrue
.Python type: bool Type: checkbox -
default
= None¶ Default state of the field
-
expected_value
= None¶ Base value of the field against which bound value is checked
-
-
class
bottle_utils.form.fields.
DateField
(label=None, validators=None, value=None, **options)[source]¶ Field for working with dates. This field overloads the base class’ constructor to add a
DateValidator
.Python type: str (unicode in Python 2.x) Type: text
-
class
bottle_utils.form.fields.
EmailField
(label=None, validators=None, value=None, name=None, messages={}, **options)[source]¶ Field for working with emails.
Python type: str (unicode in Python 2.x) Type: text
-
class
bottle_utils.form.fields.
ErrorMixin
[source]¶ Mixin class used to provide error rendering functionality.
-
error
¶ Human readable error message. This property evaluates to empty string if there are no errors.
-
-
class
bottle_utils.form.fields.
FileField
(label=None, validators=None, value=None, name=None, messages={}, **options)[source]¶ Field for working with file uploads.
Python type: raw value Type: file
-
class
bottle_utils.form.fields.
FloatField
(label=None, validators=None, value=None, name=None, messages={}, **options)[source]¶ Field for working with floating-point numbers.
Python type: float Type: text
-
class
bottle_utils.form.fields.
HiddenField
(label=None, validators=None, value=None, name=None, messages={}, **options)[source]¶ Field for working with hidden inputs.
Python type: str (unicode in Python 2.x) Type: hidden
-
class
bottle_utils.form.fields.
IntegerField
(label=None, validators=None, value=None, name=None, messages={}, **options)[source]¶ Field for working with integers.
Python type: int Type: text
-
class
bottle_utils.form.fields.
PasswordField
(label=None, validators=None, value=None, name=None, messages={}, **options)[source]¶ Field for working with passwords.
Python type: str (unicode in Python 2.x) Type: password
-
class
bottle_utils.form.fields.
SelectField
(label=None, validators=None, value=None, choices=None, **options)[source]¶ Field for dealing with select lists.
The
choices
argument is used to specify the list of value-label pairs that are used to present the valid choices in the interface. The field value is then checked against the list of value and the parser validates whether the supplied value is among the valid ones.Python type: str (unicode in Python 2.x) Type: select -
choices
= None¶ Iterable of value-label pairs of valid choices
-
Forms¶
-
class
bottle_utils.form.forms.
Form
(data=None, messages={})[source]¶ Base form class to be subclassed. To define a new form subclass this class:
class NewForm(Form): field1 = Field('Field 1') field2 = Field('Field 2', [Required])
Forms support field pre- and post-procesors. These methods are named after the field names by prepending
preprocess_
andpostprocess_
respectively. For example:class NewForm(Form): field1 = Field('Field 1') field2 = Field('Field 2', [Required]) def preprocess_field1(self, value): return value.replace('this', 'that') def postprocess_field1(self, value): return value + 'done'
Preprocessors can be defined for individual fields, and are ran before any validation happens over the field’s data. Preprocessors are also allowed to raise
ValidationError
, though their actual purpose is to perform some manipulation over the incoming data, before it is passed over to the validators. The return value of the preprocessor is the value that is going to be validated further.Postprocessors perform a similar purpose as preprocessors, except that they are invoked after field-level validation passes. Their return value is the value that is going to be the stored as cleaned / validated data.
-
exception
ValidationError
(message, params=None, is_form=False)¶ Error raised during field and form validation. The erorr object can be initialized using a message string, and two optional parameters,
params
andis_form
.The
params
is a dictionary of key-value pairs that are used to fill the message in with values that are only known at runtime. For example, if the message is'{value} is invalid for this field'
, we can pass aparams
argument that looks like{'value': foo}
. Theformat()
method is called on the message.Note that
message
is a key pointing to a value in themessages
dictionary on the form and field objects, not the actual message.
-
Form.
field_errors
¶ Dictionary of all field error messages. This property maps the field names to error message maps. Field names are mapped to fields’ messages property, which maps error type to actual message. This dictionary can also be used to modify the messages because message mappings are not copied.
-
Form.
field_messages
¶ Alias for
field_errors
retained for
-
Form.
fields
¶ Dictionary of all the fields found on the form instance. The return value is never cached so dynamically adding new fields to the form is allowed.
-
Form.
generic_error
¶
-
Form.
is_valid
()[source]¶ Perform full form validation over the initialized form. The method has the following side-effects:
- in case errors are found, the form’s errors container is going to be populated accordingly.
- validated and processed values are going to be put into the processed_data dictionary.
Return value is a boolean, and is
True
is form data is valid.
-
Form.
validate
()[source]¶ Perform form-level validation, which can check fields dependent on each other. The function is expected to be overridden by implementors in case form-level validation is needed, but it’s optional. In case an error is found, a ValidationError exception should be raised by the function.
-
exception
HTTP helpers (bottle_utils.http
)¶
This module provides decorators for working with HTTP headers and other aspects of HTTP.
Module contents¶
-
bottle_utils.http.
format_ts
(seconds=None)[source]¶ Given a timestamp in seconds since UNIX epoch, return a string representation suitable for use in HTTP headers according to RFC.
If
seconds
is omitted, the time is asumed to be current time.
-
bottle_utils.http.
iter_read_range
(fd, offset, length, chunksize=1048576)[source]¶ Return an iterator that allows reading files in chunks. The
fd
should be a file-like object that has aread()
method. Theoffset
value sets the start offset of the read. If thefd
object does not supportseek()
, the file will be simply read up until offset, and the read data discarded.length
argument specifies the amount of data to read. The read is not done in one go, but in chunks. The size of a chunk is specified usingchunksize
.This function is similar to
bottle._file_iter_range
but does not fail on missingseek()
attribute (e.g.,StringIO
objects).
-
bottle_utils.http.
no_cache
(func)[source]¶ Disable caching on a handler. The decorated handler will have
Cache-Control
header set toprivate, no-cache
.This is useful for responses that contain data that cannot be reused.
Simply deocrate a handler with it:
@app.get('/foo') @no_cache def not_cached(): return 'sensitive data'
-
bottle_utils.http.
send_file
(content, filename, size=None, timestamp=None)[source]¶ Convert file data into an HTTP response.
This method is used when the file data does not exist on disk, such as when it is dynamically generated.
Because the file does not exist on disk, the basic metadata which is usually read from the file itself must be supplied as arguments. The
filename
argument is the supposed filename of the file data. It is only used to set the Content-Type header, and you may safely pass in just the extension with leading period.The
size
argument is the payload size in bytes. For streaming files, this can be particularly important as the ranges are calculated baed on content length. Ifsize
is omitted, then support for ranges is not advertise and ranges are never returned.timestamp
is expected to be in seconds since UNIX epoch, and is used to calculate Last-Modified HTTP headers, as well as handle If-Modified-Since header. If omitted, current time is used, and If-Modified-Since is never checked.Note
The returned response is a completely new response object. Modifying the reponse object in the current request context is not going to affect the object returned by this function. You should modify the object returned by this function instead.
Example:
def some_handler(): import StringIO f = StringIO.StringIO('foo') return send_file(f, 'file.txt', 3, 1293281312)
The code is partly based on
bottle.static_file
, with the main difference being the use of file-like objects instead of files on disk.
Translation support (bottle_utils.i18n
)¶
How it works¶
This module provides plugins and functions for translation and language selection.
Language selection is based on URLs. Each path in the app is augmented with
locale prefix. Therefore, /foo/bar/baz
becomes /LOCALE/foo/bar/baz
where LOCALE
is any of the locales chosen as translation targets. When one
of the supported locales is found in the incoming request’s path, then that
locale is activated.
Translation is performed by calling several of the translation functions
provied by this module. These are simple gettext()
and ngettext()
wrappers that are lazily evaluated with the help of
Lazy
class.
This module does not deal with message extraction or compilation. For this, you can use the standard GNU Gettext utilities.
Setting up the app for translation¶
To activate translations and language selection, you will need to configure the plugin and middleware.
Note
The bottle plugin class, I18NPlugin
, double
as WSGI middleware.
First prepare a list of languages you want to support:
LANGS = [
('de_DE', 'Deutsch'),
('en_US', 'English'),
('fr_FR', 'français'),
('es_ES', 'español'),
('zh_CN', '中文')
]
Also decide which locale you would like to use as default.
DEFAULT_LOCAL = 'en_US'
Finally you need to decide where you want to keep the locale directory where translations are looked up.
LOCALES_DIR = './locales'
To install the plugin and middle, you can simply pass the
I18NPlugin
class a bottle app object.
from bottle_utils.i18n import I18NPlugin
app = bottle.default_app()
wsgi_app = I18NPlugin(app,
languages=LANGS,
default_locale=DEFAULT_LOCALE,
locale_dir=LOCALES_DIR)
This installs both the Bottle plugin and the WSGI middleware, and returns a WSGI application object.
If, for any reason, you do not want the i18n WSGI middleware to be the first in the stack, you can chain middleware as usual:
from bottle_utils.i18n import I18NPlugin
app = bottle.default_app()
wsgi = SomeMiddleware(app)
wsgi = I18NPlugin(wsgi, *other_args)
wsgi.install_plugin(app)
wsgi = SomeOtherPlugin(wsgi)
The install_plugin()
method only works
on the wsgi app returned from the plugin class. After wrapping with another
plugin, it is no longer available so it must be called immediately.
Translating in Python code¶
To translate in Python code, use the
lazy_gettext()
,
lazy_ngettext()
, and similar translation functions.
lazy_gettext()
is usually imported as _
, which is a common convention
(alias) for gettext()
. Other methods are aliased without the lazy_
prefix.
from bottle_utils.i18n import lazy_ngettext as ngettext, lazy_gettext as _
def handler():
return _('This is a translatable string')
This is a convention that allows the gettext utilities to successfully extract the translation strings.
Warning
The translation functions provided by this module do not work outside of request context. If you call them in a separate thread or a subprocess, you will get an exception. If your design allows for it, convert the lazy instances to strings before passing them to code running outside the request context.
Translating in templates¶
Translating in templates is highly dependent on your template engine. Some engines like Jinja2 may provide their own i18n mechanisms. In engines like SimpleTemplate and Mako, the process is pretty straightfoward. The translation methods are available in the templates using the naming convention discussed in the Translating in Python code section.
<p>{{ _('Current time') }}: {{ time }}</p>
Note
In template engines that use Python in templates (SimpleTemplate, Mako,
etc), the similarity between Python syntax and template syntax (the Python
portion of the template anyway) allows us to extract messages from the
templates the same way we do from Python code simply by asking the
xgettext
tool to treat the template files as Python source code.
Module contents¶
-
class
bottle_utils.i18n.
I18NPlugin
(app, langs, default_locale, locale_dir, domain='messages', noplugin=False)[source]¶ Bottle plugin and WSGI middleware for handling i18n routes. This class is a middleware. However, if the
app
argument is aBottle
object (bottle app), it will also install itself as a plugin. The plugin follows the version 2 API and implements theapply()
method which applies the plugin to all routes. The plugin and middleware parts were merged into one class because they depend on each other and can’t really be used separately.During initialization, the class will set up references to locales, directory paths, and build a mapping between locale names and appropriate gettext translation APIs. The translation APIs are created using the
gettext.translation()
call. This call tries to access matching .mo file in the locale directory, and will emit a warning if such file is not found. If a .mo file does not exist for a given locale, or it is not readable, the API for that locale will be downgraded to generic gettext API.The class will also update the
bottle.BaseTemplate.defaults
dict with translation-related methods so they are always available in templates (at least those that are rendered using bottle’s API. The following variables become available in all templates:_
: alias forlazy_gettext()
gettext
: alias forlazy_gettext()
ngettext
: alias forlazy_ngettext()
pgettext
: alias forlazy_pgettext()
npgettext
: alias forlazy_pngettext()
languages
: iterable containing available languages as(locale, name)
tuples
In addition, two functions for generating i18n-specific paths are added to the default context:
The middleware itself derives the desired locale from the URL. It does not read cookies or headers. It only looks for the
/ll_cc/
prefix wherell
is the two-ltter language ID, andcc
is country code. If it finds such a prefix, it will set the locale in the envionment dict (LOCALE
key) and fix the path so it doesn’t include the prefix. This allows the bottle app to have routes matching any number of locales. If it doesn’t find the prefix, it will redirect to the default locale.If there is no appropriate locale, and
LOCALE
key is therfore set toNone
, the plugin will automatically respond with a 302 redirect to a location of the default locale.The plugin reads the
LOCALE
key set by the middleware, and aliases the API for that locale asrequest.gettext
. It also setsrequest.locale
attribute to the selected locale. These attributes are used by thelazy_gettext`()
andlazy_ngettext()
, as well asi18n_path()
andi18n_url()
functions.The plugin installation during initialization can be competely suppressed, if you wish (e.g., you wish to apply the plugin yourself some other way).
The locale directory should be in a format which
gettext.translations()
understands. This is a path that contains a subtree matching this format:locale_dir/LANG/LC_MESSAGES/DOMAIN.mo
The
LANG
should match any of the supported languages, andDOMAIN
should match the specified domain.-
match_locale
(path)[source]¶ Match the locale based on prefix in request path. You can customize this method for a different way of obtaining locale information.
Returning
None
from this method causes the plugin to use the default locale.The return value of this method is stored in the environment dictionary as
LOCALE
key. It is then used by the plugin part of this class to provide translation methods to the rest of the app.
-
set_locale
(locale)[source]¶ Store the passed in
locale
in a ‘locale’ cookie, which is used to override the value of the globaldefault_locale
.
-
static
strip_prefix
(path, locale)[source]¶ Strip the locale prefix from the path. This static method is used to recalculate the request path that should be passed to Bottle. The return value of this method replaces the
PATH_INFO
key in the environment dictionary, and the original path is saved inORIGINAL_PATH
key.
-
bottle_utils.i18n.
dummy_gettext
(message)[source]¶ Mimic
gettext()
function. This is a passthrough function with the same signature asgettext()
. It can be used to simulate translation for applications that are untranslated, without the overhead of calling the realgettext()
.
-
bottle_utils.i18n.
dummy_ngettext
(singular, plural, n)[source]¶ Mimic
ngettext()
function. This is a passthrough function with the same signature asngettext()
. It can be used to simulate translation for applications that are untranslated, without the overhead of calling the realngettext()
.This function returns the verbatim singular message if
n
is 1, otherwise the verbatim plural message.
-
bottle_utils.i18n.
dummy_npgettext
(context, singular, plural, n)[source]¶ Mimic
npgettext()
function. This is a passthrough function with teh same signature asnpgettext()
. It can be used to simulate translation for applications that are untranslated, without the overhead of calling the realnpgettext()
function.
-
bottle_utils.i18n.
dummy_pgettext
(context, message)[source]¶ Mimic
pgettext()
function. This is a passthrough function with the same signature aspgettext()
. It can be used to simulate translation for applications that are untranslated, without the overhead of calling the real ``pgettext()`.
-
bottle_utils.i18n.
full_path
()[source]¶ Calculate full path including query string for current request. This is a helper function used by
i18n_path()
. It uses the current request context to obtain information about the path.
-
bottle_utils.i18n.
i18n_path
(*args, **kwargs)[source]¶ Return current request path or specified path for given or current locale. This function can be used to obtain paths for different locales.
If no
path
argument is passed, thefull_path()
is called to obtain the full path for current request.If
locale
argument is omitted, current locale is used.
-
bottle_utils.i18n.
i18n_url
(*args, **kwargs)[source]¶ Return a named route in localized form. This function is a light wrapper around Bottle’s
get_url()
function. It passes the result toi18n_path()
.If
locale
keyword argument is passed, it will be used instead of the currently selected locale.
-
bottle_utils.i18n.
i18n_view
(tpl_base_name=None, **defaults)[source]¶ Renders a template with locale name as suffix. Unlike the normal view decorator, the template name should not have an extension. The locale names are appended to the base template name using underscore (‘_’) as separator, and lower-case locale identifier.
Any additional keyword arguments are used as default template variables.
For example:
@i18n_view('foo') def render_foo(): # Renders 'foo_en' for English locale, 'foo_fr' for French, etc. return
-
bottle_utils.i18n.
lazy_gettext
(*args, **kwargs)[source]¶ Lazily evaluated version of
gettext()
.This function uses the appropriate Gettext API object based on the value of
bottle.request.gettext
set by the plugin. It will fail withAttributeError
exception if the plugin is not installed.
-
bottle_utils.i18n.
lazy_ngettext
(*args, **kwargs)[source]¶ Lazily evaluated version of
ngettext()
.This function uses the appropriate Gettext API object based on the value of
bottle.request.gettext
set by the plugin. It will fail withAttributeError
exception if the plugin is not installed.
-
bottle_utils.i18n.
lazy_npgettext
(context, singular, plural, n)[source]¶ bottle_utils.i18n.lazy_ngettext()
wrapper with message context.This function is a wrapper around
bottle_utils.i18n.lazy_ngettext()
that provides message context. It is useful in situations where messages are used in several different contexts for which separate translations may be required for different languages.The function itself is not lazy, but it returns the return value of
lazy_ngettext()
, and it is effectively lazy. Hence the name.
-
bottle_utils.i18n.
lazy_pgettext
(context, message)[source]¶ lazy_gettext()
wrapper with message context.This function is a wrapper around
lazy_gettext()
that provides message context. It is useful in situations where short messages (usually one word) are used in several different contexts for which separate translations may be needed in different languages.The function itself is not lazily evaluated, but its return value comes from
lazy_gettext()
call, and it is effectively lazy as a result.
Lazy evaluation (bottle_utils.lazy
)¶
This module provides classes and decorators for lazy evaluation of callables.
Lazily evaluated functions and methods return immediately without performing any work, and their work is performed at some later point in time when the results are actually needed. This is useful in situation when the result may or may not be needed (e.g., some branching may occur) or when evaluation of the result may not be possible at the time of a call but we know it will be possible later.
In Bottle Utils, lazy evaluation is used extensively in the
i18n
module. Because evaluating the translation context
requires a request context, and it may not be available where the call happens,
lazy evaluation postpones evaluation of the translation function until we are
sure the request context exists (e.g., some translated string is stored as a
defined constant somewhere and used later in the request handler).
How it works¶
When a function is wrapped in a Lazy
object, it behaves like
result of evaluating that function. It stores the function in one of its
properties and waits for your code to actually try to use the result. If your
code never uses the result, the wrapped function is never called. When your
code uses the result, the function is then evaluated for the first time. This
type of object is sometimes also referred to as a proxy.
The idea of ‘using’ the result is defined as an attempt to coerce or perform
any action that triggers any of the magic methods. This includes things
like adding or subtracting from another value, calling str()
, bool()
and similar methods, attempting string interpolation with either format()
method or %
operator, accessing indices or keys using subscript notation,
and so on. Attempting to access methods and properties also counts as ‘using’.
One caveat of this behavior is that, because lazy functions are created in one context and potentially evaluated in another, the state in which they are evaluated may change in unpredictable ways. On the other hand, this may create opportunities that would not exist without lazy evaluation.
More on lazy evaluation in general can be found in Content Creation Wiki.
Module contents¶
-
class
bottle_utils.lazy.
Lazy
(_func, *args, **kwargs)[source]¶ Lazy proxy object. This proxy always evaluates the function when it is used.
Any positional and keyword arguments that are passed to the constructor are stored and passed to the function except the
_func
argument which is the function itself. Because of this, the wrapped callable cannot use an argument named_func
itself.
-
class
bottle_utils.lazy.
CachingLazy
(_func, *args, **kwargs)[source]¶ Caching version of the
Lazy
class. Unlike the parent class, this class only evaluates the callable once, and remembers the resutls. On subsequent use, it returns the original result. This is probably closer to the behavior of a normal return value.
-
bottle_utils.lazy.
lazy
(fn)[source]¶ Convert a function into lazily evaluated version. This decorator causes the function to return a
Lazy
proxy instead of the actual results.Usage is simple:
@lazy def my_lazy_func(): return 'foo'
-
bottle_utils.lazy.
caching_lazy
(fn)[source]¶ Convert a function into cached lazily evaluated version. This decorator modifies the function to return a
CachingLazy
proxy instead of the actual result.This decorator has no arguments:
@caching_lazy def my_lazy_func(): return 'foo'
Social metadata (
bottle_utils.meta
)¶This module provides classes for working with social metadata (Facebook, Google+, Twitter).
How it works¶
There are two flavors of metadata classes,
SimpleMetadata
andMetadata
. Both render the title tag and description met tag, while the latter also renders a full set of social meta tags used by Facebook, Google+, and Twitter.Using any of the two classes, you normally instantiate an object passing it metadata as constructor arguments, and then simply use the objects as string values in the template. You can also call the
render()
method on the object, but that is redundant except in rare cases wherestr
type is expected.Example usage is provided for both of the classes.
Warning
Authors of this module use social metadata only very rarely. As such, the features found in this module may not always be up to date. Please file issues you find with the social metadata support to the GitHub issue tracker.
Classes¶
bottle_utils.meta.
MetaBase
[source]¶Base class for metadata. This class is a simple placeholder to collect base functionality for various subclasses.
Currently, the only functionality this base class provides is calling
render()
method when__str__()
magic method is called on the class.render
()[source]¶Render the meta object into HTML. In the base class this method renders to empty string.
bottle_utils.meta.
Metadata
(title=u'', description=u'', thumbnail=u'', url=u'')[source]¶Complete set of social meta tags. This class renders a complete set of social meta tags including schema.org properties, OpenGraph tags, and Twitter Cards markup.
The meta tags are only rendered for the arguments that are specified (i.e., one or more of the
title
,description
,thumbnail
,url
). The arguments map to common properties that have the following meanings:To render social tags, simply instantiate an object using meta data of your choosing and render the object in template (treat is as a string).
Here is an example of what it may look like in a handler function:
And here is a template:
Note
In template engines that support automatic escaping of HTML, you need to suppress escaping. For instance, in SimpleTemplates, using
{{! }}
instead of{{ }}
accomplishes this.This class does not render any of the other numerous tags (authorship tags, for instance). However, the instance methods it provides can be used to render them.
For example, to render a Twitter creator tag in a template that has access to any instance of this class:
Note
When it comes to thumbnails and canonical URLs, the social networks usually expect to see a full URL (including scheme and hostname). However, it may not feel right to hard-code these things. This class automatically converts paths to full URLs based on request data, so passing paths is fine.
itemprop
(name, value)[source]¶Render schema.org itemprop meta tag. This method renders a schema.org itemprop meta tag which uses the
itemprop
attribute to designate the name of the tag.This form is used by Google, but it’s otherwise an open standard for semantic markup. This method only renders meta tags, and not every other kind of markup that schema.org uses.
The arguments are rendered into the following markup:
make_full
(url)[source]¶Convert an input to full URL if not already a full URL. This static method will ensure that the specified url is a full URL.
This method only checks if the provided URL starts with ‘http’, though, so it is possible to trick it using a path that looks like ‘httpfoo’: it is clearly not a full URL, but will be treated as one. If the input value is user-supplied, please perform a more through check.
Under the hood, this method uses
bottle_utils.common.full_url()
to convert paths to full URLs.nameprop
(namespace, name, value)[source]¶Render a generic name property. This method renders a generic name property meta tag that uses
name
attribute to designate the tag name.Each tag name consist of namespace and name parts. Most notably, Twitter Card markup uses this form.
The arguments are rendered like this:
ogprop
(name, value)[source]¶Renders OpenGraph meta tag. This method renders a property meta tag that uses ‘og’ namespace.
The arguments are rendered like this:
prop
(namespace, name, value)[source]¶Render a generic property meta tag. This method renders a generic property meta tags that uses
property
attribute to designate the tag name.Each tag name consists of two parts: namespace and name. Most notably, OpenGraph uses this form with ‘og’ namespace.
The arguments are rendered like this:
render
()[source]¶Render the meta object into HTML.
twitterprop
(name, value)[source]¶Renders Twitter Card markup. This method renders Twitter Card markup meta data. That is a name property meta tag with ‘twitter’ namespace.
The arguments are rendered like so:
bottle_utils.meta.
SimpleMetadata
(title=u'', description=u'')[source]¶The basic (classic) metadata. This class is used to render title tag and description meta tag.
Both title and description are option. If neither is supplied, it is rendered into empty string.
Here is a simple example handler:
In the template, simply render this object in
<head>
section where you would normally have the<title>
tag.:This renders the following tags:
Note
In template engines that support automatic escaping of HTML, you need to suppress escaping. For instance, in SimpleTemplates, using
{{! }}
instead of{{ }}
accomplishes this.meta
(attr, name, value)[source]¶Render a generic
<meta>
tag. This function is the basis for rendering most of the social meta tags.The arguments are rendered like this:
render
()[source]¶Render the meta object as HTML.
simple
(name, value)[source]¶Render a simple ‘name’ meta tag. This function renders a meta tag that uses the ‘name’ attribute.
The arguments are rendered like this: