Skip to content
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

gh-117398: Add datetime C-API type check test for subinterpreters #119604

Merged
merged 40 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
0db4a81
Update _testmultiphase.c
neonene May 27, 2024
593f05a
Update test_misc.py
neonene May 27, 2024
d85c8bc
ingore import error on subinterp with GIL disabled
neonene May 27, 2024
9b667d7
revert
neonene May 28, 2024
6a67b45
Update Modules/_testcapi/datetime.c
neonene May 28, 2024
f21ef4a
revert
neonene May 29, 2024
ac9ad4b
add test for subinterpreters
neonene May 29, 2024
e4f6cc1
Merge branch 'main' into capi_type_check
neonene May 29, 2024
f0654f5
restore _testmultiphase check for WASI?
neonene May 29, 2024
17cb0c1
use test_datetime_capi() instead of PyDateTime_IMPORT
neonene May 29, 2024
fdfe135
remove redundant PyDateTimeAPI check
neonene May 29, 2024
c7d9de4
add Py_MOD_GIL_NOT_USED
neonene May 29, 2024
b89801c
ignore dlopen error on WASI
neonene May 30, 2024
cb5d65b
Merge branch 'main' into capi_type_check
neonene May 30, 2024
dc9c5e3
edit comment
neonene May 30, 2024
76695c7
Merge branch 'main' into capi_type_check
neonene May 30, 2024
6d57d33
rely on support module to run subinterps
neonene May 30, 2024
4a04542
nit
neonene May 30, 2024
ba08b04
add blank lines
neonene May 31, 2024
8c26d7e
simplify WASI check
neonene Jun 1, 2024
0360151
use _interpreters.new_config()
neonene Jun 1, 2024
b2c1e70
do not run_in_subinterp()
neonene Jun 2, 2024
23909a8
use @requires_subinterpreters instead of builtin _testcapi check
neonene Jun 2, 2024
daac381
do not use function to create module
neonene Jun 2, 2024
bf4d78a
do not copy config dict
neonene Jun 2, 2024
8c53a58
Merge branch 'main' into capi_type_check
neonene Jun 4, 2024
b3460b4
add test for all OSes
neonene Jun 4, 2024
aab36c3
_datetime does now multi-phase init
neonene Jun 4, 2024
378b1fd
remove test for all OSes
neonene Jun 4, 2024
df4c43e
remove duplicate test for main interpreter
neonene Jun 4, 2024
5ce05a4
reuse existing PyMethodDef
neonene Jun 4, 2024
ba41ef1
use expected config of InterpreterConfigTests instead
neonene Jun 4, 2024
272f25f
move static type assertions to test_datetime_capi()
neonene Jun 5, 2024
0d82c3c
Merge branch 'main' into capi_type_check
neonene Jun 5, 2024
17615ef
WASI support (only on legacy subinterp)
neonene Jun 5, 2024
9c46fe0
use _interpreters.new_config()
neonene Jun 13, 2024
0c40fc8
move test to datetimetester.py
neonene Jun 13, 2024
55beee7
Merge branch 'main' into capi_type_check
neonene Jun 13, 2024
b861bd3
rename test case
neonene Jun 13, 2024
a1421dd
simplify conditions in support.run_in_subinterp_with_config()
neonene Jun 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions Lib/test/datetimetester.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import re
import struct
import sys
import textwrap
import unittest
import warnings

Expand All @@ -38,6 +39,10 @@
import _testcapi
except ImportError:
_testcapi = None
try:
import _interpreters
except ModuleNotFoundError:
_interpreters = None

# Needed by test_datetime
import _strptime
Expand Down Expand Up @@ -6780,6 +6785,42 @@ def test_datetime_from_timestamp(self):

self.assertEqual(dt_orig, dt_rt)

def test_type_check_in_subinterp(self):
script = textwrap.dedent(f"""
if {_interpreters is None}:
neonene marked this conversation as resolved.
Show resolved Hide resolved
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())
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
48 changes: 45 additions & 3 deletions Modules/_testcapi/datetime.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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