Skip to content

Commit a6ff751

Browse files
committed
Upgrade to typogrify 2.0.7 and add this version to the repository
- Legacy-Id: 8988
1 parent bcacf99 commit a6ff751

8 files changed

Lines changed: 725 additions & 0 deletions

File tree

typogrify/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__version__ = "2.0.7"

typogrify/filters.py

Lines changed: 372 additions & 0 deletions
Large diffs are not rendered by default.

typogrify/packages/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Packages live here.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
# titlecase v0.5.1
4+
# Copyright (C) 2008-2010, Stuart Colville.
5+
# https://pypi.python.org/pypi/titlecase
6+
7+
"""
8+
Original Perl version by: John Gruber http://daringfireball.net/ 10 May 2008
9+
Python version by Stuart Colville http://muffinresearch.co.uk
10+
License: http://www.opensource.org/licenses/mit-license.php
11+
"""
12+
13+
import re
14+
15+
__all__ = ['titlecase']
16+
__version__ = '0.5.1'
17+
18+
SMALL = 'a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|v\.?|via|vs\.?'
19+
PUNCT = r"""!"#$%&'‘()*+,\-./:;?@[\\\]_`{|}~"""
20+
21+
SMALL_WORDS = re.compile(r'^(%s)$' % SMALL, re.I)
22+
INLINE_PERIOD = re.compile(r'[a-z][.][a-z]', re.I)
23+
UC_ELSEWHERE = re.compile(r'[%s]*?[a-zA-Z]+[A-Z]+?' % PUNCT)
24+
CAPFIRST = re.compile(r"^[%s]*?([A-Za-z])" % PUNCT)
25+
SMALL_FIRST = re.compile(r'^([%s]*)(%s)\b' % (PUNCT, SMALL), re.I)
26+
SMALL_LAST = re.compile(r'\b(%s)[%s]?$' % (SMALL, PUNCT), re.I)
27+
SUBPHRASE = re.compile(r'([:.;?!][ ])(%s)' % SMALL)
28+
APOS_SECOND = re.compile(r"^[dol]{1}['‘]{1}[a-z]+$", re.I)
29+
ALL_CAPS = re.compile(r'^[A-Z\s%s]+$' % PUNCT)
30+
UC_INITIALS = re.compile(r"^(?:[A-Z]{1}\.{1}|[A-Z]{1}\.{1}[A-Z]{1})+$")
31+
MAC_MC = re.compile(r"^([Mm]a?c)(\w+)")
32+
33+
def titlecase(text):
34+
35+
"""
36+
Titlecases input text
37+
38+
This filter changes all words to Title Caps, and attempts to be clever
39+
about *un*capitalizing SMALL words like a/an/the in the input.
40+
41+
The list of "SMALL words" which are not capped comes from
42+
the New York Times Manual of Style, plus 'vs' and 'v'.
43+
44+
"""
45+
46+
lines = re.split('[\r\n]+', text)
47+
processed = []
48+
for line in lines:
49+
all_caps = ALL_CAPS.match(line)
50+
words = re.split('[\t ]', line)
51+
tc_line = []
52+
for word in words:
53+
if all_caps:
54+
if UC_INITIALS.match(word):
55+
tc_line.append(word)
56+
continue
57+
else:
58+
word = word.lower()
59+
60+
if APOS_SECOND.match(word):
61+
word = word.replace(word[0], word[0].upper())
62+
word = word.replace(word[2], word[2].upper())
63+
tc_line.append(word)
64+
continue
65+
if INLINE_PERIOD.search(word) or UC_ELSEWHERE.match(word):
66+
tc_line.append(word)
67+
continue
68+
if SMALL_WORDS.match(word):
69+
tc_line.append(word.lower())
70+
continue
71+
72+
match = MAC_MC.match(word)
73+
if match:
74+
tc_line.append("%s%s" % (match.group(1).capitalize(),
75+
match.group(2).capitalize()))
76+
continue
77+
78+
hyphenated = []
79+
for item in word.split('-'):
80+
hyphenated.append(CAPFIRST.sub(lambda m: m.group(0).upper(), item))
81+
tc_line.append("-".join(hyphenated))
82+
83+
84+
result = " ".join(tc_line)
85+
86+
result = SMALL_FIRST.sub(lambda m: '%s%s' % (
87+
m.group(1),
88+
m.group(2).capitalize()
89+
), result)
90+
91+
result = SMALL_LAST.sub(lambda m: m.group(0).capitalize(), result)
92+
93+
result = SUBPHRASE.sub(lambda m: '%s%s' % (
94+
m.group(1),
95+
m.group(2).capitalize()
96+
), result)
97+
98+
processed.append(result)
99+
100+
return "\n".join(processed)
101+
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
"""Tests for titlecase"""
5+
6+
7+
import os
8+
import sys
9+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../'))
10+
11+
from titlecase import titlecase
12+
13+
TEST_DATA = (
14+
(
15+
"Q&A with steve jobs: 'that's what happens in technology'",
16+
"Q&A With Steve Jobs: 'That's What Happens in Technology'"
17+
),
18+
(
19+
"What is AT&T's problem?",
20+
"What Is AT&T's Problem?"
21+
),
22+
(
23+
"Apple deal with AT&T falls through",
24+
"Apple Deal With AT&T Falls Through"
25+
),
26+
(
27+
"this v that",
28+
"This v That"
29+
),
30+
(
31+
"this v. that",
32+
"This v. That"
33+
),
34+
(
35+
"this vs that",
36+
"This vs That"
37+
),
38+
(
39+
"this vs. that",
40+
"This vs. That"
41+
),
42+
(
43+
"The SEC's Apple probe: what you need to know",
44+
"The SEC's Apple Probe: What You Need to Know"
45+
),
46+
(
47+
"'by the Way, small word at the start but within quotes.'",
48+
"'By the Way, Small Word at the Start but Within Quotes.'"
49+
),
50+
(
51+
"Small word at end is nothing to be afraid of",
52+
"Small Word at End Is Nothing to Be Afraid Of"
53+
),
54+
(
55+
"Starting Sub-Phrase With a Small Word: a Trick, Perhaps?",
56+
"Starting Sub-Phrase With a Small Word: A Trick, Perhaps?"
57+
),
58+
(
59+
"Sub-Phrase With a Small Word in Quotes: 'a Trick, Perhaps?'",
60+
"Sub-Phrase With a Small Word in Quotes: 'A Trick, Perhaps?'"
61+
),
62+
(
63+
'sub-phrase with a small word in quotes: "a trick, perhaps?"',
64+
'Sub-Phrase With a Small Word in Quotes: "A Trick, Perhaps?"'
65+
),
66+
(
67+
'"Nothing to Be Afraid of?"',
68+
'"Nothing to Be Afraid Of?"'
69+
),
70+
(
71+
'"Nothing to be Afraid Of?"',
72+
'"Nothing to Be Afraid Of?"'
73+
),
74+
(
75+
'a thing',
76+
'A Thing'
77+
),
78+
(
79+
"2lmc Spool: 'gruber on OmniFocus and vapo(u)rware'",
80+
"2lmc Spool: 'Gruber on OmniFocus and Vapo(u)rware'"
81+
),
82+
(
83+
'this is just an example.com',
84+
'This Is Just an example.com'
85+
),
86+
(
87+
'this is something listed on del.icio.us',
88+
'This Is Something Listed on del.icio.us'
89+
),
90+
(
91+
'iTunes should be unmolested',
92+
'iTunes Should Be Unmolested'
93+
),
94+
(
95+
'reading between the lines of steve jobs’s ‘thoughts on music’',
96+
'Reading Between the Lines of Steve Jobs’s ‘Thoughts on Music’'
97+
),
98+
(
99+
'seriously, ‘repair permissions’ is voodoo',
100+
'Seriously, ‘Repair Permissions’ Is Voodoo'
101+
),
102+
(
103+
'generalissimo francisco franco: still dead; kieren McCarthy: still a jackass',
104+
'Generalissimo Francisco Franco: Still Dead; Kieren McCarthy: Still a Jackass'
105+
),
106+
(
107+
"O'Reilly should be untouched",
108+
"O'Reilly Should Be Untouched"
109+
),
110+
(
111+
"my name is o'reilly",
112+
"My Name Is O'Reilly"
113+
),
114+
(
115+
"WASHINGTON, D.C. SHOULD BE FIXED BUT MIGHT BE A PROBLEM",
116+
"Washington, D.C. Should Be Fixed but Might Be a Problem"
117+
),
118+
(
119+
"THIS IS ALL CAPS AND SHOULD BE ADDRESSED",
120+
"This Is All Caps and Should Be Addressed"
121+
),
122+
(
123+
"Mr McTavish went to MacDonalds",
124+
"Mr McTavish Went to MacDonalds"
125+
),
126+
(
127+
"this shouldn't\nget mangled",
128+
"This Shouldn't\nGet Mangled"
129+
),
130+
(
131+
"this is http://foo.com",
132+
"This Is http://foo.com"
133+
)
134+
)
135+
136+
def test_all_caps_regex():
137+
"""Test - all capitals regex"""
138+
from titlecase import ALL_CAPS
139+
assert bool(ALL_CAPS.match('THIS IS ALL CAPS')) is True
140+
141+
def test_initials_regex():
142+
"""Test - uppercase initals regex with A.B"""
143+
from titlecase import UC_INITIALS
144+
assert bool(UC_INITIALS.match('A.B')) is True
145+
146+
def test_initials_regex_2():
147+
"""Test - uppercase initals regex with A.B."""
148+
from titlecase import UC_INITIALS
149+
assert bool(UC_INITIALS.match('A.B.')) is True
150+
151+
def test_initials_regex_3():
152+
"""Test - uppercase initals regex with ABCD"""
153+
from titlecase import UC_INITIALS
154+
assert bool(UC_INITIALS.match('ABCD')) is False
155+
156+
def check_input_matches_expected_output(in_, out):
157+
"""Function yielded by test generator"""
158+
try :
159+
assert titlecase(in_) == out
160+
except AssertionError:
161+
print("%s != %s" % (titlecase(in_), out))
162+
raise
163+
164+
165+
def test_input_output():
166+
"""Generated tests"""
167+
for data in TEST_DATA:
168+
yield check_input_matches_expected_output, data[0], data[1]
169+
170+
171+
if __name__ == "__main__":
172+
import nose
173+
nose.main()
174+

typogrify/templatetags/__init__.py

Whitespace-only changes.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from typogrify.filters import amp, caps, initial_quotes, smartypants, titlecase, typogrify, widont, TypogrifyError
2+
from functools import wraps
3+
import jinja2
4+
from jinja2.exceptions import TemplateError
5+
6+
7+
def make_safe(f):
8+
"""
9+
A function wrapper to make typogrify play nice with jinja2's
10+
unicode support.
11+
12+
"""
13+
@wraps(f)
14+
def wrapper(text):
15+
f.is_safe = True
16+
out = text
17+
try:
18+
out = f(text)
19+
except TypogrifyError as e:
20+
raise TemplateError(e.message)
21+
return jinja2.Markup(out)
22+
wrapper.is_safe = True
23+
return wrapper
24+
25+
26+
def register(env):
27+
"""
28+
Call this to register the template filters for jinj2.
29+
"""
30+
env.filters['amp'] = make_safe(amp)
31+
env.filters['caps'] = make_safe(caps)
32+
env.filters['initial_quotes'] = make_safe(initial_quotes)
33+
env.filters['smartypants'] = make_safe(smartypants)
34+
env.filters['titlecase'] = make_safe(titlecase)
35+
env.filters['typogrify'] = make_safe(typogrify)
36+
env.filters['widont'] = make_safe(widont)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from typogrify.filters import amp, caps, initial_quotes, smartypants, titlecase, typogrify, widont, TypogrifyError
2+
from functools import wraps
3+
from django.conf import settings
4+
from django import template
5+
from django.utils.safestring import mark_safe
6+
from django.utils.encoding import force_str
7+
8+
9+
register = template.Library()
10+
11+
12+
def make_safe(f):
13+
"""
14+
A function wrapper to make typogrify play nice with django's
15+
unicode support.
16+
17+
"""
18+
@wraps(f)
19+
def wrapper(text):
20+
text = force_str(text)
21+
f.is_safe = True
22+
out = text
23+
try:
24+
out = f(text)
25+
except TypogrifyError as e:
26+
if settings.DEBUG:
27+
raise e
28+
return text
29+
return mark_safe(out)
30+
wrapper.is_safe = True
31+
return wrapper
32+
33+
34+
register.filter('amp', make_safe(amp))
35+
register.filter('caps', make_safe(caps))
36+
register.filter('initial_quotes', make_safe(initial_quotes))
37+
register.filter('smartypants', make_safe(smartypants))
38+
register.filter('titlecase', make_safe(titlecase))
39+
register.filter('typogrify', make_safe(typogrify))
40+
register.filter('widont', make_safe(widont))

0 commit comments

Comments
 (0)