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

51 lines
3.2 KiB
Markdown

# 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, `yield`s 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