Skip to content

fix(tests): run offline with only the runtime requirements (the guard moves into conftest) - #13

Merged
memeshee merged 1 commit into
mainfrom
fix/tests-run-without-dev-deps
Nov 7, 2026
Merged

memeshee merged 1 commit into
mainfrom
fix/tests-run-without-dev-deps

Conversation

@memeshee

@memeshee memeshee commented Nov 7, 2026

Copy link
Copy Markdown
Owner

Why

The Nov 6 review ran pip install -r requirements.txt and then pytest, and the whole run died before collecting a test:

ERROR: usage: python -m pytest [options] [file_or_dir] [file_or_dir] [...]
python -m pytest: error: unrecognized arguments: --disable-socket --allow-hosts=127.0.0.1,localhost,::1
  inifile: pytest.ini

--disable-socket comes from the pytest-socket plugin, which is in requirements-dev.txt only. On a runtime-only install pytest refuses to start. ci.yml installs requirements-dev.txt, which is why CI was green on a suite that a reviewer could not run. Reproduced locally in a venv with requirements.txt + pytest, and it is fixed there: 275 passed, 13 deselected on Python 3.13, empty $HOME, no .env.

What changed

  • conftest.py — the offline guard is now stdlib: socket.connect, connect_ex and getaddrinfo are wrapped and raise OfflineViolation for anything outside loopback unless the test carries the network marker. No plugin, no ini flag.
  • pytest.ini — addopts = -m "not network". Nothing in it requires a dev-only package.
  • requirements-dev.txt — pytest-socket removed (unused now; supersedes chore(deps-dev): update pytest-socket requirement from >=0.7.1 to >=0.8.1 #11).
  • tests/test_offline_guard.py (new) — tests the mechanism, not the promise: DNS and connect are both refused unmarked, loopback and local bind still work, the marker lifts the guard, a clobbered wrapper is re-asserted.
  • ci.yml — new blocking reviewer-path job: runtime requirements + pytest only, bare pytest and python -m pytest, empty $HOME, plus the guard tests. This configuration can no longer go untested.
  • README — the Tests section now states the runtime-only install is sufficient, and why the guard left pytest.ini.

The part that needed a second look

Wrapping socket.connect was not enough. pytest-socket's per-test teardown restores the real C connect, so with the plugin installed the guard was silently disarmed after the first test — the DNS wrapper survived, the connect wrapper did not. The wrappers are captured once and re-asserted in pytest_runtest_setup, and there is a test for exactly that. Proved the guard still bites by stripping the network marker off a live-calling test: OfflineViolation: blocked DNS lookup for 'api.x402.celo.org'.

Verification

configuration result
runtime reqs + pytest only, Py 3.13, empty HOME, no .env 275 passed, 13 deselected
same, bare pytest from repo root 275 passed
same, read-only checkout 275 passed
dev reqs, --cov-fail-under=75 275 passed, 79.21%
ruff check . + compileall clean

A reviewer's sandbox installs `requirements.txt` and runs whatever `pytest` the
machine has. Our pytest.ini addopts passed `--disable-socket`, which only exists
when the `pytest-socket` plugin from requirements-dev.txt is installed, so on
that install pytest refused to start at all:

    ERROR: usage: python -m pytest [options] [file_or_dir] [...]
    python -m pytest: error: unrecognized arguments: --disable-socket
      --allow-hosts=127.0.0.1,localhost,::1

Not one test ran. CI stayed green because it installs requirements-dev.txt, so
the review reported "still failing tests" on a commit whose suite was fine.

The offline guarantee is now stdlib code in conftest.py: `socket.connect`,
`connect_ex` and `getaddrinfo` are wrapped and refuse anything outside loopback
until a `network`-marked test lifts them. Deps: pytest-socket is gone, nothing in
pytest.ini needs a dev-only package.

Two things that fix alone would not have caught:

- the wrappers are re-asserted in pytest_runtest_setup, because pytest-socket's
  per-test teardown restores the real `socket.connect` and had silently disarmed
  the guard partway through the run (found by testing the guard, not the suite);
- `reviewer-path` in ci.yml installs runtime requirements + pytest only and runs
  both `pytest` and `python -m pytest` with an empty $HOME, so this exact
  configuration can never go untested again.

tests/test_offline_guard.py tests the mechanism: DNS and connect are both
refused for an unmarked test, loopback still works, the marker lifts the guard,
and a clobbered wrapper is put back. Verified with 275 tests passing on Python
3.13 with only requirements.txt + pytest, empty HOME, no .env, read-only
checkout; plus ruff and the 79% coverage floor on the dev install.
@vercel

vercel Bot commented Nov 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
site Ready Ready Preview Nov 7, 2026 7:50pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
impay Ignored Ignored Nov 7, 2026 7:50pm UTC

@memeshee
memeshee merged commit 7aed877 into main Nov 7, 2026
8 checks passed
@memeshee
memeshee deleted the fix/tests-run-without-dev-deps branch November 7, 2026 19:53
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.

1 participant