Test hygiene: dataset-loader timeouts, live test tiers, perf tests that can fail (#508, #510, #511) - #529
Conversation
…eout pd.read_csv(url) carries no timeout, so distillateflow() / oildoe() against a black-holing host blocked the caller indefinitely (#508). _read_remote_csv now fetches with urllib.request.urlopen(url, timeout=...) into a buffer and hands that to pandas. The default of 30 s lives on the config settings singleton as dataset_fetch_timeout, overridable via PROCESS_IMPROVE_DATASET_FETCH_TIMEOUT or a caller argument. Timeouts and URL errors still surface as the documented RuntimeError naming the URL. An on-disk cache stays out of scope. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
…8 assertions The tests in tests/perf/ contained no assertions, had no stored baseline, and pytest-benchmark disables itself under the default -n auto, so a 100x slowdown passed green while the docstrings claimed regression tracking (#511). Option 2 from the issue: assert the cost-shape properties the ENG-18 lazy-frame work actually needs protected. The public DataFrame views are built exactly once and then cached (identity plus a counted single build), pickling excludes the cache and the views rebuild correctly, repeated transform / predict / diagnose calls cause zero lazy-frame rebuilds, and check_random_state passes a Generator through by identity while resolving an int seed to a fresh generator with bit-identical draws. Verified the new tests fail when the _LazyFrame cache write is removed. CONTRIBUTING.md's performance-regression policy now describes this honestly; the ENG-15 wall-clock benchmark CI job stays planned. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
…imeError The loaders now wrap network failures (including timeouts) in the module's documented RuntimeError, so the offline skip helper must catch that too instead of failing when openmv.net is unreachable. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
The typecheck gate is red on main itself: the unpinned mcp dependency resolves to mcp 2.x, where FastMCP was renamed MCPServer, so mypy fails on src/process_improve/mcp_server.py. This ports the #528 fix verbatim (mcp_server.py plus the mcp>=2.0 pin in both pyproject.toml occurrences) so this PR's CI can pass on its own. It becomes a no-op once #528 merges; this PR's own version bump and CHANGELOG entries for #508/#510/#511 are in a separate commit. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
…d slow marks The tiers were documented but unused: -m 'not slow' deselected almost nothing and -m 'not dataset' still hit the network (#510). - pytest.ini addopts gains --strict-markers, so a typo'd marker is a collection error instead of a silent warning. - test_pca_foods in tests/test_multivariate.py, the one test fetching from openmv.net, now carries @pytest.mark.dataset; a tests/ sweep for urlopen / openmv / http found no other unmarked network fetches. - 42 tests measured at >= 5 s with --durations on this runner now carry @pytest.mark.slow (threshold is 2 s per CONTRIBUTING.md; the margin keeps the marks honest on faster machines). The two end-to-end tests crossing library boundaries (sensory pipeline, sklearn halving grid search) also carry @pytest.mark.integration. - Wall clock: full suite 6:15, -m 'not slow and not dataset' 1:32 on the same runner. - Both CI test jobs run plain pytest with no -m filter, so every tier still executes in CI. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
PATCH bump for the #508/#510/#511 test-hygiene fixes. CITATION.cff carries the same version and today's date-released; CHANGELOG.md gains the 1.73.4 section and updated link footer. The version assumes the earlier queued 1.73.x PRs merge first. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
…rtion CodeQL flags a self-comparison; two named reads assert the same cache-identity property without the identical-values pattern. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
…p test is deterministic test_budget_clamped_to_minimum_model_size fails intermittently because the pyoptex path never implemented the documented k + 1 budget floor; ported verbatim from #531, no-ops once it merges. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
|
The macOS failure on the previous head was Generated by Claude Code |
The dispatcher budget floor alone was not sufficient: the shortfall happens inside point_exchange, which could end below number_points on 1 to 2% of unseeded runs. Ported verbatim from #531; no-ops once it merges. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
Completes the earlier port: non-finite scores from a numerically singular X'X now read as unacceptable rather than unbeatable, which was the underlying freeze behind the run-count shortfall. No-ops once #531 merges. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
…e-library-issues-hr7xxk-testhygiene # Conflicts: # CHANGELOG.md # CITATION.cff # pyproject.toml
…e-library-issues-hr7xxk-testhygiene # Conflicts: # CHANGELOG.md # CITATION.cff # pyproject.toml
…e-library-issues-hr7xxk-testhygiene # Conflicts: # CHANGELOG.md # CITATION.cff # pyproject.toml
…e-library-issues-hr7xxk-testhygiene # Conflicts: # CHANGELOG.md # CITATION.cff # pyproject.toml
…e-library-issues-hr7xxk-testhygiene # Conflicts: # CHANGELOG.md # CITATION.cff # pyproject.toml
Summary
_read_remote_csvnow downloads with an explicit timeout viaurllib.request.urlopen(url, timeout=...)into a buffer handed to pandas, sodistillateflow()/oildoe()raise the documentedRuntimeError(naming the URL) against a black-holing host instead of hanging forever. The default of 30 s is a newdataset_fetch_timeoutknob on the config settings singleton, overridable viaPROCESS_IMPROVE_DATASET_FETCH_TIMEOUTor a caller argument. An on-disk cache was deliberately not added (out of scope; can be a follow-up).-m "not slow"skips nothing and-m "not dataset"still hits the network #510: the ENG-29 test tiers are now real.--strict-markersis on inpytest.ini(a typo'd marker is a collection error), the one network-fetching test (test_pca_foodsintests/test_multivariate.py) carries@pytest.mark.datasetso-m "not dataset"performs no network access (atests/sweep forurlopen/openmv/httpfound no other unmarked fetches), and 42 tests measured at >= 5 s via--durationsnow carry@pytest.mark.slow(threshold is 2 s per CONTRIBUTING.md; the margin keeps the marks honest on faster machines). Two end-to-end tests (sensory pipeline, sklearn halving grid search) also carry@pytest.mark.integration. Wall clock on this runner: full suite 6:15,-m "not slow and not dataset"1:32. Both CI test jobs run plain pytest with no-mfilter, so every tier still executes in CI.tests/perf/had zero assertions, no stored baseline, and pytest-benchmark disables itself under the default-n auto, so nothing could ever fail. Implemented the issue's option 2: they now assert the deterministic cost-shape properties the ENG-18_LazyFramework needs protected: the public DataFrame views are built exactly once and cached (identity plus a counted single build), pickling excludes_frame_cacheand the views rebuild correctly after unpickling, and repeatedtransform/predict/diagnosecalls cause zero lazy-frame rebuilds;check_random_statepasses aGeneratorthrough by identity and resolves anintseed to a fresh generator with bit-identical draws. Verified the new tests fail when the_LazyFramecache write is temporarily removed.CONTRIBUTING.md's performance-regression policy now describes this honestly; the ENG-15 wall-clock benchmark CI job stays planned, and no CI workflow was added.Also ports the mcp 2.x migration from #528 (
mcp_server.pyplus themcp>=2.0pin) in its own commit, so this PR's typecheck gate can be green; it becomes a no-op once #528 merges.Version is bumped to 1.73.4 (with
CITATION.cffandCHANGELOG.mdin sync); this assumes the earlier queued 1.73.x PRs merge first.Test plan
uv run pytest tests/test_experiments_datasets.py tests/test_sec10_path_and_fetch.py tests/perf/ --no-cov -q: 30 passed, 2 skipped (the two live openmv.net tests; that host is blocked by this environment's proxy, so they skip through the newRuntimeErrorpath, which is itself the Remote dataset loaders have no timeout: distillateflow() / oildoe() hang forever against a black-holing host #508 behaviour under test). All new timeout tests are monkeypatched, no real network.uv run pytest -m "not slow and not dataset" --no-cov -q: 2611 passed, 5 skipped in 1:32 with--strict-markerson.--no-cov, with all extras): 2701 passed, 8 skipped, 0 failed in 6:15. Local verification otherwise used targeted runs because this sandbox's proxy blocks openmv.net (the dataset host); CI runs the full matrix with the coverage gate._LazyFramecache write is temporarily removed..github/workflows/run-tests.ymlverified to run every tier (no-mfilter in either test job).uv run ruff check .,uv run ruff format --check ., anduv run mypy src/process_improveall pass.Checklist
pyproject.toml(PATCH for fixes/docs/config, MINOR for new features)ruff check .passesCHANGELOG.mdupdatedGenerated by Claude Code