Skip to content

Commit d7f5a75

Browse files
committed
Merge branch 'release/2.3.12'
2 parents 11397f2 + 2fe6050 commit d7f5a75

File tree

12 files changed

+82
-15
lines changed

12 files changed

+82
-15
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ python:
99
- "3.3"
1010
- "3.4"
1111
- "3.5"
12+
- "3.6"
1213
- "pypy"
1314
# command to install dependencies
1415
install:

CHANGELOG.textile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
h1. Textile Changelog
22

3+
h2. Version 2.3.12
4+
* Bugfix: Don't die on pre blocks with unicode characters. ("#43":https://github.com/textile/python-textile/issues/43)
5+
* Bugfix: Fix regressions introduced into the code between 2.2.2 and 2.3.11. (Special thanks to "@adam-iris":https://github.com/adam-iris for providing pull request "#44":https://github.com/textile/python-textile/pull/44)
6+
* Bugfix: Don't just die when processing poorly-formatted textile lists. ("#37":https://github.com/textile/python-textile/issues/37)
7+
* Add Python 3.6 to testing.
8+
* Add a "print the version string and exit" argument to the cli tool: @pytextile -v@
9+
310
h2. Version 2.3.11
411
* Bugfix: Don't strip leading dot from image URIs ("#42":https://github.com/textile/python-textile/issues/42)
512

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ def get_version():
5252
'Programming Language :: Python :: 3.3',
5353
'Programming Language :: Python :: 3.4',
5454
'Programming Language :: Python :: 3.5',
55+
'Programming Language :: Python :: 3.6',
5556
],
5657
keywords='textile,text,html markup',
5758
install_requires=['six',],
@@ -66,4 +67,3 @@ def get_version():
6667
include_package_data=True,
6768
zip_safe=False,
6869
)
69-

tests/test_block.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,10 @@ def test_blockcode_in_README():
6262
with open('tests/fixtures/README.txt') as f:
6363
expect = ''.join(f.readlines())
6464
assert result == expect
65+
66+
def test_blockcode_comment():
67+
input = '###.. block comment\nanother line\n\np. New line'
68+
expect = '\t<p>New line</p>'
69+
t = textile.Textile()
70+
result = t.parse(input)
71+
assert result == expect

tests/test_cli.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import subprocess
33
import sys
44

5+
import textile
6+
57
def test_console_script():
68
command = [sys.executable, '-m', 'textile', 'README.textile']
79
try:
@@ -15,3 +17,15 @@ def test_console_script():
1517
if type(result) == bytes:
1618
result = result.decode('utf-8')
1719
assert result == expect
20+
21+
def test_version_string():
22+
command = [sys.executable, '-m', 'textile', '-v']
23+
try:
24+
result = subprocess.check_output(command)
25+
except AttributeError:
26+
command[2] = 'textile.__main__'
27+
result = subprocess.Popen(command,
28+
stdout=subprocess.PIPE).communicate()[0]
29+
if type(result) == bytes:
30+
result = result.decode('utf-8')
31+
assert result.strip() == textile.__version__

tests/test_github_issues.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def test_github_issue_21():
2727
bar
2828
</foo>'''
2929
result = textile.textile(text)
30-
expect = '\t<h1>xml example</h1>\n\n<pre><code>\n&lt;foo&gt;\n bar\n&lt;/foo&gt;\n</code></pre>'
30+
expect = '\t<h1>xml example</h1>\n\n<pre><code>\n&lt;foo&gt;\n bar\n&lt;/foo&gt;</code></pre>'
3131
assert result == expect
3232

3333
def test_github_issue_22():
@@ -98,6 +98,21 @@ def test_github_issue_37():
9898
expect = '\t<p>\t<ol>\n\t\t<li>xxx</li>\n\t\t<li>yyy</li>\n\t</ol><br />\n<strong>blah</strong></p>'
9999
assert result == expect
100100

101+
text = '*Highlights*\n\n* UNITEK Y-3705A Type-C Universal DockingStation Pro\n* USB3.0/RJ45/EARPHONE/MICROPHONE/HDMI 6 PORT HUB 1.2m Data Cable 5V 4A Power Adaptor\n*\n* Dimensions: 25cm x 13cm x 9cm\n* Weight: 0.7kg'
102+
result = textile.textile(text)
103+
expect = '''\t<p><strong>Highlights</strong></p>
104+
105+
\t<ul>
106+
\t\t<li><span class="caps">UNITEK</span> Y-3705A Type-C Universal DockingStation Pro</li>
107+
\t\t<li>USB3.0/RJ45/EARPHONE/MICROPHONE/HDMI 6 <span class="caps">PORT</span> <span class="caps">HUB</span> 1.2m Data Cable 5V 4A Power Adaptor</li>
108+
\t</ul>
109+
*
110+
\t<ul>
111+
\t\t<li>Dimensions: 25cm x 13cm x 9cm</li>
112+
\t\t<li>Weight: 0.7kg</li>
113+
\t</ul>'''
114+
assert result == expect
115+
101116
def test_github_issue_40():
102117
text = '\r\n'
103118
result = textile.textile(text)
@@ -109,3 +124,9 @@ def test_github_issue_42():
109124
result = textile.textile(text)
110125
expect = '\t<p><img alt="" src="./image.png" /></p>'
111126
assert result == expect
127+
128+
def test_github_issue_43():
129+
text = 'pre. smart ‘quotes’ are not smart!'
130+
result = textile.textile(text)
131+
expect = '<pre>smart ‘quotes’ are not smart!</pre>'
132+
assert result == expect

tests/test_urls.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ def test_urls():
4646
expect = '\t<p>A link that starts with an h is <a href="/test/">handled</a> incorrectly.</p>'
4747
assert result == expect
4848

49+
result = t.parse('A link that starts with a space" raises":/test/ an exception.')
50+
expect = '\t<p><a href="/test/">A link that starts with a space&#8221; raises</a> an exception.</p>'
51+
assert result == expect
52+
53+
result = t.parse('A link that "contains a\nnewline":/test/ raises an exception.')
54+
expect = '\t<p>A link that <a href="/test/">contains a\nnewline</a> raises an exception.</p>'
55+
assert result == expect
56+
4957
def test_rel_attribute():
5058
t = Textile(rel='nofollow')
5159
result = t.parse('"$":http://domain.tld')

tests/test_values.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@
219219
'\t<p style="font-size:0.8em;"><strong>TxStyle</strong> is a documentation project of Textile 2.4 for <a href="http://texpattern.com">Textpattern <span class="caps">CMS</span></a>.</p>'),
220220
(""""Übermensch":http://de.wikipedia.org/wiki/Übermensch""", """\t<p><a href="http://de.wikipedia.org/wiki/%C3%9Cbermensch">Übermensch</a></p>"""),
221221
("""Here is some text with a <!-- Commented out[1] --> block.\n\n<!-- Here is a single <span>line</span> comment block -->\n\n<!-- Here is a whole\nmultiline\n<span>HTML</span>\nComment\n-->\n\nbc. <!-- Here is a comment block in a code block. -->""",
222-
"""\t<p>Here is some text with a <!-- Commented out[1] --> block.</p>\n\n\t<p><!-- Here is a single <span>line</span> comment block --></p>\n\n\t<p><!-- Here is a whole\nmultiline\n<span>HTML</span>\nComment\n--></p>\n\n<pre><code>&lt;!-- Here is a comment block in a code block. --&gt;\n</code></pre>"""),
222+
"""\t<p>Here is some text with a <!-- Commented out[1] --> block.</p>\n\n\t<p><!-- Here is a single <span>line</span> comment block --></p>\n\n\t<p><!-- Here is a whole\nmultiline\n<span>HTML</span>\nComment\n--></p>\n\n<pre><code>&lt;!-- Here is a comment block in a code block. --&gt;</code></pre>"""),
223223
(""""Textile(c)" is a registered(r) 'trademark' of Textpattern(tm) -- or TXP(That's textpattern!) -- at least it was - back in '88 when 2x4 was (+/-)5(o)C ... QED!\n\np{font-size: 200%;}. 2(1/4) 3(1/2) 4(3/4)""",
224224
"""\t<p>&#8220;Textile&#169;&#8221; is a registered&#174; &#8216;trademark&#8217; of Textpattern&#8482; &#8212; or <acronym title="That&#8217;s textpattern!"><span class="caps">TXP</span></acronym> &#8212; at least it was &#8211; back in &#8217;88 when 2&#215;4 was &#177;5&#176;C &#8230; <span class="caps">QED</span>!</p>\n\n\t<p style="font-size: 200%;">2&#188; 3&#189; 4&#190;</p>"""),
225225
("""|=. Testing colgroup and col syntax\n|:\\5. 80\n|a|b|c|d|e|\n\n|=. Testing colgroup and col syntax|\n|:\\5. 80|\n|a|b|c|d|e|""", """\t<table>\n\t<caption>Testing colgroup and col syntax</caption>\n\t<colgroup span="5" width="80">\n\t</colgroup>\n\t\t<tr>\n\t\t\t<td>a</td>\n\t\t\t<td>b</td>\n\t\t\t<td>c</td>\n\t\t\t<td>d</td>\n\t\t\t<td>e</td>\n\t\t</tr>\n\t</table>\n\n\t<table>\n\t<caption>Testing colgroup and col syntax</caption>\n\t<colgroup span="5" width="80">\n\t</colgroup>\n\t\t<tr>\n\t\t\t<td>a</td>\n\t\t\t<td>b</td>\n\t\t\t<td>c</td>\n\t\t\t<td>d</td>\n\t\t\t<td>e</td>\n\t\t</tr>\n\t</table>"""),
@@ -230,7 +230,7 @@
230230
(""";(class#id) Term 1\n: Def 1\n: Def 2\n: Def 3""",
231231
"""\t<dl class="class" id="id">\n\t\t<dt>Term 1</dt>\n\t\t<dd>Def 1</dd>\n\t\t<dd>Def 2</dd>\n\t\t<dd>Def 3</dd>\n\t</dl>"""),
232232
("""*Here is a comment*\n\nHere is *(class)a comment*\n\n*(class)Here is a class* that is a little extended and is\n*followed* by a strong word!\n\nbc. ; Content-type: text/javascript\n; Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\n; Expires: Sat, 24 Jul 2003 05:00:00 GMT\n; Last-Modified: Wed, 1 Jan 2025 05:00:00 GMT\n; Pragma: no-cache\n\n*123 test*\n\n*test 123*\n\n**123 test**\n\n**test 123**""",
233-
"""\t<p><strong>Here is a comment</strong></p>\n\n\t<p>Here is <strong class="class">a comment</strong></p>\n\n\t<p><strong class="class">Here is a class</strong> that is a little extended and is<br />\n<strong>followed</strong> by a strong word!</p>\n\n<pre><code>; Content-type: text/javascript\n; Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\n; Expires: Sat, 24 Jul 2003 05:00:00 GMT\n; Last-Modified: Wed, 1 Jan 2025 05:00:00 GMT\n; Pragma: no-cache\n</code></pre>\n\n\t<p><strong>123 test</strong></p>\n\n\t<p><strong>test 123</strong></p>\n\n\t<p><b>123 test</b></p>\n\n\t<p><b>test 123</b></p>"""),
233+
"""\t<p><strong>Here is a comment</strong></p>\n\n\t<p>Here is <strong class="class">a comment</strong></p>\n\n\t<p><strong class="class">Here is a class</strong> that is a little extended and is<br />\n<strong>followed</strong> by a strong word!</p>\n\n<pre><code>; Content-type: text/javascript\n; Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\n; Expires: Sat, 24 Jul 2003 05:00:00 GMT\n; Last-Modified: Wed, 1 Jan 2025 05:00:00 GMT\n; Pragma: no-cache</code></pre>\n\n\t<p><strong>123 test</strong></p>\n\n\t<p><strong>test 123</strong></p>\n\n\t<p><b>123 test</b></p>\n\n\t<p><b>test 123</b></p>"""),
234234
("""#_(first#list) one\n# two\n# three\n\ntest\n\n#(ordered#list2).\n# one\n# two\n# three\n\ntest\n\n#_(class_4).\n# four\n# five\n# six\n\ntest\n\n#_ seven\n# eight\n# nine\n\ntest\n\n# one\n# two\n# three\n\ntest\n\n#22 22\n# 23\n# 24""",
235235
"""\t<ol class="first" id="list" start="1">\n\t\t<li>one</li>\n\t\t<li>two</li>\n\t\t<li>three</li>\n\t</ol>\n\n\t<p>test</p>\n\n\t<ol class="ordered" id="list2">\n\t\t<li>one</li>\n\t\t<li>two</li>\n\t\t<li>three</li>\n\t</ol>\n\n\t<p>test</p>\n\n\t<ol class="class_4" start="4">\n\t\t<li>four</li>\n\t\t<li>five</li>\n\t\t<li>six</li>\n\t</ol>\n\n\t<p>test</p>\n\n\t<ol start="7">\n\t\t<li>seven</li>\n\t\t<li>eight</li>\n\t\t<li>nine</li>\n\t</ol>\n\n\t<p>test</p>\n\n\t<ol>\n\t\t<li>one</li>\n\t\t<li>two</li>\n\t\t<li>three</li>\n\t</ol>\n\n\t<p>test</p>\n\n\t<ol start="22">\n\t\t<li>22</li>\n\t\t<li>23</li>\n\t\t<li>24</li>\n\t</ol>"""),
236236
("""# one\n##3 one.three\n## one.four\n## one.five\n# two\n\ntest\n\n#_(continuation#section2).\n# three\n# four\n##_ four.six\n## four.seven\n# five\n\ntest\n\n#21 twenty-one\n# twenty-two""",

textile/__main__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,18 @@ def main():
1313
'accepts input as a file or stdin and can write out to '
1414
'a file or stdout.')
1515
parser = argparse.ArgumentParser(prog=prog, description=description)
16+
parser.add_argument('-v', '--version', action='store_true',
17+
help='show the version number and exit')
1618
parser.add_argument('infile', nargs='?', type=argparse.FileType(),
1719
help='a textile file to be converted')
1820
parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'),
1921
help='write the output of infile to outfile')
2022
options = parser.parse_args()
2123

24+
if options.version:
25+
print(textile.VERSION)
26+
sys.exit()
27+
2228
infile = options.infile or sys.stdin
2329
outfile = options.outfile or sys.stdout
2430
with infile:

textile/core.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,6 @@ def textileLists(self, text):
298298

299299
def fTextileList(self, match):
300300
text = re.split(r'\n(?=[*#;:])', match.group(), flags=re.M)
301-
# import pdb; pdb.set_trace()
302301
pt = ''
303302
result = []
304303
ls = OrderedDict()
@@ -315,7 +314,7 @@ def fTextileList(self, match):
315314
content = content.strip()
316315
else:
317316
result.append(line)
318-
break
317+
continue
319318

320319
nl = ''
321320
ltype = list_type(tl)
@@ -465,7 +464,7 @@ def block(self, text):
465464
else:
466465
# if we're inside an extended block, add the text from the
467466
# previous extension to the front
468-
if ext:
467+
if ext and out:
469468
line = '{0}\n\n{1}'.format(out.pop(), line)
470469
whitespace = ' \t\n\r\f\v'
471470
if ext or not line[0] in whitespace:
@@ -494,7 +493,7 @@ def block(self, text):
494493
cite = ''
495494
graf = ''
496495

497-
if ext:
496+
if ext and out:
498497
out.append(generate_tag(block.outer_tag, out.pop(),
499498
block.outer_atts))
500499
return '\n\n'.join(out)
@@ -672,7 +671,10 @@ def markStartOfLinks(self, text):
672671
balanced = balanced - 1
673672
if re.search(r'\S$', possibility, flags=re.U): # pragma: no branch
674673
balanced = balanced + 1
675-
possibility = possible_start_quotes.pop()
674+
try:
675+
possibility = possible_start_quotes.pop()
676+
except IndexError:
677+
break
676678
else:
677679
# If quotes occur next to each other, we get zero
678680
# length strings. eg. ...""Open the door,
@@ -756,9 +758,9 @@ def fLink(self, m):
756758
$'''.format(cls_re_s, regex_snippets['space']), inner,
757759
flags=re.X | re.U)
758760

759-
atts = m.group('atts') or ''
760-
text = m.group('text') or '' or inner
761-
title = m.group('title') or ''
761+
atts = (m and m.group('atts')) or ''
762+
text = (m and m.group('text')) or inner
763+
title = (m and m.group('title')) or ''
762764

763765
pop, tight = '', ''
764766
counts = { '[': None, ']': url.count(']'), '(': None, ')': None }

0 commit comments

Comments
 (0)