|
3 | 3 |
|
4 | 4 | Extracts ``.. code-block:: python`` snippets from RST files and executes them |
5 | 5 | in isolated namespaces with synthetic data and mock dataset loaders. Fails on |
6 | | -all exceptions except NameError (context-dependent snippets). |
| 6 | +all exceptions except NameError (context-dependent snippets) and |
| 7 | +ImportError for known third-party packages (comparison-page snippets). |
7 | 8 | """ |
8 | 9 |
|
9 | 10 | import re |
@@ -100,6 +101,11 @@ def _extract_snippets(rst_path: Path) -> List[Tuple[int, str]]: |
100 | 101 | r"wide_to_long\(", # references undefined wide_data variable |
101 | 102 | ] |
102 | 103 |
|
| 104 | +# Third-party packages imported by comparison-page snippets that may not |
| 105 | +# be installed in the test environment. Only these are exempt from |
| 106 | +# ImportError failures — diff_diff and stdlib imports must succeed. |
| 107 | +_THIRD_PARTY_MODULES = {"pyfixest", "linearmodels", "differences"} |
| 108 | + |
103 | 109 |
|
104 | 110 | def _should_skip(code: str) -> Optional[str]: |
105 | 111 | """Return a reason string if the snippet should be skipped, else None.""" |
@@ -354,11 +360,18 @@ def test_doc_snippet(test_id: str, code: str, skip_reason: Optional[str]): |
354 | 360 | # context block (e.g. ``results`` from an earlier fit). This is |
355 | 361 | # expected for isolated execution — not an API mismatch. |
356 | 362 | pass |
357 | | - except ImportError: |
358 | | - # ImportError covers both ModuleNotFoundError (comparison pages |
359 | | - # importing pyfixest, linearmodels, etc.) and optional-dependency |
360 | | - # guards (e.g. matplotlib required for plotting functions). |
361 | | - pass |
| 363 | + except ImportError as exc: |
| 364 | + # Only suppress ImportError for known third-party packages that |
| 365 | + # comparison-page snippets import. In-package (diff_diff.*) and |
| 366 | + # stdlib import failures should still fail the test. |
| 367 | + mod_name = getattr(exc, "name", "") or "" |
| 368 | + top_level = mod_name.split(".")[0] |
| 369 | + if top_level not in _THIRD_PARTY_MODULES: |
| 370 | + pytest.fail( |
| 371 | + f"Snippet {test_id} raised ImportError for " |
| 372 | + f"'{mod_name}': {exc}\n\n" |
| 373 | + f"Code:\n{textwrap.indent(code, ' ')}" |
| 374 | + ) |
362 | 375 | except Exception as exc: |
363 | 376 | pytest.fail( |
364 | 377 | f"Snippet {test_id} raised {type(exc).__name__}: {exc}\n\n" |
|
0 commit comments