diff --git a/CHANGELOG b/CHANGELOG index cad8958d7..e640c5352 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,8 @@ 2.6.4.dev ---------- +- add a doctest option for doctest flags + - Improve assertion failure reporting on iterables, by using ndiff and pprint. - removed outdated japanese docs from source tree. diff --git a/_pytest/doctest.py b/_pytest/doctest.py index f61730717..2dd8706ad 100644 --- a/_pytest/doctest.py +++ b/_pytest/doctest.py @@ -6,6 +6,8 @@ from _pytest.python import FixtureRequest, FuncFixtureInfo from py._code.code import TerminalRepr, ReprFileLocation def pytest_addoption(parser): + parser.addini('doctest_optionflags', 'option flags for doctests', + type="args", default=["ELLIPSIS"]) group = parser.getgroup("collect") group.addoption("--doctest-modules", action="store_true", default=False, @@ -87,6 +89,24 @@ class DoctestItem(pytest.Item): def reportinfo(self): return self.fspath, None, "[doctest] %s" % self.name +def _get_flag_lookup(): + import doctest + return dict(DONT_ACCEPT_TRUE_FOR_1=doctest.DONT_ACCEPT_TRUE_FOR_1, + DONT_ACCEPT_BLANKLINE=doctest.DONT_ACCEPT_BLANKLINE, + NORMALIZE_WHITESPACE=doctest.NORMALIZE_WHITESPACE, + ELLIPSIS=doctest.ELLIPSIS, + IGNORE_EXCEPTION_DETAIL=doctest.IGNORE_EXCEPTION_DETAIL, + COMPARISON_FLAGS=doctest.COMPARISON_FLAGS) + +def get_optionflags(parent): + import doctest + optionflags_str = parent.config.getini("doctest_optionflags") + flag_lookup_table = _get_flag_lookup() + flag_acc = 0 + for flag in optionflags_str: + flag_acc |= flag_lookup_table[flag] + return flag_acc + class DoctestTextfile(DoctestItem, pytest.File): def runtest(self): import doctest @@ -101,7 +121,7 @@ class DoctestTextfile(DoctestItem, pytest.File): fixture_request._fillfixtures() failed, tot = doctest.testfile( str(self.fspath), module_relative=False, - optionflags=doctest.ELLIPSIS, + optionflags=get_optionflags(self), extraglobs=dict(getfixture=fixture_request.getfuncargvalue), raise_on_error=True, verbose=0) @@ -119,7 +139,8 @@ class DoctestModule(pytest.File): doctest_globals = dict(getfixture=fixture_request.getfuncargvalue) # uses internal doctest module parsing mechanism finder = doctest.DocTestFinder() - runner = doctest.DebugRunner(verbose=0, optionflags=doctest.ELLIPSIS) + optionflags= get_optionflags(self) + runner = doctest.DebugRunner(verbose=0, optionflags=optionflags) for test in finder.find(module, module.__name__, extraglobs=doctest_globals): if test.examples: # skip empty doctests diff --git a/doc/en/customize.txt b/doc/en/customize.txt index ac263b1fa..bea6f1dee 100644 --- a/doc/en/customize.txt +++ b/doc/en/customize.txt @@ -126,3 +126,8 @@ Builtin configuration file options derived class. See :ref:`change naming conventions` for examples. + +.. confval:: doctest_optionflags + + One or more doctest flag names from the standard ``doctest`` module. + :doc:`See how py.test handles doctests `. diff --git a/doc/en/doctest.txt b/doc/en/doctest.txt index c612d9a23..000aa1653 100644 --- a/doc/en/doctest.txt +++ b/doc/en/doctest.txt @@ -60,3 +60,12 @@ It is possible to use fixtures using the ``getfixture`` helper:: Also, :ref:`usefixtures` and :ref:`autouse` fixtures are supported when executing text doctest files. + +The standard ``doctest`` module provides some setting flags to configure the +strictness of doctest tests. In py.test You can enable those flags those flags +using the configuration file. To make pytest ignore trailing whitespaces and +ignore lengthy exception stack traces you can just write:: + + # content of pytest.ini + [pytest] + doctest_optionflags= NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL diff --git a/testing/test_doctest.py b/testing/test_doctest.py index c6c05a45d..aa1795874 100644 --- a/testing/test_doctest.py +++ b/testing/test_doctest.py @@ -289,3 +289,63 @@ class TestDoctests: """) reprec = testdir.inline_run(p, "--doctest-modules") reprec.assertoutcome(failed=1, passed=1) + + def test_ignored_whitespace(self, testdir): + testdir.makeini(""" + [pytest] + doctest_optionflags = ELLIPSIS NORMALIZE_WHITESPACE + """) + p = testdir.makepyfile(""" + class MyClass: + ''' + >>> a = "foo " + >>> print(a) + foo + ''' + pass + """) + reprec = testdir.inline_run(p, "--doctest-modules") + reprec.assertoutcome(passed=1) + + def test_non_ignored_whitespace(self, testdir): + testdir.makeini(""" + [pytest] + doctest_optionflags = ELLIPSIS + """) + p = testdir.makepyfile(""" + class MyClass: + ''' + >>> a = "foo " + >>> print(a) + foo + ''' + pass + """) + reprec = testdir.inline_run(p, "--doctest-modules") + reprec.assertoutcome(failed=1, passed=0) + + def test_ignored_whitespace_glob(self, testdir): + testdir.makeini(""" + [pytest] + doctest_optionflags = ELLIPSIS NORMALIZE_WHITESPACE + """) + p = testdir.maketxtfile(xdoc=""" + >>> a = "foo " + >>> print(a) + foo + """) + reprec = testdir.inline_run(p, "--doctest-glob=x*.txt") + reprec.assertoutcome(passed=1) + + def test_non_ignored_whitespace_glob(self, testdir): + testdir.makeini(""" + [pytest] + doctest_optionflags = ELLIPSIS + """) + p = testdir.maketxtfile(xdoc=""" + >>> a = "foo " + >>> print(a) + foo + """) + reprec = testdir.inline_run(p, "--doctest-glob=x*.txt") + reprec.assertoutcome(failed=1, passed=0)