tests.test_doctests

PyDRex: Run doctests for all submodules.

 1"""> PyDRex: Run doctests for all submodules."""
 2
 3import doctest
 4import importlib
 5import os
 6import pkgutil
 7
 8import numpy as np
 9import pydrex
10import pytest
11from pydrex import logger as _log
12from pydrex.exceptions import Error
13
14
15def _get_submodule_list():
16    # Reset NumPy print options because doctests are just string matches, and typing out
17    # so many significant digits in doctests is annoying.
18    np.set_printoptions()
19    modules = ["pydrex." + m.name for m in pkgutil.iter_modules(pydrex.__path__)]
20    for module in modules:
21        try:
22            importlib.import_module(module)
23        except ModuleNotFoundError:
24            modules.remove(module)
25    return modules
26
27
28@pytest.mark.parametrize("module", _get_submodule_list())
29def test_doctests(module, capsys, verbose):
30    """Run doctests for all submodules."""
31    with capsys.disabled():  # Pytest output capturing messes with doctests.
32        _log.info("running doctests for %s...", module)
33        try:
34            n_fails, n_tests = doctest.testmod(
35                importlib.import_module(module),
36                raise_on_error=True,
37                verbose=verbose > 1,  # Run pytest with -vv to show doctest details.
38            )
39            if n_fails > 0:
40                raise AssertionError(
41                    f"there were {n_fails} doctest failures from {module}"
42                )
43        except doctest.DocTestFailure as e:
44            if e.test.lineno is None:
45                lineno = ""
46            else:
47                lineno = f":{e.test.lineno + 1 + e.example.lineno}"
48            raise AssertionError(
49                f"{e.test.name} ({module}{lineno}) failed with:"
50                + os.linesep
51                + os.linesep
52                + e.got
53            ) from None
54        except doctest.UnexpectedException as e:
55            if e.test.lineno is None:
56                lineno = ""
57            else:
58                lineno = f":{e.test.lineno + 1 + e.example.lineno}"
59            err_type, err, _ = e.exc_info
60            if err_type == NameError:  # Raised on missing optional functions.
61                # Issue warning but let the test suite pass.
62                _log.warning(
63                    "skipping doctest of missing optional symbol in %s", module
64                )
65            elif err_type == np.core._exceptions._ArrayMemoryError:
66                # Faiures to allocate should not be fatal to the doctest test suite.
67                _log.warning(
68                    "skipping doctests for module %s due to insufficient memory", module
69                )
70            else:
71                raise Error(
72                    f"{err_type.__qualname__} encountered in {e.test.name} ({module}{lineno})"
73                ) from err
@pytest.mark.parametrize('module', _get_submodule_list())
def test_doctests(module, capsys, verbose):
29@pytest.mark.parametrize("module", _get_submodule_list())
30def test_doctests(module, capsys, verbose):
31    """Run doctests for all submodules."""
32    with capsys.disabled():  # Pytest output capturing messes with doctests.
33        _log.info("running doctests for %s...", module)
34        try:
35            n_fails, n_tests = doctest.testmod(
36                importlib.import_module(module),
37                raise_on_error=True,
38                verbose=verbose > 1,  # Run pytest with -vv to show doctest details.
39            )
40            if n_fails > 0:
41                raise AssertionError(
42                    f"there were {n_fails} doctest failures from {module}"
43                )
44        except doctest.DocTestFailure as e:
45            if e.test.lineno is None:
46                lineno = ""
47            else:
48                lineno = f":{e.test.lineno + 1 + e.example.lineno}"
49            raise AssertionError(
50                f"{e.test.name} ({module}{lineno}) failed with:"
51                + os.linesep
52                + os.linesep
53                + e.got
54            ) from None
55        except doctest.UnexpectedException as e:
56            if e.test.lineno is None:
57                lineno = ""
58            else:
59                lineno = f":{e.test.lineno + 1 + e.example.lineno}"
60            err_type, err, _ = e.exc_info
61            if err_type == NameError:  # Raised on missing optional functions.
62                # Issue warning but let the test suite pass.
63                _log.warning(
64                    "skipping doctest of missing optional symbol in %s", module
65                )
66            elif err_type == np.core._exceptions._ArrayMemoryError:
67                # Faiures to allocate should not be fatal to the doctest test suite.
68                _log.warning(
69                    "skipping doctests for module %s due to insufficient memory", module
70                )
71            else:
72                raise Error(
73                    f"{err_type.__qualname__} encountered in {e.test.name} ({module}{lineno})"
74                ) from err

Run doctests for all submodules.