From 61674692269b075afe737fc566ec46d7169e838b Mon Sep 17 00:00:00 2001 From: scoder Date: Mon, 26 May 2008 19:47:57 +0200 Subject: [PATCH] [svn r3758] r4374@delle: sbehnel | 2008-05-26 12:12:39 +0200 doctest work-arounds for Py3 --HG-- branch : trunk --- doc/extensions.txt | 8 ++++---- doc/objectify.txt | 2 +- doc/sax.txt | 2 +- doc/validation.txt | 6 +++--- doc/xpathxslt.txt | 12 ++++++------ src/lxml/tests/common_imports.py | 25 ++++++++++++++++++++++++- src/lxml/tests/test_dtd.py | 4 ++-- src/lxml/tests/test_objectify.py | 4 ++-- src/lxml/tests/test_relaxng.py | 5 +++-- src/lxml/tests/test_sax.py | 4 ++-- src/lxml/tests/test_xmlschema.py | 5 +++-- src/lxml/tests/test_xpathevaluator.py | 12 ++++++++++-- src/lxml/tests/test_xslt.py | 6 +++--- 13 files changed, 64 insertions(+), 31 deletions(-) diff --git a/doc/extensions.txt b/doc/extensions.txt index 89000c805..574a022ad 100644 --- a/doc/extensions.txt +++ b/doc/extensions.txt @@ -240,7 +240,7 @@ the global mapping of the FunctionNamespace objects: >>> e2('/foo:a') Traceback (most recent call last): ... - XPathEvalError: Undefined namespace prefix + lxml.etree.XPathEvalError: Undefined namespace prefix Evaluator-local extensions @@ -405,13 +405,13 @@ XPath node-sets: 'Alpha' >>> print(etree.tostring(r[0])) - AlphaBeta + b'AlphaBeta' >>> print(etree.tostring(r[1])) - GammaDelta + b'GammaDelta' >>> print(etree.tostring(r[2])) - + b'' The current implementation deep-copies newly created elements in node-sets. Only the elements and their children are passed on, no outlying parents or diff --git a/doc/objectify.txt b/doc/objectify.txt index fd51bb8b6..e575468a5 100644 --- a/doc/objectify.txt +++ b/doc/objectify.txt @@ -471,7 +471,7 @@ Or an invalid document: >>> xml = "test" >>> a = objectify.fromstring(xml, parser) Traceback (most recent call last): - XMLSyntaxError: Element 'c': This element is not expected. + lxml.etree.XMLSyntaxError: Element 'c': This element is not expected. Note that the same works for parse-time DTD validation, except that DTDs do not support any data types by design. diff --git a/doc/sax.txt b/doc/sax.txt index f573a05b1..21ecec9ed 100644 --- a/doc/sax.txt +++ b/doc/sax.txt @@ -51,7 +51,7 @@ property of the handler: >>> tree = handler.etree >>> lxml.etree.tostring(tree.getroot()) - 'Hello world' + b'Hello world' By passing a ``makeelement`` function the constructor of ``ElementTreeContentHandler``, e.g. the one of a parser you configured, you diff --git a/doc/validation.txt b/doc/validation.txt index 28662bee0..8c7b287ea 100644 --- a/doc/validation.txt +++ b/doc/validation.txt @@ -88,7 +88,7 @@ will raise an exception: >>> root = etree.fromstring("no int", parser) Traceback (most recent call last): - XMLSyntaxError: Element 'a': 'no int' is not a valid value of the atomic type 'xs:integer'. + lxml.etree.XMLSyntaxError: Element 'a': 'no int' is not a valid value of the atomic type 'xs:integer'. If you want the parser to succeed regardless of the outcome of the validation, you should use a non validating parser and run the @@ -200,7 +200,7 @@ If you prefer getting an exception when validating, you can use the >>> relaxng.assertValid(doc2) Traceback (most recent call last): ... - DocumentInvalid: Did not expect element c there, line 1 + lxml.etree.DocumentInvalid: Did not expect element c there, line 1 >>> relaxng.assert_(doc2) Traceback (most recent call last): @@ -307,7 +307,7 @@ If you prefer getting an exception when validating, you can use the >>> xmlschema.assertValid(doc2) Traceback (most recent call last): ... - DocumentInvalid: Element 'c': This element is not expected. Expected is ( b )., line 1 + lxml.etree.DocumentInvalid: Element 'c': This element is not expected. Expected is ( b )., line 1 >>> xmlschema.assert_(doc2) Traceback (most recent call last): diff --git a/doc/xpathxslt.txt b/doc/xpathxslt.txt index 7d84e3ed5..9733ec854 100644 --- a/doc/xpathxslt.txt +++ b/doc/xpathxslt.txt @@ -337,7 +337,7 @@ XPath expression: >>> find = etree.XPath("\\") Traceback (most recent call last): ... - XPathSyntaxError: Invalid expression + lxml.etree.XPathSyntaxError: Invalid expression lxml will also try to give you a hint what went wrong, so if you pass a more complex expression, you may get a somewhat more specific error: @@ -347,7 +347,7 @@ complex expression, you may get a somewhat more specific error: >>> find = etree.XPath("//*[1.1.1]") Traceback (most recent call last): ... - XPathSyntaxError: Invalid predicate + lxml.etree.XPathSyntaxError: Invalid predicate During evaluation, lxml will emit an XPathEvalError on errors: @@ -357,7 +357,7 @@ During evaluation, lxml will emit an XPathEvalError on errors: >>> find(root) Traceback (most recent call last): ... - XPathEvalError: Undefined namespace prefix + lxml.etree.XPathEvalError: Undefined namespace prefix This works for the ``XPath`` class, however, the other evaluators (including the ``xpath()`` method) are one-shot operations that do parsing and evaluation @@ -369,17 +369,17 @@ in one step. They therefore raise evaluation exceptions in all cases: >>> find = root.xpath("//*[1.1.1]") Traceback (most recent call last): ... - XPathEvalError: Invalid predicate + lxml.etree.XPathEvalError: Invalid predicate >>> find = root.xpath("//ns:a") Traceback (most recent call last): ... - XPathEvalError: Undefined namespace prefix + lxml.etree.XPathEvalError: Undefined namespace prefix >>> find = root.xpath("\\") Traceback (most recent call last): ... - XPathEvalError: Invalid expression + lxml.etree.XPathEvalError: Invalid expression Note that lxml versions before 1.3 always raised an ``XPathSyntaxError`` for all errors, including evaluation errors. The best way to support older diff --git a/src/lxml/tests/common_imports.py b/src/lxml/tests/common_imports.py index 7c8fb0a66..3741da325 100644 --- a/src/lxml/tests/common_imports.py +++ b/src/lxml/tests/common_imports.py @@ -43,6 +43,7 @@ def make_version_tuple(version_string): import doctest # check if the system version has everything we need doctest.DocFileSuite + doctest.DocTestParser doctest.NORMALIZE_WHITESPACE doctest.ELLIPSIS except (ImportError, AttributeError): @@ -59,7 +60,7 @@ def sorted(seq, **kwargs): else: locals()['sorted'] = sorted -if sys.version_info >= (3,): +if sys.version_info[0] >= 3: # Python 3 unicode = str def _str(s, encoding="UTF-8"): @@ -71,6 +72,16 @@ def BytesIO(*args): if args and isinstance(args[0], str): args = (args[0].encode("UTF-8"),) return _BytesIO(*args) + + doctest_parser = doctest.DocTestParser() + _fix_unicode = re.compile(r'(\s+)u(["\'])').sub + def make_doctest(filename): + filename = os.path.normpath(os.path.join(os.path.dirname(__file__), filename)) + doctests = open(filename).read() + doctests = _fix_unicode(r'\1\2', doctests) + return doctest.DocTestCase( + doctest_parser.get_doctest( + doctests, {}, os.path.basename(filename), filename, 0)) else: # Python 2 def _str(s, encoding="UTF-8"): @@ -80,6 +91,18 @@ def _bytes(s, encoding="UTF-8"): from StringIO import StringIO BytesIO = StringIO + doctest_parser = doctest.DocTestParser() + _fix_exceptions = re.compile(r'(\s+)(?:\w+\.)+([^.]*(?:Error|Exception):)').sub + _fix_bytes = re.compile(r'(\s+)b(["\'])').sub + def make_doctest(filename): + filename = os.path.normpath(os.path.join(os.path.dirname(__file__), filename)) + doctests = open(filename).read() + doctests = _fix_exceptions(r'\1\2', doctests) + doctests = _fix_bytes(r'\1\2', doctests) + return doctest.DocTestCase( + doctest_parser.get_doctest( + doctests, {}, os.path.basename(filename), filename, 0)) + class HelperTestCase(unittest.TestCase): def tearDown(self): gc.collect() diff --git a/src/lxml/tests/test_dtd.py b/src/lxml/tests/test_dtd.py index 5dc5b5694..0cb034d5d 100644 --- a/src/lxml/tests/test_dtd.py +++ b/src/lxml/tests/test_dtd.py @@ -11,7 +11,7 @@ sys.path.insert(0, this_dir) # needed for Py3 from common_imports import etree, StringIO, BytesIO, _bytes, doctest -from common_imports import HelperTestCase, fileInTestDir +from common_imports import HelperTestCase, fileInTestDir, make_doctest class ETreeDtdTestCase(HelperTestCase): def test_dtd(self): @@ -131,7 +131,7 @@ def test_suite(): suite = unittest.TestSuite() suite.addTests([unittest.makeSuite(ETreeDtdTestCase)]) suite.addTests( - [doctest.DocFileSuite('../../../doc/validation.txt')]) + [make_doctest('../../../doc/validation.txt')]) return suite if __name__ == '__main__': diff --git a/src/lxml/tests/test_objectify.py b/src/lxml/tests/test_objectify.py index c49a40c96..8aa4094dc 100644 --- a/src/lxml/tests/test_objectify.py +++ b/src/lxml/tests/test_objectify.py @@ -12,7 +12,7 @@ sys.path.insert(0, this_dir) # needed for Py3 from common_imports import etree, HelperTestCase, fileInTestDir -from common_imports import SillyFileLike, canonicalize, doctest +from common_imports import SillyFileLike, canonicalize, doctest, make_doctest from common_imports import _bytes, _str, StringIO, BytesIO from lxml import objectify @@ -2329,7 +2329,7 @@ def test_suite(): suite.addTests([unittest.makeSuite(ObjectifyTestCase)]) if sys.version_info >= (2,4): suite.addTests( - [doctest.DocFileSuite('../../../doc/objectify.txt')]) + [make_doctest('../../../doc/objectify.txt')]) return suite if __name__ == '__main__': diff --git a/src/lxml/tests/test_relaxng.py b/src/lxml/tests/test_relaxng.py index 0b4599877..14e4a25ff 100644 --- a/src/lxml/tests/test_relaxng.py +++ b/src/lxml/tests/test_relaxng.py @@ -10,7 +10,8 @@ if this_dir not in sys.path: sys.path.insert(0, this_dir) # needed for Py3 -from common_imports import etree, doctest, BytesIO, _bytes, HelperTestCase, fileInTestDir +from common_imports import etree, BytesIO, _bytes, HelperTestCase, fileInTestDir +from common_imports import doctest, make_doctest class ETreeRelaxNGTestCase(HelperTestCase): def test_relaxng(self): @@ -158,7 +159,7 @@ def test_suite(): suite = unittest.TestSuite() suite.addTests([unittest.makeSuite(ETreeRelaxNGTestCase)]) suite.addTests( - [doctest.DocFileSuite('../../../doc/validation.txt')]) + [make_doctest('../../../doc/validation.txt')]) return suite if __name__ == '__main__': diff --git a/src/lxml/tests/test_sax.py b/src/lxml/tests/test_sax.py index b4846167e..7eae6571c 100644 --- a/src/lxml/tests/test_sax.py +++ b/src/lxml/tests/test_sax.py @@ -10,7 +10,7 @@ if this_dir not in sys.path: sys.path.insert(0, this_dir) # needed for Py3 -from common_imports import HelperTestCase, doctest, BytesIO, _bytes +from common_imports import HelperTestCase, doctest, make_doctest, BytesIO, _bytes from lxml import sax from xml.dom import pulldom @@ -221,7 +221,7 @@ def test_suite(): suite = unittest.TestSuite() suite.addTests([unittest.makeSuite(ETreeSaxTestCase)]) suite.addTests( - [doctest.DocFileSuite('../../../doc/sax.txt')]) + [make_doctest('../../../doc/sax.txt')]) return suite if __name__ == '__main__': diff --git a/src/lxml/tests/test_xmlschema.py b/src/lxml/tests/test_xmlschema.py index bcd9c3de5..70ed2cc0e 100644 --- a/src/lxml/tests/test_xmlschema.py +++ b/src/lxml/tests/test_xmlschema.py @@ -10,7 +10,8 @@ if this_dir not in sys.path: sys.path.insert(0, this_dir) # needed for Py3 -from common_imports import etree, doctest, BytesIO, HelperTestCase, fileInTestDir +from common_imports import etree, BytesIO, HelperTestCase, fileInTestDir +from common_imports import doctest, make_doctest class ETreeXMLSchemaTestCase(HelperTestCase): def test_xmlschema(self): @@ -156,7 +157,7 @@ def test_suite(): suite = unittest.TestSuite() suite.addTests([unittest.makeSuite(ETreeXMLSchemaTestCase)]) suite.addTests( - [doctest.DocFileSuite('../../../doc/validation.txt')]) + [make_doctest('../../../doc/validation.txt')]) return suite if __name__ == '__main__': diff --git a/src/lxml/tests/test_xpathevaluator.py b/src/lxml/tests/test_xpathevaluator.py index c6aa5db8f..89cf5d142 100644 --- a/src/lxml/tests/test_xpathevaluator.py +++ b/src/lxml/tests/test_xpathevaluator.py @@ -10,7 +10,8 @@ if this_dir not in sys.path: sys.path.insert(0, this_dir) # needed for Py3 -from common_imports import etree, HelperTestCase, doctest, _bytes, BytesIO +from common_imports import etree, HelperTestCase, _bytes, BytesIO +from common_imports import doctest, make_doctest class ETreeXPathTestCase(HelperTestCase): """XPath tests etree""" @@ -630,6 +631,13 @@ def xpath(): ... print("Got error") Got error """ + +if sys.version_info[0] >= 3: + xpath.__doc__ = xpath.__doc__.replace(" u'", " '") + xpath.__doc__ = xpath.__doc__.replace(" XPathResultError", + " lxml.etree.XPathResultError") + xpath.__doc__ = xpath.__doc__.replace(" exactly 2 arguments", + " exactly 2 positional arguments") def test_suite(): suite = unittest.TestSuite() @@ -638,7 +646,7 @@ def test_suite(): suite.addTests([unittest.makeSuite(ETreeETXPathClassTestCase)]) suite.addTests([doctest.DocTestSuite()]) suite.addTests( - [doctest.DocFileSuite('../../../doc/xpathxslt.txt')]) + [make_doctest('../../../doc/xpathxslt.txt')]) return suite if __name__ == '__main__': diff --git a/src/lxml/tests/test_xslt.py b/src/lxml/tests/test_xslt.py index e0fe637ce..6e969352a 100644 --- a/src/lxml/tests/test_xslt.py +++ b/src/lxml/tests/test_xslt.py @@ -23,7 +23,7 @@ basestring = str from common_imports import etree, BytesIO, HelperTestCase, fileInTestDir -from common_imports import doctest, _bytes, _str +from common_imports import doctest, _bytes, _str, make_doctest class ETreeXSLTTestCase(HelperTestCase): """XSLT tests etree""" @@ -1355,9 +1355,9 @@ def test_suite(): if is_python3: suite.addTests([unittest.makeSuite(Py3XSLTTestCase)]) suite.addTests( - [doctest.DocFileSuite('../../../doc/extensions.txt')]) + [make_doctest('../../../doc/extensions.txt')]) suite.addTests( - [doctest.DocFileSuite('../../../doc/xpathxslt.txt')]) + [make_doctest('../../../doc/xpathxslt.txt')]) return suite if __name__ == '__main__':