Skip to content

Commit 0f347bf

Browse files
Fix crash when TypedDict contains incorrect metadata (#853)
1 parent 5c11f01 commit 0f347bf

File tree

3 files changed

+28
-0
lines changed

3 files changed

+28
-0
lines changed

msgspec/_core.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8377,6 +8377,9 @@ TypedDictInfo_error_missing(TypedDictInfo *self, PyObject *dict, PathNode *path)
83778377
}
83788378
}
83798379
}
8380+
// Should be unreachable, but may happen if the TypedDict info
8381+
// is inconsistent.
8382+
assert(0);
83808383
}
83818384

83828385
static int

msgspec/_utils.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,13 @@ def get_typeddict_info(obj):
235235
hints[k] = v.__args__[0]
236236
else:
237237
hints[k] = v
238+
239+
# This can happen if there is a bug in the TypedDict implementation;
240+
# such a bug was present in Python 3.14.
241+
if not all(k in hints for k in required):
242+
raise RuntimeError(
243+
f"Required set {required} contains keys that are no in hints: {hints.keys()}"
244+
)
238245
return hints, required
239246

240247

tests/test_common.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2112,6 +2112,24 @@ class Ex(Base, total=False):
21122112
dec.decode(proto.encode({"b": "two"}))
21132113
assert "Object missing required field `a`" == str(rec.value)
21142114

2115+
@pytest.mark.parametrize("use_typing_extensions", [False, True])
2116+
def test_broken_typeddict(self, proto, use_typing_extensions):
2117+
# Check that we don't crash if a TypedDict has incorrect
2118+
# introspection data.
2119+
if use_typing_extensions:
2120+
tex = pytest.importorskip("typing_extensions")
2121+
cls = tex.TypedDict
2122+
else:
2123+
cls = TypedDict
2124+
2125+
class Ex(cls, total=False):
2126+
c: str
2127+
Ex.__annotations__ = {"c": "str"}
2128+
Ex.__required_keys__ = {"a", "b"}
2129+
2130+
with pytest.raises(RuntimeError):
2131+
proto.Decoder(Ex)
2132+
21152133
@pytest.mark.parametrize("use_typing_extensions", [False, True])
21162134
def test_required_and_notrequired(self, proto, use_typing_extensions):
21172135
if use_typing_extensions:

0 commit comments

Comments
 (0)