diff --git a/Doc/library/concurrent.interpreters.rst b/Doc/library/concurrent.interpreters.rst index 2c509ab13a6acfd..bfbb12624e7d62c 100644 --- a/Doc/library/concurrent.interpreters.rst +++ b/Doc/library/concurrent.interpreters.rst @@ -189,6 +189,7 @@ objects are either directly shared or copied efficiently. For example: * :class:`str` * :class:`int` * :class:`float` +* :class:`complex` * :class:`tuple` (of similarly supported objects) There are a small number of Python types that actually share mutable diff --git a/Lib/test/test__interpreters.py b/Lib/test/test__interpreters.py index ec5a26bc1c05ad8..b37e2261079c878 100644 --- a/Lib/test/test__interpreters.py +++ b/Lib/test/test__interpreters.py @@ -104,6 +104,7 @@ def test_default_shareables(self): True, False, 100.0, + 1+2j, (1, ('spam', 'eggs')), ] for obj in shareables: @@ -603,6 +604,7 @@ def test_shareable_types(self): 'spam', b'spam', 42, + 1+2j, ] for obj in objects: with self.subTest(obj): diff --git a/Lib/test/test_crossinterp.py b/Lib/test/test_crossinterp.py index f4bf5a66ad21550..c298570373ddc44 100644 --- a/Lib/test/test_crossinterp.py +++ b/Lib/test/test_crossinterp.py @@ -124,6 +124,10 @@ def ignore_byteswarning(): -1.0, 0.12345678, -0.12345678, + # complex + 0j, + 1+2j, + -1-2j, ] TUPLE_EXCEPTION = (0, 1.0, EXCEPTION) TUPLE_OBJECT = (0, 1.0, OBJECT) @@ -1326,6 +1330,9 @@ def test_float(self): -0.12345678, ]) + def test_complex(self): + self.assert_roundtrip_equal([0j, 1+2j, -1-2j, 1.5+2.5j]) + def test_tuple(self): self.assert_roundtrip_equal([ (), diff --git a/Lib/test/test_interpreters/test_api.py b/Lib/test/test_interpreters/test_api.py index aac3cdd717668ca..4b9d88f50647bde 100644 --- a/Lib/test/test_interpreters/test_api.py +++ b/Lib/test/test_interpreters/test_api.py @@ -1306,6 +1306,7 @@ def test_stateless_func_returns_arg(self): for arg in [ None, 10, + 1+2j, 'spam!', b'spam!', (1, 2, 'spam!'), @@ -1903,6 +1904,7 @@ def test_default_shareables(self): True, False, 100.0, + 1+2j, (), (1, ('spam', 'eggs'), True), ] diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-06-22-43-15.gh-issue-157047.ecyJp1.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-06-22-43-15.gh-issue-157047.ecyJp1.rst new file mode 100644 index 000000000000000..2e987f6fb0573f3 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-06-22-43-15.gh-issue-157047.ecyJp1.rst @@ -0,0 +1 @@ +Added support for sharing of :class:`complex` type with interpreters API. diff --git a/Python/crossinterp_data_lookup.h b/Python/crossinterp_data_lookup.h index 54422ad2335cb62..06c7fcfdeb77b0d 100644 --- a/Python/crossinterp_data_lookup.h +++ b/Python/crossinterp_data_lookup.h @@ -555,6 +555,30 @@ _float_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *xidata) return 0; } +// complex + +static PyObject * +_new_complex_object(_PyXIData_t *xidata) +{ + Py_complex *value_ptr = xidata->data; + return PyComplex_FromCComplex(*value_ptr); +} + +static int +_complex_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *xidata) +{ + if (_PyXIData_InitWithSize( + xidata, tstate->interp, sizeof(Py_complex), NULL, + _new_complex_object + ) < 0) + { + return -1; + } + Py_complex *shared = (Py_complex *)xidata->data; + *shared = PyComplex_AsCComplex(obj); + return 0; +} + // None static PyObject * @@ -825,6 +849,11 @@ _register_builtins_for_crossinterpreter_data(dlregistry_t *xidregistry) Py_FatalError("could not register float for cross-interpreter sharing"); } + // complex + if (REGISTER(&PyComplex_Type, _complex_shared) != 0) { + Py_FatalError("could not register complex for cross-interpreter sharing"); + } + // tuple if (REGISTER_FALLBACK(&PyTuple_Type, _tuple_shared) != 0) { Py_FatalError("could not register tuple for cross-interpreter sharing");