Commits

Graham Higgins  committed 2491a6d

py27 - Ran 117 tests in 4.475s OK

py32 - Ran 91 tests in 1.109s FAILED (failures=6)

  • Participants
  • Parent commits 1f9cd81

Comments (0)

Files changed (10)

File strainer/case.py

 import sys
-from cStringIO import StringIO
+PY3 = True if sys.version_info[:1] == (3,) else False
+try:
+    from io import StringIO
+except ImportError:
+    try:
+        from cStringIO import StringIO
+    except ImportError:
+        from StringIO import StringIO
 
 import inspect
 import traceback
             def append_delayed_and_print_traceback(e):
                 # With the caught exception, log it, and delay it
                 delayed.append(e)
-                log.debug(traceback.format_exc(sys.exc_info()[2]))
+                if PY3:
+                    log.debug(traceback.format_tb(e.__traceback__)[0])
+                else:
+                    log.debug(traceback.format_exc(sys.exc_info()[2]))
                 log.error(str(e))
 
             def get_and_call_super(klass):

File strainer/middleware.py

 from . import xhtmlify
 import logging
 try:
-    from cStringIO import StringIO
+    from io import StringIO
 except ImportError:
-    from StringIO import StringIO
+    try:
+        from cStringIO import StringIO
+    except ImportError:
+        from StringIO import StringIO
 
 
 __all__ = ['XHTMLValidatorMiddleware', 'XHTMLifyMiddleware',
             return output.write
         app_iter = self.app(environ, dummy_start_response)
         for line in app_iter:
-            output.write(line)
+            output.write(line if xhtmlify.PY3 else line.decode())
         if hasattr(app_iter, 'close'):
             app_iter.close()
         response = output.getvalue()

File strainer/operators.py

-from .xhtmlify import xhtmlify, XMLParsingError, ValidationError
+from .xhtmlify import xhtmlify, XMLParsingError, ValidationError, PY3
 from xml.etree import ElementTree as etree
 from xml.parsers.expat import ExpatError
 import copy
     except ValidationError as e:
         raise XMLParsingError(
             'Could not parse needle: %s into xml. %s' %
-            (needle, e.message))
+            (needle, e.args[0] if PY3 else e.message))
     try:
         haystack_s = normalize_to_xhtml(haystack)
     except ValidationError as e:
         raise XMLParsingError(
             'Could not parse haystack: %s into xml. %s' %
-            (haystack, e.message))
+            (haystack, e.args[0] if PY3 else e.message))
     return needle_s in haystack_s
 
 
     except ValidationError as e:
         raise XMLParsingError(
             'Could not parse needle: %s into xml. %s' %
-            (needle, e.message))
+            (needle, e.args[0] if PY3 else e.message))
     try:
         haystack_s = normalize_to_xhtml(haystack)
     except ValidationError as e:
         raise XMLParsingError(
             'Could not parse haystack: %s into xml. %s' %
-            (haystack, e.message))
+            (haystack, e.args[0] if PY3 else e.message))
     return needle_s == haystack_s
 
 
 
     # this needs to be recursive so we can '&ignore'-out ids anywhere
     # in a json stream
-    for key in set(ca.keys() + cb.keys()):
+    for key in set(list(ca.keys()) + list(cb.keys())):
         if key not in ca:
             log.error('%s!= %s\n key "%s" not in first argument' %
                       (ca, cb, key))
         if v1 == '&ignore' or v2 == '&ignore':
             log.info('Ignored comparison for key: %s', key)
             continue
-        if not isinstance(v2, basestring) and isinstance(v1, basestring):
+        if not isinstance(v2, str) and isinstance(v1, str):
             if not eq_pprint(type(v1), type(v2)):
                 log.error(
                     'The types of values for "%s" do not match (%s vs. %s)' %
 
 
 def eq_json(a, b):
-    if isinstance(a, basestring):
+    if isinstance(a, str):
         a = loads(a)
-    if isinstance(b, basestring):
+    if isinstance(b, str):
         b = loads(b)
 
     return eq_dict(a, b)
 
 
-__all__ = [_key for _key in locals().keys() if not _key.startswith('_')]
+__all__ = [_key for _key in list(locals().keys()) if not _key.startswith('_')]

File strainer/validate.py

 
 import os
 import re
-import urlparse
+try:
+    import urllib.parse
+except ImportError:
+    import urlparse
 
 lxml = None  # imported dynamically on first use
 
 
 from pkg_resources import resource_string
 from strainer.doctypes import *
+from strainer.xhtmlify import PY3
 
 
 __all__ = ['validate_xhtml', 'validate_xhtml_fragment', 'XHTMLSyntaxError',
         tline = doctype.count('\n')
         message = re.sub(r'line (\d+)',
                          lambda m: 'line %s' % (int(m.group(1)) - tline),
-                         e.message)
+                         e.args[0] if PY3 else e.message)
         raise XHTMLSyntaxError(message)
 
 
         # relative to the fragment.
         message = re.sub(r'line (\d+)',
                          lambda m: 'line %s' % (int(m.group(1)) - tline),
-                         e.message)
+                         e.args[0] if PY3 else e.message)
         raise XHTMLSyntaxError(message)
 
 

File strainer/wellformed.py

 """Performs basic XHTML wellformedness checks."""
 import xml.sax
 import xml.sax.handler
-import htmlentitydefs
+try:
+    import html.entities as htmlentitydefs
+except ImportError:
+    import htmlentitydefs
 
 from xml.sax._exceptions import SAXParseException
-
+from strainer.xhtmlify import PY3
 
 __all__ = ['is_wellformed_xml', 'is_wellformed_xhtml']
 
                 column -= len(doctype) - (doctype.rfind('\n') + 1)
             # Convert column to 1-based indexing
             record_error('line %d, column %d: %s' % (
-                line, column + 1, e.message
+                line, column + 1, e.args[0] if PY3 else e.message
             ))
         return False
 

File strainer/xhtmlify.py

 """An HTML to XHTML converter."""
 from __future__ import print_function
 import re
+try:
+    import html.entities as htmlentitydefs
+    PY3 = True
+except ImportError:
+    import htmlentitydefs
+    PY3 = False
 
 import codecs
 import encodings.aliases
 import six
 
-from six.moves import html_entities as htmlentitydefs
+# from six.moves import html_entities as htmlentitydefs
 
 
 __all__ = [
     'fix_xmldecl',
     'sniff_encoding',
     'ValidationError',
+    'PY3',
 ]
 
 # if true, show stack of tags in error messages
         elif text[:2] == "&#":
             # character reference
             try:
+                uchr = chr if PY3 else unichr
                 if text[:3] in ("&#x", "&#X"):
-                    c = unichr(int(text[3:-1], 16))
+                    c = uchr(int(text[3:-1], 16))
                 else:
-                    c = unichr(int(text[2:-1], 10))
+                    c = uchr(int(text[2:-1], 10))
             except ValueError:
                 pass
             else:
     encodingdecl = ''
     if encoding is not None:
         EncName_re = re.compile(r'[A-Za-z][A-Za-z0-9._-]*\Z')  # from XML spec
-        if isinstance(encoding, basestring) and EncName_re.match(encoding):
+        if isinstance(encoding, str) and EncName_re.match(encoding):
             encodingdecl = ' encoding="%s"' % encoding
         else:
             # Don't tell them expected format, guessing won't help
                      '''ABCDEFGHIJKLMNOPQRSTUVWXYZ'''
                      '''0123456789.-_ \t\r\n<?'"[]:()+*>''')
     assert encode(chars_we_need * 3) == encode(chars_we_need) * 3, enc
-    L = lambda s: re.escape(encode(s))  # encoded form of literal s
+    L = lambda s: re.escape(str(s) if PY3 else encode(s))  # encoded form of literal s
     group = lambda s: '(%s)' % s
-    optional = lambda s: '(?:%s)?' % s
-    oneof = lambda opts: '(?:%s)' % '|'.join(opts)
+    # optional = lambda s: '(?:%s)?' % s
+    oneof = lambda opts: '(?:%s)' % '|'.join([str(opt) for opt in opts])
     charset = lambda s: oneof([L(c) for c in s])
     all_until = lambda s: '(?:(?!%s).)*' % s
-    caseless = lambda s: oneof([L(c.lower()) for c in s] +
-                               [L(c.upper()) for c in s])
+    # caseless = lambda s: oneof([L(c.lower()) for c in s] +
+    #                            [L(c.upper()) for c in s])
     upper = charset('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
     lower = charset('abcdefghijklmnopqrstuvwxyz')
     digits = charset('0123456789')
     VERSION = encode('version')
     ENCODING = encode('encoding')
     STANDALONE = encode('standalone')
-    StartDecl = ''.join([prefix, Ss, L('<'), Ss, L('?'), Ss,
+    StartDecl = ''.join([str(prefix), Ss, L('<'), Ss, L('?'), Ss,
                          oneof([L('xml'), L('xmL'), L('xMl'), L('xML'),
                                 L('Xml'), L('XmL'), L('XMl'), L('XML')])])
     Attr = ''.join([group(Sp), group(Name), group(''.join([Ss, L('='), Ss])),
     EndDecl = ''.join([
         group(Ss), oneof([''.join([L('?'), Ss, L('>')]), L('>')])
     ])
-    m = re.match(StartDecl, xml)
+    m = re.match(StartDecl, str(xml) if PY3 else xml)
     if m:
         pos = m.end()
         attrs = {}
     if not encoding:
         encoding = sniff_encoding(html)
     unicode_input = isinstance(html, six.text_type)
-    if unicode_input:
+    if unicode_input and not PY3:
         html = html.encode(encoding, 'strict')
     if not isinstance(html, str):
         raise TypeError("Expected string, got %s" % type(html))
-    html = html.decode(encoding, 'replace')
+    if not PY3:
+        html = html.decode(encoding, 'replace')
     # "in HTML, the Formfeed character (U+000C) is treated as white space"
     html = html.replace(six.u('\u000C'), six.u(' '))
     # Replace disallowed characters with U+FFFD (unicode replacement char)
             lineno -= 1
             offset = len(snippet) - snippet.rfind('\n')
         message = re.sub(r'line \d+', 'line %d' % lineno,
-                         e.message, count=1)
+                         e.args[0] if PY3 else e.message, count=1)
         message = re.sub(r'column \d+', 'column %d' % offset,
                          message, count=1)
         parse_error = xml.parsers.expat.ExpatError(message)
     prefix = encode('')  # any header such as a UTF-8 BOM
     if enc in ('utf_16_le', 'utf_16_be'):
         prefix = six.u('\ufeff').encode(enc)  # the standard approach fails
-    L = lambda s: re.escape(encode(s))  # encoded form of literal s
+    L = lambda s: re.escape(str(s) if PY3 else encode(s))  # encoded form of literal s
     optional = lambda s: '(?:%s)?' % s
-    oneof = lambda opts: '(?:%s)' % '|'.join(opts)
+    oneof = lambda opts: '(?:%s)' % '|'.join(
+            [str(opt) if PY3 else opt for opt in opts])
     charset = lambda s: oneof([L(c) for c in s])
     upper = charset('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
     lower = charset('abcdefghijklmnopqrstuvwxyz')
         ])
     ])
     R = ''.join([
-        prefix,
+        str(prefix) if PY3 else prefix,
         L('<?xml'),
         VersionInfo,
         optional(EncodingDecl),
         Ss,
         L('?>')
     ])
-    m = re.match(R, xml)
+    m = re.match(R, str(xml) if PY3 else xml)
     if m:
         encvalue = m.group('enc_dq')
         if encvalue is None:

File tests/test_case.py

 from __future__ import print_function
 import sys
+PY3 = True if sys.version_info[:1] == (3,) else False
+
 from strainer.case import call_super, STestCase, DelayedException
 from nose.tools import eq_, raises
 
         self.capture_stdout()
 
     def _call(self, name):
-        print(name)
-    
+        print(name if PY3 else name.decode())
+
     def foo(self):
         """There is no superclass here"""
         self._call('foo0')

File tests/test_operators.py

 import strainer.operators as ops
+from strainer.xhtmlify import PY3
 from nose.tools import raises
 
 
         <div></div>
         </form>"""
     e = """<form action="" class="required tableform" method="post"><div /></form>"""
-    r =ops.normalize_to_xhtml(s)
+    e = e.encode('ascii') if PY3 else e
+    r = ops.normalize_to_xhtml(s)
     assert r == e, r
 
 def test_normalize_to_xhtml_with_escapes():
         <div></div>&nbsp;
         </form>"""
     e = """<form action="" class="required tableform" method="post"><div /></form>"""
-    r =ops.normalize_to_xhtml(s)
+    e = e.encode('ascii') if PY3 else e
+    r = ops.normalize_to_xhtml(s)
     assert r == e, r
 
 def test_fix_xml_with_namespace():
     </body>
     </html>"""
     e = """<html><body><form action="" class="required tableform" method="post"><div /></form></body></html>"""
-    r =ops.normalize_to_xhtml(s)
+    e = e.encode('ascii') if PY3 else e
+    r = ops.normalize_to_xhtml(s)
+    assert r == e, r
 
 def test_eq_xhtml():
     b = "<foo><bar>Value</bar></foo>"

File tests/test_validate.py

 from strainer.validate import *
 from strainer.doctypes import DOCTYPE_XHTML1_STRICT
+from strainer.xhtmlify import PY3
 
 
 def test_validate_xhtml():
     validate_xhtml(DOCTYPE_XHTML1_STRICT +
         '<html><head><title/></head><body/></html>')
 
+
 def test_validate_xhtml_fragment():
     validate_xhtml_fragment('<a/>')
 
+
 def test_validate_invalid_xhtml():
     try:
         validate_xhtml('<html/>', doctype=DOCTYPE_XHTML1_STRICT)
     except XHTMLSyntaxError as e:
-        assert 'line 1, column 8' in e.message, e.message
-        assert 'Element html content does not follow the DTD' in e.message
-        assert 'expecting (head, body)' in e.message.replace(' ,', ',')
+        emsg = e.args[0] if PY3 else e.message
+        assert 'line 1, column 8' in emsg, emsg
+        assert 'Element html content does not follow the DTD' in emsg
+        assert 'expecting (head, body)' in emsg.replace(' ,', ',')
+
 
 def test_validate_invalid_xhtml_fragment():
     try:
         validate_xhtml_fragment('</p>')
     except XHTMLSyntaxError as e:
-        assert e.message==('Opening and ending tag mismatch: '
-                           'div line 0 and p, line 1, column 5'), e.message
+        emsg = e.args[0] if PY3 else e.message
+        assert emsg == ('Opening and ending tag mismatch: '
+                        'div line 0 and p, line 1, column 5'), emsg

File tests/test_xhtmlify.py

 import re
 import encodings.aliases
 import codecs
-
+import sys
+PY3 = True if sys.version_info[:1] == (3,) else False
 from strainer.xhtmlify import xhtmlify as _xhtmlify, xmlparse, ValidationError
 from strainer.xhtmlify import sniff_encoding, fix_xmldecl
 from strainer.doctypes import DOCTYPE_XHTML1_STRICT