From 8d4bf9fba5aed6b8dde8f62b5362139f551cf8b9 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Sun, 2 Aug 2026 19:08:01 +1000 Subject: [PATCH 1/2] CI: Run docstring examples via pytest --doctest-modules Wires the docstring-example sweep from gh-866 into ci.yml so examples cannot silently rot again after the gh-864 fixes. A new quantecon/conftest.py resolves the two blockers raised in gh-866: - An autouse fixture restores NumPy print options after each test, so the game_theory examples that set precision=4 no longer leak process-global state into doctests collected later (previously 8 spurious failures in markov, optimize and random). - collect_ignore excludes util/notebooks.py (fetches over the network) and util/timing.py (prints wall-clock durations), keeping the rendered docs free of `# doctest: +SKIP` directives. The CI step runs on Linux only: one platform is enough to stop drift, and it sidesteps --ignore-glob path-separator issues on Windows. The DeprecationWarning from util/array.py::searchsorted needs no handling since no strict warning filter is configured. Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 7 +++++++ quantecon/conftest.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 quantecon/conftest.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2138b704..415caf83 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,6 +55,13 @@ jobs: shell: bash -l {0} run: | pytest quantecon + - name: Run docstring examples (doctest) + # one platform is enough to stop examples drifting, and keeping + # this off Windows avoids path-separator issues with --ignore-glob + if: runner.os == 'Linux' + shell: bash -l {0} + run: | + pytest --doctest-modules quantecon --ignore-glob='*/tests/*' coverage: name: Coverage diff --git a/quantecon/conftest.py b/quantecon/conftest.py new file mode 100644 index 00000000..ab5413be --- /dev/null +++ b/quantecon/conftest.py @@ -0,0 +1,33 @@ +""" +Pytest configuration for the ``--doctest-modules`` run (see gh-866). + +""" +import numpy as np +import pytest + +# These modules have docstring examples that cannot pass verbatim: +# `fetch_nb_dependencies` fetches over the network, and the `timing` +# examples print wall-clock durations that vary per run. Exclude them +# here rather than annotating the examples with `# doctest: +SKIP`, +# which would render visibly in the published docs. +collect_ignore = [ + "util/notebooks.py", + "util/timing.py", +] + + +@pytest.fixture(autouse=True) +def _restore_printoptions(): + """ + Restore NumPy print options after each test. + + Several `game_theory` docstring examples call + `np.set_printoptions(precision=4)` for readability and deliberately + do not restore it. Print options are process-global, so without + this fixture every doctest collected after those examples would + render arrays at the leaked precision and fail. + + """ + saved = np.get_printoptions() + yield + np.set_printoptions(**saved) From 0a7f0e7c0afe36f77a90559d9f7e43a728704564 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Mon, 3 Aug 2026 09:08:26 +1000 Subject: [PATCH 2/2] CI: move doctest conftest.py to the repository root qe_apidoc.py discovers Tools pages by globbing quantecon/[a-z0-9]*.py, so an in-package conftest.py would be picked up as a public module and fail the docs-drift check; the root location also keeps a module that imports pytest out of the installed wheel. Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 6 +++--- quantecon/conftest.py => conftest.py | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) rename quantecon/conftest.py => conftest.py (60%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 415caf83..20024113 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,14 +50,14 @@ jobs: - name: flake8 Tests shell: bash -l {0} run: | - flake8 --select=F401,F405,E231 quantecon + flake8 --select=F401,F405,E231 quantecon conftest.py - name: Run Tests (pytest) shell: bash -l {0} run: | pytest quantecon - name: Run docstring examples (doctest) - # one platform is enough to stop examples drifting, and keeping - # this off Windows avoids path-separator issues with --ignore-glob + # one platform is enough to stop examples drifting, and float + # reprs are the platform-sensitive part of doctest output if: runner.os == 'Linux' shell: bash -l {0} run: | diff --git a/quantecon/conftest.py b/conftest.py similarity index 60% rename from quantecon/conftest.py rename to conftest.py index ab5413be..9fb2fcc8 100644 --- a/quantecon/conftest.py +++ b/conftest.py @@ -1,6 +1,14 @@ """ Pytest configuration for the ``--doctest-modules`` run (see gh-866). +This lives at the repository root rather than inside the package on +purpose. `docs/qe_apidoc.py` discovers the "Tools" pages by globbing +``../quantecon/[a-z0-9]*.py``, so a `quantecon/conftest.py` would be +picked up as a public module and generate a docs page for itself, +failing the docs-drift check in CI. Keeping it here also keeps a +module that imports pytest -- not a runtime dependency -- out of the +installed wheel. + """ import numpy as np import pytest @@ -9,10 +17,11 @@ # `fetch_nb_dependencies` fetches over the network, and the `timing` # examples print wall-clock durations that vary per run. Exclude them # here rather than annotating the examples with `# doctest: +SKIP`, -# which would render visibly in the published docs. +# which would render visibly in the published docs. Paths are relative +# to this file, i.e. to the repository root. collect_ignore = [ - "util/notebooks.py", - "util/timing.py", + "quantecon/util/notebooks.py", + "quantecon/util/timing.py", ]