refactor: reference payloads become test fixtures, not package data (#162) - #166
Merged
Conversation
`reference_payloads` sat inside `src/span_panel_api/` and `packages/schema-1/src/span_panel_api_schema_1/`, so both wheels carried it — not through any packaging declaration, but because a directory inside a package directory ships. No runtime path read either capture, so every install of both distributions paid for 56 KB of test data it could not use, and the import surface committed each distribution to a promise it never meant to make. It shipped that way for a real reason: a vendored copy has no version, goes stale in silence, and a consumer's conformance gate then verifies its declarations against a schema no panel runs. The reason does not survive inspection. Detecting staleness never needed the file, only the version claim, and `importlib.metadata.version(...)` gives any consumer that without a checkout. A vendored copy that records the release it was taken from and asserts it against the installed distribution gets the loud failure the package data was protecting. Both captures move to `tests/reference_payloads/`, split the way the distributions were: `bootstrap` holds the homie schema document and imports nothing an adapter-less environment lacks, `schema_one` holds the retained-topic tree and the replay that reads it, which reaches the eBus SDK. Keeping the split means a test that wants the schema document does not drag the SDK in behind it. `devices_from_tree` / `device_from_topics` stay beside the capture for the reason they were written: separating them would put the same twelve lines of replay in each of the modules that read it. Imported as a top-level package, the same arrangement that makes `from conftest import ...` work throughout this suite. Two guards, because nothing declares what ships and so nothing would object to this recurring. `tests/test_packaging.py` fails if a capture reappears inside any shipped package, derived from the manifests rather than a hardcoded list; CI fails if any built wheel carries one, which is where it is finally true rather than inferred. A third resolves `spec_lock.json`'s recorded capture path, which nothing read before — the path went stale in this very change with nothing objecting. The mypy hook now checks `tests/reference_payloads/` alone out of `tests/`. Its five accessors were type-checked under --strict as package data and are read by twenty test modules; moving them should not quietly cost them that. Closes the library half of #162.
cayossarian
force-pushed
the
fix/162-fixtures-out-of-wheels
branch
from
August 26, 2026 05:34
051d72b to
48b64a4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #162.
Both distributions shipped a test fixture inside the runtime wheel — 56 KB of capture data that no runtime path reads, downloaded by every Home Assistant user installing this library. Verified before changing anything: nothing under
src/importsreference_payloads, in either distribution.Removing rather than adding
The issue proposed a separate fixtures distribution, pinned in lockstep. That works, but the cost is permanent: a fourth PyPI project, its own trusted publisher, a release cut in step with every adapter release, and a fourth pin for consumers to keep aligned. That is a standing obligation taken on to avoid 56 KB.
The alternative it ruled out was vendoring, on one specific ground recorded in
723e941:That objection is answerable. Detecting staleness never needed the file — only the version claim, which
importlib.metadatareports for an installed distribution with no checkout and no network call. A vendored copy that records the release it came from can be held against reality, and fail when the two disagree.So the payloads become ordinary repository fixtures under
tests/reference_payloads/, and the one external consumer vendors its own copy with that guard. Nothing needs publishing that did not already exist.Breaking
span_panel_api.reference_payloadsandspan_panel_api_schema_1.reference_payloadsare no longer importable from either distribution. Both changelogs say so plainly rather than describing this as a packaging tidy-up: anything importing those accessors breaks on upgrade. In practice that is one known consumer, which moves in the same change on its side.The accessors themselves are unchanged in behaviour and live beside the payloads they read —
devices_from_treeanddevice_from_topicsstay with the capture for the reason723e941gave for shipping them together, which has not changed: four test modules here otherwise hold the same twelve lines of replay.Asserted against the built artifact, not the source tree
These payloads shipped without any packaging declaration asking them to — a directory inside a package directory ships. Nothing in the manifests would object to that happening again, so the check has to look at what was actually built:
ci.ymlunzips every wheel indist/and fails if any carries areference_payloadspath component or a bare capture filename. It globs rather than naming the three known distributions, so an adapter added underpackages/is covered the day it exists, and it fails if no wheels were built at all rather than passing vacuously.tests/test_packaging.pycatches the same regression earlier, deriving both the capture names and the package list from disk and the manifests rather than hardcoding either. It also carries a test whose only job is to fail if manifest discovery finds fewer distributions than exist — a parametrised test whose parameter list silently empties is how a suite reports green while checking nothing.Verification
1081 passed / 7 skipped, mypy clean across 41 source files (down from 43 — two
__init__.pymodules leftsrc/, which is the move showing up in the type surface).Built all three wheels locally and confirmed none carries a payload.
Not published
Folds into the unreleased 3.1.0 — no version bump.