Skip to content

msgspec tests crash with PYTHON_LAZY_IMPORTS=all on 3.15 #1095

Open

Description

@sobolevn

Refs #1090 (comment)

On the latest 3.15-dev I am using: PYTHON_LAZY_IMPORTS=all pytest -o testpaths=tests/unit --assert=plain -vv

It produces:

Current thread 0x000000020e02a0c0 (most recent call first):
  File "<string>", line 6 in <module>
  File "/Users/sobolev/Desktop/msgspec/tests/unit/utils.py", line 20 in temp_module
  File "/Users/sobolev/.pyenv/versions/3.15-dev/lib/python3.15/contextlib.py", line 203 in __enter__
  File "/Users/sobolev/Desktop/msgspec/tests/unit/test_struct.py", line 2608 in test_classvar
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/_pytest/python.py", line 167 in pytest_pyfunc_call
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/pluggy/_callers.py", line 121 in _multicall
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/pluggy/_manager.py", line 120 in _hookexec
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/pluggy/_hooks.py", line 512 in __call__
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/_pytest/python.py", line 1707 in runtest
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/_pytest/runner.py", line 184 in pytest_runtest_call
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/pluggy/_callers.py", line 121 in _multicall
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/pluggy/_manager.py", line 120 in _hookexec
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/pluggy/_hooks.py", line 512 in __call__
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/_pytest/runner.py", line 250 in <lambda>
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/_pytest/runner.py", line 361 in from_call
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/_pytest/runner.py", line 249 in call_and_report
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/_pytest/runner.py", line 139 in runtestprotocol
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/_pytest/runner.py", line 118 in pytest_runtest_protocol
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/pluggy/_callers.py", line 121 in _multicall
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/pluggy/_manager.py", line 120 in _hookexec
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/pluggy/_hooks.py", line 512 in __call__
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/_pytest/main.py", line 408 in pytest_runtestloop
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/pluggy/_callers.py", line 121 in _multicall
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/pluggy/_manager.py", line 120 in _hookexec
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/pluggy/_hooks.py", line 512 in __call__
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/_pytest/main.py", line 384 in _main
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/_pytest/main.py", line 330 in wrap_session
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/_pytest/main.py", line 377 in pytest_cmdline_main
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/pluggy/_callers.py", line 121 in _multicall
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/pluggy/_manager.py", line 120 in _hookexec
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/pluggy/_hooks.py", line 512 in __call__
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/_pytest/config/__init__.py", line 229 in _main
  File "/Users/sobolev/Desktop/msgspec/.venv/lib/python3.15/site-packages/_pytest/config/__init__.py", line 253 in _console_main
  File "/Users/sobolev/Desktop/msgspec/.venv/bin/pytest", line 10 in <module>

Current thread's C stack trace (most recent call first):
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at _Py_DumpStack+0x44 [0x1030620c4]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at faulthandler_fatal_error+0x210 [0x10307c370]
  Binary file "/usr/lib/system/libsystem_platform.dylib", at _sigtramp+0x38 [0x1a00d16a4]
  Binary file "/Users/sobolev/Desktop/msgspec/src/msgspec/_core.cpython-315-darwin.so", at structmeta_is_classvar+0x1c4 [0x10424ad3c]
  Binary file "/Users/sobolev/Desktop/msgspec/src/msgspec/_core.cpython-315-darwin.so", at structmeta_collect_fields+0x470 [0x104248de0]
  Binary file "/Users/sobolev/Desktop/msgspec/src/msgspec/_core.cpython-315-darwin.so", at StructMeta_new_inner+0x42c [0x104247bf8]
  Binary file "/Users/sobolev/Desktop/msgspec/src/msgspec/_core.cpython-315-darwin.so", at StructMeta_new+0x20c [0x1042900e4]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at type_call+0x54 [0x102f0eb70]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at _PyObject_MakeTpCall+0x130 [0x102e7a2fc]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at builtin___build_class__+0x640 [0x102fc120c]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at PyObject_Vectorcall+0x58 [0x102e7aa54]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at _Py_VectorCallInstrumentation_StackRefSteal+0x12c [0x102fc6ed4]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at _PyEval_EvalFrameDefault+0x19f4 [0x102fc9670]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at PyEval_EvalCode+0x1ac [0x102fc6734]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at run_mod+0x278 [0x103048fc8]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at _PyRun_StringFlagsWithName+0xfc [0x10304702c]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at builtin_exec+0x59c [0x102fc2e3c]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at _PyEval_EvalFrameDefault+0x2888 [0x102fca504]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at gen_send_ex+0x214 [0x102e97e40]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at gen_iternext+0x1c [0x102e96698]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at builtin_next+0x64 [0x102fc3cc8]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at _PyEval_EvalFrameDefault+0x25f4 [0x102fca270]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at _PyEval_Vector+0x20c [0x102fc697c]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at _PyObject_VectorcallPrepend+0xa8 [0x102e7bc34]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at _PyVectorcall_Call+0x74 [0x102e7a920]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at _PyEval_EvalFrameDefault+0x2b70 [0x102fca7ec]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at _PyEval_Vector+0x20c [0x102fc697c]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at _PyObject_VectorcallDictTstate+0x90 [0x102e7a0ac]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at _PyObject_Call_Prepend+0x98 [0x102e7b0a8]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at slot_tp_call+0x7c [0x102f168fc]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at _PyObject_MakeTpCall+0x130 [0x102e7a2fc]
  Binary file "/Users/sobolev/.pyenv/versions/3.15-dev/lib/libpython3.15.dylib", at _Py_VectorCall_StackRefSteal+0x114 [0x102fc6bb0]
  <truncated rest of calls>

Extension modules: msgspec._core, msgpack._cmsgpack (total: 2)
[1]    67332 segmentation fault  PYTHON_LAZY_IMPORTS=all pytest -o testpaths=tests/unit --assert=plain

The offending test: tests/unit/test_struct.py::TestClassVar::test_classvar[True-2]

@pytest.mark.parametrize("case", [1, 2, 3, 4, 5])
@pytest.mark.parametrize("future_annotations", [True, False])
def test_classvar(self, case, future_annotations):
source = getattr(self, f"case{case}")()
if future_annotations:
source = " from __future__ import annotations\n" + source
with temp_module(source) as mod:
assert mod.Ex.__struct_fields__ == ("a", "b")
assert mod.Ex.cv2 == 1

Not sure for now what is crashing: msgspec or CPython :)

Activity

  1. sobolevn commented on Jun 21, 2026

    @sobolevn
    MemberAuthor

    This is a msgspec issue:

    Repro:

    # ex.py
    from __future__ import annotations
    import typing
    from msgspec import Struct
    
    class Ex(Struct):
        a: int
        cv1: typing.ClassVar
        b: int
        cv2: typing.ClassVar[int] = 1

    Output after my initial fix:

    » PYTHON_LAZY_IMPORTS=all python ex.py
    Traceback (most recent call last):
      File "/Users/sobolev/Desktop/msgspec/ex.py", line 5, in <module>
        class Ex(Struct):
        ...<3 lines>...
            cv2: typing.ClassVar[int] = 1
    AttributeError: 'lazy_import' object has no attribute 'ClassVar'
    
  2. self-assigned this
    on Jun 21, 2026
  3. sobolevn commented on Jun 21, 2026

    @sobolevn
    MemberAuthor

    There's no clear API to work with lazy imports from the C code 🙈

    I can't even use PyLazyImport_CheckExact or PyLazyImport_Type because they are internal: https://github.com/python/cpython/blob/8270ae560c632f2ee88ab6c6b33562227d0deaae/Include/internal/pycore_lazyimportobject.h

    So, I would suggest using PyImport_ImportModule instead of

    if (*module_ns == NULL) {
        *module_ns = structmeta_get_module_ns(mod, info);
    }
    if (*module_ns == NULL) return 0;
    PyObject *temp = PyDict_GetItemString(*module_ns, "typing");

    there's no other way, as far as I understand 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions