diff --git a/Lib/test/test__interpreters.py b/Lib/test/test__interpreters.py index fd444f1f06ce48..3c8f22402a4d69 100644 --- a/Lib/test/test__interpreters.py +++ b/Lib/test/test__interpreters.py @@ -99,6 +99,7 @@ def test_default_shareables(self): shareables = [ # singletons None, + NotImplemented, # builtin objects b'spam', 'spam', @@ -126,7 +127,6 @@ class SubBytes(bytes): not_shareables = [ # singletons - NotImplemented, ..., # builtin types and objects type, @@ -156,13 +156,14 @@ def _assert_values(self, values): self.assertIs(type(got), type(obj)) def test_singletons(self): - for obj in [None]: + for obj in [None, NotImplemented]: with self.subTest(obj): xid = _testinternalcapi.get_crossinterp_data(obj) got = _testinternalcapi.restore_crossinterp_data(xid) # XXX What about between interpreters? self.assertIs(got, obj) + self.assertIs(type(got), type(obj)) def test_types(self): self._assert_values([ diff --git a/Lib/test/test_interpreters/test_api.py b/Lib/test/test_interpreters/test_api.py index 01856d9bf67657..4fa7b63b7b0ea9 100644 --- a/Lib/test/test_interpreters/test_api.py +++ b/Lib/test/test_interpreters/test_api.py @@ -1101,6 +1101,7 @@ def test_default_shareables(self): shareables = [ # singletons None, + NotImplemented, # builtin objects b'spam', 'spam', @@ -1129,7 +1130,6 @@ class SubBytes(bytes): not_shareables = [ # singletons - NotImplemented, ..., # builtin types and objects type, diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-05-12-15-19-40.gh-issue-118965.Lr3qAz.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-05-12-15-19-40.gh-issue-118965.Lr3qAz.rst new file mode 100644 index 00000000000000..dbcd40f897aa13 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-05-12-15-19-40.gh-issue-118965.Lr3qAz.rst @@ -0,0 +1 @@ +Added support for sharing :data:`NotImplemented` singleton between subinterpreters. diff --git a/Python/crossinterp_data_lookup.h b/Python/crossinterp_data_lookup.h index 48e5d9762cd697..4b2f6aaf33af91 100644 --- a/Python/crossinterp_data_lookup.h +++ b/Python/crossinterp_data_lookup.h @@ -438,6 +438,24 @@ _none_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data) return 0; } +// NotImplemented + +static PyObject * +_new_notimplemented_object(_PyCrossInterpreterData *data) +{ + assert(_Py_IsImmortal(Py_NotImplemented)); + return Py_NotImplemented; +} + +static int +_notimplemented_shared(PyThreadState *tstate, PyObject *obj, + _PyCrossInterpreterData *data) +{ + _PyCrossInterpreterData_Init(data, tstate->interp, NULL, NULL, + _new_notimplemented_object); + return 0; +} + // bool static PyObject * @@ -567,6 +585,13 @@ _register_builtins_for_crossinterpreter_data(dlregistry_t *xidregistry) Py_FatalError("could not register None for cross-interpreter sharing"); } + // NotImplemented + if (_xidregistry_add_type(xidregistry, + (PyTypeObject *)PyObject_Type(Py_NotImplemented), + _notimplemented_shared) != 0) { + Py_FatalError("could not register NotImplemented for cross-interpreter sharing"); + } + // int if (_xidregistry_add_type(xidregistry, &PyLong_Type, _long_shared) != 0) { Py_FatalError("could not register int for cross-interpreter sharing");