Skip to content

fix: export SpanPanelAdapterIncompatibleError, correct the README badges (3.0.1) - #159

Merged
cayossarian merged 1 commit into
mainfrom
fix/export-adapter-incompatible
Aug 23, 2026
Merged

fix: export SpanPanelAdapterIncompatibleError, correct the README badges (3.0.1)#159
cayossarian merged 1 commit into
mainfrom
fix/export-adapter-incompatible

Conversation

@cayossarian

Copy link
Copy Markdown
Member

The defect

3.0.0 documented SpanPanelAdapterIncompatibleError as a top-level export in three places — this changelog, the README's error table (line 401), and SpanMqttClient.connect's own docstring, which names it as something the caller receives — but it was omitted from __init__.py:

SpanPanelAdapterMissingError        in __all__=1   getattr=True
SpanPanelSchemaVersionError         in __all__=1   getattr=True
SpanPanelAdapterIncompatibleError   in __all__=0   getattr=False

resolve_adapter raises it into caller hands (adapters.py:213, :222) rather than logging it, so a consumer following the documented API got an ImportError at exactly the point it was trying to handle a real failure. Its two siblings are in the same import block; this was an omission, not a design choice.

Purely additive — the class, its attributes and its raise sites are unchanged.

Why it shipped, and the guard that now catches it

test_public_api_unchanged.py pins __all__ against a hand-transcribed set. That catches the two drifting apart, but not a name missing from both — and the same omission was made in both places.

The new check derives the expected set from the module rather than transcribing it.

Falsified against the 3.0.0 state (both files reverted, new guard kept):

test_all_is_unchanged                    PASSED
test_every_exported_name_is_importable   PASSED
test_every_public_exception_is_exported  FAILED
  AssertionError: defined in span_panel_api.exceptions but not exported
  from the package: ['SpanPanelAdapterIncompatibleError'].

Both existing guards pass on the bug. Only the new one fires, and it names the class.

Badges

  • Release badge read schema-1-v1.0.0. github/v/release returns the newest tag by date, and this repository now publishes three distributions into one tag namespace, so it showed whichever released last. Now filtered on v*; verified it returns v3.0.0.
  • Python badge was hardcoded at 3.10+ — five minor versions below the real floor, for the whole of 3.0.0, because nothing connected it to requires-python. Now read from PyPI via pypi/pyversions, which needs the classifiers this adds. Verified in the built wheel.
  • Added version badges for both adapters. The repository ships three distributions and the header showed one.
  • The PyPI badge needed no change. It read v2.6.4 in the report that started this, but that was a stale CDN cache; shields already returns v3.0.0.

Version support

The old notice covered only the 1.x sunset, leaving 2.x looking current. It is closed to new work — the parent/child data model, adoption, discovery and extension properties all landed on 3.x — so the table says so, and spells out that 2.x → 3.x is an install rather than only an upgrade. Also dropped "v2" from the tagline.

Hot-loading accuracy

Step 1 now states what current firmware actually reports (the canonical 1.0) before describing the tolerant and rejecting branches, and the 1.0-beta example is gone from the README, the dispatch docstring and the changelog. Every replacement example was checked against select_adapter_key rather than read off the regex:

'1.0'   -> schema_1                      'v1.0'  -> RAISES
'1'     -> schema_1 (non-canonical)      'x'     -> RAISES
'1_0'   -> schema_1 (non-canonical)      None    -> schema_0 (flat)

Verification

20/20 hooks passed
936 passed, 11 skipped
Total coverage: 95.38%
wheel metadata: Version 3.0.1, Requires-Python <4.0,>=3.14, classifiers present

3.0.0 documented `SpanPanelAdapterIncompatibleError` as a top-level export
in three places -- this changelog, the README error table, and
`SpanMqttClient.connect`'s own docstring, which names it as something the
caller receives -- but omitted it from `__init__.py`. `resolve_adapter`
raises it into caller hands rather than logging it, so a consumer
following the documented API got an ImportError at exactly the point it
was trying to handle a real failure. Additive: the class, its attributes
and its raise sites are unchanged.

The reason it shipped is that the existing guard compares `__all__`
against a hand-transcribed set, so it catches the two drifting apart but
not a name missing from both -- and the same omission was made in both.
The new check derives the expected set from the module instead.
Falsified against the 3.0.0 state: both existing guards pass on the bug,
and only the new one fails, naming the class.

Badges: the release badge read `schema-1-v1.0.0`, because
`github/v/release` returns the newest tag by date and this repository
publishes three distributions from one tag namespace; it now filters on
`v*`. The Python badge was hardcoded at `3.10+` -- five minor versions
below the real floor -- so it is now read from PyPI, which needs the
classifiers this adds. Added version badges for both adapters, since the
repository ships three distributions and showed one. The PyPI badge
needed no change; it was showing a stale value from a CDN cache and has
since caught up on its own.

Version support: the notice covered only the 1.x sunset. 2.x is closed to
new work and every capability since 3.0.0 landed on 3.x, so the table now
says that rather than leaving 2.x looking current. Also dropped "v2" from
the tagline.
@cayossarian
cayossarian merged commit cee7b28 into main Aug 23, 2026
6 checks passed
@cayossarian
cayossarian deleted the fix/export-adapter-incompatible branch August 23, 2026 04:17
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