WebHelpers is a package designed to ease common tasks developers need that are usually done for formatting or displaying data in templates.
Helpers available by module:
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.
>>> 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'
Return approximate-time-distance string for from_time till now.
Same as distance_of_time_in_words but the endpoint is now.
Functions that convert from text markup languages to HTML
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 import markdown. If neither is available, it will fall back to webhelpers.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, or safe_mode="remove" to strip it.
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.
Powerful HTML helpers that produce more than just simple tags.
Turn all urls and email addresses into clickable links.
>>> auto_link("Go to http://www.planetpython.com and say hello to firstname.lastname@example.org") literal(u'Go to <a href="http://www.planetpython.com">http://www.planetpython.com</a> and say hello to <a href="mailto:email@example.com">firstname.lastname@example.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. Any html_attrs that you pass will be applied to the inner input element. In particular, pass
disabled = True/False
as 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 and src as followed:
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.
# 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>
>> 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>
# 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>
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 or td element or in between p 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”.
Highlight all occurrences of phrase in text.
This inserts “<strong class=”highlight”>...</strong>” around every occurrence.
Changed in WebHelpers 1.0b2: new implementation using HTML builder. Allow phrase to be list or regex. Deprecate highlighter and change its default value to None. Add case_sensitive, class_, and **attrs arguments.
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 unless name is specified. Additional HTML options, such as class or id, can be passed in the html_attrs hash.
You can also make it difficult for spiders to harvest email address by obfuscating them.
>>> mail_to("email@example.com", "My email", cc="firstname.lastname@example.org", bcc="email@example.com", subject="This is an example email", body= "This is the body of the message.") literal(u'<a href="mailto:firstname.lastname@example.org?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>')
Strip link tags from text leaving just the link label.
>>> strip_links('<a href="something">else</a>') 'else'
The MIMEType helper assists in delivering appropriate content types for a single action in a controller, based on several requirements:
If the URL ends in an extension, the mime-type associated with that is given the highest preference. Since some browsers fail to properly set their Accept headers to indicate they should be served HTML, the next check looks to see if its at least in the list. This way those browsers will still get the HTML they are expecting.
Finally, if the client didn’t include an extension, and doesn’t have HTML in the list of Accept headers, than the desired mime-type is returned if the server can send it.
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.
Create a MIMEType alias to a full mimetype.
An alias may not contain the / character.
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.
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.
# 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``.
Number formatting and calculation helpers.
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'
Return the mean (i.e., average) of a sequence of numbers.
>>> mean([5, 10]) 7.5
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 =  # 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.
What percent of whole is part?
>>> percent_of(5, 100) 5.0 >>> percent_of(13, 26) 50.0
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...
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/or float), 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.
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 are None 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 are int, long, or float. The default is false, which accepts any value. This is meant for instances or subclasses that don’t want non-numeric values.
Helpers that are neither text, numeric, container, or date.
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.
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.
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.
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.
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
Accumulate a list of messages to show at the next page request.
Instantiate a Flash object.
session_key is the key to save the messages under in the user’s session.
categories is an optional list which overrides the default list of categories.
default_category overrides the default category used for messages when none is specified.
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. Raise ValueError 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.
Return all accumulated messages and delete them from the session.
The return value is a list of Message objects.
Functions that output text (not HTML).
Helpers for filtering, formatting, and transforming strings.
Truncate string s at the first occurrence of sub.
If inclusive is true, truncate just after sub rather than at it.
>>> chop_at("plutocratic brats", "rat") 'plutoc' >>> chop_at("plutocratic brats", "rat", True) 'plutocrat'
Extract an excerpt from the text, or ‘’ if the phrase isn’t found.
>>> excerpt("hello my world", "my", 3) '...lo my wo...'
Chop sub off the front of s if present.
>>> lchop("##This is a comment.##", "##") 'This is a comment.##'
The difference between lchop and s.lstrip is that lchop strips only the exact prefix, while s.lstrip treats the argument as a set of leading characters to delete regardless of order.
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.
>>> plural(2, "ox", "oxen") '2 oxen' >>> plural(2, "ox", "oxen", False) 'oxen'
Chop sub off the end of s if present.
>>> rchop("##This is a comment.##", "##") '##This is a comment.'
The difference between rchop and s.rstrip is that rchop strips only the exact suffix, while s.rstrip treats the argument as a set of trailing characters to delete regardless of order.
Strip the leading whitespace in all lines in s.
This deletes all leading whitespace. textwrap.dedent deletes only the whitespace common to all lines.
Truncate text with replacement characters.
>>> truncate('Once upon a time in a world far far away', 14) 'Once upon a...'
Wrap all paragraphs in a text string to the specified width.
width may be an int or a textwrap.TextWrapper instance. The latter allows you to set other options besides the width, and is more efficient when wrapping many texts.