Skip to content

Commit

Permalink
Merge pull request scientific-python#175 from lpsinger/doctest-ufunc-…
Browse files Browse the repository at this point in the history
…skip

Doctests in ufuncs should respect __doctest_skip__
  • Loading branch information
pllim authored Feb 25, 2022
2 parents bd14e46 + 6bdc668 commit feea983
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 18 deletions.
9 changes: 5 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ providing the following features:
* handling doctests that use remote data in conjunction with the
`pytest-remotedata`_ plugin (see `Remote Data`_)
* optional inclusion of ``*.rst`` files for doctests (see `Setup and Configuration`_)
* inclusion of doctests in docstrings of Numpy ufuncs
* optional inclusion of doctests in docstrings of Numpy ufuncs

.. _pytest-remotedata: https://github.com/astropy/pytest-remotedata

Expand Down Expand Up @@ -71,9 +71,10 @@ Usage
Setup and Configuration
~~~~~~~~~~~~~~~~~~~~~~~

This plugin provides two command line options: ``--doctest-plus`` for enabling
the advanced features mentioned above, and ``--doctest-rst`` for including
``*.rst`` files in doctest collection.
This plugin provides three command line options: ``--doctest-plus`` for enabling
the advanced features mentioned above, ``--doctest-rst`` for including
``*.rst`` files in doctest collection, and ``--doctest-ufunc`` for including
doctests in docstrings of Numpy ufuncs.

This plugin can also be enabled by default by adding ``doctest_plus = enabled``
to the ``[tool:pytest]`` section of the package's ``setup.cfg`` file.
Expand Down
44 changes: 30 additions & 14 deletions pytest_doctestplus/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ def pytest_addoption(parser):
"features not found in the normal doctest "
"plugin")

parser.addoption("--doctest-ufunc", action="store_true",
help="enable running doctests in docstrings of Numpy "
"ufuncs")

parser.addoption("--doctest-rst", action="store_true",
help=(
"Enable running doctests in .rst documentation. "
Expand Down Expand Up @@ -121,6 +125,9 @@ def pytest_addoption(parser):
parser.addini("doctest_plus", "enable running doctests with additional "
"features not found in the normal doctest plugin")

parser.addini("doctest_ufunc", "enable running doctests in docstrings of "
"Numpy ufuncs")

parser.addini("doctest_norecursedirs",
"like the norecursedirs option but applies only to doctest "
"collection", type="args", default=())
Expand Down Expand Up @@ -176,6 +183,8 @@ def pytest_configure(config):
run_regular_doctest = config.option.doctestmodules and not config.option.doctest_plus
use_doctest_plus = config.getini(
'doctest_plus') or config.option.doctest_plus or config.option.doctest_only
use_doctest_ufunc = config.getini(
'doctest_ufunc') or config.option.doctest_ufunc
if doctest_plugin is None or run_regular_doctest or not use_doctest_plus:
return

Expand Down Expand Up @@ -248,17 +257,11 @@ def collect(self):
options = get_optionflags(self) | FIX

# uses internal doctest module parsing mechanism
finder = DocTestFinderPlus()
finder = DocTestFinderPlus(doctest_ufunc=use_doctest_ufunc)
runner = doctest.DebugRunner(
verbose=False, optionflags=options, checker=OutputChecker())

tests = finder.find(module)
for method in module.__dict__.values():
if _is_numpy_ufunc(method):
found = finder.find(method, module=module)
tests += found

for test in tests:
for test in finder.find(module):
if test.examples: # skip empty doctests
ignore_warnings_context_needed = False
show_warnings_context_needed = False
Expand Down Expand Up @@ -636,6 +639,10 @@ class DocTestFinderPlus(doctest.DocTestFinder):
_import_cache = {}
_module_checker = ModuleChecker()

def __init__(self, *args, doctest_ufunc=False, **kwargs):
super().__init__(*args, **kwargs)
self._doctest_ufunc = doctest_ufunc

@classmethod
def check_required_modules(cls, mods):
"""Check that modules in `mods` list are available.
Expand Down Expand Up @@ -664,13 +671,22 @@ def check_required_modules(cls, mods):

def find(self, obj, name=None, module=None, globs=None, extraglobs=None):
tests = doctest.DocTestFinder.find(self, obj, name, module, globs, extraglobs)

if name is None and hasattr(obj, '__name__'):
name = obj.__name__
else:
raise ValueError("DocTestFinder.find: name must be given "
"when obj.__name__ doesn't exist: {!r}"
.format((type(obj),)))

if self._doctest_ufunc:
for ufunc_name, ufunc_method in obj.__dict__.items():
if _is_numpy_ufunc(ufunc_method):
tests += doctest.DocTestFinder.find(
self, ufunc_method, f'{name}.{ufunc_name}',
module=obj, globs=globs, extraglobs=extraglobs)

if hasattr(obj, '__doctest_skip__') or hasattr(obj, '__doctest_requires__'):
if name is None and hasattr(obj, '__name__'):
name = obj.__name__
else:
raise ValueError("DocTestFinder.find: name must be given "
"when obj.__name__ doesn't exist: {!r}"
.format((type(obj),)))

def test_filter(test):
for pat in getattr(obj, '__doctest_skip__', []):
Expand Down
3 changes: 3 additions & 0 deletions tests/test_doctestplus.py
Original file line number Diff line number Diff line change
Expand Up @@ -1033,4 +1033,7 @@ def foo():
build_dir, = glob.glob(str(testdir.tmpdir / 'build/lib.*'))

result = testdir.inline_run(build_dir, '--doctest-plus', '--doctest-modules')
result.assertoutcome(passed=1, failed=0)

result = testdir.inline_run(build_dir, '--doctest-plus', '--doctest-modules', '--doctest-ufunc')
result.assertoutcome(passed=2, failed=0)

0 comments on commit feea983

Please sign in to comment.