|
| 1 | +# Upstream Doctest Backport Audit Report |
| 2 | + |
| 3 | +**Date:** 2025-11-25 |
| 4 | +**Audited Repositories:** |
| 5 | +- CPython doctest: `~/study/c/cpython/Lib/doctest.py` |
| 6 | +- pytest doctest plugin: `~/study/python/pytest/src/_pytest/doctest.py` |
| 7 | +- Sphinx doctest extension: `~/work/reStructuredText/sphinx/sphinx/ext/doctest.py` |
| 8 | + |
| 9 | +## Executive Summary |
| 10 | + |
| 11 | +After comprehensive audit of **115 commits** across all three upstream sources (CPython 27, pytest 35, Sphinx 53), **only 2 backports are needed**: |
| 12 | + |
| 13 | +1. pytest `9cd14b4ff` (2024-02-06) - Autouse fixtures fix |
| 14 | +2. Sphinx `ad0c343d3` (2025-01-04) - Regex whitespace fix |
| 15 | + |
| 16 | +### Key Architectural Insight |
| 17 | + |
| 18 | +**gp-libs' `DocutilsDocTestFinder` is NOT a subclass of `doctest.DocTestFinder`**. It's a completely different implementation: |
| 19 | +- Parses reStructuredText/Markdown documents using docutils/myst-parser |
| 20 | +- Extracts doctest blocks from markup nodes (not Python source inspection) |
| 21 | +- Uses `doctest.DocTestParser.get_doctest()` to create `DocTest` objects |
| 22 | +- Delegates test execution to standard `doctest.DocTestRunner` |
| 23 | + |
| 24 | +CPython fixes to `_from_module()`, `_find_lineno()`, and `_find()` don't apply because gp-libs doesn't use these methods. |
| 25 | + |
| 26 | +**Note:** The `_from_module()` method at lines 402-426 of `doctest_docutils.py` is dead code - it's never called and would fail if called (calls `super()._from_module()` but no parent class has this method). This could be cleaned up separately. |
| 27 | + |
| 28 | +--- |
| 29 | + |
| 30 | +## Backports Required (Chronological Order) |
| 31 | + |
| 32 | +### 1. pytest Autouse Fixtures Fix (2024-02-06) |
| 33 | + |
| 34 | +**Source:** pytest commit `9cd14b4ff` |
| 35 | +**GitHub:** https://github.com/pytest-dev/pytest/commit/9cd14b4ff |
| 36 | +**Issue:** pytest-dev/pytest#11929 |
| 37 | +**Type:** Bug Fix |
| 38 | + |
| 39 | +**Problem:** Autouse fixtures defined in `conftest.py` may not be picked up for doctest collection because `_nodeid_autousenames` is consulted at collection time before fixtures are parsed. |
| 40 | + |
| 41 | +**File:** `src/pytest_doctest_docutils.py` |
| 42 | + |
| 43 | +**Change:** Add after line ~307 in `DocTestDocutilsFile.collect()`: |
| 44 | +```python |
| 45 | +# While doctests in .rst/.md files don't support fixtures directly, |
| 46 | +# we still need to pick up autouse fixtures. |
| 47 | +# Backported from pytest commit 9cd14b4ff (2024-02-06). |
| 48 | +# https://github.com/pytest-dev/pytest/commit/9cd14b4ff |
| 49 | +self.session._fixturemanager.parsefactories(self) |
| 50 | +``` |
| 51 | + |
| 52 | +--- |
| 53 | + |
| 54 | +### 2. Sphinx Doctest Flag Regex Fix (2025-01-04) |
| 55 | + |
| 56 | +**Source:** Sphinx commit `ad0c343d3` |
| 57 | +**GitHub:** https://github.com/sphinx-doc/sphinx/pull/13164 |
| 58 | +**Type:** Bug Fix |
| 59 | + |
| 60 | +**Problem:** The `doctestopt_re` regex doesn't match leading whitespace before `# doctest:`, causing trailing whitespace in rendered output when flags are trimmed. |
| 61 | + |
| 62 | +**File:** `src/doctest_docutils.py` line 33 |
| 63 | + |
| 64 | +**Before:** |
| 65 | +```python |
| 66 | +doctestopt_re = re.compile(r"#\s*doctest:.+$", re.MULTILINE) |
| 67 | +``` |
| 68 | + |
| 69 | +**After:** |
| 70 | +```python |
| 71 | +doctestopt_re = re.compile(r"[ \t]*#\s*doctest:.+$", re.MULTILINE) |
| 72 | +``` |
| 73 | + |
| 74 | +--- |
| 75 | + |
| 76 | +## Comprehensive Commit Audit |
| 77 | + |
| 78 | +### CPython doctest.py (27 commits since 2022-01-01) |
| 79 | + |
| 80 | +| Date | Commit | Type | Description | Applicable? | Reason | |
| 81 | +|------|--------|------|-------------|-------------|--------| |
| 82 | +| 2025-07-25 | `fece15d29f2` | bug fix | cached functions lineno | NO | Uses `_find_lineno()` - gp-libs gets line numbers from docutils nodes | |
| 83 | +| 2025-07-15 | `cb59eaefeda` | docs | testmod docstring | NO | Documentation only | |
| 84 | +| 2025-05-31 | `ad39f017881` | feature | unittest subtests | AUTO | Uses `DocTestCase` - gp-libs uses pytest | |
| 85 | +| 2025-05-30 | `cb8a72b301f` | bug fix | unittest error report | AUTO | Uses `DocTestCase` - gp-libs uses pytest | |
| 86 | +| 2025-05-05 | `4ac916ae33b` | feature | argparse color | NO | Unrelated module | |
| 87 | +| 2025-01-20 | `6f167d71347` | refactor | color detection stdout | AUTO | Internal to `DocTestRunner` - inherited via stdlib | |
| 88 | +| 2024-09-24 | `af8403a58db` | feature | pdb commands arg | NO | Unrelated module | |
| 89 | +| 2024-05-22 | `ef172521a9e` | style | docstring backticks | NO | Documentation/style only | |
| 90 | +| 2024-05-01 | `3b3f8dea575` | refactor | colorize module move | AUTO | Internal refactoring - inherited via stdlib | |
| 91 | +| 2024-04-24 | `345e1e04ec7` | test | color test resilience | NO | Test changes only | |
| 92 | +| 2024-04-24 | `975081b11e0` | feature | color output | AUTO | `DocTestRunner` feature - inherited via Python 3.13+ | |
| 93 | +| 2024-04-10 | `4bb7d121bc0` | bug fix | wrapped builtin fix | NO | Uses `_find_lineno()` - gp-libs doesn't use this | |
| 94 | +| 2024-03-28 | `29829b58a83` | bug fix | skip reporting | AUTO | Uses `DocTestCase` - gp-libs uses pytest | |
| 95 | +| 2024-03-27 | `ce00de4c8cd` | style | pluralization | AUTO | `DocTestRunner.summarize()` - inherited via stdlib | |
| 96 | +| 2024-02-19 | `872cc9957a9` | bug fix | -OO mode fix | AUTO | Uses `DocTestCase` - gp-libs uses pytest | |
| 97 | +| 2024-02-14 | `bb791c7728e` | bug fix | decorated fn lineno | NO | Uses `_find_lineno()` - gp-libs doesn't use this | |
| 98 | +| 2023-12-15 | `8f8f0f97e12` | bug fix | property lineno | NO | Uses `_find_lineno()` - gp-libs doesn't use this | |
| 99 | +| 2023-11-25 | `fbb9027a037` | bug fix | DocTest.__lt__ None | AUTO | `DocTest` class - inherited via stdlib | |
| 100 | +| 2023-11-04 | `18c954849bc` | bug fix | SyntaxError subclass | AUTO | `DocTestRunner.__run()` - inherited via stdlib | |
| 101 | +| 2023-10-21 | `fd60549c0ac` | bug fix | exception notes | AUTO | `DocTestRunner.__run()` - inherited via stdlib | |
| 102 | +| 2023-09-02 | `4f9b706c6f5` | feature | skip counting | AUTO | `TestResults`/`DocTestRunner` - inherited via stdlib | |
| 103 | +| 2023-08-07 | `85793278793` | bug fix | regex escape class | NO | Uses `_find_lineno()` - gp-libs doesn't use this | |
| 104 | +| 2023-01-13 | `b5d43479503` | refactor | getframemodulename | NO | Internal CPython change | |
| 105 | +| 2022-12-30 | `79c10b7da84` | bug fix | MethodWrapperType | NO | Uses `_from_module()` - gp-libs doesn't call this | |
| 106 | +| 2022-05-19 | `8db2b3b6878` | bug fix | empty DocTest lineno | NO | Uses `_find_lineno()` - gp-libs doesn't use this | |
| 107 | +| 2022-03-22 | `7ba7eae5080` | bug fix | globs teardown | AUTO | Uses `DocTestCase` - gp-libs uses pytest | |
| 108 | +| 2022-01-08 | `0fc58c1e051` | refactor | CodeType simplify | NO | Uses `_find_lineno()` - gp-libs doesn't use this | |
| 109 | + |
| 110 | +**Summary:** 0 backports needed. 14 AUTO-inherited via stdlib, 13 NOT applicable. |
| 111 | + |
| 112 | +--- |
| 113 | + |
| 114 | +### pytest doctest.py (35 commits since 2022-01-01) |
| 115 | + |
| 116 | +| Date | Commit | Type | Description | Applicable? | Reason | |
| 117 | +|------|--------|------|-------------|-------------|--------| |
| 118 | +| 2025-09-12 | `bb712f151` | version | Drop Python 3.9 | NO | Version support change | |
| 119 | +| 2024-11-29 | `17c5bbbda` | style | %r specifiers | NO | Style fix - internal to pytest | |
| 120 | +| 2024-11-20 | `1bacc0007` | typing | re namespace | NO | Typing style - internal to pytest | |
| 121 | +| 2024-11-10 | `05ed0d0f9` | typing | deprecated-typing-alias | NO | Typing compat - internal to pytest | |
| 122 | +| 2024-11-10 | `a4cb74e86` | chore | CI after py3.8 drop | NO | CI/docs change | |
| 123 | +| 2024-08-29 | `c947145fb` | compat | typing.Self fix | NO | Typing compat - internal to pytest | |
| 124 | +| 2024-08-14 | `b08b41cef` | chore | pre-commit update | NO | Tooling update | |
| 125 | +| 2024-06-17 | `9295f9fff` | style | `__future__` annotations | CONSIDER | Style modernization - could match | |
| 126 | +| 2024-06-18 | `49374ec7a` | bug fix | patch condition fix | NO | `MockAwareDocTestFinder` - gp-libs uses `DocutilsDocTestFinder` | |
| 127 | +| 2024-06-07 | `f94109937` | refactor | finder cleanup | NO | `MockAwareDocTestFinder` - gp-libs uses `DocutilsDocTestFinder` | |
| 128 | +| 2024-05-27 | `48cb8a2b3` | chore | pre-commit update | NO | Tooling update | |
| 129 | +| 2024-04-30 | `4788165e6` | style | format specifiers | NO | Style fix - internal to pytest | |
| 130 | +| 2024-03-13 | `c0532dda1` | chore | pre-commit update | NO | Tooling update | |
| 131 | +| 2024-02-23 | `010ce2ab0` | typing | from_parent return types | AUTO | Typing - inherited via `DoctestItem` | |
| 132 | +| 2024-02-06 | `9cd14b4ff` | bug fix | autouse fixtures | **BACKPORT** | **DocTestDocutilsFile needs this!** | |
| 133 | +| 2024-02-06 | `6e5008f19` | refactor | module import | AUTO | `DoctestModule` - inherited for .py files | |
| 134 | +| 2024-01-31 | `4588653b2` | chore | migrate to ruff | NO | Tooling change | |
| 135 | +| 2024-01-28 | `878af85ae` | typing | disallow untyped defs | NO | Typing strictness - internal to pytest | |
| 136 | +| 2024-01-13 | `06dbd3c21` | refactor | conftest handling | AUTO | `DoctestModule` - inherited for .py files | |
| 137 | +| 2023-09-08 | `6ad9499c9` | typing | missing annotations | NO | Typing - internal to pytest | |
| 138 | +| 2023-09-08 | `2ed2e9208` | typing | remove Optionals | NO | Typing - internal to pytest | |
| 139 | +| 2023-09-08 | `ab63ebb3d` | refactor | inline _setup_fixtures | AUTO | `DoctestItem` - inherited | |
| 140 | +| 2023-09-08 | `b3a981d38` | refactor | fixture funcargs | AUTO | Fixture internals - inherited | |
| 141 | +| 2023-09-07 | `e787d2ed4` | merge | cached_property PR | AUTO | Merge commit | |
| 142 | +| 2023-09-01 | `82bd63d31` | feature | fixturenames field | AUTO | `DoctestItem` - inherited | |
| 143 | +| 2023-08-20 | `a357c7abc` | test | coverage ignore | NO | Test coverage change | |
| 144 | +| 2023-08-19 | `7a625481d` | review | PR suggestions | AUTO | Part of cached_property work | |
| 145 | +| 2023-08-19 | `ebd571bb1` | refactor | _from_module move | NO | `MockAwareDocTestFinder` - gp-libs uses different finder | |
| 146 | +| 2023-08-16 | `d4fb6ac9f` | bug fix | cached_property | NO | `MockAwareDocTestFinder` - gp-libs has own implementation | |
| 147 | +| 2023-07-16 | `9e164fc4f` | refactor | FixtureRequest abstract | AUTO | Fixture internals - inherited | |
| 148 | +| 2023-07-10 | `01f38aca4` | docs | fixture comments | NO | Documentation only | |
| 149 | +| 2023-02-07 | `59e7d2bbc` | chore | pre-commit update | NO | Tooling update | |
| 150 | +| 2022-10-07 | `8e7ce60c7` | typing | export DoctestItem | AUTO | **Authored by Tony Narlock** - typing export | |
| 151 | +| 2022-06-29 | `c34eaaaa1` | bug fix | importmode pass | AUTO | `DoctestModule` - inherited for .py files | |
| 152 | +| 2022-05-31 | `e54c6a136` | docs | code-highlight default | NO | Documentation only | |
| 153 | +| 2022-05-10 | `231e22063` | docs | docstrings move | NO | Documentation only | |
| 154 | +| 2022-01-31 | `9d2ffe207` | chore | pre-commit fixes | NO | Tooling update | |
| 155 | + |
| 156 | +**Summary:** 1 backport needed (`9cd14b4ff`). 12 AUTO-inherited, 22 NOT applicable. |
| 157 | + |
| 158 | +--- |
| 159 | + |
| 160 | +### Sphinx doctest.py (53 commits since 2022-01-01) |
| 161 | + |
| 162 | +| Date | Commit | Type | Description | Applicable? | Reason | |
| 163 | +|------|--------|------|-------------|-------------|--------| |
| 164 | +| 2025-09-01 | `14717292b` | bug fix | default group config | NO | Sphinx builder-specific | |
| 165 | +| 2025-06-07 | `3044d6753` | refactor | avoid self.app | NO | Sphinx builder-specific | |
| 166 | +| 2025-06-06 | `77a0d6658` | refactor | extract nested functions | NO | Sphinx builder-specific | |
| 167 | +| 2025-06-03 | `987ccb2a9` | style | str.partition | NO | Style - internal to Sphinx | |
| 168 | +| 2025-03-24 | `5831b3eea` | feature | doctest_fail_fast | NO | Already via pytest `-x` and `continue_on_failure` | |
| 169 | +| 2025-02-10 | `f96904146` | typing | config valid_types | NO | Sphinx config system | |
| 170 | +| 2025-01-22 | `2d41d43ce` | typing | no-any-generics | NO | Typing - internal to Sphinx | |
| 171 | +| 2025-01-16 | `a56fdad70` | refactor | colour module | NO | Sphinx console module | |
| 172 | +| 2025-01-14 | `c4daa95c0` | style | Ruff D category | NO | Linting rules | |
| 173 | +| 2025-01-13 | `f6d1665f8` | typing | frozensets | NO | Typing - internal to Sphinx | |
| 174 | +| 2025-01-12 | `72ce43619` | typing | runtime typing imports | NO | Typing - internal to Sphinx | |
| 175 | +| 2025-01-07 | `44aced1ab` | docs | confval directives | NO | Documentation only | |
| 176 | +| 2025-01-04 | `ad0c343d3` | bug fix | regex whitespace | **BACKPORT** | **doctestopt_re used directly!** | |
| 177 | +| 2025-01-02 | `b5f9ac8af` | style | RUF100 lint | NO | Linting rules | |
| 178 | +| 2024-12-17 | `01d993b35` | style | auto formatting | NO | Formatting only | |
| 179 | +| 2024-11-03 | `7801bd77b` | style | os.path absolute | NO | Import style | |
| 180 | +| 2024-10-19 | `e58dd58f3` | style | PLR6201 lint | NO | Linting rules | |
| 181 | +| 2024-10-10 | `d135d2eba` | typing | Builder.write final | NO | Sphinx builder-specific | |
| 182 | +| 2024-08-13 | `fadb6b10c` | bug fix | --fail-on-warnings | NO | Sphinx CLI-specific | |
| 183 | +| 2024-07-23 | `de15d61a4` | refactor | pathlib usage | NO | Sphinx project module | |
| 184 | +| 2024-07-22 | `9e3f4521d` | version | Drop Python 3.9 | NO | Version support change | |
| 185 | +| 2024-04-01 | `cb8a28dd7` | typing | color stubs | NO | Typing - internal to Sphinx | |
| 186 | +| 2024-03-23 | `22cee4209` | typing | types-docutils | NO | Typing stubs change | |
| 187 | +| 2024-03-22 | `6c92c5c0f` | chore | ruff version bump | NO | Tooling update | |
| 188 | +| 2024-03-21 | `d59b15837` | typing | ExtensionMetadata | NO | Typing - internal to Sphinx | |
| 189 | +| 2024-03-03 | `7f582a56b` | bug fix | resource leak | NO | Sphinx builder file handle - gp-libs doesn't have this | |
| 190 | +| 2024-02-01 | `aff95789a` | chore | Ruff 0.2.0 config | NO | Tooling update | |
| 191 | +| 2024-01-16 | `55f308998` | style | str.join | NO | Style - internal to Sphinx | |
| 192 | +| 2024-01-14 | `f7fbfaa47` | style | pydocstyle rules | NO | Linting rules | |
| 193 | +| 2024-01-03 | `259118d18` | typing | valid_types narrow | NO | Typing - internal to Sphinx | |
| 194 | +| 2024-01-03 | `19b295051` | typing | rebuild narrow | NO | Typing - internal to Sphinx | |
| 195 | +| 2023-08-13 | `f844055dd` | style | SIM115 context | NO | Style - internal to Sphinx | |
| 196 | +| 2023-08-13 | `9bcf1d8bb` | style | TCH001 import | NO | Import organization | |
| 197 | +| 2023-08-13 | `36012b7d9` | style | TCH002 import | NO | Import organization | |
| 198 | +| 2023-07-28 | `92e60b3f1` | typing | type:ignore params | NO | Typing - internal to Sphinx | |
| 199 | +| 2023-07-28 | `ff20efcd7` | refactor | show_successes tweaks | NO | Follow-up to show_successes feature | |
| 200 | +| 2023-07-28 | `aef544515` | feature | doctest_show_successes | NO | pytest handles verbosity natively | |
| 201 | +| 2023-07-25 | `ad61e4115` | version | Drop Python 3.8 | NO | Version support change | |
| 202 | +| 2023-07-23 | `4de540efb` | typing | strict optional | NO | Typing - internal to Sphinx | |
| 203 | +| 2023-02-17 | `c8f4a03da` | style | COM812 fix | NO | Linting rules | |
| 204 | +| 2023-01-02 | `4032070e8` | style | pyupgrade | NO | Style modernization - Sphinx specific | |
| 205 | +| 2023-01-01 | `14a9289d7` | style | PEP 604 types | CONSIDER | Style modernization - could match | |
| 206 | +| 2022-12-30 | `26f79b0d2` | style | PEP 595 types | NO | PEP 595 is about datetime | |
| 207 | +| 2022-12-30 | `f4c8a0a68` | style | `__future__` annotations | CONSIDER | Style modernization - could match | |
| 208 | +| 2022-12-29 | `7fb45a905` | style | bandit checks | NO | Security linting | |
| 209 | +| 2022-12-29 | `b89c33fc0` | style | pygrep-hooks | NO | Linting rules | |
| 210 | +| 2022-09-25 | `9ced73631` | bug fix | highlighting lexers | NO | Sphinx highlighting-specific | |
| 211 | +| 2022-09-08 | `ba548f713` | docs | is_allowed_version | NO | **Authored by Tony Narlock** - Different parameter order in gp-libs | |
| 212 | +| 2022-07-18 | `a504ac610` | typing | typing strictness | NO | Typing - internal to Sphinx | |
| 213 | +| 2022-03-24 | `a432bf8c1` | docs | PEP links | NO | Documentation only | |
| 214 | +| 2022-02-20 | `6bb7b891a` | style | copyright fields | NO | Style - internal to Sphinx | |
| 215 | +| 2022-02-20 | `b691ebcc3` | style | PEP 257 docstrings | NO | Docstring style | |
| 216 | +| 2022-02-20 | `5694e0ce6` | style | docstring indent | NO | Docstring style | |
| 217 | +| 2022-02-20 | `4f5a3269a` | style | docstring first line | NO | Docstring style | |
| 218 | +| 2022-02-19 | `6b8bccec5` | style | module titles | NO | Docstring style | |
| 219 | +| 2022-01-02 | `05a898ecb` | compat | Node.findall | NO | Already in `docutils_compat.py` | |
| 220 | + |
| 221 | +**Summary:** 1 backport needed (`ad0c343d3`). 0 AUTO-inherited, 52 NOT applicable. |
| 222 | + |
| 223 | +--- |
| 224 | + |
| 225 | +## Summary Statistics |
| 226 | + |
| 227 | +| Repository | Total Commits | Backport Needed | Auto-Inherited | Not Applicable | |
| 228 | +|------------|--------------|-----------------|----------------|----------------| |
| 229 | +| CPython | 27 | 0 | 14 | 13 | |
| 230 | +| pytest | 35 | 1 | 12 | 22 | |
| 231 | +| Sphinx | 53 | 1 | 0 | 52 | |
| 232 | +| **Total** | **115** | **2** | **26** | **87** | |
| 233 | + |
| 234 | +## Applicability Legend |
| 235 | + |
| 236 | +- **BACKPORT**: Needs to be manually backported to gp-libs |
| 237 | +- **AUTO**: Automatically inherited via stdlib/pytest dependency upgrades |
| 238 | +- **NO**: Not applicable to gp-libs architecture |
| 239 | +- **CONSIDER**: Optional style modernization (not a bug fix) |
| 240 | + |
| 241 | +## Optional: Style Modernization (Separate Effort) |
| 242 | + |
| 243 | +Some commits marked "CONSIDER" could be applied as style modernization: |
| 244 | +- `9295f9fff` (pytest) / `f4c8a0a68` (Sphinx): `from __future__ import annotations` - **Already in gp-libs** |
| 245 | +- `14a9289d7` (Sphinx): PEP 604 types (`X | Y` instead of `Union[X, Y]`) |
| 246 | + |
| 247 | +These are style choices, not bug fixes or API compatibility issues. |
0 commit comments