Skip to content

gh-117398: datetime: Make use of C-API capsules for sub-interpreters #117413

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 16 commits into from
20 changes: 17 additions & 3 deletions Include/datetime.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,24 @@ typedef struct {
* */
#ifndef _PY_DATETIME_IMPL
/* Define global variable for the C API and a macro for setting it. */
static PyDateTime_CAPI *PyDateTimeAPI = NULL;
static PyDateTime_CAPI *_pydatetimeapi_main = NULL;

#define PyDateTime_IMPORT \
PyDateTimeAPI = (PyDateTime_CAPI *)PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0)
static inline void _import_pydatetime(void) {
if (PyInterpreterState_Get() == PyInterpreterState_Main()) {
_pydatetimeapi_main = PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0);
}
}
#define PyDateTime_IMPORT _import_pydatetime()

static inline PyDateTime_CAPI *_get_pydatetime_api(void) {
if (PyInterpreterState_Get() == PyInterpreterState_Main()) {
return _pydatetimeapi_main;
}
else {
return PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0);
}
}
#define PyDateTimeAPI _get_pydatetime_api()

/* Macro for access to the UTC singleton */
#define PyDateTime_TimeZone_UTC PyDateTimeAPI->TimeZone_UTC
Expand Down
16 changes: 16 additions & 0 deletions Lib/test/test_capi/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2203,6 +2203,22 @@ def test_module_state_shared_in_global(self):
subinterp_attr_id = os.read(r, 100)
self.assertEqual(main_attr_id, subinterp_attr_id)

@unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module")
def test_datetime_capi(self):
script = textwrap.dedent("""
import importlib.machinery
import importlib.util
fullname = '_test_datetime_capi'
origin = importlib.util.find_spec('_testmultiphase').origin
loader = importlib.machinery.ExtensionFileLoader(fullname, origin)
spec = importlib.util.spec_from_loader(fullname, loader)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
""")
exec(script)
ret = support.run_in_subinterp(script)
self.assertEqual(ret, 0)


@requires_subinterpreters
class InterpreterIDTests(unittest.TestCase):
Expand Down
43 changes: 43 additions & 0 deletions Modules/_testmultiphase.c
Original file line number Diff line number Diff line change
Expand Up @@ -952,3 +952,46 @@ PyInit__test_shared_gil_only(void)
{
return PyModuleDef_Init(&shared_gil_only_def);
}


#include "datetime.h"

static int
datetime_capi_exec(PyObject *m)
{
_pydatetimeapi_main = NULL;
PyDateTime_IMPORT;
if (PyDateTimeAPI == NULL) {
return -1;
}
if (PyDateTimeAPI != PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0)) {
return -1;
}
if (PyInterpreterState_Get() == PyInterpreterState_Main()) {
if (PyDateTimeAPI != _pydatetimeapi_main) {
return -1;
}
}
else {
if (PyDateTimeAPI == _pydatetimeapi_main) {
return -1;
}
}
return 0;
}

static PyModuleDef_Slot datetime_capi_slots[] = {
{Py_mod_exec, datetime_capi_exec},
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
{0, NULL},
};

static PyModuleDef datetime_capi_def = TEST_MODULE_DEF("_test_datetime_capi",
datetime_capi_slots,
testexport_methods);

PyMODINIT_FUNC
PyInit__test_datetime_capi(void)
{
return PyModuleDef_Init(&datetime_capi_def);
}