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
~110 (85%) are one structural false positive: stubtest can't see through the C-level __init__/__new__ signatures synthesized for Struct subclasses and for the Meta/Ext/UnsetType C types (70 come from the Struct subclasses in inspect.py alone). These want an allowlist, not a fix.
The remaining ~20 are actionable:
msgspec.structs.__all__ is not present in the stub.
11 public json/msgpack callables (decode, encode, decode_lines, encode_lines, json.format, and the Decoder/Encoder methods) mark their first arg positional-only (/) in the stub, but the runtime accepts it as a keyword. Either the stub drops / or the runtime is made positional-only, needs a call.
7 private msgspec._utils helpers leak into the check (no .pyi); simplest is to exclude _utils.
So the real signal is ~13 items behind a roughly 10-line allowlist, with 85% of the raw output being one repeated false positive.
This is exactly the stub/runtime drift the spring stub PRs fixed manually (#1043@final/@disjoint_base, #1062 missing __class_getitem__), so wiring it into CI should stop that recurring. mypy is already in the test-typing group, so no new dependency.
Happy to open a PR adding a stubtest step to the test-typing job with an allowlist plus the fixes above. @sobolevn does that split sound right, and any preference on the positional-only mismatch (relax the stubs vs make the runtime positional-only)?
Please, go ahead with the PR :)
We must always prefer the real function over the typing one.
Because some people might not use typing and use the keyword form for the call, if we replace it with posonly parameter, it will be a breaking change for them. But, allowing pos-or-keyword calls in the existing functions / methods is a new feature.
Activity
Siyet commentedon Jul 4, 2026
Agreed this is worth adding. I ran
stubtestagainst currentmain(mypy 2.1.0) to see where we stand:Breakdown:
__init__/__new__signatures synthesized forStructsubclasses and for theMeta/Ext/UnsetTypeC types (70 come from theStructsubclasses ininspect.pyalone). These want an allowlist, not a fix.msgspec.structs.__all__is not present in the stub.msgspec.StructMetais a disjoint base at runtime but isn't marked@disjoint_basein the stub (same class of drift Annotate types withoutPy_TPFLAGS_BASETYPEas@final#1043 fixed by hand).json/msgpackcallables (decode,encode,decode_lines,encode_lines,json.format, and theDecoder/Encodermethods) mark their first arg positional-only (/) in the stub, but the runtime accepts it as a keyword. Either the stub drops/or the runtime is made positional-only, needs a call.msgspec._utilshelpers leak into the check (no.pyi); simplest is to exclude_utils.So the real signal is ~13 items behind a roughly 10-line allowlist, with 85% of the raw output being one repeated false positive.
This is exactly the stub/runtime drift the spring stub PRs fixed manually (#1043
@final/@disjoint_base, #1062 missing__class_getitem__), so wiring it into CI should stop that recurring.mypyis already in thetest-typinggroup, so no new dependency.Happy to open a PR adding a stubtest step to the
test-typingjob with an allowlist plus the fixes above. @sobolevn does that split sound right, and any preference on the positional-only mismatch (relax the stubs vs make the runtime positional-only)?sobolevn commentedon Jul 4, 2026
Please, go ahead with the PR :)
We must always prefer the real function over the typing one.
Because some people might not use typing and use the keyword form for the call, if we replace it with posonly parameter, it will be a breaking change for them. But, allowing pos-or-keyword calls in the existing functions / methods is a new feature.
Run stubtest in the type-checking CI job (msgspec#1116)