[3.13] gh-117398: Add datetime C-API type check test for subinterpreters (gh-120463)

Check if the DateTime C-API type matches the datetime.date type on main and shared/isolated subinterpreters.

(cherry picked from commit 50a389565a, AKA gh-119604)

Co-authored-by: neonene <53406459+neonene@users.noreply.github.com>
This commit is contained in:
Miss Islington (bot) 2024-06-13 20:30:42 +02:00 committed by GitHub
parent e0f4dd8ec5
commit 15c3d0013d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 87 additions and 4 deletions

View File

@ -13,6 +13,7 @@ import random
import re
import struct
import sys
import textwrap
import unittest
import warnings
@ -38,6 +39,10 @@ try:
import _testcapi
except ImportError:
_testcapi = None
try:
import _interpreters
except ModuleNotFoundError:
_interpreters = None
# Needed by test_datetime
import _strptime
@ -6798,6 +6803,42 @@ class CapiTest(unittest.TestCase):
self.assertEqual(dt_orig, dt_rt)
def test_type_check_in_subinterp(self):
script = textwrap.dedent(f"""
if {_interpreters is None}:
import _testcapi as module
module.test_datetime_capi()
else:
import importlib.machinery
import importlib.util
fullname = '_testcapi_datetime'
origin = importlib.util.find_spec('_testcapi').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)
def run(type_checker, obj):
if not type_checker(obj, True):
raise TypeError(f'{{type(obj)}} is not C API type')
import _datetime
run(module.datetime_check_date, _datetime.date.today())
run(module.datetime_check_datetime, _datetime.datetime.now())
run(module.datetime_check_time, _datetime.time(12, 30))
run(module.datetime_check_delta, _datetime.timedelta(1))
run(module.datetime_check_tzinfo, _datetime.tzinfo())
""")
if _interpreters is None:
ret = support.run_in_subinterp(script)
self.assertEqual(ret, 0)
else:
for name in ('isolated', 'legacy'):
with self.subTest(name):
config = _interpreters.new_config(name).__dict__
ret = support.run_in_subinterp_with_config(script, **config)
self.assertEqual(ret, 0)
def load_tests(loader, standard_tests, pattern):
standard_tests.addTest(ZoneInfoCompleteTest())

View File

@ -1788,7 +1788,7 @@ def run_in_subinterp_with_config(code, *, own_gil=None, **config):
config['gil'] = 'shared'
elif gil == 2:
config['gil'] = 'own'
else:
elif not isinstance(gil, str):
raise NotImplementedError(gil)
config = types.SimpleNamespace(**config)
return _testinternalcapi.run_in_subinterp_with_config(code, config)

View File

@ -22,10 +22,17 @@ test_datetime_capi(PyObject *self, PyObject *args)
test_run_counter++;
PyDateTime_IMPORT;
if (PyDateTimeAPI) {
Py_RETURN_NONE;
if (PyDateTimeAPI == NULL) {
return NULL;
}
return NULL;
// The following C API types need to outlive interpreters, since the
// borrowed references to them can be held by users without being updated.
assert(!PyType_HasFeature(PyDateTimeAPI->DateType, Py_TPFLAGS_HEAPTYPE));
assert(!PyType_HasFeature(PyDateTimeAPI->TimeType, Py_TPFLAGS_HEAPTYPE));
assert(!PyType_HasFeature(PyDateTimeAPI->DateTimeType, Py_TPFLAGS_HEAPTYPE));
assert(!PyType_HasFeature(PyDateTimeAPI->DeltaType, Py_TPFLAGS_HEAPTYPE));
assert(!PyType_HasFeature(PyDateTimeAPI->TZInfoType, Py_TPFLAGS_HEAPTYPE));
Py_RETURN_NONE;
}
/* Functions exposing the C API type checking for testing */
@ -479,3 +486,38 @@ _PyTestCapi_Init_DateTime(PyObject *mod)
}
return 0;
}
/* ---------------------------------------------------------------------------
* Test module for subinterpreters.
*/
static int
_testcapi_datetime_exec(PyObject *mod)
{
if (test_datetime_capi(NULL, NULL) == NULL) {
return -1;
}
return 0;
}
static PyModuleDef_Slot _testcapi_datetime_slots[] = {
{Py_mod_exec, _testcapi_datetime_exec},
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
{0, NULL},
};
static struct PyModuleDef _testcapi_datetime_module = {
PyModuleDef_HEAD_INIT,
.m_name = "_testcapi_datetime",
.m_size = 0,
.m_methods = test_methods,
.m_slots = _testcapi_datetime_slots,
};
PyMODINIT_FUNC
PyInit__testcapi_datetime(void)
{
return PyModuleDef_Init(&_testcapi_datetime_module);
}