Files
2026-06-01 21:42:05 +00:00

3.2 KiB

Pytest source notes

Repo: pytest-dev/pytest Local checkout: /home/ubuntu/repos/rodin-sources/pytest

Why this repo is useful

  • Pytest is a strong source for package-facade patterns and lifecycle-heavy test helper patterns.
  • It is especially useful because the public package is deliberately small compared to the internal _pytest.* implementation tree.

The public package is a curated facade over internal modules

Repeated evidence

  • src/pytest/__init__.py:6-92 re-exports the supported testing API from many _pytest.* implementation modules.
  • src/pytest/__init__.py:98-186 defines __all__ explicitly, turning the package root into a maintained public surface.
  • src/pytest/__init__.py:23-30 includes compatibility-minded exports like yield_fixture, showing that the facade also absorbs historical API pressure.

Why it matters

Repeated signal: large libraries can keep internal structure fluid while giving users one stable import surface. The top-level package behaves like an API contract, not just a mirror of file layout.

Caveat / counterexample

This pattern does create maintenance pressure: once the facade exports a name, deprecating or removing it becomes a public compatibility event. Pytest accepts that tradeoff intentionally.

Fixture cleanup is modeled as an explicit lifetime boundary

Repeated evidence

  • testing/test_monkeypatch.py:17-23 defines a fixture that snapshots global state, yields the resource, then restores state after the test.
  • testing/test_threadexception.py:84-90 uses a yield fixture where the teardown action intentionally runs after test execution.
  • doc/en/how-to/fixtures.rst:551-553 marks yield fixtures as the recommended path.
  • doc/en/how-to/fixtures.rst:669-677 contrasts them with addfinalizer, explicitly framing finalizers as the alternative when needed.

Why it matters

Repeated signal: pytest prefers resource lifetime that is legible in source order: setup before yield, teardown after yield. That shape scales better than hidden cleanup hooks.

Caveat / counterexample

request.addfinalizer(...) still exists for cases where teardown must be registered dynamically, but pytest's own docs present it as the less straightforward option. That is important evidence that yield fixtures are the convention, not just one possible style.

Failure expectations are explicit context boundaries

Repeated evidence

  • testing/test_monkeypatch.py:31-32, testing/test_monkeypatch.py:50-51, and testing/test_monkeypatch.py:76-85 repeatedly use with pytest.raises(...) around the exact failing operation.
  • testing/acceptance_test.py:513-514 and testing/test_pluginmanager.py:254-255 show the same shape in broader integration tests.

Why it matters

Repeated signal: pytest encourages failure expectations that wrap the smallest relevant operation, keeping the expected failure boundary local and visible.

Pattern candidates supported by this repo

  • expose a stable top-level facade over private implementation packages
  • use explicit __all__/re-export curation for public APIs
  • model test resource lifetime with yield fixtures
  • express expected failures with tight context-manager boundaries