Utilities¶
These functions are not dependent on Flask. They implement common patterns in Flask-based applications.
-
class
coaster.utils.
LabeledEnum
[source]¶ Labeled enumerations. Declarate an enumeration with values and labels (for use in UI):
>>> class MY_ENUM(LabeledEnum): ... FIRST = (1, "First") ... THIRD = (3, "Third") ... SECOND = (2, "Second")
LabeledEnum
will convert any attribute that is a 2-tuple into a value and label pair. Access values as direct attributes of the enumeration:>>> MY_ENUM.FIRST 1 >>> MY_ENUM.SECOND 2 >>> MY_ENUM.THIRD 3
Access labels via dictionary lookup on the enumeration:
>>> MY_ENUM[MY_ENUM.FIRST] 'First' >>> MY_ENUM[2] 'Second' >>> MY_ENUM.get(3) 'Third' >>> MY_ENUM.get(4) is None True
Retrieve a full list of values and labels with
.items()
. Items are sorted by value regardless of the original definition order since Python doesn’t provide a way to preserve that order:>>> MY_ENUM.items() [(1, 'First'), (2, 'Second'), (3, 'Third')] >>> MY_ENUM.keys() [1, 2, 3] >>> MY_ENUM.values() ['First', 'Second', 'Third']
However, if you really want manual sorting, add an __order__ list. Anything not in it will be sorted by value as usual:
>>> class RSVP(LabeledEnum): ... RSVP_Y = ('Y', "Yes") ... RSVP_N = ('N', "No") ... RSVP_M = ('M', "Maybe") ... RSVP_B = ('U', "Unknown") ... RSVP_A = ('A', "Awaiting") ... __order__ = (RSVP_Y, RSVP_N, RSVP_M) >>> RSVP.items() [('Y', 'Yes'), ('N', 'No'), ('M', 'Maybe'), ('A', 'Awaiting'), ('U', 'Unknown')]
Three value tuples are assumed to be (value, name, title) and the name and title are converted into NameTitle(name, title):
>>> class NAME_ENUM(LabeledEnum): ... FIRST = (1, 'first', "First") ... THIRD = (3, 'third', "Third") ... SECOND = (2, 'second', "Second") >>> NAME_ENUM.FIRST 1 >>> NAME_ENUM[NAME_ENUM.FIRST] NameTitle(name='first', title='First') >>> NAME_ENUM[NAME_ENUM.SECOND].name 'second' >>> NAME_ENUM[NAME_ENUM.THIRD].title 'Third'
Given a name, the value can be looked up:
>>> NAME_ENUM.value_for('first') 1 >>> NAME_ENUM.value_for('second') 2
-
class
coaster.utils.
NameTitle
(name, title)¶ -
name
¶ Alias for field number 0
-
title
¶ Alias for field number 1
-
-
coaster.utils.
base_domain_matches
(d1, d2)[source]¶ Check if two domains have the same base domain, using the Public Suffix List.
>>> base_domain_matches('https://hasjob.co', 'hasjob.co') True >>> base_domain_matches('hasgeek.hasjob.co', 'hasjob.co') True >>> base_domain_matches('hasgeek.com', 'hasjob.co') False >>> base_domain_matches('static.hasgeek.co.in', 'hasgeek.com') False >>> base_domain_matches('static.hasgeek.co.in', 'hasgeek.co.in') True >>> base_domain_matches('example@example.com', 'example.com') True
-
coaster.utils.
buid
()[source]¶ Return a new random id that is exactly 22 characters long, by encoding a UUID4 in URL-safe Base64. See http://en.wikipedia.org/wiki/Base64#Variants_summary_table
>>> len(newid()) 22 >>> newid() == newid() False >>> isinstance(newid(), unicode) True
-
coaster.utils.
check_password
(reference, attempt)[source]¶ Compare a reference password with the user attempt.
>>> check_password('{PLAIN}foo', 'foo') True >>> check_password(u'{PLAIN}bar', 'bar') True >>> check_password(u'{UNKNOWN}baz', 'baz') False >>> check_password(u'no-encoding', u'no-encoding') False >>> check_password(u'{SSHA}q/uVU8r15k/9QhRi92CWUwMJu2DM6TUSpp25', u're-foo') True >>> check_password('{SSHA}q/uVU8r15k/9QhRi92CWUwMJu2DM6TUSpp25', 're-foo') True
-
coaster.utils.
domain_namespace_match
(domain, namespace)[source]¶ Checks if namespace is related to the domain because the base domain matches.
>>> domain_namespace_match('hasgeek.com', 'com.hasgeek') True >>> domain_namespace_match('funnel.hasgeek.com', 'com.hasgeek.funnel') True >>> domain_namespace_match('app.hasgeek.com', 'com.hasgeek.peopleflow') True >>> domain_namespace_match('app.hasgeek.in', 'com.hasgeek.peopleflow') False >>> domain_namespace_match('peopleflow.local', 'local.peopleflow') True
-
coaster.utils.
for_tsquery
(text)[source]¶ Tokenize text into a valid PostgreSQL to_tsquery query.
>>> for_tsquery(" ") '' >>> for_tsquery("This is a test") "'This is a test'" >>> for_tsquery('Match "this AND phrase"') "'Match this'&'phrase'" >>> for_tsquery('Match "this & phrase"') "'Match this'&'phrase'" >>> for_tsquery("This NOT that") "'This'&!'that'" >>> for_tsquery("This & NOT that") "'This'&!'that'" >>> for_tsquery("This > that") "'This > that'" >>> for_tsquery("Ruby AND (Python OR JavaScript)") "'Ruby'&('Python'|'JavaScript')" >>> for_tsquery("Ruby AND NOT (Python OR JavaScript)") "'Ruby'&!('Python'|'JavaScript')" >>> for_tsquery("Ruby NOT (Python OR JavaScript)") "'Ruby'&!('Python'|'JavaScript')" >>> for_tsquery("Ruby (Python OR JavaScript) Golang") "'Ruby'&('Python'|'JavaScript')&'Golang'" >>> for_tsquery("Ruby (Python OR JavaScript) NOT Golang") "'Ruby'&('Python'|'JavaScript')&!'Golang'" >>> for_tsquery("Java*") "'Java':*" >>> for_tsquery("Java**") "'Java':*" >>> for_tsquery("Android || Python") "'Android'|'Python'" >>> for_tsquery("Missing (bracket") "'Missing'&('bracket')" >>> for_tsquery("Extra bracket)") "('Extra bracket')" >>> for_tsquery("Android (Python ())") "'Android'&('Python')" >>> for_tsquery("Android (Python !())") "'Android'&('Python')" >>> for_tsquery("()") '' >>> for_tsquery("() Python") "'Python'" >>> for_tsquery("!() Python") "'Python'" >>> for_tsquery("*") ''
-
coaster.utils.
format_currency
(value, decimals=2)[source]¶ Return a number suitably formatted for display as currency, with thousands separated by commas and up to two decimal points.
>>> format_currency(1000) u'1,000' >>> format_currency(100) u'100' >>> format_currency(999.95) u'999.95' >>> format_currency(99.95) u'99.95' >>> format_currency(100000) u'100,000' >>> format_currency(1000.00) u'1,000' >>> format_currency(1000.41) u'1,000.41' >>> format_currency(23.21, decimals=3) u'23.210' >>> format_currency(1000, decimals=3) u'1,000' >>> format_currency(123456789.123456789) u'123,456,789.12'
-
coaster.utils.
get_email_domain
(email)[source]¶ Return the domain component of an email address. Returns None if the provided string cannot be parsed as an email address.
>>> get_email_domain('test@example.com') 'example.com' >>> get_email_domain('test+trailing@example.com') 'example.com' >>> get_email_domain('foobar') >>> get_email_domain('foo@bar@baz') >>> get_email_domain('foobar@') >>> get_email_domain('@foobar')
-
coaster.utils.
getbool
(value)[source]¶ Returns a boolean from any of a range of values. Returns None for unrecognized values. Numbers other than 0 and 1 are considered unrecognized.
>>> getbool(True) True >>> getbool(1) True >>> getbool('1') True >>> getbool('t') True >>> getbool(2) >>> getbool(0) False >>> getbool(False) False >>> getbool('n') False
-
coaster.utils.
make_name
(text, delim=u'-', maxlength=50, checkused=None, counter=2)[source]¶ Generate an ASCII name slug. If a checkused filter is provided, it will be called with the candidate. If it returns True, make_name will add counter numbers starting from 2 until a suitable candidate is found.
Parameters: >>> make_name('This is a title') 'this-is-a-title' >>> make_name('Invalid URL/slug here') 'invalid-url-slug-here' >>> make_name('this.that') 'this-that' >>> make_name('this:that') 'this-that' >>> make_name("How 'bout this?") 'how-bout-this' >>> make_name(u"How’s that?") u'hows-that' >>> make_name(u'K & D') u'k-d' >>> make_name('billion+ pageviews') 'billion-pageviews' >>> make_name(u'हिन्दी slug!') u'hindii-slug' >>> make_name(u'__name__', delim=u'_') u'name' >>> make_name(u'how_about_this', delim=u'_') u'how_about_this' >>> make_name(u'and-that', delim=u'_') u'and_that' >>> make_name(u'Umlauts in Mötörhead') u'umlauts-in-motorhead' >>> make_name('Candidate', checkused=lambda c: c in ['candidate']) 'candidate2' >>> make_name('Candidate', checkused=lambda c: c in ['candidate'], counter=1) 'candidate1' >>> make_name('Candidate', checkused=lambda c: c in ['candidate', 'candidate1', 'candidate2'], counter=1) 'candidate3' >>> make_name('Long title, but snipped', maxlength=20) 'long-title-but-snipp' >>> len(make_name('Long title, but snipped', maxlength=20)) 20 >>> make_name('Long candidate', maxlength=10, checkused=lambda c: c in ['long-candi', 'long-cand1']) 'long-cand2' >>> make_name(u'Lǝnkǝran') u'lankaran' >>> make_name(u'example@example.com') u'example-example-com'
-
coaster.utils.
make_password
(password, encoding=u'BCRYPT')[source]¶ Make a password with PLAIN, SSHA or BCRYPT (default) encoding.
>>> make_password('foo', encoding='PLAIN') u'{PLAIN}foo' >>> make_password(u'bar', encoding='PLAIN') u'{PLAIN}bar' >>> make_password(u're-foo', encoding='SSHA')[:6] u'{SSHA}' >>> make_password('bar-foo', encoding='SSHA')[:6] u'{SSHA}' >>> make_password(u're-foo')[:8] u'{BCRYPT}' >>> make_password('bar-foo')[:8] u'{BCRYPT}' >>> make_password('foo') == make_password('foo') False >>> check_password(make_password('ascii'), 'ascii') True >>> check_password(make_password('mixed'), u'mixed') True >>> check_password(make_password(u'unicode'), u'unicode') True
-
coaster.utils.
md5sum
(data)[source]¶ Return md5sum of data as a 32-character string.
>>> md5sum('random text') 'd9b9bec3f4cc5482e7c5ef43143e563a' >>> md5sum(u'random text') 'd9b9bec3f4cc5482e7c5ef43143e563a' >>> len(md5sum('random text')) 32
-
coaster.utils.
newid
()¶ Return a new random id that is exactly 22 characters long, by encoding a UUID4 in URL-safe Base64. See http://en.wikipedia.org/wiki/Base64#Variants_summary_table
>>> len(newid()) 22 >>> newid() == newid() False >>> isinstance(newid(), unicode) True
-
coaster.utils.
newpin
(digits=4)[source]¶ Return a random numeric string with the specified number of digits, default 4.
>>> len(newpin()) 4 >>> len(newpin(5)) 5 >>> newpin().isdigit() True
-
coaster.utils.
newsecret
()[source]¶ Make a secret key for email confirmation and all that stuff. 44 characters long.
>>> len(newsecret()) 44 >>> newsecret() == newsecret() False
-
coaster.utils.
nullint
(value)[source]¶ Return int(value) if bool(value) is not False. Return None otherwise. Useful for coercing optional values to an integer.
>>> nullint('10') 10 >>> nullint('') is None True
-
coaster.utils.
nullstr
(value)[source]¶ Return str(value) if bool(value) is not False. Return None otherwise. Useful for coercing optional values to a string.
>>> nullstr(10) '10' >>> nullstr('') is None True
-
coaster.utils.
nullunicode
(value)[source]¶ Return unicode(value) if bool(value) is not False. Return None otherwise. Useful for coercing optional values to a string.
>>> nullunicode(10) u'10' >>> nullunicode('') is None True
-
coaster.utils.
sanitize_html
(value, valid_tags={'em': [], 'pre': [], 'code': [], 'h3': [], 'h6': [], 'h4': [], 'h5': [], 'mark': [], 'strong': [], 'sub': [], 'img': ['src', 'width', 'height', 'align', 'alt'], 'ul': [], 'li': ['start'], 'sup': [], 'cite': [], 'dl': [], 'blockquote': [], 'hr': [], 'dd': [], 'ol': [], 'abbr': ['title'], 'br': [], 'dt': [], 'ins': [], 'a': ['href', 'title', 'target', 'rel'], 'b': [], 'i': [], 'p': [], 'del': []}, strip=True)[source]¶ Strips unwanted markup out of HTML.
-
coaster.utils.
simplify_text
(text)[source]¶ Simplify text to allow comparison.
>>> simplify_text("Awesome Coder wanted at Awesome Company") 'awesome coder wanted at awesome company' >>> simplify_text("Awesome Coder, wanted at Awesome Company! ") 'awesome coder wanted at awesome company' >>> simplify_text(u"Awesome Coder, wanted at Awesome Company! ") u'awesome coder wanted at awesome company'
-
coaster.utils.
valid_username
(candidate)[source]¶ Check if a username is valid.
>>> valid_username('example person') False >>> valid_username('example_person') False >>> valid_username('exampleperson') True >>> valid_username('example-person') True >>> valid_username('a') True >>> valid_username('a-') or valid_username('ab-') or valid_username('-a') or valid_username('-ab') False
-
coaster.utils.
word_count
(text, html=True)[source]¶ Return the count of words in the given text. If the text is HTML (default True), tags are stripped before counting. Handles punctuation and bad formatting like.this when counting words, but assumes conventions for Latin script languages. May not be reliable for other languages.