mirror of https://github.com/python/cpython
gh-117398: Add datetime C-API type check test for subinterpreters (gh-119604)
Check if the DateTime C-API type matches the datetime.date type on main and shared/isolated subinterpreters.
This commit is contained in:
parent
c2d810b6d4
commit
50a389565a
|
@ -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
|
||||
|
@ -6780,6 +6785,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())
|
||||
|
|
|
@ -1808,7 +1808,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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue