WebHelpers¶
Version: | 1.3, released 2011-03-23 |
---|---|
PyPI: | http://pypi.python.org/pypi/WebHelpers |
Docs: | http://sluggo.scrapping.cc/python/WebHelpers/index.html |
Source: | https://bitbucket.org/bbangert/webhelpers (Mercurial) |

WebHelpers is a wide variety of utility functions for web applications and other applications. It can be used with any web framework. See What’s New for a list of changes and upgrading hints.
Version 1.3 improves Pyramid support in Paginate via URL generator classes. (Note: 1.3b1 had a performance regression in Paginate. This is fixed in 1.3 final.)
WebHelpers includes the widely-used HTML tag builder with smart escaping and convenience functions for common tags such as form fields. The common builder ensures the tags are syntactically correct and prevent cross-site scripting attacks and double-escaping.
Other helpers perform text processing, split a large number of records into pages, generate Atom/RSS feeds with geographical (GIS) data, handle MIME types, calculate numerica statistics, and more. There are also high-level container types, including a value counter and accumulator. There are lists of country names, country codes, US states, Canadian provinces, and UK counties.
WebHelpers itself depends only on MarkupSafe, which has an optional C speedup for HTML escaping. However, a few individual helpers depend on Routes, Unidecode, WebOb, or Pylons as noted in their documentation. WebHelpers requires Python 2.4 or higher, and has not yet been tested with Python 3. An extensive test suite for doctest and Nose is included.
For support/questions/patches, please use the pylons-discuss mailing list.
WebHelpers Documentation¶
All helpers are organized into subpackages.
webhelpers.constants
¶
Place names and other constants often used in web forms.
Countries¶
-
webhelpers.constants.
country_codes
()¶ Return a list of all country names as tuples. The tuple value is the country’s 2-letter ISO code and its name; e.g.,
("GB", "United Kingdom")
. The countries are in name order.Can be used like this:
import webhelpers.constants as constants from webhelpers.html.tags import select select("country", country_codes(), prompt="Please choose a country ...")
See here for more information: http://www.iso.org/iso/english_country_names_and_code_elements
States & Provinces¶
-
webhelpers.constants.
us_states
()¶ List of USA states.
Return a list of
(abbreviation, name)
for all US states, sorted by name. Includes the District of Columbia.
-
webhelpers.constants.
us_territories
()¶ USA postal abbreviations for territories, protectorates, and military.
The return value is a list of
(abbreviation, name)
tuples. The locations are sorted by name.
-
webhelpers.constants.
canada_provinces
()¶ List of Canadian provinces.
Return a list of
(abbreviation, name)
tuples for all Canadian provinces and territories, sorted by name.
-
webhelpers.constants.
uk_counties
()¶ Return a list of UK county names.
Deprecations¶
The timezone helpers were removed in WebHelpers 0.6. Install the PyTZ package if you need them.
webhelpers.containers
¶
Container objects, and helpers for lists and dicts.
This would have been called this “collections” except that Python 2 can’t import a top-level module that’s the same name as a module in the current package.
Classes¶
-
class
webhelpers.containers.
Counter
¶ I count the number of occurrences of each value registered with me.
Call the instance to register a value. The result is available as the
.result
attribute. Example:>>> counter = Counter() >>> counter("foo") >>> counter("bar") >>> counter("foo") >>> sorted(counter.result.items()) [('bar', 1), ('foo', 2)] >> counter.result {'foo': 2, 'bar': 1}
To see the most frequently-occurring items in order:
>>> counter.get_popular(1) [(2, 'foo')] >>> counter.get_popular() [(2, 'foo'), (1, 'bar')]
Or if you prefer the list in item order:
>>> counter.get_sorted_items() [('bar', 1), ('foo', 2)]
-
classmethod
correlate
(class_, iterable)¶ Build a Counter from an iterable in one step.
This is the same as adding each item individually.
>>> counter = Counter.correlate(["A", "B", "A"]) >>> counter.result["A"] 2 >>> counter.result["B"] 1
-
get_popular
(max_items=None)¶ Return the results as as a list of
(count, item)
pairs, with the most frequently occurring items first.If
max_items
is provided, return no more than that many items.
-
get_sorted_items
()¶ Return the result as a list of
(item, count)
pairs sorted by item.
-
classmethod
-
class
webhelpers.containers.
Accumulator
¶ Accumulate a dict of all values for each key.
Call the instance to register a value. The result is available as the
.result
attribute. Example:>>> bowling_scores = Accumulator() >>> bowling_scores("Fred", 0) >>> bowling_scores("Barney", 10) >>> bowling_scores("Fred", 1) >>> bowling_scores("Barney", 9) >>> sorted(bowling_scores.result.items()) [('Barney', [10, 9]), ('Fred', [0, 1])] >> bowling_scores.result {'Fred': [0, 1], 'Barney': [10, 9]}
The values are stored in the order they’re registered.
Alternatives to this class include
paste.util. multidict.MultiDict
in Ian Bicking’s Paste package.-
classmethod
correlate
(class_, iterable, key)¶ Create an Accumulator based on several related values.
key
is a function to calculate the key for each item, akin tolist.sort(key=)
.This is the same as adding each item individually.
-
classmethod
-
class
webhelpers.containers.
UniqueAccumulator
¶ Accumulate a dict of unique values for each key.
The values are stored in an unordered set.
Call the instance to register a value. The result is available as the
.result
attribute.
-
class
webhelpers.containers.
defaultdict
(missing_func)¶ A dict that automatically creates values for missing keys. This is the same as
collections.defaultdict
in the Python standard library. It’s provided here for Python 2.4, which doesn’t have that class.When you try to read a key that’s missing, I call
missing_func
without args to create a value. The result is inserted into the dict and returned. Many Python type constructors can be used asmissing_func
. Passinglist
orset
creates an empty dict or set. Passingint
creates the integer0
. These are useful in the following ways:>> d = defaultdict(list); d[ANYTHING].append(SOMEVALUE) >> d = defaultdict(set); d[ANYTHING].include(SOMEVALUE) >> d = defaultdict(int); d[ANYTHING] += 1
-
class
webhelpers.containers.
DumbObject
(**kw)¶ A container for arbitrary attributes.
Usage:
>>> do = DumbObject(a=1, b=2) >>> do.b 2
Alternatives to this class include
collections.namedtuple
in Python 2.6, andformencode.declarative.Declarative
in Ian Bicking’s FormEncode package. Both alternatives offer more features, butDumbObject
shines in its simplicity and lack of dependencies.
Functions¶
-
webhelpers.containers.
correlate_dicts
(dicts, key)¶ Correlate several dicts under one superdict.
If you have several dicts each with a ‘name’ key, this puts them in a container dict keyed by name.
>>> d1 = {"name": "Fred", "age": 41} >>> d2 = {"name": "Barney", "age": 31} >>> flintstones = correlate_dicts([d1, d2], "name") >>> sorted(flintstones.keys()) ['Barney', 'Fred'] >>> flintstones["Fred"]["age"] 41
If you’re having trouble spelling this method correctly, remember: “relate” has one ‘l’. The ‘r’ is doubled because it occurs after a prefix. Thus “correlate”.
-
webhelpers.containers.
correlate_objects
(objects, attr)¶ Correlate several objects under one dict.
If you have several objects each with a ‘name’ attribute, this puts them in a dict keyed by name.
>>> class Flintstone(DumbObject): ... pass ... >>> fred = Flintstone(name="Fred", age=41) >>> barney = Flintstone(name="Barney", age=31) >>> flintstones = correlate_objects([fred, barney], "name") >>> sorted(flintstones.keys()) ['Barney', 'Fred'] >>> flintstones["Barney"].age 31
If you’re having trouble spelling this method correctly, remember: “relate” has one ‘l’. The ‘r’ is doubled because it occurs after a prefix. Thus “correlate”.
-
webhelpers.containers.
del_quiet
(dic, keys)¶ Delete several keys from a dict, ignoring those that don’t exist.
This modifies the dict in place.
>>> d ={"A": 1, "B": 2, "C": 3} >>> del_quiet(d, ["A", "C"]) >>> d {'B': 2}
-
webhelpers.containers.
distribute
(lis, columns, direction, fill=None)¶ Distribute a list into a N-column table (list of lists).
lis
is a list of values to distribute.columns
is an int greater than 1, specifying the number of columns in the table.direction
is a string beginning with “H” (horizontal) or “V” (vertical), case insensitive. This affects how values are distributed in the table, as described below.fill
is a value that will be placed in any remaining cells if the data runs out before the last row or column is completed. This must be an immutable value such asNone
,""
, 0, “ ”, etc. If you use a mutable value like[]
and later change any cell containing the fill value, all other cells containing the fill value will also be changed.The return value is a list of lists, where each sublist represents a row in the table.
table[0]
is the first row.table[0][0]
is the first column in the first row.table[0][1]
is the second column in the first row.This can be displayed in an HTML table via the following Mako template:
<table> % for row in table: <tr> % for cell in row: <td>${cell}</td> % endfor cell </tr> % endfor row </table>
In a horizontal table, each row is filled before going on to the next row. This is the same as dividing the list into chunks:
>>> distribute([1, 2, 3, 4, 5, 6, 7, 8], 3, "H") [[1, 2, 3], [4, 5, 6], [7, 8, None]]
In a vertical table, the first element of each sublist is filled before going on to the second element. This is useful for displaying an alphabetical list in columns, or when the entire column will be placed in a single <td> with a <br /> between each element:
>>> food = ["apple", "banana", "carrot", "daikon", "egg", "fish", "gelato", "honey"] >>> table = distribute(food, 3, "V", "") >>> table [['apple', 'daikon', 'gelato'], ['banana', 'egg', 'honey'], ['carrot', 'fish', '']] >>> for row in table: ... for item in row: ... print "%-9s" % item, ... print "." # To show where the line ends. ... apple daikon gelato . banana egg honey . carrot fish .
Alternatives to this function include a NumPy matrix of objects.
-
webhelpers.containers.
except_keys
(dic, keys)¶ Return a copy of the dict without the specified keys.
>>> except_keys({"A": 1, "B": 2, "C": 3}, ["A", "C"]) {'B': 2}
-
webhelpers.containers.
extract_keys
(dic, keys)¶ Return two copies of the dict. The first has only the keys specified. The second has all the other keys from the original dict.
>> extract_keys({"From": "F", "To": "T", "Received", R"}, ["To", "From"]) ({"From": "F", "To": "T"}, {"Received": "R"}) >>> regular, extra = extract_keys({"From": "F", "To": "T", "Received": "R"}, ["To", "From"]) >>> sorted(regular.keys()) ['From', 'To'] >>> sorted(extra.keys()) ['Received']
-
webhelpers.containers.
only_some_keys
(dic, keys)¶ Return a copy of the dict with only the specified keys present.
dic
may be any mapping. The return value is always a Python dict.>> only_some_keys({"A": 1, "B": 2, "C": 3}, ["A", "C"]) >>> sorted(only_some_keys({"A": 1, "B": 2, "C": 3}, ["A", "C"]).items()) [('A', 1), ('C', 3)]
-
webhelpers.containers.
ordered_items
(dic, key_order, other_keys=True, default=<class 'webhelpers.misc.NotGiven'>)¶ Like
dict.iteritems()
but with a specified key order.Arguments:
dic
is any mapping.key_order
is a list of keys. Items will be yielded in this order.other_keys
is a boolean.default
is a value returned if the key is not in the dict.
This yields the items listed in
key_order
. If a key does not exist in the dict, yield the default value if specified, otherwise skip the missing key. Afterwards, ifother_keys
is true, yield the remaining items in an arbitrary order.Usage:
>>> dic = {"To": "you", "From": "me", "Date": "2008/1/4", "Subject": "X"} >>> dic["received"] = "..." >>> order = ["From", "To", "Subject"] >>> list(ordered_items(dic, order, False)) [('From', 'me'), ('To', 'you'), ('Subject', 'X')]
-
webhelpers.containers.
get_many
(d, required=None, optional=None, one_of=None)¶ Extract values from a dict for unpacking into simple variables.
d
is a dict.required
is a list of keys that must be in the dict. The corresponding values will be the first elements in the return list. Raise KeyError if any of the keys are missing.optional
is a list of optional keys. The corresponding values will be appended to the return list, substituting None for missing keys.one_of
is a list of alternative keys. Take the first key that exists and append its value to the list. Raise KeyError if none of the keys exist. This argument will append exactly one value if specified, or will do nothing if not specified.Example:
uid, action, limit, offset = get_many(request.params, required=['uid', 'action'], optional=['limit', 'offset'])
Contributed by Shazow.
-
webhelpers.containers.
transpose
(array)¶ Turn a list of lists sideways, making columns into rows and vice-versa.
array
must be rectangular; i.e., all elements must be the same length. Otherwise the behavior is undefined: you may getIndexError
or missing items.Examples:
>>> transpose([["A", "B", "C"], ["D", "E", "F"]]) [['A', 'D'], ['B', 'E'], ['C', 'F']] >>> transpose([["A", "B"], ["C", "D"], ["E", "F"]]) [['A', 'C', 'E'], ['B', 'D', 'F']] >>> transpose([]) []
Here’s a pictoral view of the first example:
A B C => A D D E F B E C F
This can be used to turn an HTML table into a group of div columns. An HTML table is row major: it consists of several <tr> rows, each containing several <td> cells. But a <div> layout consists of only one row, each containing an entire subarray. The <div>s have style “float:left”, which makes them appear horizontally. The items within each <div> are placed in their own <div>’s or separated by <br />, which makes them appear vertically. The point is that an HTML table is row major (
array[0]
is the first row), while a group of div columns is column major (array[0]
is the first column).transpose()
can be used to switch between the two.
-
webhelpers.containers.
unique
(it)¶ Return a list of unique elements in the iterable, preserving the order.
Usage:
>>> unique([None, "spam", 2, "spam", "A", "spam", "spam", "eggs", "spam"]) [None, 'spam', 2, 'A', 'eggs']
webhelpers.date
¶
Date and time helpers.
-
webhelpers.date.
distance_of_time_in_words
(from_time, to_time=0, granularity='second', round=False)¶ Return the absolute time-distance string for two datetime objects, ints or any combination you can dream of.
If times are integers, they are interpreted as seconds from now.
granularity
dictates where the string calculation is stopped. If set to seconds (default) you will receive the full string. If another accuracy is supplied you will receive an approximation. Available granularities are: ‘century’, ‘decade’, ‘year’, ‘month’, ‘day’, ‘hour’, ‘minute’, ‘second’Setting
round
to true will increase the result by 1 if the fractional value is greater than 50% of the granularity unit.Examples:
>>> distance_of_time_in_words(86399, round=True, granularity='day') '1 day' >>> distance_of_time_in_words(86399, granularity='day') 'less than 1 day' >>> distance_of_time_in_words(86399) '23 hours, 59 minutes and 59 seconds' >>> distance_of_time_in_words(datetime(2008,3,21, 16,34), ... datetime(2008,2,6,9,45)) '1 month, 15 days, 6 hours and 49 minutes' >>> distance_of_time_in_words(datetime(2008,3,21, 16,34), ... datetime(2008,2,6,9,45), granularity='decade') 'less than 1 decade' >>> distance_of_time_in_words(datetime(2008,3,21, 16,34), ... datetime(2008,2,6,9,45), granularity='second') '1 month, 15 days, 6 hours and 49 minutes'
-
webhelpers.date.
time_ago_in_words
(from_time, granularity='second', round=False)¶ Return approximate-time-distance string for
from_time
till now.Same as
distance_of_time_in_words
but the endpoint is now.
webhelpers.feedgenerator
¶
This is a port of Django’s feeed generator for creating RSS and Atom feeds. The Geo classes for publishing geographical (GIS) data are also ported.
Syndication feed generation library – used for generating RSS, etc.
Sample usage:
>>> import webhelpers.feedgenerator as feedgenerator
>>> feed = feedgenerator.Rss201rev2Feed(
... title=u"Poynter E-Media Tidbits",
... link=u"http://www.poynter.org/column.asp?id=31",
... description=u"A group weblog by the sharpest minds in online media/journalism/publishing.",
... language=u"en",
... )
>>> feed.add_item(title="Hello", link=u"http://www.holovaty.com/test/", description="Testing.")
>>> fp = open('test.rss', 'w')
>>> feed.write(fp, 'utf-8')
>>> fp.close()
For definitions of the different versions of RSS, see: http://diveintomark.org/archives/2004/02/04/incompatible-rss
Classes¶
-
class
webhelpers.feedgenerator.
SyndicationFeed
(title, link, description, language=None, author_email=None, author_name=None, author_link=None, subtitle=None, categories=None, feed_url=None, feed_copyright=None, feed_guid=None, ttl=None, **kwargs)¶ Base class for all syndication feeds. Subclasses should provide write()
-
add_item
(title, link, description, author_email=None, author_name=None, author_link=None, pubdate=None, comments=None, unique_id=None, enclosure=None, categories=(), item_copyright=None, ttl=None, **kwargs)¶ Adds an item to the feed. All args are expected to be Python Unicode objects except pubdate, which is a datetime.datetime object, and enclosure, which is an instance of the Enclosure class.
-
add_item_elements
(handler, item)¶ Add elements on each item (i.e. item/entry) element.
-
add_root_elements
(handler)¶ Add elements in the root (i.e. feed/channel) element. Called from write().
-
item_attributes
(item)¶ Return extra attributes to place on each item (i.e. item/entry) element.
-
latest_post_date
()¶ Returns the latest item’s pubdate. If none of them have a pubdate, this returns the current date/time.
-
num_items
()¶
-
root_attributes
()¶ Return extra attributes to place on the root (i.e. feed/channel) element. Called from write().
-
write
(outfile, encoding)¶ Outputs the feed in the given encoding to outfile, which is a file-like object. Subclasses should override this.
-
writeString
(encoding)¶ Returns the feed in the given encoding as a string.
-
-
class
webhelpers.feedgenerator.
Enclosure
(url, length, mime_type)¶ Represents an RSS enclosure
-
class
webhelpers.feedgenerator.
RssFeed
(title, link, description, language=None, author_email=None, author_name=None, author_link=None, subtitle=None, categories=None, feed_url=None, feed_copyright=None, feed_guid=None, ttl=None, **kwargs)¶ -
add_root_elements
(handler)¶
-
endChannelElement
(handler)¶
-
mime_type
= 'application/rss+xml'¶
-
rss_attributes
()¶
-
write
(outfile, encoding)¶
-
write_items
(handler)¶
-
-
class
webhelpers.feedgenerator.
RssUserland091Feed
(title, link, description, language=None, author_email=None, author_name=None, author_link=None, subtitle=None, categories=None, feed_url=None, feed_copyright=None, feed_guid=None, ttl=None, **kwargs)¶ -
add_item_elements
(handler, item)¶
-
-
class
webhelpers.feedgenerator.
Rss201rev2Feed
(title, link, description, language=None, author_email=None, author_name=None, author_link=None, subtitle=None, categories=None, feed_url=None, feed_copyright=None, feed_guid=None, ttl=None, **kwargs)¶ -
add_item_elements
(handler, item)¶
-
-
class
webhelpers.feedgenerator.
Atom1Feed
(title, link, description, language=None, author_email=None, author_name=None, author_link=None, subtitle=None, categories=None, feed_url=None, feed_copyright=None, feed_guid=None, ttl=None, **kwargs)¶ -
add_item_elements
(handler, item)¶
-
add_root_elements
(handler)¶
-
mime_type
= 'application/atom+xml'¶
-
ns
= u'http://www.w3.org/2005/Atom'¶
-
root_attributes
()¶
-
write
(outfile, encoding)¶
-
write_items
(handler)¶
-
DefaultFeed
is an alias for Rss201rev2Feed
.
Functions¶
-
webhelpers.feedgenerator.
rfc2822_date
(date)¶
-
webhelpers.feedgenerator.
rfc3339_date
(date)¶
-
webhelpers.feedgenerator.
get_tag_uri
(url, date)¶ Creates a TagURI. See http://diveintomark.org/archives/2004/05/28/howto-atom-id
GIS subclasses¶
These classes allow you to include geometries (e.g., latitude/longitude) in your feed. The implementation is in a mixin class:
-
class
webhelpers.feedgenerator.
GeoFeedMixin
¶ This mixin provides the necessary routines for SyndicationFeed subclasses to produce simple GeoRSS or W3C Geo elements.
Subclasses recognize a
geometry
keyword argument to.add_item()
. The value may be any of several types:- a 2-element tuple or list of floats representing latitude/longitude:
(X, Y)
. This is called a “point”. - a 4-element tuple or list of floats representing a box:
(X0, Y0, X1, Y1)
. - a tuple or list of two points:
( (X0, Y0), (X1, Y1) )
. - a
Geometry
instance. (Or any compatible class.) This provides limited support for points, lines, and polygons. Read theGeometry
docstring and the source ofGeoFeedMixin.add_georss_element()
before using this.
The mixin provides one class attribute:
-
is_input_latitude_first
¶ The default value False indicates that input data is in latitude/longitude order. Change to True if the input data is longitude/latitude. The output is always written latitude/longitude to conform to the GeoRSS spec.
The reason for this attribute is that the Django original stores data in longitude/latutude order and reverses the arguments before writing. WebHelpers does not do this by default, but if you’re using Django data or other data that has longitude first, you’ll have to set this.
Methods:
-
add_georss_element
(handler, item, w3c_geo=False)¶ This routine adds a GeoRSS XML element using the given item and handler.
-
add_georss_point
(handler, coords, w3c_geo=False)¶ Adds a GeoRSS point with the given coords using the given handler. Handles the differences between simple GeoRSS and the more popular W3C Geo specification.
-
georss_coords
(coords)¶ In GeoRSS coordinate pairs are ordered by lat/lon and separated by a single white space. Given a tuple of coordinates, this will return a unicode GeoRSS representation.
- a 2-element tuple or list of floats representing latitude/longitude:
Two concrete subclasses are provided:
-
class
webhelpers.feedgenerator.
GeoAtom1Feed
(title, link, description, language=None, author_email=None, author_name=None, author_link=None, subtitle=None, categories=None, feed_url=None, feed_copyright=None, feed_guid=None, ttl=None, **kwargs)¶
-
class
webhelpers.feedgenerator.
W3CGeoFeed
(title, link, description, language=None, author_email=None, author_name=None, author_link=None, subtitle=None, categories=None, feed_url=None, feed_copyright=None, feed_guid=None, ttl=None, **kwargs)¶
A minimal geometry class is included:
-
class
webhelpers.feedgenerator.
Geometry
(geom_type, coords)¶ A basic geometry class for
GeoFeedMixin
.Instances have two public attributes:
-
geom_type
¶ “point”, “linestring”, “linearring”, “polygon”
-
coords
¶ For point, a tuple or list of two floats:
(X, Y)
.For linestring or linearring, a string:
"X0 Y0 X1 Y1 ..."
.For polygon, a list of strings:
["X0 Y0 X1 Y1 ..."]
. Only the first element is used because the Geo classes support only the exterior ring.
The constructor does not check its argument types.
This class was created for WebHelpers based on the interface expected by
GeoFeedMixin.add_georss_element()
. The class is untested. Please send us feedback on whether it works for you.-
webhelpers.html
¶
HTML generation helpers.
All public objects in the webhelpers.html.builder
subpackage are also
available in the webhelpers.html
namespace. Most programs will want
to put this line in their code:
from webhelpers.html import *
Or you can import the most frequently-used objects explicitly:
from webhelpers.html import HTML, escape, literal
webhelpers.html.builder
¶
HTML/XHTML tag builder
HTML Builder provides:
- an
HTML
object that creates (X)HTML tags in a Pythonic way. - a
literal
class used to mark strings containing intentional HTML markup. - a smart
escape()
function that preserves literals but escapes other strings that may accidentally contain markup characters (“<”, “>”, “&”, ‘”’, “’”) or malicious Javascript tags. Escaped strings are returned as literals to prevent them from being double-escaped later.
literal
is a subclass of unicode
, so it works with all string methods
and expressions. The only thing special about it is the .__html__
method,
which returns the string itself. The escape()
function follows a simple
protocol: if the object has an .__html__
method, it calls that rather than
.__str__
to get the HTML representation. Third-party libraries that do not
want to import literal
(and this create a dependency on WebHelpers) can put
an .__html__
method in their own classes returning the desired HTML
representation.
WebHelpers 1.2 uses MarkupSafe, a package which provides an enhanced
implementation of this protocol. Mako and Pylons have also switched to
MarkupSafe. Its advantages are a C speedup for escaping,
escaping single-quotes for security, and adding new methods to
literal
. literal is now a subclass of markupsafe.Markup
.
escape is markupsafe.escape_silent
. (The latter does not exist yet in
MarkupSafe 0.9.3, but WebHelpers itself converts None to “” in the meantime).
Single-quote escaping affects HTML attributes that are written like this: alt=’Some text.’ rather than the normal alt=”Some text.” If the text is a replaceable parameter whose value contains a single quote, the browser would think the value ends earlier than it does, thus enabling a potential cross-site scripting (XSS) attack. WebHelpers 1.0 and earlier escaped double quotes but not single quotes. MarkupSafe escapes both double and single quotes, preventing this sort of attack.
MarkupSafe has some slight differences which should not cause compatibility
issues but may in the following edge cases. (A) The force
argument to
escape()
is gone. We doubt it was ever used. (B) The default encoding of
literal()
is “ascii” instead of “utf-8”. (C) Double quotes are escaped as
“"” instead of “"”. Single quotes are escaped as “'”.
When literal
is used in a mixed expression containing both literals and
ordinary strings, it tries hard to escape the strings and return a literal.
However, this depends on which value has “control” of the expression.
literal
seems to be able to take control with all combinations of the +
operator, but with %
and join
it must be on the left side of the
expression. So these all work:
"A" + literal("B")
literal(", ").join(["A", literal("B")])
literal("%s %s") % (16, literal("kg"))
But these return an ordinary string which is prone to double-escaping later:
"\n".join([literal('<span class="foo">Foo!</span>'), literal('Bar!')])
"%s %s" % (literal("16"), literal("<em>kg</em>"))
Third-party libraries that don’t want to import literal
and thus avoid a
dependency on WebHelpers can add an .__html__
method to any class, which
can return the same as .__str__
or something else. escape()
trusts the
HTML method and does not escape the return value. So only strings that lack
an .__html__
method will be escaped.
The HTML
object has the following methods for tag building:
HTML(*strings)
Escape the string args, concatenate them, and return a literal. This is the same as
escape(s)
but accepts multiple strings. Multiple args are useful when mixing child tags with text, such as:html = HTML("The king is a >>", HTML.strong("fink"), "<<!")
HTML.literal(*strings)
- Same as
literal
but concatenates multiple arguments. HTML.comment(*strings)
- Escape and concatenate the strings, and wrap the result in an HTML comment.
HTML.tag(tag, *content, **attrs)
Create an HTML tag
tag
with the keyword args converted to attributes. The other positional args become the content for the tag, and are escaped and concatenated. If an attribute name conflicts with a Python keyword (notably “class”), append an underscore. If an attribute value isNone
, the attribute is not inserted. Two special keyword args are recognized:c
- Specifies the content. This cannot be combined with content in positional args. The purpose of this argument is to position the content at the end of the argument list to match the native HTML syntax more closely. Its use is entirely optional. The value can be a string, a tuple, or a tag.
_closed
- If present and false, do not close the tag. Otherwise the tag will be closed with a closing tag or an XHTML-style trailing slash as described below.
_nl
- If present and true, insert a newline before the first content element, between each content element, and at the end of the tag.
Example:
>>> HTML.tag("a", href="http://www.yahoo.com", name=None, ... c="Click Here") literal(u'<a href="http://www.yahoo.com">Click Here</a>')
HTML.__getattr__
Same as
HTML.tag
but using attribute access. Example:>>> HTML.a("Foo", href="http://example.com/", class_="important") literal(u'<a class="important" href="http://example.com/">Foo</a>')
HTML.cdata
Wrap the text in a “<![CDATA[ ... ]]>” section. Plain strings will not be escaped because CDATA itself is an escaping syntax.
>>> HTML.cdata(u"Foo") literal(u'<![CDATA[Foo]]>')
>>> HTML.cdata(u"<p>") literal(u'<![CDATA[<p>]]>')
About XHTML and HTML¶
This builder always produces tags that are valid as both HTML and XHTML.
“Void” tags – those which can never have content like <br>
and <input>
– are written like <br />
, with a space and a trailing /
.
Only void tags get this treatment. The library will never, for
example, produce <script src="..." />
, which is invalid HTML. Instead
it will produce <script src="..."></script>
.
The W3C HTML validator validates these
constructs as valid HTML Strict. It does produce warnings, but those
warnings warn about the ambiguity if this same XML-style self-closing
tags are used for HTML elements that are allowed to take content (<script>
,
<textarea>
, etc). This library never produces markup like that.
Rather than add options to generate different kinds of behavior, we felt it was better to create markup that could be used in different contexts without any real problems and without the overhead of passing options around or maintaining different contexts, where you’d have to keep track of whether markup is being rendered in an HTML or XHTML context.
If you _really_ want tags without training slashes (e.g., <br>`)`, you can
abuse ``_closed=False
to produce them.
Classes¶
-
class
webhelpers.html.builder.
literal
(s, encoding=None, errors=strict')¶ Represents an HTML literal.
This subclass of unicode has a
.__html__()
method that is detected by theescape()
function.Also, if you add another string to this string, the other string will be quoted and you will get back another literal object. Also
literal(...) % obj
will quote any value(s) fromobj
. If you do something likeliteral(...) + literal(...)
, neither string will be changed becauseescape(literal(...))
doesn’t change the original literal.Changed in WebHelpers 1.2: the implementation is now now a subclass of
markupsafe.Markup
. This brings some new methods:.escape
(class method),.unescape
, and.striptags
.-
classmethod
escape
(s)¶ Same as the
escape
function but return the proper subclass in subclasses.
-
unescape
()¶ Unescape markup again into an text_type string. This also resolves known HTML4 and XHTML entities:
>>> Markup("Main » <em>About</em>").unescape() u'Main \xbb <em>About</em>'
Unescape markup into an text_type string and strip all tags. This also resolves known HTML4 and XHTML entities. Whitespace is normalized to one:
>>> Markup("Main » <em>About</em>").striptags() u'Main \xbb About'
-
classmethod
-
class
webhelpers.html.builder.
HTML
¶ Described above.
Functions¶
-
webhelpers.html.builder.
lit_sub
(*args, **kw)¶ Literal-safe version of re.sub. If the string to be operated on is a literal, return a literal result. All arguments are passed directly to
re.sub
.
-
webhelpers.html.builder.
url_escape
(s, safe='/')¶ Urlencode the path portion of a URL. This is the same function as
urllib.quote
in the Python standard library. It’s exported here with a name that’s easier to remember.
The markupsafe
package has a function soft_unicode
which converts a
string to Unicode if it’s not already. Unlike the Python builtin unicode()
,
it will not convert Markup
(literal
) to plain Unicode, to avoid
overescaping. This is not included in WebHelpers but you may find it useful.
webhelpers.html.converters
¶
Functions that convert from text markup languages to HTML and back.
-
webhelpers.html.converters.
format_paragraphs
(text, preserve_lines=False)¶ Convert text to HTML paragraphs.
text
:- the text to convert. Split into paragraphs at blank lines (i.e., wherever two or more consecutive newlines appear), and wrap each paragraph in a <p>.
preserve_lines
:- If true, add <br /> before each single line break
-
webhelpers.html.converters.
markdown
(text, markdown=None, **kwargs)¶ Format the text to HTML with Markdown formatting.
Markdown is a wiki-like text markup language, originally written by John Gruber for Perl. The helper converts Markdown text to HTML.
There are at least two Python implementations of Markdown. Markdown <http://www.freewisdom.org/projects/python-markdown/>`_is the original port, and version 2.x contains extensions for footnotes, RSS, etc. Markdown2 is another port which claims to be faster and to handle edge cases better.
You can pass the desired Markdown module as the
markdown
argument, or the helper will try to importmarkdown
. If neither is available, it will fall back towebhelpers.markdown
, which is Freewisdom’s Markdown 1.7 without extensions.IMPORTANT: If your source text is untrusted and may contain malicious HTML markup, pass
safe_mode="escape"
to escape it,safe_mode="replace"
to replace it with a scolding message, orsafe_mode="remove"
to strip it.
-
webhelpers.html.converters.
nl2br
(text)¶ Insert a <br /> before each newline.
-
webhelpers.html.converters.
textilize
(text, sanitize=False)¶ Format the text to HTML with Textile formatting.
This function uses the PyTextile library which is included with WebHelpers.
Additionally, the output can be sanitized which will fix tags like <img />, <br /> and <hr /> for proper XHTML output.
webhelpers.html.grid
¶
A helper to make an HTML table from a list of dicts, objects, or sequences.
A set of CSS styles complementing this helper is in “webhelpers/html/public/stylesheets/grid.css”. To use them, include the stylesheet in your applcation and set your <table> class to “stylized”.
The documentation below is not very clear. This is a known bug. We need a native English speaker who uses the module to volunteer to rewrite it.
This module is written and maintained by Ergo^.
A demo is available. Run the following command to produce some HTML tables:
python -m webhelpers.html.grid_demo OUTPUT_DIR
A subclass specialized for Pylons is in webhelpers.pylonslib.grid
.
Grid
class¶
-
class
webhelpers.html.grid.
Grid
(itemlist, columns, column_labels=None, column_formats=None, start_number=1, order_column=None, order_direction=None, request=None, url=None, **kw)¶ This class is designed to aid programmer in the task of creation of tables/grids - structures that are mostly built from datasets.
To create a grid at minimum one one needs to pass a dataset, like a list of dictionaries, or sqlalchemy proxy or query object:
grid = Grid(itemlist, ['_numbered','c1', 'c2','c4'])
where itemlist in this simple scenario is a list of dicts:
[{‘c1’:1,’c2’...}, {‘c1’...}, ...]This helper also received the list that defines order in which columns will be rendered - also keep note of special column name that can be passed in list that defines order -
_numbered
- this adds additional column that shows the number of item. For paging sql data there one can passstart_number
argument to the grid to define where to start counting. Descendant sorting on_numbered
column decrements the value, you can change how numberign function behaves by overloadingcalc_row_no
property.Converting the grid to a string renders the table rows. That’s just the <tr> tags, not the <table> around them. The part outside the <tr>s have too many variations for us to render it. In many template systems, you can simply assign the grid to a template variable and it will be automatically converted to a string. Example using a Mako template:
<table class="stylized"> <caption>My Lovely Grid</caption> <col class="c1" /> ${my_grid} </table>
The names of the columns will get automatically converted for humans ie. foo_bar becomes Foo Bar. If you want the title to be something else you can change the grid.labels dict. If you want the column
part_no
to becomeCatalogue Number
just do:grid.labels[``part_no``] = u'Catalogue Number'
It may be desired to exclude some or all columns from generation sorting urls (used by subclasses that are sorting aware). You can use grids exclude_ordering property to pass list of columns that should not support sorting. By default sorting is disabled - this
exclude_ordering
contains every column name.Since various programmers have different needs, Grid is highly customizable. By default grid attempts to read the value from dict directly by key. For every column it will try to output value of current_row[‘colname’].
Since very often this behavior needs to be overridden like we need date formatted, use conditionals or generate a link one can use the
column_formats
dict and pass a rendering function/lambda to it. For example we want to apppendfoo
to part number:def custem_part_no_td(col_num, i, item): return HTML.td(`Foo %s` % item[``part_no``]) grid.column_formats[``part_no``] = custem_part_no_td
You can customize the grids look and behavior by overloading grids instance render functions:
grid.default_column_format(self, column_number, i, record, column_name) by default generates markup like: <td class="cNO">VALUE</td> grid.default_header_column_format(self, column_number, column_name, header_label) by default generates markup like: <td class="cNO COLUMN_NAME">VALUE</td> grid.default_header_ordered_column_format(self, column_number, order, column_name, header_label) Used by grids that support ordering of columns in the grid like, webhelpers.pylonslib.grid.GridPylons. by default generates markup like: <td class="cNO ordering ORDER_DIRECTION COLUMN_NAME">LABEL</td> grid.default_header_record_format(self, headers) by default generates markup like: <tr class="header">HEADERS_MARKUP</tr> grid.default_record_format(self, i, record, columns) Make an HTML table from a list of objects, and soon a list of sequences, a list of dicts, and a single dict. <tr class="ODD_OR_EVEN">RECORD_MARKUP</tr> grid.generate_header_link(self, column_number, column, label_text) by default just sets the order direction and column properties for grid. Actual link generation is handled by sublasses of Grid. grid.numbered_column_format(self, column_number, i, record) by default generates markup like: <td class="cNO">RECORD_NO</td>
-
generate_header_link
(column_number, column, label_text)¶ This handles generation of link and then decides to call
self.default_header_ordered_column_format
orself.default_header_column_format
based on whether current column is the one that is used for sorting.you need to extend Grid class and overload this method implementing ordering here, whole operation consists of setting self.order_column and self.order_dir to their CURRENT values, and generating new urls for state that header should set set after its clicked
(additional kw are passed to url gen. - like for webhelpers.paginate) example URL generation code below:
GET = dict(self.request.copy().GET) # needs dict() for py2.5 compat self.order_column = GET.pop("order_col", None) self.order_dir = GET.pop("order_dir", None) # determine new order if column == self.order_column and self.order_dir == "asc": new_order_dir = "dsc" else: new_order_dir = "asc" self.additional_kw['order_col'] = column self.additional_kw['order_dir'] = new_order_dir # generate new url for example url_generator uses # pylons's url.current() or pyramid's current_route_url() new_url = self.url_generator(**self.additional_kw) # set label for header with link label_text = HTML.tag("a", href=new_url, c=label_text)
-
-
class
webhelpers.html.grid.
ObjectGrid
(itemlist, columns, column_labels=None, column_formats=None, start_number=1, order_column=None, order_direction=None, request=None, url=None, **kw)¶ A grid class for a sequence of objects.
This grid class assumes that the rows are objects rather than dicts, and uses attribute access to retrieve the column values. It works well with SQLAlchemy ORM instances.
webhelpers.html.tags
¶
Helpers that produce simple HTML tags.
Most helpers have an **attrs
argument to specify additional HTML
attributes. A trailing underscore in the name will be deleted; this is
especially important for attributes that are identical to Python keywords;
e.g., class_
. Some helpers handle certain keywords specially; these are
noted in the helpers’ docstrings.
To create your own custom tags, see webhelpers.html.builder
.
A set of CSS styles complementing these helpers is in
webhelpers/public/stylesheets/webhelpers.css
.
Form tags¶
An open tag for a form that will submit to
url
.You must close the form yourself by calling
end_form()
or outputting </form>.Options:
method
- The method to use when submitting the form, usually either “GET” or “POST”. If “PUT”, “DELETE”, or another verb is used, a hidden input with name _method is added to simulate the verb over POST.
multipart
- If set to True, the enctype is set to “multipart/form-data”. You must set it to true when uploading files, or the browser will submit the filename rather than the file.
hidden_fields
- Additional hidden fields to add to the beginning of the form. It may
be a dict or an iterable of key-value tuples. This is implemented by
calling the object’s
.items()
method if it has one, or just iterating the object. (This will successfuly get multiple values for the same key in WebOb MultiDict objects.)
Because input tags must be placed in a block tag rather than directly inside the form, all hidden fields will be put in a ‘<div style=”display:none”>’. The style prevents the <div> from being displayed or affecting the layout.
Examples:
>>> form("/submit") literal(u'<form action="/submit" method="post">') >>> form("/submit", method="get") literal(u'<form action="/submit" method="get">') >>> form("/submit", method="put") literal(u'<form action="/submit" method="post"><div style="display:none">\n<input name="_method" type="hidden" value="put" />\n</div>\n') >>> form("/submit", "post", multipart=True) literal(u'<form action="/submit" enctype="multipart/form-data" method="post">')
Changed in WebHelpers 1.0b2: add <div> and
hidden_fields
arg.Changed in WebHelpers 1.2: don’t add an “id” attribute to hidden tags generated by this helper; they clash if there are multiple forms on the page.
Output “</form>”.
Example:
>>> end_form() literal(u'</form>')
Create a standard text field.
value
is a string, the content of the text field.id
is the HTML ID attribute, and should be passed as a keyword argument. By default the ID is the same as the name filtered through_make_safe_id_component()
. Pass None to suppress the ID attribute entirely.type
is the input field type, normally “text”. You can override it for HTML 5 input fields that don’t have their own helper; e.g., “search”, “email”, “date”.Options:
disabled
- If set to True, the user will not be able to usethis input.
size
- The number of visible characters that will fit in theinput.
maxlength
- The maximum number of characters that the browserwill allow the user to enter.
The remaining keyword args will be standard HTML attributes for the tag.
Example, a text input field:
>>> text("address") literal(u'<input id="address" name="address" type="text" />')
HTML 5 example, a color picker:
>>> text("color", type="color") literal(u'<input id="color" name="color" type="color" />')
Create a text input area.
Example:
>>> textarea("body", "", cols=25, rows=10) literal(u'<textarea cols="25" id="body" name="body" rows="10"></textarea>')
Create a hidden field.
Create a file upload field.
If you are using file uploads then you will also need to set the multipart option for the form.
Example:
>>> file('myfile') literal(u'<input id="myfile" name="myfile" type="file" />')
Create a password field.
Takes the same options as
text()
.
Create a check box.
Arguments:
name
– the widget’s name.value
– the value to return to the application if the box is checked.checked
– true if the box should be initially checked.label
– a text label to display to the right of the box.id
is the HTML ID attribute, and should be passed as a keyword argument. By default the ID is the same as the name filtered through_make_safe_id_component()
. Pass None to suppress the ID attribute entirely.The following HTML attributes may be set by keyword argument:
disabled
- If true, checkbox will be grayed out.readonly
- If true, the user will not be able to modify the checkbox.
To arrange multiple checkboxes in a group, see webhelpers.containers.distribute().
Example:
>>> checkbox("hi") literal(u'<input id="hi" name="hi" type="checkbox" value="1" />')
Create a radio button.
Arguments:
name
– the field’s name.value
– the value returned to the application if the button is pressed.checked
– true if the button should be initially pressed.label
– a text label to display to the right of the button.The id of the radio button will be set to the name + ‘_’ + value to ensure its uniqueness. An
id
keyword arg overrides this. (Note that this behavior is unique to theradio()
helper.)To arrange multiple radio buttons in a group, see webhelpers.containers.distribute().
Create a submit button with the text
value
as the caption.
Create a dropdown selection box.
name
– the name of this control.selected_values
– a string or list of strings or integers giving the value(s) that should be preselected.options
– anOptions
object or iterable of(value, label)
pairs. The label will be shown on the form; the option will be returned to the application if that option is chosen. If you pass a string or int instead of a 2-tuple, it will be used for both the value and the label. If the value is a tuple or a list, it will be added as an optgroup, with label as label.
id
is the HTML ID attribute, and should be passed as a keyword argument. By default the ID is the same as the name. filtered through_make_safe_id_component()
. Pass None to suppress the ID attribute entirely.CAUTION: the old rails helper
options_for_select
had the label first. The order was reversed because most real-life collections have the value first, including dicts of the form{value: label}
. For those dicts you can simply passD.items()
as this argument.HINT: You can sort options alphabetically by label via:
sorted(my_options, key=lambda x: x[1])
The following options may only be keyword arguments:
multiple
– if true, this control will allow multipleselections.
prompt
– if specified, an extra option will be prepended to the list: (“”,prompt
). This is intended for those “Please choose ...” pseudo-options. Its value is “”, equivalent to not making a selection.
Any other keyword args will become HTML attributes for the <select>.
Examples (call, result):
>>> select("currency", "$", [["$", "Dollar"], ["DKK", "Kroner"]]) literal(u'<select id="currency" name="currency">\n<option selected="selected" value="$">Dollar</option>\n<option value="DKK">Kroner</option>\n</select>') >>> select("cc", "MasterCard", [ "VISA", "MasterCard" ], id="cc", class_="blue") literal(u'<select class="blue" id="cc" name="cc">\n<option value="VISA">VISA</option>\n<option selected="selected" value="MasterCard">MasterCard</option>\n</select>') >>> select("cc", ["VISA", "Discover"], [ "VISA", "MasterCard", "Discover" ]) literal(u'<select id="cc" name="cc">\n<option selected="selected" value="VISA">VISA</option>\n<option value="MasterCard">MasterCard</option>\n<option selected="selected" value="Discover">Discover</option>\n</select>') >>> select("currency", None, [["$", "Dollar"], ["DKK", "Kroner"]], prompt="Please choose ...") literal(u'<select id="currency" name="currency">\n<option selected="selected" value="">Please choose ...</option>\n<option value="$">Dollar</option>\n<option value="DKK">Kroner</option>\n</select>') >>> select("privacy", 3L, [(1, "Private"), (2, "Semi-public"), (3, "Public")]) literal(u'<select id="privacy" name="privacy">\n<option value="1">Private</option>\n<option value="2">Semi-public</option>\n<option selected="selected" value="3">Public</option>\n</select>') >>> select("recipients", None, [([("u1", "User1"), ("u2", "User2")], "Users"), ([("g1", "Group1"), ("g2", "Group2")], "Groups")]) literal(u'<select id="recipients" name="recipients">\n<optgroup label="Users">\n<option value="u1">User1</option>\n<option value="u2">User2</option>\n</optgroup>\n<optgroup label="Groups">\n<option value="g1">Group1</option>\n<option value="g2">Group2</option>\n</optgroup>\n</select>')
A tuple of
Option
objects for theselect()
helper.select()
calls this automatically so you don’t have to. However, you may find it useful for organizing your code, and its methods can be convenient.This class has multiple jobs:
- Canonicalize the options given to
select()
into a consistent format. - Avoid canonicalizing the same data multiple times. It subclasses tuple rather than a list to guarantee that nonconformant elements won’t be added after canonicalization.
- Provide convenience methods to iterate the values and labels separately.
>>> opts = Options(["A", 1, ("b", "B")]) >>> opts Options([(u'A', u'A'), (u'1', u'1'), (u'b', u'B')]) >>> list(opts.values()) [u'A', u'1', u'b'] >>> list(opts.labels()) [u'A', u'1', u'B'] >>> opts[2].value u'b' >>> opts[2].label u'B'
Iterate the label element of each pair.
Iterate the value element of each pair.
- Canonicalize the options given to
An option for an HTML select.
A simple container with two attributes,
.value
and.label
.
A container for Options
Format the user-visible title for a form field.
Use this for forms that have a text title above or next to each field.
title
– the name of the field; e.g., “First Name”.required
– if true, append a *” to the title and use the ‘required’ HTML format (see example); otherwise use the ‘not required’ format.label_for
– if provided, put<label for="ID">
around the title. The value should be the HTML ID of the input field related to this title. Per the HTML standard, the ID should point to a single control (input, select, textarea), not to multiple controls (fieldset, group of checkboxes, group of radio buttons). ID’s are set by passing the keyword argid
to the appropriate helper.Note that checkboxes and radio buttions typically have their own individual labels in addition to the title. You can set these with the
label
argument tocheckbox()
andradio()
.This helper does not accept other keyword arguments.
See webhepers/public/stylesheets/webhelpers.css for suggested styles.
>>> title("First Name") literal(u'<span class="not-required">First Name</span>') >>> title("Last Name", True) literal(u'<span class="required">Last Name <span class="required-symbol">*</span></span>') >>> title("First Name", False, "fname") literal(u'<span class="not-required"><label for="fname">First Name</label></span>') >>> title("Last Name", True, label_for="lname") literal(u'<span class="required"><label for="lname">Last Name</label> <span class="required-symbol">*</span></span>')
Return an inline HTML snippet explaining which fields are required.
See webhepers/public/stylesheets/webhelpers.css for suggested styles.
>>> required_legend() literal(u'<span class="required required-symbol">*</span> = required')
ModelTags
class¶
A nice way to build a form for a database record.
ModelTags allows you to build a create/update form easily. (This is the C and U in CRUD.) The constructor takes a database record, which can be a SQLAlchemy mapped class, or any object with attributes or keys for the field values. Its methods shadow the the form field helpers, but it automatically fills in the value attribute based on the current value in the record. (It also knows about the ‘checked’ and ‘selected’ attributes for certain tags.)
You can also use the same form to input a new record. Pass
None
or""
instead of a record, and it will set all the current values to a default value, which is either the default keyword arg to the method, or “” if not specified.(Hint: in Pylons you can put
mt = ModelTags(c.record)
in your template, and then if the record doesn’t exist you can either setc.record = None
or not set it at all. That’s because nonexistentc
attributes resolve to “” unless you’ve setconfig["pylons.strict_c"] = True
. However, having ac
attribute that’s sometimes set and sometimes not is arguably bad programming style.)Build a checkbox field.
The box will be initially checked if the value of the corresponding database field is true.
The submitted form value will be “1” if the box was checked. If the box is unchecked, no value will be submitted. (This is a downside of the standard checkbox tag.)
To display multiple checkboxes in a group, see webhelper.containers.distribute().
Same as text but format a date value into a date string.
The value can be a datetime.date, datetime.datetime, None, or “”. The former two are converted to a string using the date format passed to the constructor. The latter two are converted to “”.
If there’s no database record, consult keyword arg default. It it’s the string “today”, use todays’s date. Otherwise it can be any of the values allowed above. If no default is specified, the text field is initialized to “”.
Hint: you may wish to attach a Javascript calendar to the field.
Build a file upload field.
User agents may or may not respect the contents of the ‘value’ attribute.
Build a hidden HTML field.
Build a password field.
This is the same as a text box but the value will not be shown on the screen as the user types.
Build a radio button.
The radio button will initially be selected if the database value equals
checked_value
. On form submission the value will bechecked_value
if the button was selected, or""
otherwise.In case of a ModelTags object that is created from scratch (e.g.
new_employee=ModelTags(None)
) the option that should be checked can be set by the ‘default’ parameter. As in:new_employee.radio('status', checked_value=7, default=7)
The control’s ‘id’ attribute will be modified as follows:
- If not specified but an ‘id_format’ was given to the constructor, generate an ID based on the format.
- If an ID was passed in or was generated by step (1), append an
underscore and the checked value. Before appending the checked
value, lowercase it, change any spaces to
"_"
, and remove any non-alphanumeric characters except underscores and hyphens. - If no ID was passed or generated by step (1), the radio button will not have an ‘id’ attribute.
To display multiple radio buttons in a group, see webhelper.containers.distribute().
Build a dropdown select box or list box.
See the
select()
function for the meaning of the arguments.If the corresponding database value is not a list or tuple, it’s wrapped in a one-element list. But if it’s “” or
None
, an empty list is substituted. This is to accommodate multiselect lists, which may have multiple values selected.
Build a text box.
Build a rectangular text area.
Hyperlinks¶
Create a hyperlink with the given text pointing to the URL.
If the label is
None
or empty, the URL will be used as the label.This function does not modify the URL in any way. The label will be escaped if it contains HTML markup. To prevent escaping, wrap the label in a
webhelpers.html.literal()
.
Same as
link_to
but return just the label if the condition is false.This is useful in a menu when you don’t want the current option to be a link. The condition will be something like:
actual_value != value_of_this_menu_item
.
The opposite of
link_to
. Return just the label if the condition is true.
Table tags¶
<th> for a “click-to-sort-by” column.
Convenience function for a sortable column. If this is the current sort column, just display the label and set the cell’s class to
class_if_sort_column
.current_order
is the table’s current sort order.column_order
is the value pertaining to this column. In other words, if the two are equal, the table is currently sorted by this column.If this is the sort column, display the label and set the <th>’s class to
class_if_sort_column
.If this is not the sort column, display an <a> hyperlink based on
label
,url
, andlink_attrs
(a dict), and set the <th>’s class toclass_if_not_sort_column
.url
is the literal href= value for the link. Pylons users would typically pass something likeurl=h.url_for("mypage", sort="date")
.**attrs
are additional attributes for the <th> tag.If you prefer a <td> tag instead of <th>, pass
name="td"
.To change the sort order via client-side Javascript, pass
url=None
and the appropriate Javascript attributes inlink_attrs
.Examples:
>>> sort = "name" >>> th_sortable(sort, "name", "Name", "?sort=name") literal(u'<th class="sort">Name</th>') >>> th_sortable(sort, "date", "Date", "?sort=date") literal(u'<th><a href="?sort=date">Date</a></th>') >>> th_sortable(sort, "date", "Date", None, link_attrs={"onclick": "myfunc()"}) literal(u'<th><a onclick="myfunc()">Date</a></th>')
Other non-form tags¶
Return an ordered list with each item wrapped in <li>.
items
- list of strings.
default
- value returned _instead of the <ol>_ if there are no items in the list.
If
None
, return an empty <ol>. li_attrs
- dict of attributes for the <li> tags.
Examples:
>>> ol(["foo", "bar"]) literal(u'<ol>\n<li>foo</li>\n<li>bar</li>\n</ol>') >>> ol(["A", "B"], li_attrs={"class_": "myli"}, class_="mylist") literal(u'<ol class="mylist">\n<li class="myli">A</li>\n<li class="myli">B</li>\n</ol>') >>> ol([]) literal(u'')
Return an unordered list with each item wrapped in <li>.
items
- list of strings.
default
- value returned _instead of the <ul>_ if there are no items in the list.
If
None
, return an empty <ul>. li_attrs
- dict of attributes for the <li> tags.
Examples:
>>> ul(["foo", "bar"]) literal(u'<ul>\n<li>foo</li>\n<li>bar</li>\n</ul>') >>> ul(["A", "B"], li_attrs={"class_": "myli"}, class_="mylist") literal(u'<ul class="mylist">\n<li class="myli">A</li>\n<li class="myli">B</li>\n</ul>') >>> ul([]) literal(u'<ul></ul>') >>> ul([], default="") '' >>> ul([], default=literal('<span class="no-data">No data</span>')) literal(u'<span class="no-data">No data</span>') >>> ul(["A"], default="NOTHING") literal(u'<ul>\n<li>A</li>\n</ul>')
Return an image tag for the specified
source
.url
- The URL of the image. (This must be the exact URL desired. A previous version of this helper added magic prefixes; this is no longer the case.)
alt
- The img’s alt tag. Non-graphical browsers and screen readers will output this instead of the image. If the image is pure decoration and uninteresting to non-graphical users, pass “”. To omit the alt tag completely, pass None.
width
- The width of the image, default is not included.
height
- The height of the image, default is not included.
path
- Calculate the width and height based on the image file at
path
if possible. May not be specified ifwidth
orheight
is specified. The results are also written to the debug log for troubleshooting. use_pil
- If true, calcuate the image dimensions using the Python Imaging
Library, which must be installed. Otherwise use a pure Python
algorithm which understands fewer image formats and may be less
accurate. This flag controls whether
webhelpers.media.get_dimensions_pil
orwebhelpers.media.get_dimensions
is called. It has no effect ifpath
is not specified.
Examples:
>>> image('/images/rss.png', 'rss syndication') literal(u'<img alt="rss syndication" src="/images/rss.png" />') >>> image('/images/xml.png', "") literal(u'<img alt="" src="/images/xml.png" />') >>> image("/images/icon.png", height=16, width=10, alt="Edit Entry") literal(u'<img alt="Edit Entry" height="16" src="/images/icon.png" width="10" />') >>> image("/icons/icon.gif", alt="Icon", width=16, height=16) literal(u'<img alt="Icon" height="16" src="/icons/icon.gif" width="16" />') >>> image("/icons/icon.gif", None, width=16) literal(u'<img alt="" src="/icons/icon.gif" width="16" />')
A break tag (“<br />”) followed by a newline. This is a literal constant, not a function.
Head tags and document type¶
Return CSS link tags for the specified stylesheet URLs.
urls
should be the exact URLs desired. A previous version of this helper added magic prefixes; this is no longer the case.Examples:
>>> stylesheet_link('/stylesheets/style.css') literal(u'<link href="/stylesheets/style.css" media="screen" rel="stylesheet" type="text/css" />') >>> stylesheet_link('/stylesheets/dir/file.css', media='all') literal(u'<link href="/stylesheets/dir/file.css" media="all" rel="stylesheet" type="text/css" />')
Return script include tags for the specified javascript URLs.
urls
should be the exact URLs desired. A previous version of this helper added magic prefixes; this is no longer the case.Specify the keyword argument
defer=True
to enable the script defer attribute.Examples:
>>> print javascript_link('/javascripts/prototype.js', '/other-javascripts/util.js') <script src="/javascripts/prototype.js" type="text/javascript"></script> <script src="/other-javascripts/util.js" type="text/javascript"></script> >>> print javascript_link('/app.js', '/test/test.1.js') <script src="/app.js" type="text/javascript"></script> <script src="/test/test.1.js" type="text/javascript"></script>
Return a link tag allowing auto-detecting of RSS or ATOM feed.
The auto-detection of feed for the current page is only for browsers and news readers that support it.
url
- The URL of the feed. (This should be the exact URLs desired. A previous version of this helper added magic prefixes; this is no longer the case.)
feed_type
- The type of feed. Specifying ‘rss’ or ‘atom’ automatically translates to a type of ‘application/rss+xml’ or ‘application/atom+xml’, respectively. Otherwise the type is used as specified. Defaults to ‘rss’.
Examples:
>>> auto_discovery_link('http://feed.com/feed.xml') literal(u'<link href="http://feed.com/feed.xml" rel="alternate" title="RSS" type="application/rss+xml" />') >>> auto_discovery_link('http://feed.com/feed.xml', feed_type='atom') literal(u'<link href="http://feed.com/feed.xml" rel="alternate" title="ATOM" type="application/atom+xml" />') >>> auto_discovery_link('app.rss', feed_type='atom', title='atom feed') literal(u'<link href="app.rss" rel="alternate" title="atom feed" type="application/atom+xml" />') >>> auto_discovery_link('/app.html', feed_type='text/html') literal(u'<link href="/app.html" rel="alternate" title="" type="text/html" />')
Document type declarations for HTML and XHTML.
Create a <!DOCTYPE> for HTML 4.
Usage:
>>> Doctype().html4() literal(u'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">') >>> Doctype().html4("strict") literal(u'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd">') >>> Doctype().html4("frameset") literal(u'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">')
Create a <!DOCTYPE> for HTML 5.
Usage:
>>> Doctype().html5() literal(u'<!doctype html>')
Create a <!DOCTYPE> for XHTML 1.
Usage:
>>> Doctype().xhtml1() literal(u'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">') >>> Doctype().xhtml1("strict") literal(u'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">') >>> Doctype().xhtml1("frameset") literal(u'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">')
Create an XML declaration.
Usage:
>>> xml_declaration() literal(u'<?xml version="1.0" encoding="utf-8" ?>')
Utility functions¶
Add CSS classes to a tag programmatically.
This helper is meant to be used as the
class_
argument to a tag helper.The argument is an iterable of
(class, condition)
pairs, where eachclass
is a string andcondition
is a boolean. The function returns a space-separated list of classes whose conditions were true.If all conditions are false, return
None
. This tells the caller to suppress the “class” attribute entirely.Examples:
>>> arg = [("first", False), ("even", True)] >>> HTML.td("My content.", class_=css_classes(arg)) literal(u'<td class="even">My content.</td>') >>> arg = [("first", True), ("even", True)] >>> HTML.td("My content.", class_=css_classes(arg)) literal(u'<td class="first even">My content.</td>') >>> arg = [("first", False), ("even", False)] >>> HTML.td("My content.", class_=css_classes(arg)) literal(u'<td>My content.</td>')
Convert boolean values into proper HTML attributes.
attrs
is a dict of HTML attributes, which will be modified in place.bool_attrs
is a list of attribute names.For every element in
bool_attrs
, I look for a corresponding key inattrs
. If its value is true, I change the value to match the key. For example, I convertselected=True
intoselected="selected"
. If the value is false, I delete the key.
webhelpers.html.tools
¶
HTML helpers that are more than just simple tags.
There are no helpers to prettify HTML or canonicalize whitespace because BeautifulSoup and HTMLTidy handle this well.
-
webhelpers.html.tools.
auto_link
(text, link='all', **href_attrs)¶ Turn all urls and email addresses into clickable links.
link
- Used to determine what to link. Options are “all”, “email_addresses”, or “urls”
href_attrs
- Additional attributes for generated <a> tags.
Example:
>>> auto_link("Go to http://www.planetpython.com and say hello to guido@python.org") literal(u'Go to <a href="http://www.planetpython.com">http://www.planetpython.com</a> and say hello to <a href="mailto:guido@python.org">guido@python.org</a>')
Generate a form containing a sole button that submits to
url
.Use this method instead of
link_to
for actions that do not have the safe HTTP GET semantics implied by using a hypertext link.The parameters are the same as for
link_to
. Anyhtml_attrs
that you pass will be applied to the innerinput
element. In particular, passdisabled = True/Falseas part of
html_attrs
to control whether the button is disabled. The generated form element is given the class ‘button-to’, to which you can attach CSS styles for display purposes.The submit button itself will be displayed as an image if you provide both
type
andsrc
as followed:type=’image’, src=’icon_delete.gif’The
src
path should be the exact URL desired. A previous version of this helper added magical prefixes but this is no longer the case.Example 1:
# inside of controller for "feeds" >> button_to("Edit", url(action='edit', id=3)) <form method="post" action="/feeds/edit/3" class="button-to"> <div><input value="Edit" type="submit" /></div> </form>
Example 2:
>> button_to("Destroy", url(action='destroy', id=3), .. method='DELETE') <form method="POST" action="/feeds/destroy/3" class="button-to"> <div> <input type="hidden" name="_method" value="DELETE" /> <input value="Destroy" type="submit" /> </div> </form>
Example 3:
# Button as an image. >> button_to("Edit", url(action='edit', id=3), type='image', .. src='icon_delete.gif') <form method="POST" action="/feeds/edit/3" class="button-to"> <div><input alt="Edit" src="/images/icon_delete.gif" type="image" value="Edit" /></div> </form>
Note
This method generates HTML code that represents a form. Forms are “block” content, which means that you should not try to insert them into your HTML where only inline content is expected. For example, you can legally insert a form inside of a
div
ortd
element or in betweenp
elements, but not in the middle of a run of text, nor can you place a form within another form. (Bottom line: Always validate your HTML before going public.)Changed in WebHelpers 1.2: Preserve case of “method” arg for XHTML compatibility. E.g., “POST” or “PUT” causes method=”POST”; “post” or “put” causes method=”post”.
-
webhelpers.html.tools.
js_obfuscate
(content)¶ Obfuscate data in a Javascript tag.
Example:
>>> js_obfuscate("<input type='hidden' name='check' value='valid' />") literal(u'<script type="text/javascript">\n//<![CDATA[\neval(unescape(\'%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%69%6e%70%75%74%20%74%79%70%65%3d%27%68%69%64%64%65%6e%27%20%6e%61%6d%65%3d%27%63%68%65%63%6b%27%20%76%61%6c%75%65%3d%27%76%61%6c%69%64%27%20%2f%3e%27%29%3b\'))\n//]]>\n</script>')
-
webhelpers.html.tools.
highlight
(text, phrase, highlighter=None, case_sensitive=False, class_='highlight', **attrs)¶ Highlight all occurrences of
phrase
intext
.This inserts “<strong class=”highlight”>...</strong>” around every occurrence.
Arguments:
text
:- The full text.
phrase
:- A phrase to find in the text. This may be a string, a list of strings, or a compiled regular expression. If a string, it’s regex-escaped and compiled. If a list, all of the strings will be highlighted. This is done by regex-escaping all elements and then joining them using the regex “|” token.
highlighter
:- Deprecated. A replacement expression for the regex substitution.
This was deprecated because it bypasses the HTML builder and creates
tags via string mangling. The previous default was ‘<strong
class=”highlight”>1</strong>’, which mimics the normal behavior of
this function.
phrase
must be a string ifhighlighter
is specified. Overridesclass_
andattrs_
arguments. case_sensitive
:- If false (default), the phrases are searched in a case-insensitive
manner. No effect if
phrase
is a regex object. class_
:- CSS class for the <strong> tag.
**attrs
:- Additional HTML attributes for the <strong> tag.
Changed in WebHelpers 1.0b2: new implementation using HTML builder. Allow
phrase
to be list or regex. Deprecatehighlighter
and change its default value to None. Addcase_sensitive
,class_
, and**attrs
arguments.
-
webhelpers.html.tools.
mail_to
(email_address, name=None, cc=None, bcc=None, subject=None, body=None, replace_at=None, replace_dot=None, encode=None, **html_attrs)¶ Create a link tag for starting an email to the specified
email_address
.This
email_address
is also used as the name of the link unlessname
is specified. Additional HTML options, such as class or id, can be passed in thehtml_attrs
hash.You can also make it difficult for spiders to harvest email address by obfuscating them.
Examples:
>>> mail_to("me@domain.com", "My email", encode = "javascript") literal(u'<script type="text/javascript">\n//<![CDATA[\neval(unescape(\'%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%4d%79%20%65%6d%61%69%6c%3c%2f%61%3e%27%29%3b\'))\n//]]>\n</script>') >>> mail_to("me@domain.com", "My email", encode = "hex") literal(u'<a href="mailto:%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d">My email</a>')
You can also specify the cc address, bcc address, subject, and body parts of the message header to create a complex e-mail using the corresponding
cc
,bcc
,subject
, andbody
keyword arguments. Each of these options are URI escaped and then appended to theemail_address
before being output. Be aware that javascript keywords will not be escaped and may break this feature when encoding with javascript.Examples:
>>> mail_to("me@domain.com", "My email", cc="ccaddress@domain.com", bcc="bccaddress@domain.com", subject="This is an example email", body= "This is the body of the message.") literal(u'<a href="mailto:me@domain.com?cc=ccaddress%40domain.com&bcc=bccaddress%40domain.com&subject=This%20is%20an%20example%20email&body=This%20is%20the%20body%20of%20the%20message.">My email</a>')
-
webhelpers.html.tools.
strip_links
(text)¶ Strip link tags from
text
leaving just the link label.Example:
>>> strip_links('<a href="something">else</a>') 'else'
Delete any HTML tags in the text, leaving their contents intact. Convert newlines to spaces, and <br /> to newlines.
- Example::
>>> strip_tags('Text <em>emphasis</em> <script>Javascript</script>.') 'Text emphasis Javascript.' >>> strip_tags('Ordinary <!-- COMMENT! --> text.') 'Ordinary COMMENT! text.' >>> strip_tags('Line\n1<br />Line 2') 'Line 1\nLine 2'
Implementation copied from
WebOb
.webhelpers.html.converters
contains more sophisticated versions of this.
webhelpers.media
¶
Multimedia helpers for images, etc.
-
webhelpers.media.
choose_height
(new_width, width, height)¶ Return the height corresponding to
new_width
that’s proportional to the original size (width
xheight
).
-
webhelpers.media.
get_dimensions_pil
(path, default=(None, None))¶ Get an image’s size using the Python Imaging Library (PIL).
path
is the path of the image file.default
is returned if the size could not be ascertained. This usually means the file does not exist or is not in a format recognized by PIL.The normal return value is a tuple:
(width, height)
.Depends on the Python Imaging Library. If your application is not otherwise using PIL, see the
get_dimensions()
function, which does not have external dependencies.
-
webhelpers.media.
get_dimensions
(path, default=(None, None))¶ Get an image’s size using only the Python standard library.
path
is the path of the image file.default
is returned if the size could not be ascertained. This usually means the file does not exist or is not in a recognized format. PIL. Only JPG, PNG, GIF, and BMP are supported at this time.The normal return value is a tuple:
(width, height)
.The algorithms are based on a PyCode recipe by Perenzo/Welch/Ray.
This helper recognizes fewer image formats and is potentially less accurate than
get_dimensions_pil()
.Running this module as a script tests this helper. It will print the size of each image file specified on the command line.
webhelpers.mimehelper
¶
MIME Type helpers
This helper depends on the WebOb package, and has optional Pylons support.
-
class
webhelpers.mimehelper.
MIMETypes
(environ)¶ MIMETypes registration mapping
The MIMETypes object class provides a single point to hold onto all the registered mimetypes, and their association extensions. It’s used by the mimetypes method to determine the appropriate content type to return to a client.
-
classmethod
add_alias
(alias, mimetype)¶ Create a MIMEType alias to a full mimetype.
Examples:
add_alias('html', 'text/html')
add_alias('xml', 'application/xml')
An
alias
may not contain the/
character.
-
aliases
= {}¶
-
classmethod
init
()¶ Loads a default mapping of extensions and mimetypes
These are suitable for most web applications by default. Additional types can be added by using the mimetypes module.
-
mimetype
(content_type)¶ Check the PATH_INFO of the current request and client’s HTTP Accept to attempt to use the appropriate mime-type.
If a content-type is matched, return the appropriate response content type, and if running under Pylons, set the response content type directly. If a content-type is not matched, return
False
.This works best with URLs that end in extensions that differentiate content-type. Examples:
http://example.com/example
,http://example.com/example.xml
,http://example.com/example.csv
Since browsers generally allow for any content-type, but should be sent HTML when possible, the html mimetype check should always come first, as shown in the example below.
Example:
# some code likely in environment.py MIMETypes.init() MIMETypes.add_alias('html', 'text/html') MIMETypes.add_alias('xml', 'application/xml') MIMETypes.add_alias('csv', 'text/csv') # code in a Pylons controller def someaction(self): # prepare a bunch of data # ...... # prepare MIMETypes object m = MIMETypes(request.environ) if m.mimetype('html'): return render('/some/template.html') elif m.mimetype('atom'): return render('/some/xml_template.xml') elif m.mimetype('csv'): # write the data to a csv file return csvfile else: abort(404) # Code in a non-Pylons controller. m = MIMETypes(environ) response_type = m.mimetype('html') # ``response_type`` is a MIME type or ``False``.
-
classmethod
webhelpers.misc
¶
Helpers that are neither text, numeric, container, or date.
Data processing¶
-
webhelpers.misc.
all
(seq[, pred])¶ Is
pred(elm)
true for all elements?With the default predicate, this is the same as Python 2.5’s
all()
function; i.e., it returns true if all elements are true.>>> all(["A", "B"]) True >>> all(["A", ""]) False >>> all(["", ""]) False >>> all(["A", "B", "C"], lambda x: x <= "C") True >>> all(["A", "B", "C"], lambda x: x < "C") False
From recipe in itertools docs.
-
webhelpers.misc.
any
(seq[, pred])¶ Is
pred(elm)
is true for any element?With the default predicate, this is the same as Python 2.5’s
any()
function; i.e., it returns true if any element is true.>>> any(["A", "B"]) True >>> any(["A", ""]) True >>> any(["", ""]) False >>> any(["A", "B", "C"], lambda x: x <= "C") True >>> any(["A", "B", "C"], lambda x: x < "C") True
From recipe in itertools docs.
-
webhelpers.misc.
no
(seq[, pred])¶ Is
pred(elm)
false for all elements?With the default predicate, this returns true if all elements are false.
>>> no(["A", "B"]) False >>> no(["A", ""]) False >>> no(["", ""]) True >>> no(["A", "B", "C"], lambda x: x <= "C") False >>> no(["X", "Y", "Z"], lambda x: x <="C") True
From recipe in itertools docs.
-
webhelpers.misc.
count_true
(seq[, pred])¶ How many elements is
pred(elm)
true for?With the default predicate, this counts the number of true elements.
>>> count_true([1, 2, 0, "A", ""]) 3 >>> count_true([1, "A", 2], lambda x: isinstance(x, int)) 2
This is equivalent to the
itertools.quantify
recipe, which I couldn’t get to work.
-
webhelpers.misc.
convert_or_none
(value, type_)¶ Return the value converted to the type, or None if error.
type_
may be a Python type or any function taking one argument.>>> print convert_or_none("5", int) 5 >>> print convert_or_none("A", int) None
-
webhelpers.misc.
flatten
(iterable)¶ Recursively iterate lists and tuples.
Examples:
>>> list(flatten([1, [2, 3], 4])) [1, 2, 3, 4] >>> list(flatten([1, (2, 3, [4]), 5])) [1, 2, 3, 4, 5]
Exceptions and deprecation¶
-
webhelpers.misc.
deprecate
(message, pending=False, stacklevel=2)¶ Issue a deprecation warning.
message
: the deprecation message.pending
: if true, usePendingDeprecationWarning
. If false (default), useDeprecationWarning
. Python displays deprecations and ignores pending deprecations by default.stacklevel
: passed towarnings.warn
. The default level 2 makes the traceback end at the caller’s level. Higher numbers make it end at higher levels.
-
webhelpers.misc.
format_exception
(exc=None)¶ Format the exception type and value for display, without the traceback.
This is the function you always wished were in the
traceback
module but isn’t. It’s different fromtraceback.format_exception
, which includes the traceback, returns a list of lines, and has a trailing newline.If you don’t provide an exception object as an argument, it will call
sys.exc_info()
to get the current exception.
-
class
webhelpers.misc.
DeclarativeException
(message=None)¶ A simpler way to define an exception with a fixed message.
Subclasses have a class attribute
.message
, which is used if no message is passed to the constructor. The default message is the empty string.Example:
>>> class MyException(DeclarativeException): ... message="can't frob the bar when foo is enabled" ... >>> try: ... raise MyException() ... except Exception, e: ... print e ... can't frob the bar when foo is enabled
-
message
= ''¶
-
-
class
webhelpers.misc.
OverwriteError
(filename, message="not overwriting '%s'")¶ Refusing to overwrite an existing file or directory.
webhelpers.number
¶
Number formatting, numeric helpers, and numeric statistics.
Calculations¶
-
webhelpers.number.
percent_of
(part, whole)¶ What percent of
whole
ispart
?>>> percent_of(5, 100) 5.0 >>> percent_of(13, 26) 50.0
Statistics¶
-
webhelpers.number.
mean
(r)¶ Return the mean (i.e., average) of a sequence of numbers.
>>> mean([5, 10]) 7.5
-
webhelpers.number.
average
(r)¶ Another name for
mean(r)
.
-
webhelpers.number.
median
(r)¶ Return the median of an iterable of numbers.
The median is the point at which half the numbers are lower than it and half the numbers are higher. This gives a better sense of the majority level than the mean (average) does, because the mean can be skewed by a few extreme numbers at either end. For instance, say you want to calculate the typical household income in a community and you’ve sampled four households:
>>> incomes = [18000] # Fast food crew >>> incomes.append(24000) # Janitor >>> incomes.append(32000) # Journeyman >>> incomes.append(44000) # Experienced journeyman >>> incomes.append(67000) # Manager >>> incomes.append(9999999) # Bill Gates >>> median(incomes) 49500.0 >>> mean(incomes) 1697499.8333333333
The median here is somewhat close to the majority of incomes, while the mean is far from anybody’s income.
This implementation makes a temporary list of all numbers in memory.
-
webhelpers.number.
standard_deviation
(r, sample=True)¶ Standard deviation.
From the Python Cookbook. Population mode contributed by Lorenzo Catucci.
Standard deviation shows the variability within a sequence of numbers. A small standard deviation means the numbers are close to each other. A large standard deviation shows they are widely different. In fact it shows how far the numbers tend to deviate from the average. This can be used to detect whether the average has been skewed by a few extremely high or extremely low values.
Most natural and random phenomena follow the normal distribution (aka the bell curve), which says that most values are close to average but a few are extreme. E.g., most people are close to 5‘9” tall but a few are very tall or very short. If the data does follow the bell curve, 68% of the values will be within 1 standard deviation (stdev) of the average, and 95% will be within 2 standard deviations. So a university professor grading exams on a curve might give a “C” (mediocre) grade to students within 1 stdev of the average score, “B” (better than average) to those within 2 stdevs above, and “A” (perfect) to the 0.25% higher than 2 stdevs. Those between 1 and 2 stdevs below get a “D” (poor), and those below 2 stdevs... we won’t talk about them.
By default the helper computes the unbiased estimate for the population standard deviation, by applying an unbiasing factor of sqrt(N/(N-1)).
If you’d rather have the function compute the population standard deviation, pass
sample=False
.The following examples are taken from Wikipedia. http://en.wikipedia.org/wiki/Standard_deviation
>>> standard_deviation([0, 0, 14, 14]) 8.082903768654761... >>> standard_deviation([0, 6, 8, 14]) 5.773502691896258... >>> standard_deviation([6, 6, 8, 8]) 1.1547005383792515 >>> standard_deviation([0, 0, 14, 14], sample=False) 7.0 >>> standard_deviation([0, 6, 8, 14], sample=False) 5.0 >>> standard_deviation([6, 6, 8, 8], sample=False) 1.0
(The results reported in Wikipedia are those expected for whole population statistics and therefore are equal to the ones we get by setting
sample=False
in the later tests.)# Fictitious average monthly temperatures in Southern California. # Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec >>> standard_deviation([70, 70, 70, 75, 80, 85, 90, 95, 90, 80, 75, 70]) 9.003366373785... >>> standard_deviation([70, 70, 70, 75, 80, 85, 90, 95, 90, 80, 75, 70], sample=False) 8.620067027323... # Fictitious average monthly temperatures in Montana. # Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec >>> standard_deviation([-32, -10, 20, 30, 60, 90, 100, 80, 60, 30, 10, -32]) 45.1378360405574... >>> standard_deviation([-32, -10, 20, 30, 60, 90, 100, 80, 60, 30, 10, -32], sample=False) 43.2161878106906...
-
webhelpers.number.
format_number
(n, thousands=', ', decimal='.')¶ Format a number with a thousands separator and decimal delimiter.
n
may be an int, long, float, or numeric string.thousands
is a separator to put after each thousand.decimal
is the delimiter to put before the fractional portion if any.The default style has a thousands comma and decimal point per American usage:
>>> format_number(1234567.89) '1,234,567.89' >>> format_number(123456) '123,456' >>> format_number(-123) '-123'
Various European and international styles are also possible:
>>> format_number(1234567.89, " ") '1 234 567.89' >>> format_number(1234567.89, " ", ",") '1 234 567,89' >>> format_number(1234567.89, ".", ",") '1.234.567,89'
-
class
webhelpers.number.
SimpleStats
(numeric=False)¶ Calculate a few simple statistics on data.
This class calculates the minimum, maximum, and count of all the values given to it. The values are not saved in the object. Usage:
>>> stats = SimpleStats() >>> stats(2) # Add one data value. >>> stats.extend([6, 4]) # Add several data values at once.
The statistics are available as instance attributes:
>>> stats.count 3 >>> stats.min 2 >>> stats.max 6
Non-numeric data is also allowed:
>>> stats2 = SimpleStats() >>> stats2("foo") >>> stats2("bar") >>> stats2.count 2 >>> stats2.min 'bar' >>> stats2.max 'foo'
.min
and.max
areNone
until the first data value is registered.Subclasses can override
._init_stats
and._update_stats
to add additional statistics.The constructor accepts one optional argument,
numeric
. If true, the instance accepts only values that areint
,long
, orfloat
. The default is false, which accepts any value. This is meant for instances or subclasses that don’t want non-numeric values.-
__call__
(value)¶ Add a data value.
-
extend
(values)¶ Add several data values at once, akin to
list.extend
.
-
-
class
webhelpers.number.
Stats
¶ A container for data and statistics.
This class extends
SimpleStats
by calculating additional statistics, and by storing all data seen. All values must be numeric (int
,long
, and/orfloat
), and you must call.finish()
to generate the additional statistics. That’s because the statistics here cannot be calculated incrementally, but only after all data is known.>>> stats = Stats() >>> stats.extend([5, 10, 10]) >>> stats.count 3 >>> stats.finish() >>> stats.mean 8.33333333333333... >>> stats.median 10 >>> stats.standard_deviation 2.8867513459481287
All data is stored in a list and a set for later use:
>>> stats.list [5, 10, 10] >> stats.set set([5, 10])
(The double prompt “>>” is used to hide the example from doctest.)
The stat attributes are
None
until you call.finish()
. It’s permissible – though not recommended – to add data after calling.finish()
and then call.finish()
again. This recalculates the stats over the entire data set.In addition to the hook methods provided by
SimpleStats
, subclasses can override._finish-stats
to provide additional statistics.-
__call__
(value)¶ Add a data value.
-
extend
(values)¶ Add several data values at once, akin to
list.extend
.
-
finish
()¶ Finish calculations. (Call after adding all data values.)
Call this after adding all data values, or the results will be incomplete.
-
Number formatting¶
-
webhelpers.number.
format_data_size
(size, unit, precision=1, binary=False, full_name=False)¶ Format a number using SI units (kilo, mega, etc.).
size
: The number as a float or int.unit
: The unit name in plural form. Examples: “bytes”, “B”.precision
: How many digits to the right of the decimal point. Default is 1. 0 suppresses the decimal point.binary
: If false, use base-10 decimal prefixes (kilo = K = 1000). If true, use base-2 binary prefixes (kibi = Ki = 1024).full_name
: If false (default), use the prefix abbreviation (“k” or “Ki”). If true, use the full prefix (“kilo” or “kibi”). If false, use abbreviation (“k” or “Ki”).Examples:
>>> format_data_size(1024, "B") '1.0 kB' >>> format_data_size(1024, "B", 2) '1.02 kB' >>> format_data_size(1024, "B", 2, binary=True) '1.00 KiB' >>> format_data_size(54000, "Wh", 0) '54 kWh' >>> format_data_size(85000, "m/h", 0) '85 km/h' >>> format_data_size(85000, "m/h", 0).replace("km/h", "klicks") '85 klicks'
-
webhelpers.number.
format_byte_size
(size, precision=1, binary=False, full_name=False)¶ Same as
format_data_size
but specifically for bytes.Examples:
>>> format_byte_size(2048) '2.0 kB' >>> format_byte_size(2048, full_name=True) '2.0 kilobytes'
-
webhelpers.number.
format_bit_size
(size, precision=1, binary=False, full_name=False)¶ Same as
format_data_size
but specifically for bits.Examples:
>>> format_bit_size(2048) '2.0 kb' >>> format_bit_size(2048, full_name=True) '2.0 kilobits'
webhelpers.paginate
¶
paginate: a module to help split up lists or results from ORM queries¶
What is pagination?¶
This module helps dividing large lists of items into pages. The user is shown one page at a time and can navigate to other pages. Imagine you are offering a company phonebook and let the user search the entries. If the search result contains 23 entries but you may want to display no more than 10 entries at once. The first page contains entries 1-10, the second 11-20 and the third 21-23. See the documentation of the “Page” class for more information.
How do I use it?¶
One page of items is represented by the Page object. A Page gets initialized with at least two arguments and usually three:
- The collection of items to pick a range from.
- The page number we want to display. (Default is 1: the first page.)
- A URL generator callback. (This tells what the URLs to other pages are.
It’s required if using the
pager()
method, although it may be omitted under Pylons for backward compatibility. It is required for Pyramid.)
Here’s an interactive example.
First we’ll create a URL generator using the basic PageURL
class, which
works with all frameworks and has no dependencies. It creates URLs by
overriding the ‘page’ query parameter.
# Instantiate the URL generator, and call it to see what it does.
>>> url_for_page = PageURL("/articles/2013", {"page": "3"})
>>> url_for_page(page=2)
'/articles/2013?page=2'
Now we can create a collection and instantiate the Page:
# Create a sample collection of 1000 items
>>> my_collection = range(1000)
# Create a Page object for the 3rd page (20 items per page is the default)
>>> my_page = Page(my_collection, page=3, url=url_for_page)
# The page object can be printed directly to get its details
>>> my_page
Page:
Collection type: <type 'list'>
(Current) page: 3
First item: 41
Last item: 60
First page: 1
Last page: 50
Previous page: 2
Next page: 4
Items per page: 20
Number of items: 1000
Number of pages: 50
<BLANKLINE>
# Print a list of items on the current page
>>> my_page.items
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59]
# The *Page* object can be used as an iterator:
>>> for my_item in my_page: print my_item,
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
# The .pager() method returns an HTML fragment with links to surrounding
# pages.
# [The ">>" prompt is to hide untestable examples from doctest.]
>> my_page.pager()
1 2 [3] 4 5 .. 50 (this is actually HTML)
# The pager can be customized:
>> my_page.pager('$link_previous ~3~ $link_next (Page $page of $page_count)')
1 2 [3] 4 5 6 .. 50 > (Page 3 of 50)
There are many parameters that customize the Page’s behavor. See the
documentation on Page
and Page.pager()
.
URL generator¶
The constructor’s url
argument is a callback that returns URLs to other
pages. It’s required when using the Page.pager()
method except under
Pylons, where it will fall back to pylons.url.current
(Pylons 1) and then
routes.url_for
(Pylons 0.9.7). If none of these are available, you’ll get
an exception “NotImplementedError: no URL generator available”.
WebHelpers 1.3 introduces a few URL generators for convenience. PageURL is
described above. PageURL_WebOb takes a webobb.Request
object, and is
suitable for Pyramid, Pylons, TurboGears, and other frameworks that have a
WebOb-compatible Request object. Both of these classes assume that the page
number is in the ‘page’ query parameter.
Here’s an example for Pyramid and other WebOb-compatible frameworks:
# Assume ``request`` is the current request.
import webhelpers.paginate as paginate
current_page = int(request.params["page"])
q = SOME_SQLALCHEMY_QUERY
page_url = paginate.PageURL_WebOb(request)
records = paginate.Page(q, current_page, url=page_url)
If the page number is in the URL path, you’ll have to use a framework-specific URL generator. For instance, in Pyramid if the current route is “/articles/{id}/page/{page}” and the current URL is “/articles/ABC/page/3?print=1”, you can use Pyramid’s “current_route_url” function as follows:
# Assume ``request`` is the current request.
import webhelpers.paginate as paginate
from pyramid.url import current_route_url
def page_url(page):
return current_route_url(request, page=page, _query=request.GET)
q = SOME_SQLALCHEMY_QUERY
current_page = int(request.matchdict["page"])
records = Page(q, current_page, url=page_url)
This overrides the ‘page’ path variable, while leaving the ‘id’ variable and the query string intact.
The callback API is simple.
- It must accept an integer argument ‘page’, which will be passed by name.
- It should return the URL for that page.
- If you’re using AJAX ‘partial’ functionality described in the
Page.pager
docstring, the callback should also accept a ‘partial’ argument and, if true, set a query parameter ‘partial=1’. - If you use the ‘page_param’ or ‘partial_param’ argument to
Page.pager
, the ‘page’ and ‘partial’ arguments will be renamed to whatever you specify. In this case, the callback would also have to expect these other argument names.
The supplied classes adhere to this API in their
.__call__
method, all except the fourth condition. So you can use their
instances as callbacks as long as you don’t use ‘page_param’ or ‘partial_param’.
For convenience in writing callbacks that update the ‘page’ query parameter, a
make_page_url
function is available that assembles the pieces into a
complete URL. Other callbacks may find webhelpers.utl.update_params
useful,
which overrides query parameters on a more general basis.
Can I use AJAX / AJAH?¶
Yes. See partial_param and onclick in Page.pager()
.
Notes¶
Page numbers and item numbers start at 1. This concept has been used because users expect that the first page has number 1 and the first item on a page also has number 1. So if you want to use the page’s items by their index number please note that you have to subtract 1.
This module is the successor to the obsolete webhelpers.pagination
module. It is NOT API compatible.
This module is based on the code from http://workaround.org/cgi-bin/hg-paginate that is known at the “Paginate” module on PyPI. It was written by Christoph Haas <email@christoph-haas.de>, and modified by Christoph Haas and Mike Orr for WebHelpers. (c) 2007-2011.
Page Objects¶
-
class
webhelpers.paginate.
Page
(collection, page=1, items_per_page=20, item_count=None, sqlalchemy_session=None, presliced_list=False, url=None, **kwargs)¶ A list/iterator of items representing one page in a larger collection.
An instance of the “Page” class is created from a collection of things. The instance works as an iterator running from the first item to the last item on the given page. The collection can be:
- a sequence
- an SQLAlchemy query - e.g.: Session.query(MyModel)
- an SQLAlchemy select - e.g.: sqlalchemy.select([my_table])
A “Page” instance maintains pagination logic associated with each page, where it begins, what the first/last item on the page is, etc. The pager() method creates a link list allowing the user to go to other pages.
WARNING: Unless you pass in an item_count, a count will be performed on the collection every time a Page instance is created. If using an ORM, it’s advised to pass in the number of items in the collection if that number is known.
Instance attributes:
- original_collection
- Points to the collection object being paged through
- item_count
- Number of items in the collection
- page
- Number of the current page
- items_per_page
- Maximal number of items displayed on a page
- first_page
- Number of the first page - starts with 1
- last_page
- Number of the last page
- page_count
- Number of pages
- items
- Sequence/iterator of items on the current page
- first_item
- Index of first item on the current page - starts with 1
- last_item
- Index of last item on the current page
-
pager
(format='~2~', page_param='page', partial_param='partial', show_if_single_page=False, separator=' ', onclick=None, symbol_first='<<', symbol_last='>>', symbol_previous='<', symbol_next='>', link_attr={'class': 'pager_link'}, curpage_attr={'class': 'pager_curpage'}, dotdot_attr={'class': 'pager_dotdot'}, **kwargs)¶ Return string with links to other pages (e.g. “1 2 [3] 4 5 6 7”).
- format:
Format string that defines how the pager is rendered. The string can contain the following $-tokens that are substituted by the string.Template module:
- $first_page: number of first reachable page
- $last_page: number of last reachable page
- $page: number of currently selected page
- $page_count: number of reachable pages
- $items_per_page: maximal number of items per page
- $first_item: index of first item on the current page
- $last_item: index of last item on the current page
- $item_count: total number of items
- $link_first: link to first page (unless this is first page)
- $link_last: link to last page (unless this is last page)
- $link_previous: link to previous page (unless this is first page)
- $link_next: link to next page (unless this is last page)
To render a range of pages the token ‘~3~’ can be used. The number sets the radius of pages around the current page. Example for a range with radius 3:
‘1 .. 5 6 7 [8] 9 10 11 .. 500’
Default: ‘~2~’
- symbol_first
String to be displayed as the text for the %(link_first)s link above.
Default: ‘<<’
- symbol_last
String to be displayed as the text for the %(link_last)s link above.
Default: ‘>>’
- symbol_previous
String to be displayed as the text for the %(link_previous)s link above.
Default: ‘<’
- symbol_next
String to be displayed as the text for the %(link_next)s link above.
Default: ‘>’
- separator:
String that is used to separate page links/numbers in the above range of pages.
Default: ‘ ‘
- page_param:
The name of the parameter that will carry the number of the page the user just clicked on. The parameter will be passed to a url_for() call so if you stay with the default ‘:controller/:action/:id’ routing and set page_param=’id’ then the :id part of the URL will be changed. If you set page_param=’page’ then url_for() will make it an extra parameters like ‘:controller/:action/:id?page=1’. You need the page_param in your action to determine the page number the user wants to see. If you do not specify anything else the default will be a parameter called ‘page’.
Note: If you set this argument and are using a URL generator callback, the callback must accept this name as an argument instead of ‘page’. callback, becaust the callback requires its argument to be ‘page’. Instead the callback itself can return any URL necessary.
- partial_param:
When using AJAX/AJAH to do partial updates of the page area the application has to know whether a partial update (only the area to be replaced) or a full update (reloading the whole page) is required. So this parameter is the name of the URL parameter that gets set to 1 if the ‘onclick’ parameter is used. So if the user requests a new page through a Javascript action (onclick) then this parameter gets set and the application is supposed to return a partial content. And without Javascript this parameter is not set. The application thus has to check for the existence of this parameter to determine whether only a partial or a full page needs to be returned. See also the examples in this modules docstring.
Default: ‘partial’
Note: If you set this argument and are using a URL generator callback, the callback must accept this name as an argument instead of ‘partial’.
- show_if_single_page:
if True the navigator will be shown even if there is only one page
Default: False
- link_attr (optional)
A dictionary of attributes that get added to A-HREF links pointing to other pages. Can be used to define a CSS style or class to customize the look of links.
Example: { ‘style’:’border: 1px solid green’ }
Default: { ‘class’:’pager_link’ }
- curpage_attr (optional)
A dictionary of attributes that get added to the current page number in the pager (which is obviously not a link). If this dictionary is not empty then the elements will be wrapped in a SPAN tag with the given attributes.
Example: { ‘style’:’border: 3px solid blue’ }
Default: { ‘class’:’pager_curpage’ }
- dotdot_attr (optional)
A dictionary of attributes that get added to the ‘..’ string in the pager (which is obviously not a link). If this dictionary is not empty then the elements will be wrapped in a SPAN tag with the given attributes.
Example: { ‘style’:’color: #808080’ }
Default: { ‘class’:’pager_dotdot’ }
- onclick (optional)
This paramter is a string containing optional Javascript code that will be used as the ‘onclick’ action of each pager link. It can be used to enhance your pager with AJAX actions loading another page into a DOM object.
In this string the variable ‘$partial_url’ will be replaced by the URL linking to the desired page with an added ‘partial=1’ parameter (or whatever you set ‘partial_param’ to). In addition the ‘$page’ variable gets replaced by the respective page number.
Note that the URL to the destination page contains a ‘partial_param’ parameter so that you can distinguish between AJAX requests (just refreshing the paginated area of your page) and full requests (loading the whole new page).
[Backward compatibility: you can use ‘%s’ instead of ‘$partial_url’]
- jQuery example:
- “$(‘#my-page-area’).load(‘$partial_url’); return false;”
- Yahoo UI example:
- “YAHOO.util.Connect.asyncRequest(‘GET’,’$partial_url’,{
- success:function(o){YAHOO.util.Dom.get(‘#my-page-area’).innerHTML=o.responseText;} },null); return false;”
- scriptaculous example:
- “new Ajax.Updater(‘#my-page-area’, ‘$partial_url’,
- {asynchronous:true, evalScripts:true}); return false;”
- ExtJS example:
- “Ext.get(‘#my-page-area’).load({url:’$partial_url’}); return false;”
- Custom example:
- “my_load_page($page)”
Additional keyword arguments are used as arguments in the links. Otherwise the link will be created with url_for() which points to the page you are currently displaying.
URL generators¶
-
class
webhelpers.paginate.
PageURL
(path, params)¶ A simple page URL generator for any framework.
-
__call__
(page, partial=False)¶ Generate a URL for the specified page.
-
-
class
webhelpers.paginate.
PageURL_WebOb
(request, qualified=False)¶ A page URL generator for WebOb-compatible Request objects.
I derive new URLs based on the current URL but overriding the ‘page’ query parameter.
I’m suitable for Pyramid, Pylons, and TurboGears, as well as any other framework whose Request object has ‘application_url’, ‘path’, and ‘GET’ attributes that behave the same way as
webob.Request
‘s.-
__call__
(page, partial=False)¶ Generate a URL for the specified page.
-
-
webhelpers.paginate.
make_page_url
(path, params, page, partial=False, sort=True)¶ A helper function for URL generators.
I assemble a URL from its parts. I assume that a link to a certain page is done by overriding the ‘page’ query parameter.
path
is the current URL path, with or without a “scheme://host” prefix.params
is the current query parameters as a dict or dict-like object.page
is the target page number.If
partial
is true, set query param ‘partial=1’. This is to for AJAX calls requesting a partial page.If
sort
is true (default), the parameters will be sorted. Otherwise they’ll be in whatever order the dict iterates them.
webhelpers.text
¶
Functions that output text (not HTML).
Helpers for filtering, formatting, and transforming strings.
-
webhelpers.text.
chop_at
(s, sub, inclusive=False)¶ Truncate string
s
at the first occurrence ofsub
.If
inclusive
is true, truncate just aftersub
rather than at it.>>> chop_at("plutocratic brats", "rat") 'plutoc' >>> chop_at("plutocratic brats", "rat", True) 'plutocrat'
-
webhelpers.text.
collapse
(string, character=' ')¶ Removes specified character from the beginning and/or end of the string and then condenses runs of the character within the string.
Based on Ruby’s stringex package (http://github.com/rsl/stringex/tree/master)
-
webhelpers.text.
convert_accented_entities
(string)¶ Converts HTML entities into the respective non-accented letters.
Examples:
>>> convert_accented_entities("á") 'a' >>> convert_accented_entities("ç") 'c' >>> convert_accented_entities("è") 'e' >>> convert_accented_entities("î") 'i' >>> convert_accented_entities("ø") 'o' >>> convert_accented_entities("ü") 'u'
Note: This does not do any conversion of Unicode/ASCII accented-characters. For that functionality please use unidecode.
Based on Ruby’s stringex package (http://github.com/rsl/stringex/tree/master)
-
webhelpers.text.
convert_misc_entities
(string)¶ Converts HTML entities (taken from common Textile formattings) into plain text formats
Note: This isn’t an attempt at complete conversion of HTML entities, just those most likely to be generated by Textile.
Based on Ruby’s stringex package (http://github.com/rsl/stringex/tree/master)
-
webhelpers.text.
excerpt
(text, phrase, radius=100, excerpt_string='...')¶ Extract an excerpt from the
text
, or ‘’ if the phrase isn’t found.phrase
- Phrase to excerpt from
text
radius
- How many surrounding characters to include
excerpt_string
- Characters surrounding entire excerpt
Example:
>>> excerpt("hello my world", "my", 3) '...lo my wo...'
-
webhelpers.text.
lchop
(s, sub)¶ Chop
sub
off the front ofs
if present.>>> lchop("##This is a comment.##", "##") 'This is a comment.##'
The difference between
lchop
ands.lstrip
is thatlchop
strips only the exact prefix, whiles.lstrip
treats the argument as a set of leading characters to delete regardless of order.
-
webhelpers.text.
plural
(n, singular, plural, with_number=True)¶ Return the singular or plural form of a word, according to the number.
If
with_number
is true (default), the return value will be the number followed by the word. Otherwise the word alone will be returned.Usage:
>>> plural(2, "ox", "oxen") '2 oxen' >>> plural(2, "ox", "oxen", False) 'oxen'
-
webhelpers.text.
rchop
(s, sub)¶ Chop
sub
off the end ofs
if present.>>> rchop("##This is a comment.##", "##") '##This is a comment.'
The difference between
rchop
ands.rstrip
is thatrchop
strips only the exact suffix, whiles.rstrip
treats the argument as a set of trailing characters to delete regardless of order.
-
webhelpers.text.
remove_formatting
(string)¶ Simplify HTML text by removing tags and several kinds of formatting.
If the
unidecode
package is installed, it will also transliterate non-ASCII Unicode characters to their nearest pronunciation equivalent in ASCII.Based on Ruby’s stringex package (http://github.com/rsl/stringex/tree/master)
-
webhelpers.text.
replace_whitespace
(string, replace=' ')¶ Replace runs of whitespace in string
Defaults to a single space but any replacement string may be specified as an argument. Examples:
>>> replace_whitespace("Foo bar") 'Foo bar' >>> replace_whitespace("Foo bar", "-") 'Foo-bar'
Based on Ruby’s stringex package (http://github.com/rsl/stringex/tree/master)
-
webhelpers.text.
series
(items, conjunction='and', strict_commas=True)¶ Join strings using commas and a conjunction such as “and” or “or”.
Examples:
>>> series(["A", "B", "C"]) 'A, B, and C' >>> series(["A", "B", "C"], "or") 'A, B, or C' >>> series(["A", "B", "C"], strict_commas=False) 'A, B and C' >>> series(["A", "B"]) 'A and B' >>> series(["A"]) 'A' >>> series([]) ''
-
webhelpers.text.
strip_leading_whitespace
(s)¶ Strip the leading whitespace in all lines in
s
.This deletes all leading whitespace.
textwrap.dedent
deletes only the whitespace common to all lines.
-
webhelpers.text.
truncate
(text, length=30, indicator='...', whole_word=False)¶ Truncate
text
with replacement characters.length
- The maximum length of
text
before replacement indicator
- If
text
exceeds thelength
, this string will replace the end of the string whole_word
- If true, shorten the string further to avoid breaking a word in the middle. A word is defined as any string not containing whitespace. If the entire text before the break is a single word, it will have to be broken.
Example:
>>> truncate('Once upon a time in a world far far away', 14) 'Once upon a...'
-
webhelpers.text.
urlify
(string)¶ Create a URI-friendly representation of the string
Can be called manually in order to generate an URI-friendly version of any string.
If the
unidecode
package is installed, it will also transliterate non-ASCII Unicode characters to their nearest pronounciation equivalent in ASCII.- Examples::
>>> urlify("Mighty Mighty Bosstones") 'mighty-mighty-bosstones'
Based on Ruby’s stringex package (http://github.com/rsl/stringex/tree/master)
Changed in WebHelpers 1.2: urlecode the result in case it contains special characters like ”?”.
-
webhelpers.text.
wrap_paragraphs
(text, width=72)¶ Wrap all paragraphs in a text string to the specified width.
width
may be an int or atextwrap.TextWrapper
instance. The latter allows you to set other options besides the width, and is more efficient when wrapping many texts.
webhelpers.util
¶
Utility functions used by various web helpers.
This module contains support functions used by other helpers, and functions for URL manipulation. Most of these helpers predate the 0.6 reorganization; they would have been put in other subpackages if they have been created later.
-
webhelpers.util.
update_params
(_url, _debug=False, **params)¶ Update query parameters in a URL.
_url
is any URL, with or without a query string.\*\*params
are query parameters to add or replace. Each value may be a string, a list of strings, or None. Passing a list generates multiple values for the same parameter. Passing None deletes the corresponding parameter if present.Return the new URL.
Debug mode: if a pseudo-parameter
_debug=True
is passed, return a tuple:[0]
is the URL without query string or fragment,[1]
is the final query parameters as a dict, and[2]
is the fragment part of the original URL or the empty string.Usage:
>>> update_params("foo", new1="NEW1") 'foo?new1=NEW1' >>> update_params("foo?p=1", p="2") 'foo?p=2' >>> update_params("foo?p=1", p=None) 'foo' >>> update_params("http://example.com/foo?new1=OLD1#myfrag", new1="NEW1") 'http://example.com/foo?new1=NEW1#myfrag' >>> update_params("http://example.com/foo?new1=OLD1#myfrag", new1="NEW1", _debug=True) ('http://example.com/foo', {'new1': 'NEW1'}, 'myfrag') >>> update_params("http://www.mau.de?foo=2", brrr=3) 'http://www.mau.de?foo=2&brrr=3' >>> update_params("http://www.mau.de?foo=A&foo=B", foo=["C", "D"]) 'http://www.mau.de?foo=C&foo=D'
-
webhelpers.util.
cgi_escape
(s, quote=False)¶ Replace special characters ‘&’, ‘<’ and ‘>’ by SGML entities.
This is a slightly more efficient version of the cgi.escape by using ‘in’ membership to test if the replace is needed.
This function returns a plain string. Programs using the HTML builder should call
webhelpers.html.builder.escape()
instead of this to prevent double-escaping.Changed in WebHelpers 1.2: escape single-quote as well as double-quote.
-
webhelpers.util.
html_escape
(s)¶ HTML-escape a string or object.
This converts any non-string objects passed into it to strings (actually, using
unicode()
). All values returned are non-unicode strings (using&#num;
entities for all non-ASCII characters).None is treated specially, and returns the empty string.
This function returns a plain string. Programs using the HTML builder should wrap the result in
literal()
to prevent double-escaping.
-
webhelpers.util.
iri_to_uri
(iri)¶ Convert an IRI portion to a URI portion suitable for inclusion in a URL.
(An IRI is an Internationalized Resource Identifier.)
This is the algorithm from section 3.1 of RFC 3987. However, since we are assuming input is either UTF-8 or unicode already, we can simplify things a little from the full method.
Returns an ASCII string containing the encoded result.
-
class
webhelpers.util.
Partial
(*args, **kw)¶ A partial function object.
Equivalent to functools.partial, which was introduced in Python 2.5.
-
class
webhelpers.util.
SimplerXMLGenerator
(out=None, encoding='iso-8859-1')¶ A subclass of Python’s SAX XMLGenerator.
-
addQuickElement
(name, contents=None, attrs=None)¶ Add an element with no children.
-
-
class
webhelpers.util.
UnicodeMultiDict
(multi=None, encoding=None, errors='strict', decode_keys=False)¶ A MultiDict wrapper that decodes returned values to unicode on the fly.
Decoding is not applied to assigned values.
The key/value contents are assumed to be
str
/strs
orstr
/FieldStorages
(as is returned by thepaste.request.parse()
functions).Can optionally also decode keys when the
decode_keys
argument is True.FieldStorage
instances are cloned, and the clone’sfilename
variable is decoded. Itsname
variable is decoded whendecode_keys
is enabled.-
add
(key, value)¶ Add the key and value, not overwriting any previous value.
-
clear
()¶
-
copy
()¶
-
dict_of_lists
()¶ Return dict where each key is associated with a list of values.
-
getall
(key)¶ Return list of all values matching the key (may be an empty list).
-
getone
(key)¶ Return one value matching key. Raise KeyError if multiple matches.
-
has_key
(key)¶
-
items
()¶
-
iteritems
()¶
-
iterkeys
()¶
-
itervalues
()¶
-
keys
()¶
-
mixed
()¶ Return dict where values are single values or a list of values.
The value is a single value if key appears just once. It is a list of values when a key/value appears more than once in this dictionary. This is similar to the kind of dictionary often used to represent the variables in a web request.
-
pop
(key, *args)¶
-
popitem
()¶
-
setdefault
(key, default=None)¶
-
values
()¶
-
Pylons-specific subpackages¶
These work ONLY with the Pylons web framework and its derivatives (TurboGears 2). They are NOT compatible with Pyramid; see the submodule pages for alternatives.
webhelpers.pylonslib
¶
Helpers for the Pylons web framework
These helpers depend on Pylons’ request
, response
, session
objects or some other aspect of Pylons. Most of them can be easily ported to
another framework by changing the API calls.
webhelpers.pylonslib.flash
¶
Accumulate messages to show on the next page request.
The Flash
class is useful when you want to redirect to another page and also
show a status message on that page, such as “Changes saved” or
“No previous search found; returning to home page”.
THE IMPLEMENTATION DEPENDS ON PYLONS. However, it can easily be adapted for another web framework.
PYRAMID USERS: use the flash methods built into Pyramid’s Session
object.
This implementation is incompatible with Pyramid.
A typical Pylons application instantiates a Flash
object in
myapp/lib/helpers.py:
from webhelpers.pylonslib.flash import Flash as _Flash
flash = _Flash()
The helpers module is then imported into your controllers and
templates as h
. Whenever you want to set a message, call the instance:
h.flash("Record deleted.")
You can set additional messages too:
h.flash("Hope you didn't need it.")
Now make a place in your site template for the messages. In Mako you might do:
<% messages = h.flash.pop_messages() %>
% if messages:
<ul id="flash-messages">
% for message in messages:
<li>${message}</li>
% endfor
</ul>
% endif
You can style this to look however you want:
ul#flash-messages {
color: red;
background-color: #FFFFCC;
font-size: larger;
font-style: italic;
margin-left: 40px;
padding: 4px;
list-style: none;
}
Multiple flash objects¶
You can define multiple flash objects in your application to display different kinds of messages at different places on the page. For instance, you might use the main flash object for general messages, and a second flash object for “Added dookickey” / “Removed doohickey” messages next to a doohickey manager.
Message categories¶
WebHelpers 1.0 adds message categories, contributed by Wichert Akkerman.
These work like severity levels in Python’s logging system. The standard
categories are “warning”, “notice”, “error”, and “success”, with
the default being “notice”. The category is available in the message’s
.category
attribute, and is normally used to set the container’s CSS
class.
This is the only thing it does. Calling .pop_messages()
pops all messages
in the order registered, regardless of category. It is not possible to pop
only a certain category, or all levels above a certain level, or to group
messages by category. If you want to group different kinds of messages
together, or pop only certain categories while leaving other categories, you
should use multiple Flash
objects.
You can change the standard categories by overriding the .categories
and .default_category
class attributes, or by providing alternate
values using constructor keywords.
Category example¶
Let’s show a standard way of using flash messages in your site: we will demonstrate self-healing messages (similar to what Growl does on OSX) to show messages in a site.
To send a message from python just call the flash helper method:
h.flash(u"Settings have been saved")
This will tell the system to show a message in the rendered page. If you need more control you can specify a message category as well: one of warning, notice, error or success. The default category is notice. For example:
h.flash(u"Failed to send confirmation email", "warning")
We will use a very simple markup style: messages will be placed in a div
with id selfHealingFeedback
at the end of the document body. The messages
are standard paragraphs with a class indicating the message category. For
example:
<html>
<body>
<div id="content">
...
...
</div>
<div id="selfHealingFeedback">
<p class="success">Succesfully updated your settings</p>
<p class="warning">Failed to send confirmation email</p>
</div>
</body>
</html>
This can easily created from a template. If you are using Genshi this should work:
The needed CSS is very simple:
Choosing different colours for the categories is left as an exercise for the reader.
Next we create the javascript that will manage the needed behaviour (this implementation is based on jQuery):
function _SetupMessage(el) {
var remover = function () {
msg.animate({opacity: 0}, "slow")
.slideUp("slow", function() { msg.remove() }); };
msg.data("healtimer", setTimeout(remover, 10000))
.click(function() { clearTimeout(msg.data("healtimer")); remover(); });
}
function ShowMessage(message, category) {
if (!category)
category="notice";
var container = $("#selfHealingFeedback");
if (!container.length)
container=$("<div id='selfHealingFeedback'/>").appendTo("body");
var msg = $("<p/>").addClass(category).html(message);
SetupMessage(msg);
msg.appendTo(container);
}
$(document).ready(function() {
$("#selfHealingFeedback p").each(function() { SetupMessage($(this)); });
}
The SetupMessage
function configures the desired behaviour: a message
disappears after 10 seconds, or if you click on it. Removal is done using
a simple animation to avoid messages jumping around on the screen.
This function is called for all messages as soon as the document has fully
loaded. The ShowMessage
function works exactly like the flash
method
in python: you can call it with a message and optionally a category and it
will pop up a new message.
JSON integration¶
It is not unusual to perform a remote task using a JSON call and show a result message to the user. This can easily be done using a simple wrapper around the ShowMessage method:
function ShowJSONResponse(info) {
if (!info.message)
return;
ShowMessage(info.message, info.message_category);
}
You can use this direct as the success callback for the jQuery AJAX method:
$.ajax({type: "POST",
url: "http://your.domain/call/json",
dataType: "json",
success: ShowJSONResponse
});
if you need to perform extra work in your callback method you can call it yourself as well, for example:
<form action="http://your.domain/call/form">
<input type="hidden" name="json_url" value="http://your.domain/call/json">
<button>Submit</button>
</form>
<sript type="text/javascript">
$(document).ready(function() {
$("button").click(function() {
var button = $(this);
button.addClass("processing");
$.ajax({type: "POST",
url: this.form["json_url"].value,
dataType: "json",
success: function(data, status) {
button.removeClass("processing");
ShowJSONResponse(data);
},
error: function(request, status, error) {
button.removeClass("processing");
ShowMessage("JSON call failed", "error");
}
});
return false;
});
});
</script>
This sets up a simple form which can be submitted normally by non-javascript enabled browsers. If a user does have javascript an AJAX call will be made to the server and the result will be shown in a message. While the call is active the button will be marked with a processing class.
The server can return a message by including a message
field in its
response. Optionally a message_category
field can also be included
which will be used to determine the message category. For example:
@jsonify
def handler(self):
..
..
return dict(message=u"Settings successfully updated")
Classes¶
-
class
webhelpers.pylonslib.flash.
Flash
(session_key='flash', categories=None, default_category=None)¶ Accumulate a list of messages to show at the next page request.
-
__call__
(message, category=None, ignore_duplicate=False)¶ Add a message to the session.
message
is the message text.category
is the message’s category. If not specified, the default category will be used. RaiseValueError
if the category is not in the list of allowed categories.If
ignore_duplicate
is true, don’t add the message if another message with identical text has already been added. If the new message has a different category than the original message, change the original message to the new category.
-
pop_messages
()¶ Return all accumulated messages and delete them from the session.
The return value is a list of
Message
objects.
-
-
class
webhelpers.pylonslib.flash.
Message
(category, message)¶ A message returned by
Flash.pop_messages()
.Converting the message to a string returns the message text. Instances also have the following attributes:
message
: the message text.category
: the category specified when the message was created.
webhelpers.pylonslib.grid
¶
This module is DEPRECATED. Please use webhelpers.html.grid
in new
applications. Support for paged grids has been added to that module in a
framework-neutral way.
PYRAMID USERS: This implementation is incompatible with Pyramid. Use
webhelpers.html.grid
instead.
-
class
webhelpers.pylonslib.grid.
PylonsGrid
(request, *args, **kw)¶ Subclass of Grid that can handle header link generation for quick building of tables that support ordering of their contents, paginated results etc.
-
generate_header_link
(column_number, column, label_text)¶ This handles generation of link and then decides to call self.default_header_ordered_column_format or self.default_header_column_format based on if current column is the one that is used for sorting or not
-
-
class
webhelpers.pylonslib.grid.
PylonsObjectGrid
(request, *args, **kw)¶ This grid will work well with sqlalchemy row instances
webhelpers.pylonslib.minify
¶
Minification helpers.
This module provides enhanced versions of the javascript_link
and
stylesheet_link
helpers in webhelpers.html.tags
. These versions add
three additional arguments:
- minified: If true, reduce the file size by squeezing out whitespace and other characters insignificant to the Javascript or CSS syntax.
- combined: If true, concatenate the specified files into one file to reduce page load time.
- beaker_kwargs (dict): arguments to pass to
beaker_cache
.
Dependencies: Pylons
, Beaker
, jsmin
, and cssutils
(all
available in PyPI). If “jsmin” is not installed, the helper issues a warning
and passes Javascript through unchanged. (Changed in WebHelpers 1.1: removed
built-in “_jsmin” package due to licensing issues; details in
webhelpers/pylonslib/_jsmin.py .)
PYRAMID USERS: this implementation is incompatible with Pyramid. No Pyramid-compatible implementation is currently known.
Contributed by Pedro Algarvio and Domen Kozar <ufs@ufsoft.org>. URL: http://docs.fubar.si/minwebhelpers/
-
webhelpers.pylonslib.minify.
javascript_link
(*sources, **options)¶
-
webhelpers.pylonslib.minify.
stylesheet_link
(*sources, **options)¶
webhelpers.pylonslib.secure_form
¶
Secure Form Tag Helpers – For prevention of Cross-site request forgery (CSRF) attacks.
Generates form tags that include client-specific authorization tokens to be verified by the destined web app.
PYRAMID USERS: Use the csrf_token methods built into Pyramid’s Session
object. This implementation is incompatible with Pyramid.
Authorization tokens are stored in the client’s session. The web app can then verify the request’s submitted authorization token with the value in the client’s session.
This ensures the request came from the originating page. See http://en.wikipedia.org/wiki/Cross-site_request_forgery for more information.
Pylons provides an authenticate_form
decorator that does this verification
on the behalf of controllers.
These helpers depend on Pylons’ session
object. Most of them can be easily
ported to another framework by changing the API calls.
The helpers are implemented in such a way that it should be easy to create your own helpers if you are using helpers for AJAX calls.
authentication_token() returns the current authentication token, creating one and storing it in the session if it doesn’t already exist.
auth_token_hidden_field() creates a hidden field (wrapped in an invisible div; I don’t know if this is necessary, but the old WebHelpers had it like this) containing the authentication token.
secure_form() is form() plus auth_token_hidden_field().
-
webhelpers.pylonslib.secure_form.
authentication_token
()¶ Return the current authentication token, creating one if one doesn’t already exist.
-
webhelpers.pylonslib.secure_form.
secure_form
(url, method='POST', multipart=False, **attrs)¶ Start a form tag that points the action to an url. This form tag will also include the hidden field containing the auth token.
The url options should be given either as a string, or as a
url()
function. The method for the form defaults to POST.Options:
multipart
- If set to True, the enctype is set to “multipart/form-data”.
method
- The method to use when submitting the form, usually either “GET” or “POST”. If “PUT”, “DELETE”, or another verb is used, a hidden input with name _method is added to simulate the verb over POST.
Non-essential subpackages¶
webhelpers.markdown
¶
webhelpers.markdown
is a copy of Markdown 1.7, used as a fallback for
webhelpers.html.converters.markdown()
if the full Markdown package is not
installed. See the Markdown website for documentation on the Markdown
format and this module. Markdown is now at version 2.x and contains new
features and plugins which are too big to include in WebHelpers. There is also
an alternate implementation called Markdown2. Both are available on PyPI. See
the markdown()
documentation for how to use them with WebHelpers.
What’s New in WebHelpers¶
This is a high-level overview of recent changes. Incompatible changes are in boldface; these may require modifying your application. See Changelog for the full changelog.
Version 1.3¶
webhelpers.paginate: Add URL generator classes for new frameworks like Pyramid.
webhelpers.html.grid: Add ability to use URL generator classes for paged display.
webhelpers.pylonslib.grid: Deprecated. Use webhelpers.html.grid, which now supports paged display.
Version 1.2¶
webhelpers.html: The HTML builder now uses Armin Ronacher’s
“MarkupSafe” package, which Mako and Pylons have also switched to. MarkupSafe
has a C speedup for escaping, escapes single-quotes for greater security (to
close a potential XSS attack route), and adds new methods to literal
.
literal is now a subclass of markupsafe.Markup
;
escape is a wrapper for markupsafe.escape_silent
.
webhelpers.html.tags: The text()
helper has a “type” argument for new
HTML 5 input types.
webhelpers.html.tags: No longer adds an “id” attribute to hidden fields
generated by the ``form()`` helper, to prevent IDs from clashing if the page
contains multiple forms. To create a hidden field with an ID, call hidden()
directly.
webhelpers.util: update_params
now supports query parameters with
multiple values.
Version 1.1¶
webhelpers.pylonslib.minify: The Javascript minification code was removed due to a non-free license. The helper now minifies Javascript only if the “jsmin” package is installed. Otherwise it issues a warning and leaves the Javascript unchanged. CSS minification is not affected. Details are in webhelpers/pylonslib/_minify.py .
Version 1.0¶
WebHelpers 1.0 has a lot of new features compared to 0.6.4. Several modules deprecated in 0.6.4 were removed, but otherwise there are only a few API incompatibilities with the 0.6 series.
Deleted packages¶
The following deprecated packages were removed: rails, commands, hinclude,
htmlgen, pagination, and string24. Most of the functionality of the rails
helpers was replaced by new helpers in the date
, html
, misc
,
number
, and text
packages. Prototype and Scriptaculous are not
replaced; WebHelpers no longer ships with Javascript libraries. pagination
was replaced by paginate
. number_to_human_size()
is in the unfinished
directory in the source distribution; you can copy it to your application if
you need it. If you can’t switch to the replacement helpers,
stick with WebHelpers 0.6.4.
secure_form¶
webhelpers.html.secure_form was moved to webhelpers.pylonslib.secure_form because it depends on Pylons.
webhelpers.constants¶
uk_counties() now returns tuples rather than strings.
webhelpers.feedgenerator¶
webhelpers.feedgenerator
was upgraded to the Django original (December 2009
version), and the “Geo” classes were added for geographical (GIS) feeds.
Points are latitude/longitude by default, but there’s a flag if your data is
longitude first (as Django is). A Geometry
class was reverse engineered for
other geometries, but it’s untested. Add a “published” property for Atom
feeds.
webhelpers.html.builder¶
New method for producing CDATA sections. The basic tag builders have a _nl
flag to add a newline between content elements and after the tag for
readability.
webhelpers.html.converters¶
markdown()
adds an argument to choose a Markdown implementation.
The Markdown included in WebHelpers will remain at version 1.7, but Markdown
2.x is available on PyPI, and a separate implementation confusingly called
“Markdown2” is also available on PyPI.
webhelpers.html.render¶
New helpers to render HTML to text, and to sanitize user input by stripping HTML tags.
webhelpers.html.tags¶
New helpers to add CSS classes to a tag programmatically, to support option groups in <select> tags, and to generate <!doctype> and <?xml ?> declarations.
image()
can calculate the width and height of an image automatically, using
either the Python Imaging Library (PIL) or a pure Python algorithm in
webhelpers.media
.
form()
puts its hidden “_method” field in a <div> for
XHTML compliance, and the hidden()
helper has a magic ID attribute to match
the other helpers.
webhelpers.html.tools¶
Ported js_obfuscate()
from the old rails helpers.
highlight()
adds new arguments for flexibility, and
is reimplemented using the HTML builder. The ‘highlighter’ argument is
deprecated.
webhelpers.misc¶
New helpers to flatten nested lists and tuples, and to
gather all the subclasses of a specified class. There’s an exception
OverwriteError
, a DeclarativeException
class for making your own
exceptions with constant messages, and a deprecate
function.
webhelpers.number¶
format_data_size()
and its derivatives format_byte_size()
and
format_bit_size()
provide a convenient way to display numbers using SI
units (“1.2 kilobytes”, “1.2 kB”, “1.0 KiB”).
webhelpers.paginate¶
webhelpers.paginate
has a new algorithm for generating URLs for page links,
has some enhancements for Javascript, works with all versions of SQLAlchemy 0.4
and higher, and has a presliced list option.
On Pylons it will use pylons.url.current
as the URL generator, or fall back
to routes.url_for
if that is not available. You can also pass a callback
function to the constructor to implement a custom generator. If none of these
are available, you’ll get a NotImplementedError
. Previous versions of
WebHelpers (through 1.0b5) used routes.url_for
unconditionally, but that
function is deprecated and is not supported in Pylons 1.x.
webhelpers.pylonslib¶
webhelpers.pylonslib
is now a package. The Flash
class accepts severity
categories, which you can use to style more severe messages differently. The
session structure is different, so delete existing HTTP sessions when
upgrading.
webhelpers.text¶
webhelpers.text
adds a suite of helpers from Ruby’s stringex package to
convert strings to URL-friendly format, and to remove inconvenient accents from
characters, etc.
webhelpers.util¶
New helper to update the query parameters in a URL.
Experimental code¶
webhelpers.html.grid
and webhelpers.pylonslib.grid
contain helpers to
make an HTML table from a list of objects such as database records. It has
a demo program and an optional stylesheet. It’s “experimental” because the
docs aren’t very clear and the API could maybe do with some changes. But it works.
webhelpers.pylonslib.minify
contains versions of javascript_link()
and
stylesheet_link()
that compress their files. It’s experimental because
their tests fail, so they probably don’t work.
Other experiments are in the “unfinished” directory in the source distribution.
Full Changelog¶
1.3 (2011-03-24)¶
- webhelpers.paginate:
- Revert Sprox patch (#59) from 1.3b1; it makes SQLAlchemy inefficient (#63). The bug reporter’s Sprox object seems to be unsliceable and therefore incompatible with paginate. Changed error message to say this if the slicing operation raises “TypeError: unhashable type”.
1.3b1 (2011-03-17)¶
Documentation:
- Some
webhelpers.misc
helpers were undocumented. - Spelling corrections throughout, done by Marius Gedminas.
- Some
webhelpers.date:
- Adjust test in ‘test_date.py’ to account for leap years. (#61, reported by Andrey Rahmatullin / wrar)
webhelpers.html.grid, webhelpers.pylonslib.grid:
- Add ‘request’ and ‘url’ args to support paged display. (webhelpers.html.grid only)
- Deprecate webhelpers.pylonslib.grid. It may be removed in a future version.
webhelpers.paginate:
- Add URL generator classes for new frameworks like Pyramid.
- In the Pylons backward compatibility code, support page parameter in the route path (e.g., “/help/page5”) when using Routes explicit mode without a URL generator.
setup.py:
- Fix typo in test requirements. (#60, Andrey Rahmatullin/wrar)
1.2 (2010-08-18)¶
- WebHelpers now depends on MarkupSafe.
literal
andescape
now use it. - webhelpers.html.builder:
literal
andescape
now use MarkupSafe, which has a C speedup for escaping, escapes single-quotes for security, and adds new methods toliteral
. Compatibility should not be a problem; but see the docs if you encounter any edge cases.
- webhelpers.html.tags:
- For new HTML 5 input fields, the
text
helper has a “type” argument. - Don’t put an “id” attribute on a hidden fields generated by the
form()
helper, including the magic_method
field. The IDs will clash if there are multiple forms on the page.
- For new HTML 5 input fields, the
- webhelpers.html.tools:
- Preserve case of “method” arg in
button_to()
for XHTML compatibility. Patch by transducer.
- Preserve case of “method” arg in
- webhelpers.text:
- Urlencode
urlify
return value in case it contains special characters like ”?”. Reported by mcd34@gmail.com.
- Urlencode
- webhelpers.util:
- Fix bug in
update_params
in handling existing query strings. Support multiple values per parameter.
- Fix bug in
1.1 (2010-08-09)¶
- webhelpers.paginate:
- Remove stray Routes import. (Other conditional Routes imports remain for backward compatibility; see module docstring.)
- webhelpers.pylonslib.minify:
- Remove _jsmin module due to licensing issues. Details are in webhelpers/pylonslib/_jsmin.py . You can install the “jsmin” package in PyPI (which has the same license), and the helper will use it. If that package is installed, the helper will use it. Otherwise the helper will emit a warning and leave the Javascript unchanged. CSS minification is not affected.
1.0rc1 (2010-05-24)¶
- webhelpers.html.tags:
- Change ‘id’ argument to all form field helpers. The default value is now NotGiven rather than None. NotGiven tells WebHelpers to create an ID attribute based on the field name (formerly None did this). None suppresses the ID attribute entirely (formerly “” did this, and still does for backward compatibility). This behavior of None is consistent with other parts of WebHelpers.
- webhelpers.misc:
- New
format_exception
helper to display an exception as Python would but without the traceback.
1.0b7 (2010-05-16)¶
- webhelpers.containers:
- Bugfix in
canada_provinces
, reported by rpetrello.
- Bugfix in
- webhelpers.html.grid / webhelpers.pylonslib.grid:
- Updates by Ergo, mainly styling and CSS classes.
- Rename classes: ObjectGrid, PylonsGrid, PylonsObjectGrid.
- webhelpers.paginate:
- New URL generation algorithm for
Page.pager()
. You can pass a callback function to the constructor, or it will fall back topylons.url.current
orroutes.url_for
(in that order). It will raiseNotImplementedError
if none of these are available.- Don’t allow extra positional args in constructor. The implementation does nothing with them, so it shouldn’t allow them.
- Import
sqlalchemy.orm
as well assqlalchemy
. User Sybiam reports an error otherwise.- Add code to work with other iterable containers, contributed by Marcin Kuzminski.
- webhelpers.pylonslib.flash:
- New argument
ignore_duplicate
to prevent adding the same message multiple times.
- New argument
1.0b6 (2010-04-23)¶
- webhelpers.containers / webhelpers.misc:
NotGiven
moved to webhelpers.misc.
- webhelpers.html.grid / webhelpers.pylonslib.grid:
- Updates by Ergo, including SQLAlchemy object grid classes.
- webhelpers.misc:
- New function
deprecate
.
- New function
- webhelpers.number:
- New functions
format_data_size
,format_byte_size
, andformat_bit_size
for displaying numbers in SI units (“1.2 kilobytes”, “1.2 kB”, “1.0 KiB”). Contributed by Wojciech Malinowski.
- New functions
1.0b5 (2010-03-18)¶
- webhelpers.html.converters:
- Re-add import of
render
andsanitize
fromwebhelpers.html.render
. That module is not public.
- Re-add import of
- webhelpers.misc:
- New exception
OverwriteError
. - Add
exclude
argument tosubclasses_only
.
- New exception
- webhelpers.text:
- Disable
convert_misc_characters
: it fails its doctests and there’s no consensus on what it should do.
- Disable
- “number_to_human_size.py” is in unfinished directory. This is an old rails helper from WebHelpers 0.6.4. It’s here pending a more comprehensive helper; see http://bitbucket.org/bbangert/webhelpers/issue/2/reinstate-number_to_human_size
1.0b4 (2010-01-24)¶
- Delete
webhelpers.string24
. WebHelpers no longer supports Python 2.3. - webhelpers.feedgenerator:
- Add a basic
Geometry
class for the Geo helpers.
- Add a basic
- webhelpers.html.grid_demo:
- Demonstrates
webhelpers.html.grid
. Run as “python -m webhelpers.html.grid_demo OUTPUT_DIRECTORY”.
- Demonstrates
- webhelpers.html.converters:
- Don’t import
render
andsanitize
to converters module. (Reversed in 1.0b5.)
- Don’t import
- webhelpers.html.secure_form:
- Move module to
webhelpers.pylonslib.secure_form
because it depends onpylons.session
.
- Move module to
- webhelpers.misc:
- New helper
flatten
to interpolate embedded lists and tuples. - New helper
subclasses_only
to extract the subclasses of an abstract base class from a module or iterable.
- New helper
- webhelpers.pylonslib.flash:
- Moved to its own module.
- Changed
Flash.__html__()
implementation. - Categories may be specified in constructor. Patch by Eli Collins.
- webhelpers.pylonslib.grid:
- Bugfixes.
- webhelpers.pylonslib.minify:
- Bugfix.
- webhelpers.util:
- Bugfix:
parse_qs
moved fromcgi
tourlparse
in Python 2.6. Patch by Mike Verdone.
- Bugfix:
1.0b3 (2009-12-29)¶
- webhelpers.feedgenerator:
- Allow either lat-lon and lon-lat formats in geometry data. The default is
lat-lon. For lon-lat, set
GeoFeedMixin.is_input_latitude_first
to false. (You can set in a subclass or instance before writing the output.) lat-lon is the most common format but GeoDjango and some other libraries use lon-lat. The XML output is always lat-lon per the GeoRSS spec.
- Allow either lat-lon and lon-lat formats in geometry data. The default is
lat-lon. For lon-lat, set
- webhelpers.html.grid:
- New module to create an HTML table from a list of records.
- webhelpers.html.tags:
- New helpers
Doctype
(class) andxml_declaration
. - Python 2.5 compatibility fix by Yuen Ho Wong. (#20)
- New helpers
- webhelpers.html.tools:
- New helper
js_obfuscate
implements the old rails helpers.
- New helper
- webhelpers.util:
- New helper
update_params
to update query parameters in a URL.
- New helper
1.0b2 (2009-12-21)¶
webhelpers.constants:
- Fix spelling of Massachusetts.
webhelpers.feedgenerator:
Sync with Django rev 11910. This adds GeoRSS and makes the API more extensible, as well as fixing a few bugs. (Re-added the Atom1 ‘published’ property.) (The ‘generator’ and ‘source’ properties were lost, but they weren’t working correctly anyway.)
GeoRSS usage: use the Geo* classes and add
geometry=(lat, lon)
to each news item. Other shapes and a (not yet implemented) Geometry class are allowed; see the source.
webhelpers.html:
New
HTML.cdata()
method for producing “<!![CDATA[ ... ]]>” sections.The basic tag builders (
HTML.a()
andHTML.tag("a")
) now have a_nl
arg which, if true, inserts a newline between content elements and at the end of the tag for readability. Example:HTML.a("A", "B", href="/") => '<a href="/">AB</a>' HTML.a("A", "B", href="/", _nl=True) => '<a href="/">\nA\nB\n</a>\n'
This does not affect HTML attributes nor the higher-level tag helpers. The exact spacing is subject to change. The tag building code has been refactored to accommodate this.
webhelpers.html.tags:
form()
puts its hidden “_method” field in a ‘<div style=”display:none”>’ to conform to XHTML syntax. The style prevents the div from being displayed or affecting the layout. A new arghidden_fields
may be a dict or iterable of additional hidden fields, which will be added to the div.- Set magic ID attribute in
hidden
helper to match behavior of the other tag helpers. image()
can now calculate the width and height automatically from an image file, using either the PIL algorithm or the pure Python algorithm inwebhelpers.media
. It also logs the dimensions to the debug log for troubleshooting.
webhelpers.html.tools:
- Reimplement
highlight()
using the HTML builder. New arguments add flexibility. Deprecate thehighlighter
argument, which creates tags via string interpolation. - Fixed
auto_link()
to parse slash characters in query string. Patch by hanula; Bitbucket issue #10. - Fix HTML overescaping and underescaping in auto_link(). Patch by Marius Gedminas. A parsing bug remains: http://pylonshq.com/project/pylonshq/ticket/657
- Reimplement
webhelpers.markdown / webhelpers.html.converters:
webhelpers.markdown
will not be upgraded to the version 2 series but will remain at 1.7. Users who want the latest bugfixes and extensions should download the full Markdown package or the alternative Markdown2 from PyPI.- The
markdown()
helper inwebhelpers.html.converters
now has support for external Markdown implementations. You can pass a specific module via themarkdown
argument, otherwise it will attempt to importmarkdown
or fall back towebhelpers.markdown
. - To see which version is autoloaded,
call
_get_markdown_module()
and inspect the.__file__
,.version
, and/or.version_info
attributes of the return value.
webhelpers.media:
- Bugfix in
get_dimensions_pil
.
- Bugfix in
webhelpers.paginate:
- Change for SQLAlchemy 0.6. (bug #11)
webhelpers.pylonslib:
- Fix HTML overescaping. Patch by Marius Gedminas.
1.0b1 (2009-11-20)¶
- Delete deprecated subpackage: rails. These are replaced by new helpers in date, html, misc, number, text.
- Delete other deprecated subpackages: commands, hinclude, htmlgen, pagination. Pagination is replaced by paginate.
- webhelpers.constants:
uk_counties
returns tuples rather than strings.
- webhelpers.feedgenerator:
rfc3339_date
now accepts date objects without crashing.- Add ‘generator’ and ‘source’ properties to RSS2 feeds. Patch by Vince Spicer. (Removed in 1.0b2 due to bugs.)
- Add ‘published’ property to Atom1 feeds.
- webhelpers.html.converters:
- New helper
render()
formats HTML to text. - New helper
sanitize()
strips HTML tags from user input.
- New helper
- webhelprs.html.tags:
- New helper
css_classes()
to add classes to a tag programmatically. - Fix bug in tag helpers when passing
id_
argument (althoughid
is recommended instead). - Add OptionGroup class and optgroup support to select(). Patch by Alexandre Bourget.
- New helper
- webhelpers.html.tools:
- New helper
strip_tags()
deletes HTML tags in a string.
- webhelpers.paginate:
- Allow all versions of SQLAlchemy > 0.3.
- convert “_range” and “_pagelink” function to Page class method so that they can be overridden
- pager “onclick” argument use template string value. So, javascript code can use “partial_url” or “page” value or any. Backward compatibility is considered.
- Add presliced list option to avoid slicing when list is already.
- webhelpers.pylonslib:
- is now a package.
- The
Flash
class now accepts severity categories, thanks to Wichert Akkerman. The docstring shows how to set up auto-fading messages using Javascript a la Mac OSX’s “Growl” feature. This is backward compatible although you should delete existing sessions when upgrading from 0.6.x. webhelpers.pylonslib.minify
contains enhanced versions ofjavascript_link
andstylesheet_link
to minify (shrink) files for more efficient transmission. (EXPERIMENTAL: tests fail in unfinished/disabled_test_pylonslib_minify.py; see http://pylonshq.com/project/pylonshq/ticket/466 .)
- webhelpers.text:
- Port several helpers from Ruby’s “stringex” package.
urlify()
converts any string to a URL-friendly equivalent.remove_formatting()
.- If the
unidecode
package is installed, these two helpers will also transliterate non-ASCII characters to their closest pronounciation equvivalent in ASCII.- Four other helpers reduce HTML entities or whitespace.
0.6.4 (12/2/2008)¶
- text(), password(), checkbox(), textarea(), and select() have a
magic ‘id attribute. If not specified it defaults to the name. To suppress
the ID entirely, pass
id=""
. This is to help set the ID for title(). radio() doesn’t do this because it generates the ID another way. hidden() doesn’t because hidden fields aren’t used with labels. - Bugfixes in mt.select():
- selected values not being passed as list.
- allow currently-selected value to be a long.
- Delete experimental module webhelpers.html.form_layout.
0.6.3 (10/7/2008)¶
- Bugfix in distribute() found by Randy Syring.
- New helpers title() and required_legend() in webhelpers.html.tags.
- New directory webhelpers/public for static files
- Suggested stylesheet webhelpers/public/stylesheets/webhelpers.css (You’ll have to manually add this to your application.)
0.6.2 (10/2/2008)¶
- nl2br() and format-paragraphs were not literal-safe.
- webhelpers.converters:
- New helper transpose() to turn a 2D list sideways (making the rows columns and the columns rows).
- webhelpers.markdown:
- Upgrade to Markdown 1.7.
- Add a warning about escaping untrusted HTML to webhelpers.html.converters.markdown() docstring.
- Did not include Markdown’s extensions due to relative import issues. Use the full Markdown package if you want footnotes or RSS.
- webhelpers.media:
- New module for muiltimedia helpers. Initial functions determine the size of an image and choose a scaling factor.
- webhelpers.html.tags:
- Options tuple contains Option objects for select/checkbox/radio groups. select() now uses this automatically.
- checkbox() and radio() now have a
label
argument.
- webhelpers.number:
- Population standard deviation contributed by Lorenzo Catucci.
- webhelpers.html.form_layout: form field layout (PRELIMINARY, UNSTABLE).
0.6.1 (7/31/2008)¶
- Include a faster version of cgi.escape for use by the literal object.
- Fixed bug in SimplerXMLGenerator that the FeedGenerator uses, so that it doesn’t use a {} arg.
- New helpers:
- nl2br() and format_paragraphs() in webhelpers.html.converters.
- ul() and ol() in webhelpers.html.tags.
- series() in webhelpers.text.
- HTML.tag() is a synonym for make_tag(), both in webhelpers.html.builder.
- Change default form method to “post” (rather than “POST”) to conform to XHTML.
- Add DeprecationWarning for webhelpers.rails package, webhelpers.rails.url_for(), and webhelpers.pagination.
0.6 (07/08/2008)¶
- Add webhelpers.html.builder to generate HTML tags with smart escaping, along with a literal type to mark preformatted strings.
- Deprecate webhelpers.rails, including its Javascript libraries (Prototype and Scriptaculous). Wrap all rails helpers in a literal.
- Many new modules:
- constants - countries, states, and provinces.
- containers - high-level collections, including flash messages.
- date - date/time (rails replacement).
- html.converters - text-to-HTML (rails replacement).
- html.tags - HTML tags (rails replacement).
- html.tools - larger HTML chunks (rails replacement).
- mail - sending email.
- misc - helpers that are neither text, numeric, container, nor date.
- number - numeric helpers and number formatters.
- paginate - successor to deprecated pagination module.
- text - non-HTML text formatting (rails replacement).
- Removed dependency on simplejson and normalized quotes. Patch by Elisha Cook.
COMPATIBILITY CHANGES IN 0.6 DEV VERSION¶
- image(), javascript_link(), stylesheet_link(), and auto_discovery_link() in webhelpers.html.tags do not add prefixes or suffixes to the URL args anymore; they output the exact URL given. Same for button_to() in webhelpers.html.tools.
- webhelpers.html.tags.javascript_path was deleted.
0.3.4 (03/18/08)¶
- Fixed missing javascripts dir.
0.3.3 (02/27/08)¶
- Fixed strip_unders so that it won’t explode during iteration when the size changes.
- Updated feedgenerator with the latest changes from Django’s version (only a few additional attributes).
0.3.2 (09/05/07)¶
- Added capability to pass pagination a SA 0.4 Session object which will be used for queries. This allows compatibility with Session.mapper’d objects and normal SA 0.4 mapper relations.
- Updated SQLAlchemy ORM pagination for SA 0.4 Session.mapper objects.
- Updated Scriptaculous to 1.7.1 beta 3 (1.7.0 is incompatible with Prototype 1.5.1). Thanks errcw. Fixes #288.
0.3.1 (07/14/07)¶
- Added the secure_form_tag helper module, for generating form tags including client-specific authorization tokens for preventing CSRF attacks. Original patch by David Turner. Fixes #157.
- current_url now accepts arguments to pass along to url_for. Fixes #251.
- Updated prototype to 1.5.1.1.
- Added image support to button_to. Patch by Alex Conrad. Fixes #184.
- Fix radio_button and submit_to_remote not handling unicode values. Fixes #235.
- Added support for the defer attribute to javascript_include_tag. Suggested by s0undt3ch. Fixes #214.
- Added a distutils command compress_resources, which can combine CSS and Javascript files, and compress Javascript via ShrinkSafe. Add “command_packages=webhelpers.commands” in [global] in setup.cfg to enable this command for your package.
0.3 (03/18/2007)¶
- WARNING: paginate now takes arguments intended for the collection object as query_args. This could affect backwards compatibility. This fixes a common issue that non-keyword arguments passed into paginate get eaten by paginate’s keyword arguments instead of being in *args to go on to the collection.
- Added environ checking with Routes so that page will be automatically pulled out of the query string, or from the Routes match dict if available.
- Added ability for paginate to check for objects that had SQLAlchemy’s assign_mapper applied to them.
- Added better range checking to paginator to require a positive value that is less than the total amount of pages available for a page.
- WARNING: Due to a typo, the Text helper highlight function no longer highlights text with the CSS class name ‘hilight’ by default: it now uses the CSS class name ‘highlight’ instead. The function’s ‘hilighter’ keyword argument has also been deprecated, use ‘highlighter’ instead.
- Fixed the broken markdown function.
- Upgraded markdown from 1.5 to 1.6a.
- Sync’d Prototype helper to 6057.
- Sync’d Urls helper to 6070.
- Sync’d Text helper to 6096.
- Sync’d Date helper to 6080.
- Sync’d Tags helper to 5857.
- Sync’d Asset tag helper to 6057.
- Sync’d Rails Number helper to 6045.
- Updated Ajax commands to internally use
with_
to avoid name conflicts with Python 2.5 and beyond. Reported by anilj. Fixes #190. - Applied patch from David Smith to decode URL parts as Routes does. Fixes #186.
- Changed pagination to give better response if its passed an invalid object. Patch from Christoph Haas.
- Fixed scriptaculous helper docs example. Fixes #178.
- Updated scriptaculous/prototype to Prototype 1.5.0 and Scriptaculous 1.7.0.
- Updated scriptaculous javascripts to 1.6.5. Fixes #155.
- Updated remote_function doc-string to more clearly indicate the arguments it can receive.
- Synced Rails Javascript helper to 5245 (escape_javascript now escaping backslashes and allow passing html_options to javascript_tag).
0.2.2 (10/20/06)¶
- Fixed tag_options function to not str() string and let html_escape handle it so unicode is properly handled. Reported with fix by Michael G. Noll.
- Added sqlalchemy.Query support to the pagination orm wrappers, patch from Andrija Zarić
- Fixed python 2.3 compliance in webhelpers.rails (use of sorted()) (Thanks Jamie Wilkinson)
0.2.1 (9/7/06)¶
- Adding counter func to text helpers, patch from Jamie Wilkinson.
- Sync’d Rails Text helper to 4994.
- Sync’d Rails Asset tag helper to 4999.
- Sync’d Rails Form tag helper to 5045, also doesn’t apply to our version.
- Sync’d Rails Javascript func to 5039, doesn’t apply to us.
- Updated Scriptaculous to 1.6.3.
- Updated Prototype to 1.5.0_rc1.
- Updated radio_button so that id’s are unique. Brings up to date with Rails changeset #4925, also fixes #103.
- More precise distance_of_time_in_words (Follows bottom half of #4989 Rails changeset)
- button_to accepts method keyword so you can PUT and DELETE with it. (Follows #4914 Rails changeset)
- Fixed auto_link to parse more valid url formats (Thanks Jamie Wilkinson).
- Sync’d text helper from latest Rails version.
- Fixed form tag’s method matching to be case insensitive.
0.2 (8/31/06)¶
- Adding simplejson req, adding use of json’ification. Updated scriptaculous helpers to split out JS generation for use in JS Generation port.
- Finished sync’ing Rails ports (urls, tags) in WebHelpers. Closes #69. url and prototype tests updated, url helpers updated to handle method argument.
- Sync’d scriptaculous helper.
- Sync’d javascript, prototype helpers and prototype.js to latest Rails modifications. Added more prototype tests.
- Sync’d form_options, form_tag helpers. form_tag’s form function can now accept other HTTP methods, and will include a hidden field for them if its not ‘get’ or ‘post’.
- Sync’d number helper, added number unit tests.
- Added markdown.py (python-markdown) for new markdown support in text helper.
- Added textile.py (PyTextile) for new textilize support in text helper.
- Brought asset/date/text helpers up to date with revision info.
0.1.3 (Release)¶
- Brought feedgenerator in line with Django’s version, which fixed the missing support for feed categories and updated classes for new-style. Other minor feed updates as well. Now synced as of Django r3143.
- Fixed typo in feedgenerator import, reported by tiksin@free.fr.
- Added
webhelpers.rails.asset_tag
, for generating links to other assets such as javascripts, stylesheets, and feeds.
Third-party helpers¶
The following third-party Python packages are not included in WebHelpers due to their size or dependencies, but are often used in WebHelpers applications.
A robust HTML/XML parser that can make sense of bad markup.
Clean up and pretty print HTML. This is a C library. There are several Python bindings to it.
Convert Unicode characters to ASCII equivalents. Accented letters and symbols are converted to a visual approximation, and non-Latin letters are converted to their standard Latin pronounciation. Several of theconvert_\*
functions inwebhelpers.text
will use Unidecode if it’s installed.
An object-oriented alternative to the path functions inos
,os.path
, andshutil
. Similar packages include path.py.
TODO¶
WebHelpers 1.x is in a soft feature freeze, so only bugfixes and small changes are likely to be made in the foreseeable future.
See also the bug list at http://bigbucket.org/bbangert/webhelpers .
webhelpers.html.grid
needs better docs. The API could maybe use some
improvement too.
The “unfinished” directory in the WebHelpers source distribution contains potential future helpers which are not finished enough for release. These are not installed by the installer; they are available only in the source tarball.
Port to Python 3.
Too many strip_tags / sanitize / bleach functions.
grid_demo: usage message shows “__main__” rather than package.module.
Development¶
WebHelpers development is coordinated on the pylons-discuss list. Proposals for new helpers and offers to help with coding or documentation are always welcome. Please post any bug reports or outlines for new helpers to the bug tracker.
New helpers are considered if they conform to the following criteria:
- Is it useful in a wide variety of applications, especially web applications?
- Does it avoid dependencies outside the Python standard library, especially C extensions which are hard to install on Windows and Macintosh?
- Is it too small to be released as its own project, and is there no other Python project more appropriate for it?
- Does it work on all Python versions from 2.4 to the latest 2.x? (Python 3 is not yet supported.)
- A small number of Pylons-specific helpers are accepted for the
webhelpers.pylonslib
package. These are ones that offer significant advantages over framework-neutral implementations, are too peripheral for the Pylons core, and are too widely useful to exclude. The docstring should explain how to port it to another web framework.