diff options
author | Martin Vilcans <martin@librador.com> | 2019-02-21 20:26:47 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-02-21 20:26:47 +0100 |
commit | c088581f5ed882554d1e27074411b2c874955010 (patch) | |
tree | 0a354ecf213d5a75aac23c890ec92b148896553e | |
parent | d9eb1a980798ff54ac9cd81ff1821f78aa57156b (diff) | |
parent | 69c11fb0aa1750225d1f9549474554bb1d3eb932 (diff) | |
download | screenplain-c088581f5ed882554d1e27074411b2c874955010.tar.gz |
Merge pull request #46 from jpyams/python3
Add Python 3 support
-rw-r--r-- | .travis.yml | 1 | ||||
-rw-r--r-- | README.markdown | 4 | ||||
-rwxr-xr-x | bin/test | 9 | ||||
-rw-r--r-- | requirements.txt | 1 | ||||
-rw-r--r-- | screenplain/export/html.py | 15 | ||||
-rw-r--r-- | screenplain/parsers/fountain.py | 5 | ||||
-rw-r--r-- | screenplain/richstring.py | 21 | ||||
-rw-r--r-- | test.py | 24 | ||||
-rw-r--r-- | tests/fdx_test.py | 2 | ||||
-rw-r--r-- | tests/fountain_test.py | 2 | ||||
-rw-r--r-- | tests/richstring_test.py | 3 |
11 files changed, 72 insertions, 15 deletions
diff --git a/.travis.yml b/.travis.yml index b90b600..2ece8ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: python python: - "2.7" + - "3.3" install: pip install -r requirements.txt script: bin/test diff --git a/README.markdown b/README.markdown index ce453af..445ad1c 100644 --- a/README.markdown +++ b/README.markdown @@ -76,3 +76,7 @@ After this, the `screenplain` command will use the working copy of your code. To run unit tests and style checks, run: bin/test + +For developing for Python 3, instead use: + + mkvirtualenv --no-site-packages --python=$(which python3) screenplain-py3 @@ -1,3 +1,8 @@ #!/bin/bash -nosetests --nocapture --with-doctest --doctest-tests $* && \ - pep8 --ignore=E402 screenplain tests +if [[ $(python -V 2>&1) =~ "Python 2" ]] +then + nosetests --nocapture --with-doctest --doctest-tests -I ^test.py $* && \ + pep8 --ignore=E402 screenplain tests +else + python test.py && pep8 --ignore=E402 screenplain tests +fi diff --git a/requirements.txt b/requirements.txt index 321e747..50f908b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ reportlab unittest2 nose pep8 +six diff --git a/screenplain/export/html.py b/screenplain/export/html.py index 1f88e64..81c0f8b 100644 --- a/screenplain/export/html.py +++ b/screenplain/export/html.py @@ -18,19 +18,22 @@ class tag(object): >>> import sys >>> from __future__ import with_statement >>> with tag(sys.stdout, 'div'): - ... sys.stdout.write('hello') + ... print('hello') ... - <div>hello</div> + <div>hello + </div> Adding classes to the element is possible: >>> with tag(sys.stdout, 'div', classes=['action']): - ... sys.stdout.write('hello') - <div class="action">hello</div> + ... print('hello') + <div class="action">hello + </div> >>> with tag(sys.stdout, 'div', classes=['action', 'centered']): - ... sys.stdout.write('hello') - <div class="action centered">hello</div> + ... print('hello') + <div class="action centered">hello + </div> """ def __init__(self, out, tag, classes=None): diff --git a/screenplain/parsers/fountain.py b/screenplain/parsers/fountain.py index 3290dd2..5434c1a 100644 --- a/screenplain/parsers/fountain.py +++ b/screenplain/parsers/fountain.py @@ -5,6 +5,7 @@ import itertools from itertools import takewhile import re +from six import next from screenplain.types import ( Slug, Action, Dialog, DualDialog, Transition, Section, PageBreak, @@ -269,7 +270,7 @@ def parse_title_page(lines): it = iter(lines) try: - line = it.next() + line = next(it) while True: key_match = title_page_key_re.match(line) if not key_match: @@ -278,7 +279,7 @@ def parse_title_page(lines): if value: # Single line key/value result.setdefault(key, []).append(value) - line = it.next() + line = next(it) else: for line in it: value_match = title_page_value_re.match(line) diff --git a/screenplain/richstring.py b/screenplain/richstring.py index e24db1a..ad667d1 100644 --- a/screenplain/richstring.py +++ b/screenplain/richstring.py @@ -4,10 +4,21 @@ import re import cgi +import six _magic_re = re.compile(u'[\ue700-\ue705]') +def _escape(s): + """Replaces special HTML characters like < + and non-ascii characters with ampersand escapes. + + """ + encoded = cgi.escape(s).encode('ascii', 'xmlcharrefreplace') + # In Py3, encoded is bytes type, so convert it to a string + return encoded.decode('ascii') + + class RichString(object): """A sequence of segments where each segment can have its own style.""" @@ -20,7 +31,10 @@ class RichString(object): return ' + '.join(repr(s) for s in self.segments) def __unicode__(self): - return ''.join(unicode(s) for s in self.segments) + return ''.join(six.text_type(s) for s in self.segments) + + def __str__(self): + return self.__unicode__() def startswith(self, string): """Checks if the first segment in this string starts with a @@ -93,6 +107,9 @@ class Segment(object): def __unicode__(self): return self.text + def __str__(self): + return self.text + def __eq__(self, other): return ( isinstance(other, Segment) and @@ -116,7 +133,7 @@ class Segment(object): re.sub( ' +', # at least two spaces lambda m: ' ' * (len(m.group(0)) - 1) + ' ', - cgi.escape(self.text).encode('ascii', 'xmlcharrefreplace'), + _escape(self.text), ) + ''.join(style.end_html for style in reversed(ordered_styles)) ) @@ -0,0 +1,24 @@ +"""Runs nosetest after preparing the test cases. + +Removes the leading u from unicode literals so +Python 3 doctests won't fail. + +""" + +from screenplain import richstring +import re + +unicode_literal = re.compile(r'u([\'"])') + +for n in ( + 'parse_emphasis', + '_unescape', + '_demagic_literals', +): + attr = getattr(richstring, n) + old_doc = getattr(attr, '__doc__') + new_doc = unicode_literal.sub(r'\1', old_doc) + setattr(attr, '__doc__', new_doc) + +import nose +nose.main(argv='nosetests --nocapture --with-doctest --doctest-tests'.split()) diff --git a/tests/fdx_test.py b/tests/fdx_test.py index b6e2bc9..497f908 100644 --- a/tests/fdx_test.py +++ b/tests/fdx_test.py @@ -3,7 +3,7 @@ # http://www.opensource.org/licenses/mit-license.php from testcompat import TestCase -from StringIO import StringIO +from six import StringIO from screenplain.export.fdx import write_text from screenplain.richstring import plain, bold, italic diff --git a/tests/fountain_test.py b/tests/fountain_test.py index fff1e48..c31cc66 100644 --- a/tests/fountain_test.py +++ b/tests/fountain_test.py @@ -9,7 +9,7 @@ from screenplain.types import ( Slug, Action, Dialog, DualDialog, Transition, Section, PageBreak ) from screenplain.richstring import plain, italic, empty_string -from StringIO import StringIO +from six import StringIO def parse(lines): diff --git a/tests/richstring_test.py b/tests/richstring_test.py index f2bed5e..ee42087 100644 --- a/tests/richstring_test.py +++ b/tests/richstring_test.py @@ -3,6 +3,7 @@ # http://www.opensource.org/licenses/mit-license.php from testcompat import TestCase +import six from screenplain.richstring import ( RichString, Segment, Bold, Italic, @@ -38,7 +39,7 @@ class RichStringOperatorTests(TestCase): s = bold('Hello') + plain(' there ') + bold('folks') self.assertEquals( u'Hello there folks', - unicode(s) + six.text_type(s) ) def test_eq(self): |