You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue was filed by claude-opus-5[1m] on behalf of @JPHutchins, who asked that the findings from the smpclient screaming-goblin kickoff session be recorded as issues for durable context. @JPHutchins corrected an earlier plan of mine to merely declare pydantic during the smp port — the intent is to drop it entirely.
smp's screaming-goblin moves off pydantic to msgspec, so pip install smp no longer pulls pydantic. smpclient never declared pydantic itself — it has been relying on it arriving transitively — and after the port the only thing still importing it is mcuboot.py.
Rather than declare a dependency we want gone, remove the need for it. This is non-breaking and independent of smp, so it can land on main before the port — then the port never has to mention pydantic at all.
@dataclass(frozen=True) × 6 — runtime validation of values that struct.Struct.unpack() has already produced as ints. ImageVersion.loads is the pattern: ImageVersion(*IMAGE_VERSION_STRUCT.unpack(data)).
The left-to-right union coercion — the one genuinely pydantic-specific behaviour:
Used at precisely one field (ImageTLVHeader.type) and one parameter (ImageInfo.get_tlv).
VendorTLV.__get_pydantic_core_schema__ — exists only to expose (2) to pydantic. The actual range check is already plain Python in VendorTLV.__new__.
Recommendation: stdlib dataclasses, not msgspec
msgspec would be the wrong tool here.mcuboot.py does no CBOR/JSON de/serialisation — struct.Struct does the binary parsing. Pulling in a serialisation library to do validation it doesn't need trades one dependency for another. Worse, IMAGE_TLV | VendorTLV | int is a union of three int-like types, which is exactly what msgspec cannot decode directly — smp hit this and had to decode as int and resolve afterwards.
ImageTLVType becomes a plain IMAGE_TLV | VendorTLV | int alias, and the coercion becomes an explicit, testable function applied at the parse boundary:
def_tlv_type(value: int) ->ImageTLVType:
"""Resolve a raw TLV type the way pydantic's left-to-right union did."""try:
returnIMAGE_TLV(value)
exceptValueError:
passtry:
returnVendorTLV(value)
exceptValueError:
returnvalue
That is strictly more explicit than a union-mode annotation, provable at the call site, and directly unit-testable with positive and negative cases — replacing implicit library behaviour with source that says what it does.
tests/test_mcuboot_tools.py also uses pydantic.TypeAdapter and will need the same treatment.
Done when
grep -r pydantic src tests is empty and pydantic appears nowhere in pyproject.toml.
Warning
LLM Disclosure
This issue was filed by
claude-opus-5[1m]on behalf of @JPHutchins, who asked that the findings from the smpclientscreaming-goblinkickoff session be recorded as issues for durable context. @JPHutchins corrected an earlier plan of mine to merely declare pydantic during the smp port — the intent is to drop it entirely.smp's
screaming-goblinmoves off pydantic to msgspec, sopip install smpno longer pulls pydantic. smpclient never declared pydantic itself — it has been relying on it arriving transitively — and after the port the only thing still importing it ismcuboot.py.Rather than declare a dependency we want gone, remove the need for it. This is non-breaking and independent of smp, so it can land on
mainbefore the port — then the port never has to mention pydantic at all.pydantic is load-bearing for exactly one thing
buys three things, and only the second is real:
@dataclass(frozen=True)× 6 — runtime validation of values thatstruct.Struct.unpack()has already produced as ints.ImageVersion.loadsis the pattern:ImageVersion(*IMAGE_VERSION_STRUCT.unpack(data)).ImageTLVHeader.type) and one parameter (ImageInfo.get_tlv).VendorTLV.__get_pydantic_core_schema__— exists only to expose (2) to pydantic. The actual range check is already plain Python inVendorTLV.__new__.Recommendation: stdlib dataclasses, not msgspec
msgspec would be the wrong tool here.
mcuboot.pydoes no CBOR/JSON de/serialisation —struct.Structdoes the binary parsing. Pulling in a serialisation library to do validation it doesn't need trades one dependency for another. Worse,IMAGE_TLV | VendorTLV | intis a union of three int-like types, which is exactly what msgspec cannot decode directly — smp hit this and had to decode asintand resolve afterwards.So:
pydantic.dataclasses.dataclass→dataclasses.dataclass(stdlib).__get_pydantic_core_schema__.ImageTLVTypebecomes a plainIMAGE_TLV | VendorTLV | intalias, and the coercion becomes an explicit, testable function applied at the parse boundary:That is strictly more explicit than a union-mode annotation, provable at the call site, and directly unit-testable with positive and negative cases — replacing implicit library behaviour with source that says what it does.
tests/test_mcuboot_tools.pyalso usespydantic.TypeAdapterand will need the same treatment.Done when
grep -r pydantic src testsis empty and pydantic appears nowhere inpyproject.toml.