Skip to content

Commit

Permalink
Merge branch 'release/2.3.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
ikirudennis committed Oct 23, 2016
2 parents 621e431 + c08c78a commit 4d64d09
Show file tree
Hide file tree
Showing 16 changed files with 190 additions and 25 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.textile
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
h1. Textile Changelog

h2. Version 2.3.4
* Bugfix: fix an issue with extended block code
* Remove misplaced shebang on non-callable files.
* Packaging: Add test-command to setup.py directly.
* Packaging: Included the tests/ directory for source-tarballs, useful for packaging checks. ("#33":https://github.com/textile/python-textile/issues/33)
* Add a cli tool `pytextile` which takes textile input and prints html output. See `pytextile -h` for details.

h2. Version 2.3.3
* Bugfix: Unicode in URL titles no longer break everything ("#30":https://github.com/textile/python-textile/issues/30)
* Display DeprecationWarning when using textile on Python 2.6.

h2. Version 2.3.2
* Bugfix: properly handle @":"@ as text, not a link.

Expand Down
11 changes: 11 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
exclude .gitignore
exclude TODO.textile
exclude .travis.yml
include CHANGELOG.textile
include CONTRIBUTORS.txt
include .coveragerc
include LICENSE.txt
include MANIFEST.in
include pytest.ini
include README.textile
include requirements.txt
6 changes: 1 addition & 5 deletions README.textile
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ Optional dependencies include:

h2. Usage

<pre>
<code>
>>> import textile
bc.. import textile
>>> s = """
... _This_ is a *test.*
...
Expand All @@ -38,8 +36,6 @@ h2. Usage

<p>Link to <a href="http://slashdot.org/">Slashdot</a></p>
>>>
</code>
</pre>

h3. Notes:

Expand Down
5 changes: 5 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from setuptools import setup, find_packages
import os
import sys
import pytest

def get_version():
basedir = os.path.dirname(__file__)
Expand All @@ -13,6 +14,8 @@ def get_version():
setup(
name='textile',
version=get_version(),
author='Dennis Burke',
author_email='[email protected]',
description='Textile processing for python.',
url='http://github.com/textile/python-textile',
packages=find_packages(),
Expand Down Expand Up @@ -40,8 +43,10 @@ def get_version():
':python_version=="2.6"': ['ordereddict>=1.1'],
'develop': ['regex', 'pytest', 'pytest-cov'],
},
entry_points={'console_scripts': ['pytextile=textile.__main__:main']},
setup_requires=['pytest-runner'],
tests_require=['pytest', 'pytest-cov'],
cmdclass = {'test': pytest},
include_package_data=True,
zip_safe=False,
)
Expand Down
46 changes: 46 additions & 0 deletions tests/fixtures/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<p><a href="https://travis-ci.org/textile/python-textile"><img alt="" src="https://travis-ci.org/textile/python-textile.svg" /></a> <a href="https://coveralls.io/github/textile/python-textile?branch=master"><img alt="" src="https://coveralls.io/repos/github/textile/python-textile/badge.svg" /></a> <a href="https://codecov.io/github/textile/python-textile"><img alt="" src="https://codecov.io/github/textile/python-textile/coverage.svg" /></a></p>

<h1>python-textile</h1>

<p>python-textile is a Python port of <a href="http://txstyle.org/">Textile</a>, Dean Allen&#8217;s humane web text generator.</p>

<h2>Installation</h2>

<p><code>pip install textile</code></p>

<p>Optional dependencies include:
<ul>
<li><a href="http://python-pillow.github.io/"><span class="caps">PIL</span>/Pillow</a> (for checking images size)</li>
<li><a href="https://pypi.python.org/pypi/regex">regex</a> (for faster unicode-aware string matching).</li>
</ul></p>

<h2>Usage</h2>

<pre><code>import textile
&gt;&gt;&gt; s = &quot;&quot;&quot;
... _This_ is a *test.*
...
... * One
... * Two
... * Three
...
... Link to &quot;Slashdot&quot;:http://slashdot.org/
... &quot;&quot;&quot;
&gt;&gt;&gt; html = textile.textile(s)
&gt;&gt;&gt; print html
&lt;p&gt;&lt;em&gt;This&lt;/em&gt; is a &lt;strong&gt;test.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One&lt;/li&gt;
&lt;li&gt;Two&lt;/li&gt;
&lt;li&gt;Three&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Link to &lt;a href=&quot;http://slashdot.org/&quot;&gt;Slashdot&lt;/a&gt;&lt;/p&gt;
&gt;&gt;&gt;</code></pre>

<h3>Notes:</h3>

<ul>
<li>Active development supports Python 2.6 or later (including Python 3.2+).</li>
</ul>
21 changes: 18 additions & 3 deletions tests/test_block.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import unicode_literals

from textile import Textile
import textile
from textile.objects import Block

try:
Expand All @@ -9,7 +9,7 @@
from ordereddict import OrderedDict

def test_block():
t = Textile()
t = textile.Textile()
result = t.block('h1. foobar baby')
expect = '\t<h1>foobar baby</h1>'
assert result == expect
Expand Down Expand Up @@ -41,9 +41,24 @@ def test_block():
assert result == expect

def test_block_tags_false():
t = Textile(block_tags=False)
t = textile.Textile(block_tags=False)
assert t.block_tags is False

result = t.parse('test')
expect = 'test'
assert result == expect

def test_blockcode_extended():
input = 'bc.. text\nmoretext\n\nevenmoretext\n\nmoremoretext\n\np. test'
expect = '<pre><code>text\nmoretext\n\nevenmoretext\n\nmoremoretext</code></pre>\n\n\t<p>test</p>'
t = textile.Textile()
result = t.parse(input)
assert result == expect

def test_blockcode_in_README():
with open('README.textile') as f:
readme = ''.join(f.readlines())
result = textile.textile(readme)
with open('tests/fixtures/README.txt') as f:
expect = ''.join(f.readlines())
assert result == expect
16 changes: 16 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import six
import subprocess

def test_console_script():
command = ['python', '-m', 'textile', 'README.textile']
try:
result = subprocess.check_output(command)
except AttributeError:
command[2] = 'textile.__main__'
result = subprocess.Popen(command,
stdout=subprocess.PIPE).communicate()[0]
with open('tests/fixtures/README.txt') as f:
expect = ''.join(f.readlines())
if type(result) == bytes:
result = result.decode('utf-8')
assert result == expect
6 changes: 6 additions & 0 deletions tests/test_github_issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,9 @@ def parseWapProfile(self, url):
\t<p>Of course there&#8217;s a lot more error handling to do (and useful data to glean off the <a href="XML"><span class="caps">XML</span></a>), but being able to cut through all the usual parsing crap is immensely gratifying.</p>""")
assert result == expect

def test_github_issue_30():
text ='"Tëxtíle (Tëxtíle)":http://lala.com'
result = textile.textile(text)
expect = '\t<p><a href="http://lala.com" title="Tëxtíle">Tëxtíle</a></p>'
assert result == expect
8 changes: 4 additions & 4 deletions tests/test_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@

('<script>alert("hello");</script>', '\t<p><script>alert(&#8220;hello&#8221;);</script></p>'),

('pre.. Hello\n\nHello Again\n\np. normal text', '<pre>Hello\n\nHello Again\n</pre>\n\n\t<p>normal text</p>'),
('pre.. Hello\n\nHello Again\n\np. normal text', '<pre>Hello\n\nHello Again</pre>\n\n\t<p>normal text</p>'),

('<pre>this is in a pre tag</pre>', '<pre>this is in a pre tag</pre>'),

Expand Down Expand Up @@ -180,7 +180,7 @@

('h2. A header\n\n\n\n\n\nsome text', '\t<h2>A header</h2>\n\n\t<p>some text</p>'),

('pre.. foo bar baz\nquux', '<pre>foo bar baz\nquux\n</pre>'),
('pre.. foo bar baz\nquux', '<pre>foo bar baz\nquux</pre>'),

('line of text\n\n leading spaces',
'\t<p>line of text</p>\n\n leading spaces'),
Expand Down Expand Up @@ -286,11 +286,11 @@
# issue 2 escaping
('"foo ==(bar)==":#foobar', '\t<p><a href="#foobar">foo (bar)</a></p>'),
# issue 14 newlines in extended pre blocks
("pre.. Hello\n\nAgain\n\np. normal text", '<pre>Hello\n\nAgain\n</pre>\n\n\t<p>normal text</p>'),
("pre.. Hello\n\nAgain\n\np. normal text", '<pre>Hello\n\nAgain</pre>\n\n\t<p>normal text</p>'),
# url with parentheses
('"python":http://en.wikipedia.org/wiki/Python_(programming_language)', '\t<p><a href="http://en.wikipedia.org/wiki/Python_%28programming_language%29">python</a></p>'),
# table with hyphen styles
('table(linkblog-thumbnail).\n|(linkblog-thumbnail-cell). apple|bear|', '\t<table class="linkblog-thumbnail">\n\t\t<tr>\n\t\t\t<td class="linkblog-thumbnail-cell" style="vertical-align:middle;">apple</td>\n\t\t\t<td>bear</td>\n\t\t</tr>\n\t</table>'),
('table(linkblog-thumbnail).\n|(linkblog-thumbnail-cell). apple|bear|', '\t<table class="linkblog-thumbnail">\n\t\t<tr>\n\t\t\t<td class="linkblog-thumbnail-cell">apple</td>\n\t\t\t<td>bear</td>\n\t\t</tr>\n\t</table>'),
# issue 32 empty table cells
("|thing|||otherthing|", "\t<table>\n\t\t<tr>\n\t\t\t<td>thing</td>\n\t\t\t<td></td>\n\t\t\t<td></td>\n\t\t\t<td>otherthing</td>\n\t\t</tr>\n\t</table>"),
# issue 36 link reference names http and https
Expand Down
12 changes: 12 additions & 0 deletions textile/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
from __future__ import unicode_literals

import sys
import warnings

from .core import textile, textile_restricted, Textile
from .version import VERSION

__all__ = ['textile', 'textile_restricted']

__version__ = VERSION


if sys.version_info[:2] == (2, 6):
warnings.warn(
"Python 2.6 is no longer supported by the Python core team, please "
"upgrade your Python. A future version of textile will drop support "
"for Python 2.6",
DeprecationWarning
)
31 changes: 31 additions & 0 deletions textile/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import argparse
import sys
import textile


def main():
"""A CLI tool in the style of python's json.tool. In fact, this is mostly
copied directly from that module. This allows us to create a stand-alone
tool as well as invoking it via `python -m textile`."""
prog = 'textile'
description = ('A simple command line interface for textile module '
'to convert textile input to HTML output. This script '
'accepts input as a file or stdin and can write out to '
'a file or stdout.')
parser = argparse.ArgumentParser(prog=prog, description=description)
parser.add_argument('infile', nargs='?', type=argparse.FileType(),
help='a textile file to be converted')
parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'),
help='write the output of infile to outfile')
options = parser.parse_args()

infile = options.infile or sys.stdin
outfile = options.outfile or sys.stdout
with infile:
output = textile.textile(''.join(infile.readlines()))
with outfile:
outfile.write(output)


if __name__ == '__main__': #pragma: no cover
main()
21 changes: 18 additions & 3 deletions textile/core.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

Expand Down Expand Up @@ -421,6 +420,7 @@ def block(self, text):
tag = 'p'
atts = cite = graf = ext = ''

last_item_is_a_shelf = False
out = []

for line in text:
Expand All @@ -430,6 +430,16 @@ def block(self, text):
match = re.search(pattern, line, flags=re.S | re.U)
# tag specified on this line.
if match:
# if we had a previous extended tag but not this time, close up
# the tag
if out:
last_item_is_a_shelf = out[-1] in self.shelf
if ext and match.group('tag') and last_item_is_a_shelf:
content = out.pop()
content = generate_tag(block.inner_tag, content,
block.inner_atts)
out.append(generate_tag(block.outer_tag, content,
block.outer_atts))
tag, atts, ext, cite, content = match.groups()
block = Block(self, **match.groupdict())
inner_block = generate_tag(block.inner_tag, block.content,
Expand All @@ -450,7 +460,7 @@ def block(self, text):
# if we're inside an extended block, add the text from the
# previous extension to the front
if ext:
line = '{0}\n{1}'.format(out.pop(), line)
line = '{0}\n\n{1}'.format(out.pop(), line)
whitespace = ' \t\n\r\f\v'
if ext or not line[0] in whitespace:
block = Block(self, tag, atts, ext, cite, line)
Expand All @@ -459,6 +469,8 @@ def block(self, text):
else:
line = generate_tag(block.outer_tag, block.content,
block.outer_atts)
if block.inner_tag == 'code':
line = block.content
if block.outer_tag != 'pre' and not has_raw_text(line):
line = "\t{0}".format(line)
else:
Expand Down Expand Up @@ -874,7 +886,10 @@ def _casesdefault(c, pop, popped, url_chars, counts, pre):
url = self.shelveURL(self.encode_url(urlunsplit(uri_parts)))
attributes = parse_attributes(atts)
if title:
attributes['title'] = title
# if the title contains unicode data, it is annoying to get Python
# 2.6 and all the latter versions working properly. But shelving
# the title is a quick and dirty solution.
attributes['title'] = self.shelve(title)
attributes['href'] = url
if self.rel:
attributes['rel'] = self.rel
Expand Down
6 changes: 4 additions & 2 deletions textile/objects/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,10 @@ def process(self):
i_tag = ''
if self.tag == 'bc':
i_tag = 'code'
self.content = self.textile.shelve(encode_html('{0}\n'.format(
self.content.rstrip("\n"))))
content = encode_html(self.content)
if not self.ext:
content = '{0}\n'.format(content)
self.content = self.textile.shelve(content)
self.outer_tag = 'pre'
self.outer_atts = self.attributes
self.inner_tag = i_tag
Expand Down
1 change: 0 additions & 1 deletion textile/regex_strings.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

Expand Down
12 changes: 6 additions & 6 deletions textile/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,24 +50,24 @@ def generate_tag(tag, content, attributes=None):
content are strings, the attributes argument is a dictionary. As
a convenience, if the content is ' /', a self-closing tag is generated."""
content = six.text_type(content)
element = ElementTree.Element(tag, attrib=attributes)
enc = 'unicode'
if six.PY2:
enc = 'UTF-8'
if not tag:
return content
element = ElementTree.Element(tag, attrib=attributes)
# FIXME: Kind of an ugly hack. There *must* be a cleaner way. I tried
# adding text by assigning it to a.text. That results in non-ascii text
# being html-entity encoded. Not bad, but not entirely matching
# php-textile either.
# adding text by assigning it to element_tag.text. That results in
# non-ascii text being html-entity encoded. Not bad, but not entirely
# matching php-textile either.
try:
element_tag = ElementTree.tostringlist(element, encoding=enc,
method='html')
element_tag.insert(len(element_tag) - 1, content)
element_text = ''.join(element_tag)
except AttributeError:
# Python 2.6 doesn't have the tostringlist method, so we have to treat
# it different.
# it differently.
element_tag = ElementTree.tostring(element, encoding=enc)
element_text = re.sub(r"<\?xml version='1.0' encoding='UTF-8'\?>\n",
'', element_tag)
Expand Down Expand Up @@ -143,7 +143,7 @@ def parse_attributes(block_attributes, element=None, include_id=True):
rowspan = m.group(1)

if element == 'td' or element == 'tr':
m = re.search(r'({0})'.format(valign_re_s), matched)
m = re.search(r'(^{0})'.format(valign_re_s), matched)
if m:
style.append("vertical-align:{0}".format(vAlign[m.group(1)]))

Expand Down
2 changes: 1 addition & 1 deletion textile/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
VERSION = '2.3.2'
VERSION = '2.3.4'

0 comments on commit 4d64d09

Please sign in to comment.