Skip to content

DOC: repo-wide documentation consistency audit - #864

Open
mmcky wants to merge 6 commits into
mainfrom
docs/consistency-audit
Open

DOC: repo-wide documentation consistency audit#864
mmcky wants to merge 6 commits into
mainfrom
docs/consistency-audit

Conversation

@mmcky

@mmcky mmcky commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

A systematic audit of the documentation surface — Sphinx sources, the apidoc generator, every docstring in the package, the repo-level prose docs, build config, and every hyperlink — together with the fixes it turned up. Opened as a draft: the diff is large, and one open question (#853) is deliberately left untouched.

Findings were verified against the code rather than taken at face value, and the resulting diff was reviewed again for regressions before this PR.

Highest-impact fixes

The published docs describe the wrong package. docs/source/conf.py put a cwd-relative path on sys.path. Sphinx runs from docs/, so it resolved to a directory that does not exist, and autodoc silently fell through to whatever quantecon happened to be installed in site-packages instead of the checkout. Read the Docs has therefore been publishing API docs generated from the installed wheel. The entry is now __file__-relative. Locally this changed the reported version in the built output from the installed 0.12.0 to the checkout's version.

quantecon.timings was documented nowhere. It is exported at top level and declares its own __all__, but grep -r timings docs/ returned zero hits. The generator now emits a Timings section, and the generated pages are committed.

A documented rebuild path was broken. qe_apidoc.py never created source/game_theory/game_generators/, so the make srcclean && python qe_apidoc.py sequence in docs/README.md crashed with FileNotFoundError. srcclean also silently skipped source/optimize, so a "clean" rebuild left stale pages.

Docstrings that contradict the code. robust_rule, robust_rule_simple and evaluate_F in _robustlq.py each documented a return order that does not match their return statement. nnash in _lqnash.py had the S1/S2 shapes swapped — the tests do not catch it because they use k_1 == k_2. Around 90 further parameter, return, default and type corrections follow, plus numpydoc structural fixes (a bare .. deprecated:: and a missing blank line before a list were both docutils errors, so those admonitions never rendered).

31 broken examples. A --doctest-modules sweep found examples showing output no supported NumPy produces (pre-1.14 array spacing), NumPy 2 scalar reprs, missing imports, and two outright NameErrors — including lorenz(), which does not exist. All 31 were fixed and each verified by running it.

Prose corrected against ground truth. The CI matrix (claimed 3.11–3.13, actually 3.12–3.14), the test count (claimed 536, actually 600), the README source-install block (ran flit install with no cd, so it could not work), the BibTeX entry (carried the Zenodo DOI on a JOSS @article), and around ten dead or redirecting URLs — two of which, lectures.quantecon.org and discourse.quantecon.org, are NXDOMAIN.

Please look closely at these two

Both are behaviour changes rather than documentation, and both are reasonable to push back on:

Change Why Risk
requires-python: >=3.7>=3.12 Matches the classifiers, the CI matrix and RTD. Stale since the 2022 flit migration. Narrows installability — users below 3.12 stop resolving new releases. Worth a line in the release notes.
Removed quantecon/util/common_messages.py Referenced nowhere (grep hits only its own definition), and it describes a graceful Numba fallback that no longer exists, since numba is a hard dependency and __init__.py hard-raises. It was importable, so this is an API removal.

Also included

Adds a docs job to CI. Nothing built the docs, which is precisely how the conf.py and srcclean breakage survived unnoticed. The job runs qe_apidoc.py and then git diff --exit-code -- docs/source, because RTD builds the committed .rst files and never runs the generator — regenerating without the drift check would pass green while RTD served stale pages. It builds without -W for now, since six warnings remain pending #853.

Fixes the unexpanded $default-branch starter-template token in ci_np2.yml, which meant that workflow's pull_request trigger never matched. Unpins sphinx<=6.2.1, added in #708 as a temporary workaround for #707, now closed — the pin held the docs on a 2023 Sphinx whose metadata tops out at Python 3.11 while RTD builds on 3.14. Deletes the dead docs/sphinxext/ (three vendored modules, all commented out of conf.py) and MANIFEST.in (names a nonexistent LICENSE.txt, and flit never reads it). The 21 deprecation shims said "will be removed v0.8.0"; v0.8.0 shipped in February 2025, so the wording is now version-agnostic — an actual removal schedule is a separate discussion.

Deliberately not addressed

The six autodoc warnings that remain are the open question in #853 and are untouched here. See #853 for new findings on it, including why emptying ce_util.__all__ is not a clean option.

Six game_theory docstrings call np.set_printoptions(precision=4) and never restore it. Harmless as rendered documentation, but under a package-wide doctest run it leaks into every module collected later. Left alone; tracked separately.

Validation

  • pytest quantecon — 600 passed, 2 pre-existing warnings
  • flake8 --select=F401,F405,E231 quantecon — clean
  • sphinx-build — succeeds, 6 warnings, all of them Six objects in the deprecated shims' __all__ are missing from the top-level quantecon namespace #853
  • Doctests per module in isolation — 83 of 85 modules clean. The two exceptions need the network and the wall clock respectively; they were left as-is rather than masked with # doctest: +SKIP, which would render visibly in the published docs.
  • qe_apidoc.py is idempotent and regenerates the committed .rst byte-for-byte, so the new CI drift gate passes.
  • An AST comparison with docstrings stripped confirms no executable code changed anywhere in quantecon/, apart from the shim deprecation strings and the removed module.

🤖 Generated with Claude Code

Systematic audit of the documentation surface (Sphinx sources, the apidoc
generator, package docstrings, repo prose, build config and hyperlinks),
plus the fixes it turned up.

Docs build
- conf.py put a cwd-relative path on sys.path. Sphinx runs from docs/, so it
  resolved to a nonexistent directory and autodoc fell through to whatever
  quantecon was installed in site-packages rather than the checkout. Read the
  Docs has therefore been publishing docs built from the installed wheel. Now
  __file__-relative.
- html_static_path = [''] copied the whole confdir (72 .rst files + conf.py)
  into the published _static/. Now [].
- Added numpy/scipy to intersphinx_mapping.

Generator
- qe_apidoc.py never created source/game_theory/game_generators/, so the
  documented `make srcclean && python qe_apidoc.py` rebuild crashed with
  FileNotFoundError; srcclean also skipped source/optimize.
- quantecon.timings is a top-level export that was documented nowhere. It now
  gets a generated section.

Docstrings
- robust_rule, robust_rule_simple and evaluate_F in _robustlq.py documented
  return orders that contradict their return statements.
- nnash in _lqnash.py had the S1/S2 shapes swapped; the tests miss it because
  they use k_1 == k_2.
- ~90 further parameter/return/default/type corrections, numpydoc structural
  fixes, and typo corrections across the package.

Examples
- A --doctest-modules sweep found 31 broken examples (stale pre-NumPy-1.14
  array spacing, NumPy 2 scalar reprs, missing imports, and two NameErrors).
  All 31 fixed and verified by execution. Per module in isolation, 83 of 85
  modules are now doctest-clean; the two exceptions need the network and the
  wall clock, and were left untouched rather than masked with doctest
  directives.

Prose and metadata
- CI matrix (was 3.11-3.13, actually 3.12-3.14), test count (was 536, actually
  600), the README source-install block (ran flit with no cd, so it failed),
  the BibTeX entry (carried the Zenodo DOI on a JOSS @Article), and ~10 dead or
  redirecting URLs including two NXDOMAIN hosts.
- The 21 deprecation shims said "will be removed v0.8.0"; v0.8.0 shipped in
  February 2025. Now version-agnostic. A removal schedule is a separate
  discussion.

Behaviour changes worth calling out in review
- requires-python: >=3.7 -> >=3.12, matching the classifiers, CI and RTD.
  This narrows installability.
- Removed quantecon/util/common_messages.py. It was referenced nowhere and
  described a Numba fallback that no longer exists, but it was importable.

Also adds a docs job to CI (nothing built the docs, which is how the conf.py
and srcclean breakage survived), fixes the unexpanded $default-branch token in
ci_np2.yml, unpins sphinx<=6.2.1 now that #707 is closed, and deletes the dead
docs/sphinxext/ and MANIFEST.in.

The six autodoc warnings that remain are the open question in #853 and are
deliberately untouched here. Refs #853.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mmcky

mmcky commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@oyamad I am working through my review of this so I have left this in draft for now. But it is looking like a good update.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR performs a repo-wide documentation consistency pass across Sphinx configuration, the apidoc generator, docstrings/doctest snippets, and repo prose docs, and also introduces a docs build job in CI to prevent future doc drift.

Changes:

  • Fixes Sphinx configuration so autodoc imports the in-repo quantecon (not an installed wheel) and improves cross-references via intersphinx.
  • Extends docs/qe_apidoc.py and committed .rst sources to include the quantecon.timings API, and fixes srcclean to fully remove generated sources.
  • Adds a docs CI job to regenerate + drift-check committed .rst sources and build HTML docs.

Reviewed changes

Copilot reviewed 99 out of 99 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
README.md Updates badges, links, install notes, citation
quantecon/util/timing.py Updates timeit docstring/examples (doctest risk)
quantecon/util/notebooks.py Clarifies docstring parameters/examples
quantecon/util/common_messages.py Removes unused module
quantecon/util/combinatorics.py Fixes doctest imports
quantecon/util/array.py Fixes deprecation directive + doc typos
quantecon/timings/timings.py Adds timings precision examples/output
quantecon/tests/util.py Updates reference URL
quantecon/tests/test_inequality.py Updates reference URL
quantecon/robustlq.py Updates deprecation shim wording
quantecon/rank_nullspace.py Updates deprecation shim wording
quantecon/random/utilities.py Fixes doctests + doc typos/clarifications
quantecon/random/init.py Documents/export draw
quantecon/quadsums.py Updates deprecation shim wording
quantecon/quad.py Fixes doc typos and clarifies parameters/returns
quantecon/optimize/tests/test_linprog_simplex.py Updates reference URL
quantecon/optimize/scalar_maximization.py Clarifies parameter defaults/order
quantecon/optimize/nelder_mead.py Improves docs + doctest stability
quantecon/optimize/linprog_simplex.py Fixes doc inconsistencies (phase flags etc.)
quantecon/optimize/lcp_lemke.py Stabilizes doctest output type
quantecon/matrix_eqn.py Updates deprecation shim wording
quantecon/markov/utilities.py Fixes doctest imports
quantecon/markov/random.py Fixes doctest formatting/imports
quantecon/markov/gth_solve.py Fixes doc typo (“jit-compiled”)
quantecon/markov/estimate.py Docstring formatting + adds missing parameter docs
quantecon/markov/ddp.py Clarifies max_iter semantics + adds method doc
quantecon/markov/core.py Doc clarifications + adds missing Parameters section
quantecon/markov/approximation.py Fixes parameter order text + doctest stability
quantecon/markov/_ddp_linprog_simplex.py Fixes doc typos/shape docs
quantecon/lss.py Updates deprecation shim wording
quantecon/lqnash.py Updates deprecation shim wording
quantecon/lqcontrol.py Updates deprecation shim wording
quantecon/lae.py Updates deprecation shim wording
quantecon/kalman.py Updates deprecation shim wording
quantecon/ivp.py Updates deprecation shim wording
quantecon/inequality.py Updates deprecation shim wording
quantecon/gridtools.py Updates deprecation shim wording
quantecon/graph_tools.py Updates deprecation shim wording
quantecon/game_theory/vertex_enumeration.py Fixes doctest imports/output stability
quantecon/game_theory/support_enumeration.py Fixes doctest imports
quantecon/game_theory/repeated_game.py Corrects return/shape docs
quantecon/game_theory/random.py Fixes “Returns” section header
quantecon/game_theory/pure_nash.py Fixes tol doc + doctest import
quantecon/game_theory/polymatrix_game.py Replaces placeholder docstring with full docs
quantecon/game_theory/normal_form_game.py Fixes doctest imports/formatting + doc clarity
quantecon/game_theory/mclennan_tourky.py Fixes doctest variable name + formatting
quantecon/game_theory/logitdyn.py Fixes parameter/attribute docs
quantecon/game_theory/lemke_howson.py Fixes doctest imports/output + adds return docs
quantecon/game_theory/game_generators/bimatrix_generators.py Normalizes doctest array formatting/imports
quantecon/game_theory/game_converters.py Adds missing Parameters/Returns blocks
quantecon/game_theory/fictplay.py Fixes doc typos and type docs
quantecon/filter.py Updates deprecation shim wording
quantecon/estspec.py Updates deprecation shim wording
quantecon/ecdf.py Updates deprecation shim wording
quantecon/dle.py Updates deprecation shim wording
quantecon/distributions.py Removes incorrect params + fixes return doc spacing
quantecon/discrete_rv.py Updates deprecation shim wording
quantecon/compute_fp.py Updates deprecation shim wording
quantecon/ce_util.py Updates deprecation shim wording
quantecon/arma.py Updates deprecation shim wording
quantecon/_robustlq.py Fixes return-order docs + type correction
quantecon/_rank_nullspace.py Fixes rank/nullspace definition text
quantecon/_quadsums.py Docstring cleanup + correct reference
quantecon/_matrix_eqn.py Docstring cleanup + default corrections
quantecon/_lss.py Fixes param name + doc typos
quantecon/_lqnash.py Fixes shape docs + typo
quantecon/_lqcontrol.py Fixes incorrect matrix description
quantecon/_lae.py Stabilizes doctest by checking shape
quantecon/_kalman.py Fixes typo + adds missing Returns docs
quantecon/_ivp.py Fixes class name refs + doc formatting
quantecon/_inequality.py Fixes doctest to call correct function
quantecon/_gridtools.py Fixes doctest imports/output stability + typos
quantecon/_graph_tools.py Fixes typo (“these”)
quantecon/_filter.py Fixes typo + wraps lines
quantecon/_dle.py Normalizes parameter names/types in docs
quantecon/_compute_fp.py Fixes docstring quoting typo
quantecon/_arma.py Fixes typo + adds missing Returns docs
pyproject.toml Raises requires-python to >=3.12
MANIFEST.in Removes unused MANIFEST.in
docs/sphinxext/only_directives.py Removes unused vendored extension
docs/sphinxext/ipython_directive.py Removes unused vendored extension
docs/sphinxext/ipython_console_highlighting.py Removes unused vendored extension
docs/source/util/common_messages.rst Removes docs page for deleted module
docs/source/util.rst Removes common_messages from toctree
docs/source/timings/timings.rst Adds committed timings API page
docs/source/timings.rst Adds timings section to docs
docs/source/setup.rst Updates PyPI + Git docs links
docs/source/index.rst Adds timings section + clarifies util content
docs/source/game_theory.rst Title-case section heading
docs/source/contributing.rst Replaces dead Discourse link with issue tracker
docs/source/conf.py Fixes sys.path import root + intersphinx mappings
docs/rtd-requirements.txt Unpins Sphinx version
docs/README.md Updates doc build instructions
docs/qe_apidoc.py Fixes generator dirs + adds timings section
docs/Makefile Fixes srcclean to remove more generated sources
CHANGELOG.md Fixes dates and removes dead link markup
.github/workflows/ci.yml Adds docs build + docs/source drift gate
.github/workflows/ci_np2.yml Fixes pull_request trigger branch
.github/copilot-instructions.md Updates repo guidance to match CI/docs reality
Comments suppressed due to low confidence (1)

quantecon/util/timing.py:350

  • This timeit(add_func, runs=2) example prints output but the docstring provides no expected output, so doctest will fail. Make the call silent (or add expected output with ellipsis).

Comment thread quantecon/util/timing.py

@oyamad oyamad left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found one issue to comment on while I was just browsing.

Comment thread quantecon/random/utilities.py
mmcky and others added 2 commits July 25, 2026 17:11
Addresses @oyamad's review on #864: seeding a doctest through NumPy's
global random state is not a convention we want in the published docs.

Replaces the `np.random.seed(1234)` in `draw` and the nine bare-int
`random_state=1234` arguments with an explicit
`rng = np.random.default_rng(1234)` passed as `random_state=rng`, so
every reproducible example in the package now uses the same modern
Generator-based pattern already used by `game_theory.random` and
`markov.approximation`.

`default_rng` seeds PCG64 via SeedSequence rather than the legacy
Mersenne Twister, so the streams differ and every expected output was
regenerated by running the example rather than by editing the old
values.

`random.draw` takes no `random_state` argument and draws from the
global state, so its example cannot be seeded this way. It now asserts
properties of the sample instead of exact values, with a Notes section
recording the limitation. Extending `draw` to accept a generator, as
suggested in review, is a behaviour change left for separate work.

Verified: 600 tests pass; doctests pass for all five modules that use a
generator in their examples; flake8 output unchanged from baseline.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coveralls

coveralls commented Jul 25, 2026

Copy link
Copy Markdown

Coverage Status

coverage: 90.562% (+0.02%) from 90.546% — docs/consistency-audit into main

@mmcky

mmcky commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

@oyamad 5e26642 implements your suggestion. The actual values change due to the change in underlying algorithm being used (despite the seed changing). Is this what you had in mind?

mmcky and others added 2 commits July 31, 2026 11:16
The Timer and timeit docstring examples show elapsed times that cannot
be reproduced exactly, so presenting them as literal expected output is
misleading. Note up front that the values are illustrative and vary with
machine and load.

Also:
- replace the fabricated "Average time: 0.0120 seconds" with a value the
  example actually produces
- show the output of the final timeit(add_func, runs=2) example, which
  prints but previously displayed nothing, unlike every other example in
  the same docstring
- add the missing "import time" so the snippets are copy-pasteable
- drop trailing whitespace on the touched lines

Addresses Copilot review feedback on #864.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread quantecon/random/utilities.py Outdated
Comment thread quantecon/random/utilities.py Outdated
The Notes block added in 63d784b was wrong in both halves. `draw` does
not always draw from NumPy's global random state -- under jit it draws
from Numba's separate internal state -- and its output can be made
reproducible, from either path:

  pure Python : np.random.seed(1234) at Python level
  jitted      : np.random.seed(1234) inside the jitted function

Both give [0 1 1 1 1 0 0 1 1 1] for size=10, stable across processes.
Numba's internal generator is Mersenne Twister, stream-compatible with
NumPy's legacy global state, so the two paths agree.

Because reproducibility is available, the property-checking example
(`draw(cdf) in (0, 1)`, `.shape`) is no longer needed and is replaced
with one that shows the values the function actually returns. The
scalar draw is wrapped in `int()` because the bare NumPy 2 repr is
`np.int64(0)`.

`np.random.seed` here is not the convention objected to in review:
`draw` accepts no `random_state`, so seeding is the only reproducibility
mechanism it has. Extending `draw` to accept a generator is tracked
separately.
@mmcky
mmcky marked this pull request as ready for review July 31, 2026 03:53
True
>>> qe.random.draw(cdf, 10).shape
(10,)
>>> np.random.seed(1234)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion, this is not a good convention. (We should not introduce doctest until #916 is implemented.)

>>> np.random.seed(1234)
>>> qe.random.draw(cdf, 10)
array([0, 1, 1, 1, 1, 0, 0, 1, 1, 1])
>>> int(qe.random.draw(cdf))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we encourage the users to use int()? (Is np.int64(0) something we want to avoid?)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I think an object repr is OK here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants