parent
46039f8687
commit
a0edbb75a4
|
@ -79,7 +79,7 @@ class DoctestItem(pytest.Item):
|
||||||
lineno = test.lineno + example.lineno + 1
|
lineno = test.lineno + example.lineno + 1
|
||||||
message = excinfo.type.__name__
|
message = excinfo.type.__name__
|
||||||
reprlocation = ReprFileLocation(filename, lineno, message)
|
reprlocation = ReprFileLocation(filename, lineno, message)
|
||||||
checker = _get_unicode_checker()
|
checker = _get_checker()
|
||||||
REPORT_UDIFF = doctest.REPORT_UDIFF
|
REPORT_UDIFF = doctest.REPORT_UDIFF
|
||||||
filelines = py.path.local(filename).readlines(cr=0)
|
filelines = py.path.local(filename).readlines(cr=0)
|
||||||
lines = []
|
lines = []
|
||||||
|
@ -118,7 +118,9 @@ def _get_flag_lookup():
|
||||||
ELLIPSIS=doctest.ELLIPSIS,
|
ELLIPSIS=doctest.ELLIPSIS,
|
||||||
IGNORE_EXCEPTION_DETAIL=doctest.IGNORE_EXCEPTION_DETAIL,
|
IGNORE_EXCEPTION_DETAIL=doctest.IGNORE_EXCEPTION_DETAIL,
|
||||||
COMPARISON_FLAGS=doctest.COMPARISON_FLAGS,
|
COMPARISON_FLAGS=doctest.COMPARISON_FLAGS,
|
||||||
ALLOW_UNICODE=_get_allow_unicode_flag())
|
ALLOW_UNICODE=_get_allow_unicode_flag(),
|
||||||
|
ALLOW_BYTES=_get_allow_bytes_flag(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_optionflags(parent):
|
def get_optionflags(parent):
|
||||||
|
@ -147,7 +149,7 @@ class DoctestTextfile(DoctestItem, pytest.Module):
|
||||||
|
|
||||||
optionflags = get_optionflags(self)
|
optionflags = get_optionflags(self)
|
||||||
runner = doctest.DebugRunner(verbose=0, optionflags=optionflags,
|
runner = doctest.DebugRunner(verbose=0, optionflags=optionflags,
|
||||||
checker=_get_unicode_checker())
|
checker=_get_checker())
|
||||||
|
|
||||||
parser = doctest.DocTestParser()
|
parser = doctest.DocTestParser()
|
||||||
test = parser.get_doctest(text, globs, name, filename, 0)
|
test = parser.get_doctest(text, globs, name, filename, 0)
|
||||||
|
@ -182,7 +184,7 @@ class DoctestModule(pytest.Module):
|
||||||
finder = doctest.DocTestFinder()
|
finder = doctest.DocTestFinder()
|
||||||
optionflags = get_optionflags(self)
|
optionflags = get_optionflags(self)
|
||||||
runner = doctest.DebugRunner(verbose=0, optionflags=optionflags,
|
runner = doctest.DebugRunner(verbose=0, optionflags=optionflags,
|
||||||
checker=_get_unicode_checker())
|
checker=_get_checker())
|
||||||
for test in finder.find(module, module.__name__):
|
for test in finder.find(module, module.__name__):
|
||||||
if test.examples: # skip empty doctests
|
if test.examples: # skip empty doctests
|
||||||
yield DoctestItem(test.name, self, runner, test)
|
yield DoctestItem(test.name, self, runner, test)
|
||||||
|
@ -204,28 +206,32 @@ def _setup_fixtures(doctest_item):
|
||||||
return fixture_request
|
return fixture_request
|
||||||
|
|
||||||
|
|
||||||
def _get_unicode_checker():
|
def _get_checker():
|
||||||
"""
|
"""
|
||||||
Returns a doctest.OutputChecker subclass that takes in account the
|
Returns a doctest.OutputChecker subclass that takes in account the
|
||||||
ALLOW_UNICODE option to ignore u'' prefixes in strings. Useful
|
ALLOW_UNICODE option to ignore u'' prefixes in strings and ALLOW_BYTES
|
||||||
when the same doctest should run in Python 2 and Python 3.
|
to strip b'' prefixes.
|
||||||
|
Useful when the same doctest should run in Python 2 and Python 3.
|
||||||
|
|
||||||
An inner class is used to avoid importing "doctest" at the module
|
An inner class is used to avoid importing "doctest" at the module
|
||||||
level.
|
level.
|
||||||
"""
|
"""
|
||||||
if hasattr(_get_unicode_checker, 'UnicodeOutputChecker'):
|
if hasattr(_get_checker, 'LiteralsOutputChecker'):
|
||||||
return _get_unicode_checker.UnicodeOutputChecker()
|
return _get_checker.LiteralsOutputChecker()
|
||||||
|
|
||||||
import doctest
|
import doctest
|
||||||
import re
|
import re
|
||||||
|
|
||||||
class UnicodeOutputChecker(doctest.OutputChecker):
|
class LiteralsOutputChecker(doctest.OutputChecker):
|
||||||
"""
|
"""
|
||||||
Copied from doctest_nose_plugin.py from the nltk project:
|
Copied from doctest_nose_plugin.py from the nltk project:
|
||||||
https://github.com/nltk/nltk
|
https://github.com/nltk/nltk
|
||||||
|
|
||||||
|
Further extended to also support byte literals.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_literal_re = re.compile(r"(\W|^)[uU]([rR]?[\'\"])", re.UNICODE)
|
_unicode_literal_re = re.compile(r"(\W|^)[uU]([rR]?[\'\"])", re.UNICODE)
|
||||||
|
_bytes_literal_re = re.compile(r"(\W|^)[bB]([rR]?[\'\"])", re.UNICODE)
|
||||||
|
|
||||||
def check_output(self, want, got, optionflags):
|
def check_output(self, want, got, optionflags):
|
||||||
res = doctest.OutputChecker.check_output(self, want, got,
|
res = doctest.OutputChecker.check_output(self, want, got,
|
||||||
|
@ -233,23 +239,27 @@ def _get_unicode_checker():
|
||||||
if res:
|
if res:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if not (optionflags & _get_allow_unicode_flag()):
|
allow_unicode = optionflags & _get_allow_unicode_flag()
|
||||||
|
allow_bytes = optionflags & _get_allow_bytes_flag()
|
||||||
|
if not allow_unicode and not allow_bytes:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
else: # pragma: no cover
|
else: # pragma: no cover
|
||||||
# the code below will end up executed only in Python 2 in
|
def remove_prefixes(regex, txt):
|
||||||
# our tests, and our coverage check runs in Python 3 only
|
return re.sub(regex, r'\1\2', txt)
|
||||||
def remove_u_prefixes(txt):
|
|
||||||
return re.sub(self._literal_re, r'\1\2', txt)
|
|
||||||
|
|
||||||
want = remove_u_prefixes(want)
|
if allow_unicode:
|
||||||
got = remove_u_prefixes(got)
|
want = remove_prefixes(self._unicode_literal_re, want)
|
||||||
|
got = remove_prefixes(self._unicode_literal_re, got)
|
||||||
|
if allow_bytes:
|
||||||
|
want = remove_prefixes(self._bytes_literal_re, want)
|
||||||
|
got = remove_prefixes(self._bytes_literal_re, got)
|
||||||
res = doctest.OutputChecker.check_output(self, want, got,
|
res = doctest.OutputChecker.check_output(self, want, got,
|
||||||
optionflags)
|
optionflags)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
_get_unicode_checker.UnicodeOutputChecker = UnicodeOutputChecker
|
_get_checker.LiteralsOutputChecker = LiteralsOutputChecker
|
||||||
return _get_unicode_checker.UnicodeOutputChecker()
|
return _get_checker.LiteralsOutputChecker()
|
||||||
|
|
||||||
|
|
||||||
def _get_allow_unicode_flag():
|
def _get_allow_unicode_flag():
|
||||||
|
@ -258,3 +268,11 @@ def _get_allow_unicode_flag():
|
||||||
"""
|
"""
|
||||||
import doctest
|
import doctest
|
||||||
return doctest.register_optionflag('ALLOW_UNICODE')
|
return doctest.register_optionflag('ALLOW_UNICODE')
|
||||||
|
|
||||||
|
|
||||||
|
def _get_allow_bytes_flag():
|
||||||
|
"""
|
||||||
|
Registers and returns the ALLOW_BYTES flag.
|
||||||
|
"""
|
||||||
|
import doctest
|
||||||
|
return doctest.register_optionflag('ALLOW_BYTES')
|
||||||
|
|
|
@ -371,6 +371,9 @@ class TestDoctests:
|
||||||
"--junit-xml=junit.xml")
|
"--junit-xml=junit.xml")
|
||||||
reprec.assertoutcome(failed=1)
|
reprec.assertoutcome(failed=1)
|
||||||
|
|
||||||
|
|
||||||
|
class TestLiterals:
|
||||||
|
|
||||||
@pytest.mark.parametrize('config_mode', ['ini', 'comment'])
|
@pytest.mark.parametrize('config_mode', ['ini', 'comment'])
|
||||||
def test_allow_unicode(self, testdir, config_mode):
|
def test_allow_unicode(self, testdir, config_mode):
|
||||||
"""Test that doctests which output unicode work in all python versions
|
"""Test that doctests which output unicode work in all python versions
|
||||||
|
@ -400,6 +403,35 @@ class TestDoctests:
|
||||||
reprec = testdir.inline_run("--doctest-modules")
|
reprec = testdir.inline_run("--doctest-modules")
|
||||||
reprec.assertoutcome(passed=2)
|
reprec.assertoutcome(passed=2)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('config_mode', ['ini', 'comment'])
|
||||||
|
def test_allow_bytes(self, testdir, config_mode):
|
||||||
|
"""Test that doctests which output bytes work in all python versions
|
||||||
|
tested by pytest when the ALLOW_BYTES option is used (either in
|
||||||
|
the ini file or by an inline comment)(#1287).
|
||||||
|
"""
|
||||||
|
if config_mode == 'ini':
|
||||||
|
testdir.makeini('''
|
||||||
|
[pytest]
|
||||||
|
doctest_optionflags = ALLOW_BYTES
|
||||||
|
''')
|
||||||
|
comment = ''
|
||||||
|
else:
|
||||||
|
comment = '#doctest: +ALLOW_BYTES'
|
||||||
|
|
||||||
|
testdir.maketxtfile(test_doc="""
|
||||||
|
>>> b'foo' {comment}
|
||||||
|
'foo'
|
||||||
|
""".format(comment=comment))
|
||||||
|
testdir.makepyfile(foo="""
|
||||||
|
def foo():
|
||||||
|
'''
|
||||||
|
>>> b'foo' {comment}
|
||||||
|
'foo'
|
||||||
|
'''
|
||||||
|
""".format(comment=comment))
|
||||||
|
reprec = testdir.inline_run("--doctest-modules")
|
||||||
|
reprec.assertoutcome(passed=2)
|
||||||
|
|
||||||
def test_unicode_string(self, testdir):
|
def test_unicode_string(self, testdir):
|
||||||
"""Test that doctests which output unicode fail in Python 2 when
|
"""Test that doctests which output unicode fail in Python 2 when
|
||||||
the ALLOW_UNICODE option is not used. The same test should pass
|
the ALLOW_UNICODE option is not used. The same test should pass
|
||||||
|
@ -413,6 +445,19 @@ class TestDoctests:
|
||||||
passed = int(sys.version_info[0] >= 3)
|
passed = int(sys.version_info[0] >= 3)
|
||||||
reprec.assertoutcome(passed=passed, failed=int(not passed))
|
reprec.assertoutcome(passed=passed, failed=int(not passed))
|
||||||
|
|
||||||
|
def test_bytes_literal(self, testdir):
|
||||||
|
"""Test that doctests which output bytes fail in Python 3 when
|
||||||
|
the ALLOW_BYTES option is not used. The same test should pass
|
||||||
|
in Python 2 (#1287).
|
||||||
|
"""
|
||||||
|
testdir.maketxtfile(test_doc="""
|
||||||
|
>>> b'foo'
|
||||||
|
'foo'
|
||||||
|
""")
|
||||||
|
reprec = testdir.inline_run()
|
||||||
|
passed = int(sys.version_info[0] == 2)
|
||||||
|
reprec.assertoutcome(passed=passed, failed=int(not passed))
|
||||||
|
|
||||||
|
|
||||||
class TestDoctestSkips:
|
class TestDoctestSkips:
|
||||||
"""
|
"""
|
||||||
|
@ -579,4 +624,4 @@ class TestDoctestAutoUseFixtures:
|
||||||
""")
|
""")
|
||||||
result = testdir.runpytest('--doctest-modules')
|
result = testdir.runpytest('--doctest-modules')
|
||||||
assert 'FAILURES' not in str(result.stdout.str())
|
assert 'FAILURES' not in str(result.stdout.str())
|
||||||
result.stdout.fnmatch_lines(['*=== 1 passed in *'])
|
result.stdout.fnmatch_lines(['*=== 1 passed in *'])
|
||||||
|
|
Loading…
Reference in New Issue