Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .justfile
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ test-typing: (
env-run "test" "pyright tests/typing"
) (
env-run "test" "pyrefly check tests/typing"
) (
env-run "test"
"python -m mypy.stubtest msgspec --allowlist tests/typing/stubtest_allowlist.txt --ignore-unused-allowlist"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still advocate for the version-based allowlists, because otherwise we would have --ignore-unused-allowlist option enabled, which can hide problems :(

)

# Run doctests.
Expand Down
3 changes: 2 additions & 1 deletion src/msgspec/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ from typing import (
overload,
)

from typing_extensions import Buffer, Self, dataclass_transform
from typing_extensions import Buffer, Self, dataclass_transform, disjoint_base

from . import inspect, json, msgpack, structs, toml, yaml

Expand All @@ -26,6 +26,7 @@ from . import inspect, json, msgpack, structs, toml, yaml
# https://github.com/python/typeshed/blob/17bde1bd5e556de001adde3c2f340ba1c3581bd2/stdlib/abc.pyi#L14-L19
_SM = TypeVar("_SM", bound="StructMeta")

@disjoint_base
class StructMeta(type):
__struct_fields__: ClassVar[tuple[str, ...]]
__struct_defaults__: ClassVar[tuple[Any, ...]]
Expand Down
18 changes: 9 additions & 9 deletions src/msgspec/_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -9910,7 +9910,7 @@ encoder_encode_into_common(
}

PyDoc_STRVAR(Encoder_encode__doc__,
"encode(self, obj)\n"
"encode(self, obj, /)\n"
"--\n"
"\n"
"Serialize an object to bytes.\n"
Expand Down Expand Up @@ -13804,7 +13804,7 @@ static PyTypeObject Encoder_Type = {
};

PyDoc_STRVAR(msgspec_msgpack_encode__doc__,
"msgpack_encode(obj, *, enc_hook=None, order=None)\n"
"msgpack_encode(obj, /, *, enc_hook=None, order=None)\n"
"--\n"
"\n"
"Serialize an object as MessagePack.\n"
Expand Down Expand Up @@ -14880,7 +14880,7 @@ JSONEncoder_encode(Encoder *self, PyObject *const *args, Py_ssize_t nargs)
}

PyDoc_STRVAR(JSONEncoder_encode_lines__doc__,
"encode_lines(self, items)\n"
"encode_lines(self, items, /)\n"
"--\n"
"\n"
"Encode an iterable of items as newline-delimited JSON, one item per line.\n"
Expand Down Expand Up @@ -14986,7 +14986,7 @@ static PyTypeObject JSONEncoder_Type = {
};

PyDoc_STRVAR(msgspec_json_encode__doc__,
"json_encode(obj, *, enc_hook=None, order=None)\n"
"json_encode(obj, /, *, enc_hook=None, order=None)\n"
"--\n"
"\n"
"Serialize an object as JSON.\n"
Expand Down Expand Up @@ -16751,7 +16751,7 @@ mpack_decode(
}

PyDoc_STRVAR(Decoder_decode__doc__,
"decode(self, buf)\n"
"decode(self, buf, /)\n"
"--\n"
"\n"
"Deserialize an object from MessagePack.\n"
Expand Down Expand Up @@ -16834,7 +16834,7 @@ static PyTypeObject Decoder_Type = {


PyDoc_STRVAR(msgspec_msgpack_decode__doc__,
"msgpack_decode(buf, *, type='Any', strict=True, dec_hook=None, ext_hook=None)\n"
"msgpack_decode(buf, /, *, type='Any', strict=True, dec_hook=None, ext_hook=None)\n"
"--\n"
"\n"
"Deserialize an object from MessagePack.\n"
Expand Down Expand Up @@ -19723,7 +19723,7 @@ msgspec_json_format(PyObject *self, PyObject *args, PyObject *kwargs)


PyDoc_STRVAR(JSONDecoder_decode__doc__,
"decode(self, buf)\n"
"decode(self, buf, /)\n"
"--\n"
"\n"
"Deserialize an object from JSON.\n"
Expand Down Expand Up @@ -19780,7 +19780,7 @@ JSONDecoder_decode(JSONDecoder *self, PyObject *const *args, Py_ssize_t nargs)
}

PyDoc_STRVAR(JSONDecoder_decode_lines__doc__,
"decode_lines(self, buf)\n"
"decode_lines(self, buf, /)\n"
"--\n"
"\n"
"Decode a list of items from newline-delimited JSON.\n"
Expand Down Expand Up @@ -19911,7 +19911,7 @@ static PyTypeObject JSONDecoder_Type = {
};

PyDoc_STRVAR(msgspec_json_decode__doc__,
"json_decode(buf, *, type='Any', strict=True, dec_hook=None)\n"
"json_decode(buf, /, *, type='Any', strict=True, dec_hook=None)\n"
"--\n"
"\n"
"Deserialize an object from JSON.\n"
Expand Down
4 changes: 2 additions & 2 deletions src/msgspec/json.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,6 @@ def schema_components(
ref_template: str = "#/$defs/{name}",
) -> tuple[tuple[dict[str, Any], ...], dict[str, Any]]: ...
@overload
def format(buf: str, /, *, indent: int = 2) -> str: ...
def format(buf: str, *, indent: int = 2) -> str: ...
@overload
def format(buf: Buffer, /, *, indent: int = 2) -> bytes: ...
def format(buf: Buffer, *, indent: int = 2) -> bytes: ...
10 changes: 10 additions & 0 deletions src/msgspec/structs.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@ from typing import Any, TypeVar, final

from . import NODEFAULT, Struct

__all__ = (
"FieldInfo",
"StructConfig",
"asdict",
"astuple",
"fields",
"force_setattr",
"replace",
)

_S = TypeVar("_S", bound=Struct)

def replace(struct: _S, /, **changes: Any) -> _S: ...
Expand Down
26 changes: 26 additions & 0 deletions tests/typing/stubtest_allowlist.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Allowlist for `python -m mypy.stubtest msgspec`.
#
# Each entry is a regex matched against the fully-qualified name of a stubtest
# finding. Entries here are known false positives or intentional gaps; real
# stub/runtime drift should be fixed rather than added here.

# msgspec.Struct subclasses get a per-class __init__ synthesized in C. stubtest
# can't see through it, so every Struct subtype reports an __init__ mismatch
# against the generic stub. Same story for the C types with a custom __new__.
msgspec\.Struct\.__init__
msgspec\.Meta\.__init__
msgspec\.Meta\.__new__
msgspec\.structs\.FieldInfo\.__init__
msgspec\.inspect\..*\.__init__
msgspec\.msgpack\.Ext\.__init__
msgspec\.msgpack\.Ext\.__new__
msgspec\.UnsetType\.__new__

# Struct.__init_subclass__ is stubbed with the config kwargs (via
# dataclass_transform) so type checkers accept `class Foo(Struct, frozen=True)`.
# At runtime those kwargs are handled by the metaclass, so __init_subclass__
# itself takes none. Surfaces on Python 3.14+.
msgspec\.Struct\.__init_subclass__

# Private, intentionally unstubbed helper module.
msgspec\._utils\..*
Loading