Skip to content

Fail CI on dead code and pytest 7.4 attribute hedges - #1

Closed
natevick wants to merge 3 commits into
mainfrom
cursor/correct-dead-code-and-hedges-8f63
Closed

natevick wants to merge 3 commits into
mainfrom
cursor/correct-dead-code-and-hedges-8f63

Conversation

@natevick

@natevick natevick commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Selective's Oct 22 simplicity pass (head 6fa455b) kept finding the same two habits: code nothing calls, and hedges around attributes pytest 7.4 already guarantees. This adds one CI check for each. Both fail on the review's example and pass once that example is fixed the way the review recommends.

selectiveci/selective-python-pytest pull request 1 from that review is gone (the API returned 404, and main is the only branch). The client on main already has the review's fixes for the stderr buffer, the dead plugin lookups, and the path / location / duration hedges. This draft targets main.

Dead code / no caller

Architecture cannot stop a later edit from adding an unread attribute, and vulture does not flag the review's buffer: append and len still count as uses, so stderr_lines is invisible at every confidence. The check is an AST scan (tools/check_dead_code.py). It treats assign, append, and a length cap as writes, and it also rejects finding #1's dead lookups (hasattr(..., "node_reporters"), try/except Exception: pass around get_plugin / stash.get, and get_plugin("html")).

Red, finding #4, buffer reintroduced into transport.py inside a copy of src/:

$ python3 tools/check_dead_code.py /tmp/proof2/src
/tmp/proof2/src/selective_pytest/transport.py:91: StdioTransport.stderr_lines is written and never read. Delete it. Nothing reads this attribute, so a capped buffer with no consumer is dead code (simplicity finding #4).
EXIT:1

Green, buffer deleted (the repo, and the review's stderr=subprocess.DEVNULL shape, which the same test locks):

$ python3 tools/check_dead_code.py
EXIT:0

Red, finding #1, the old junit/html lookups:

$ python3 tools/check_dead_code.py /tmp/proof2/junit_before.py
/tmp/proof2/junit_before.py:8: pluginmanager.get_plugin and config.stash.get return None and do not raise. Delete the try/except Exception (simplicity finding #1).
/tmp/proof2/junit_before.py:16: get_plugin('html') returns the pytest-html module, which has no _reports. Find HTMLReport by its _reports and _report attributes (simplicity finding #1).
/tmp/proof2/junit_before.py:11: hasattr(..., 'node_reporters') never matches. pytest>=7.0 keeps LogXML at config.stash.get(xml_key). Delete the duck scan (simplicity finding #1).
EXIT:1

Green, stash key plus the live _reports / _report scan:

$ python3 tools/check_dead_code.py /tmp/proof2/junit_after.py
EXIT:0

Defensive checks on what pytest guarantees

pyproject.toml already requires pytest>=7.4. mypy --strict does not flag getattr(item, "path", None) or a TypeError retry of teardown_exact; those calls type-check. The check is tools/check_pytest_contract.py. Its getattr error says to access the attribute directly because pytest>=7.4 guarantees it. The arity error says to call teardown_exact with one argument.

Red, findings #7 and #5:

$ python3 tools/check_pytest_contract.py /tmp/proof2/hedge_before.py
/tmp/proof2/hedge_before.py:17: call teardown_exact with one argument because pytest>=7.4 guarantees that signature. Do not catch TypeError to retry a pytest-6 arity (simplicity finding #5).
/tmp/proof2/hedge_before.py:3: to access the attribute directly because pytest>=7.4 guarantees it (path)
/tmp/proof2/hedge_before.py:9: to access the attribute directly because pytest>=7.4 guarantees it (location)
/tmp/proof2/hedge_before.py:14: to access the attribute directly because pytest>=7.4 guarantees it (duration)
EXIT:1

Green, direct access and teardown_exact(None) under except Exception (the review's finish_hooks):

$ python3 tools/check_pytest_contract.py /tmp/proof2/hedge_after.py
EXIT:0

The same check was red on main for four hedges of the same kind, and is green after this change:

  • item.name instead of getattr(item, "name", "")
  • report.failed and report.skipped instead of getattr(report, "failed"/"skipped", False)
  • report.nodeid instead of getattr(report, "nodeid", None)

getattr(item, "originalname", item.name) and the config.option hedges for xdist, stepwise, setuponly, and cov stay. Those attributes are not part of the pytest>=7.4 item/report contract. AGENTS.md marks them not enforced.

test (3.14, newest) is a pre-existing pytest 9.2 break

Head 672e711 failed that cell on both the push run and the pull_request run. Every other test and conformance cell passed. This PR does not touch item._nodeid = wired. The same assignment is on main (a6aae8d, plugin.py assigns _nodeid and the tests inject ids the same way).

Monday's scheduled run on main passed test (3.14, newest) because that job installed pytest 9.1.1: https://github.com/selectiveci/selective-python-pytest/actions/runs/40280624068

The integration cannot rerun that workflow (run 40280624068 cannot be rerun; Resource not accessible by integration). A push of main's tree (empty commit 8d34c16, tree f733f663, identical to a6aae8d) fails the same cell and no other: https://github.com/selectiveci/selective-python-pytest/actions/runs/40711705872

That job installed pytest 9.2.0. pytest 9.2 reads nodeid from _id, so assigning _nodeid no longer changes the id. Same lines as on 672e711:

pytest           9.2.0
FAILED tests/test_client.py::test_disable_forces_zero_and_skips_snapshot - AssertionError: ['tests/test_cases.py::test_case_pass', 'tests/test_cases.py::test_case_fail', 'tests/test_cases.py::test_case_pend', 'tests/test_cases.py::test_case_flake']
FAILED tests/test_client.py::test_long_duplicate_ids_stay_within_255 - assert False
FAILED tests/test_client.py::test_surrogate_nodeid_is_wire_safe - AssertionError: assert '~' in 'tests/test_sample.py::test_tax'
INTERNALERROR> KeyError: 'tests/test_filters.py::test_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'

Fourteen tests failed there, the same fourteen as on 672e711 (https://github.com/selectiveci/selective-python-pytest/actions/runs/40710016716). The nodeid workaround that was briefly on this branch is reverted. This draft does not paper over it.

Tests

tests/test_simplicity_checks.py locks the red and green shapes above. CI runs the same two commands in the lint job:

python3 tools/check_dead_code.py
python3 tools/check_pytest_contract.py
python3 -m pytest tests/test_simplicity_checks.py
Open in Web Open in Cursor 

cursoragent and others added 3 commits October 28, 2026 14:50
The Oct 22 simplicity pass found an unread stderr ring buffer and getattr
hedges on attributes pytest>=7.4 already guarantees. Vulture misses the
buffer because append and len count as uses, and mypy --strict does not
flag getattr-with-default. AST checks now fail on those examples and pass
once the buffer is deleted and the attributes are read directly.

Drop the remaining hedges that check still finds: item.name, report.failed,
report.skipped, and report.nodeid.

Co-authored-by: Nate Vick <natevick@users.noreply.github.com>
pytest 9.2 reads nodeid from _id. Assigning _nodeid no longer changes
the id, so the newest CI job collected the original ids and then
raised KeyError in _full_description. Write both fields, and do the
same in the tests that inject ids.

Co-authored-by: Nate Vick <natevick@users.noreply.github.com>
The newest-cell failure is on main too. pytest 9.2 reads nodeid from
_id, and main still assigns _nodeid. That is a new pytest release,
not this PR. Leave the breakage visible.

Co-authored-by: Nate Vick <natevick@users.noreply.github.com>
@natevick

natevick commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

Closing for now. We're keeping this guard only on vitest; we'll revisit if these patterns come back.

@natevick natevick closed this Nov 9, 2026
@natevick
natevick deleted the cursor/correct-dead-code-and-hedges-8f63 branch November 9, 2026 21:04
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.

2 participants