GH-137630: Convert `_interpreters` to use Argument Clinic (#137631)

This commit is contained in:
Adam Turner 2025-08-12 16:23:13 +01:00 committed by GitHub
parent 68a61b0f1d
commit be56464c4b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 1533 additions and 317 deletions

View file

@ -842,6 +842,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(call));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(call_exception_handler));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(call_soon));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(callable));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(callback));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cancel));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(capath));
@ -877,6 +878,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(command));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(comment_factory));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(compile_mode));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(config));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(consts));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(context));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(contravariant));
@ -935,6 +937,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(errors));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(event));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(eventmask));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exc));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exc_type));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exc_value));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(excepthook));
@ -1006,6 +1009,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(identity_hint));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ignore));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(imag));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(implieslink));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(importlib));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(in_fd));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(include_aliases));
@ -1055,6 +1059,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(kw));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(kw1));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(kw2));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(kwargs));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(kwdefaults));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(label));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last));
@ -1171,6 +1176,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pos1));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pos2));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(posix));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(preserve_exc));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(print_file_and_line));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(priority));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(progress));
@ -1198,9 +1204,12 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reload));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(repl));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(replace));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reqrefs));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(require_ready));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reserved));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reset));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(resetids));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(restrict));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(return));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reverse));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reversed));
@ -1227,6 +1236,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(setsigmask));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(setstate));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(shape));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(shared));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(show_cmd));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(signed));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(size));
@ -1297,6 +1307,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(uid));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(unlink));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(unraisablehook));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(updates));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(uri));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(usedforsecurity));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(value));

View file

@ -333,6 +333,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(call)
STRUCT_FOR_ID(call_exception_handler)
STRUCT_FOR_ID(call_soon)
STRUCT_FOR_ID(callable)
STRUCT_FOR_ID(callback)
STRUCT_FOR_ID(cancel)
STRUCT_FOR_ID(capath)
@ -368,6 +369,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(command)
STRUCT_FOR_ID(comment_factory)
STRUCT_FOR_ID(compile_mode)
STRUCT_FOR_ID(config)
STRUCT_FOR_ID(consts)
STRUCT_FOR_ID(context)
STRUCT_FOR_ID(contravariant)
@ -426,6 +428,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(errors)
STRUCT_FOR_ID(event)
STRUCT_FOR_ID(eventmask)
STRUCT_FOR_ID(exc)
STRUCT_FOR_ID(exc_type)
STRUCT_FOR_ID(exc_value)
STRUCT_FOR_ID(excepthook)
@ -497,6 +500,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(identity_hint)
STRUCT_FOR_ID(ignore)
STRUCT_FOR_ID(imag)
STRUCT_FOR_ID(implieslink)
STRUCT_FOR_ID(importlib)
STRUCT_FOR_ID(in_fd)
STRUCT_FOR_ID(include_aliases)
@ -546,6 +550,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(kw)
STRUCT_FOR_ID(kw1)
STRUCT_FOR_ID(kw2)
STRUCT_FOR_ID(kwargs)
STRUCT_FOR_ID(kwdefaults)
STRUCT_FOR_ID(label)
STRUCT_FOR_ID(last)
@ -662,6 +667,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(pos1)
STRUCT_FOR_ID(pos2)
STRUCT_FOR_ID(posix)
STRUCT_FOR_ID(preserve_exc)
STRUCT_FOR_ID(print_file_and_line)
STRUCT_FOR_ID(priority)
STRUCT_FOR_ID(progress)
@ -689,9 +695,12 @@ struct _Py_global_strings {
STRUCT_FOR_ID(reload)
STRUCT_FOR_ID(repl)
STRUCT_FOR_ID(replace)
STRUCT_FOR_ID(reqrefs)
STRUCT_FOR_ID(require_ready)
STRUCT_FOR_ID(reserved)
STRUCT_FOR_ID(reset)
STRUCT_FOR_ID(resetids)
STRUCT_FOR_ID(restrict)
STRUCT_FOR_ID(return)
STRUCT_FOR_ID(reverse)
STRUCT_FOR_ID(reversed)
@ -718,6 +727,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(setsigmask)
STRUCT_FOR_ID(setstate)
STRUCT_FOR_ID(shape)
STRUCT_FOR_ID(shared)
STRUCT_FOR_ID(show_cmd)
STRUCT_FOR_ID(signed)
STRUCT_FOR_ID(size)
@ -788,6 +798,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(uid)
STRUCT_FOR_ID(unlink)
STRUCT_FOR_ID(unraisablehook)
STRUCT_FOR_ID(updates)
STRUCT_FOR_ID(uri)
STRUCT_FOR_ID(usedforsecurity)
STRUCT_FOR_ID(value)

View file

@ -840,6 +840,7 @@ extern "C" {
INIT_ID(call), \
INIT_ID(call_exception_handler), \
INIT_ID(call_soon), \
INIT_ID(callable), \
INIT_ID(callback), \
INIT_ID(cancel), \
INIT_ID(capath), \
@ -875,6 +876,7 @@ extern "C" {
INIT_ID(command), \
INIT_ID(comment_factory), \
INIT_ID(compile_mode), \
INIT_ID(config), \
INIT_ID(consts), \
INIT_ID(context), \
INIT_ID(contravariant), \
@ -933,6 +935,7 @@ extern "C" {
INIT_ID(errors), \
INIT_ID(event), \
INIT_ID(eventmask), \
INIT_ID(exc), \
INIT_ID(exc_type), \
INIT_ID(exc_value), \
INIT_ID(excepthook), \
@ -1004,6 +1007,7 @@ extern "C" {
INIT_ID(identity_hint), \
INIT_ID(ignore), \
INIT_ID(imag), \
INIT_ID(implieslink), \
INIT_ID(importlib), \
INIT_ID(in_fd), \
INIT_ID(include_aliases), \
@ -1053,6 +1057,7 @@ extern "C" {
INIT_ID(kw), \
INIT_ID(kw1), \
INIT_ID(kw2), \
INIT_ID(kwargs), \
INIT_ID(kwdefaults), \
INIT_ID(label), \
INIT_ID(last), \
@ -1169,6 +1174,7 @@ extern "C" {
INIT_ID(pos1), \
INIT_ID(pos2), \
INIT_ID(posix), \
INIT_ID(preserve_exc), \
INIT_ID(print_file_and_line), \
INIT_ID(priority), \
INIT_ID(progress), \
@ -1196,9 +1202,12 @@ extern "C" {
INIT_ID(reload), \
INIT_ID(repl), \
INIT_ID(replace), \
INIT_ID(reqrefs), \
INIT_ID(require_ready), \
INIT_ID(reserved), \
INIT_ID(reset), \
INIT_ID(resetids), \
INIT_ID(restrict), \
INIT_ID(return), \
INIT_ID(reverse), \
INIT_ID(reversed), \
@ -1225,6 +1234,7 @@ extern "C" {
INIT_ID(setsigmask), \
INIT_ID(setstate), \
INIT_ID(shape), \
INIT_ID(shared), \
INIT_ID(show_cmd), \
INIT_ID(signed), \
INIT_ID(size), \
@ -1295,6 +1305,7 @@ extern "C" {
INIT_ID(uid), \
INIT_ID(unlink), \
INIT_ID(unraisablehook), \
INIT_ID(updates), \
INIT_ID(uri), \
INIT_ID(usedforsecurity), \
INIT_ID(value), \

View file

@ -1120,6 +1120,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(callable);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(callback);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
@ -1260,6 +1264,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(config);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(consts);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
@ -1492,6 +1500,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(exc);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(exc_type);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
@ -1776,6 +1788,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(implieslink);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(importlib);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
@ -1972,6 +1988,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(kwargs);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(kwdefaults);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
@ -2436,6 +2456,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(preserve_exc);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(print_file_and_line);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
@ -2544,6 +2568,14 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(reqrefs);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(require_ready);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(reserved);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
@ -2556,6 +2588,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(restrict);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(return);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
@ -2660,6 +2696,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(shared);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(show_cmd);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
@ -2940,6 +2980,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(updates);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(uri);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));

View file

@ -474,19 +474,19 @@ class CommonTests(TestBase):
def test_signatures(self):
# See https://github.com/python/cpython/issues/126654
msg = r'_interpreters.exec\(\) argument 3 must be dict, not int'
msg = r"exec\(\) argument 'shared' must be dict, not int"
with self.assertRaisesRegex(TypeError, msg):
_interpreters.exec(self.id, 'a', 1)
with self.assertRaisesRegex(TypeError, msg):
_interpreters.exec(self.id, 'a', shared=1)
msg = r'_interpreters.run_string\(\) argument 3 must be dict, not int'
msg = r"run_string\(\) argument 'shared' must be dict, not int"
with self.assertRaisesRegex(TypeError, msg):
_interpreters.run_string(self.id, 'a', shared=1)
msg = r'_interpreters.run_func\(\) argument 3 must be dict, not int'
msg = r"run_func\(\) argument 'shared' must be dict, not int"
with self.assertRaisesRegex(TypeError, msg):
_interpreters.run_func(self.id, lambda: None, shared=1)
# See https://github.com/python/cpython/issues/135855
msg = r'_interpreters.set___main___attrs\(\) argument 2 must be dict, not int'
msg = r"set___main___attrs\(\) argument 'updates' must be dict, not int"
with self.assertRaisesRegex(TypeError, msg):
_interpreters.set___main___attrs(self.id, 1)

View file

@ -0,0 +1,2 @@
The :mod:`!_interpreters` module now uses Argument Clinic to parse arguments.
Patch by Adam Turner.

View file

@ -20,12 +20,18 @@
#include "_interpreters_common.h"
#include "clinic/_interpretersmodule.c.h"
#define MODULE_NAME _interpreters
#define MODULE_NAME_STR Py_STRINGIFY(MODULE_NAME)
#define MODINIT_FUNC_NAME RESOLVE_MODINIT_FUNC_NAME(MODULE_NAME)
/*[clinic input]
module _interpreters
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=bfd967980a0de892]*/
static PyInterpreterState *
_get_current_interp(void)
{
@ -797,12 +803,12 @@ get_summary(PyInterpreterState *interp)
}
// Not converted to Argument Clinic because the function uses ``**kwargs``.
static PyObject *
interp_new_config(PyObject *self, PyObject *args, PyObject *kwds)
{
const char *name = NULL;
if (!PyArg_ParseTuple(args, "|s:" MODULE_NAME_STR ".new_config",
&name))
if (!PyArg_ParseTuple(args, "|s:" MODULE_NAME_STR ".new_config", &name))
{
return NULL;
}
@ -830,7 +836,8 @@ interp_new_config(PyObject *self, PyObject *args, PyObject *kwds)
}
PyDoc_STRVAR(new_config_doc,
"new_config(name='isolated', /, **overrides) -> type.SimpleNamespace\n\
"new_config($module, name='isolated', /, **overrides)\n\
--\n\
\n\
Return a representation of a new PyInterpreterConfig.\n\
\n\
@ -841,17 +848,28 @@ Any keyword arguments are set on the corresponding config fields,\n\
overriding the initial values.");
static PyObject *
interp_create(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"config", "reqrefs", NULL};
PyObject *configobj = NULL;
int reqrefs = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O$p:create", kwlist,
&configobj, &reqrefs)) {
return NULL;
}
/*[clinic input]
_interpreters.create
config as configobj: object(py_default="'isolated'") = NULL
*
reqrefs: bool = False
Create a new interpreter and return a unique generated ID.
The caller is responsible for destroying the interpreter before exiting,
typically by using _interpreters.destroy(). This can be managed
automatically by passing "reqrefs=True" and then using _incref() and
_decref() appropriately.
"config" must be a valid interpreter config or the name of a
predefined config ('isolated' or 'legacy'). The default
is 'isolated'.
[clinic start generated code]*/
static PyObject *
_interpreters_create_impl(PyObject *module, PyObject *configobj, int reqrefs)
/*[clinic end generated code: output=c1cc6835b1277c16 input=235ce396a23624d5]*/
{
PyInterpreterConfig config;
if (config_from_object(configobj, &config) < 0) {
return NULL;
@ -885,34 +903,22 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
}
PyDoc_STRVAR(create_doc,
"create([config], *, reqrefs=False) -> ID\n\
\n\
Create a new interpreter and return a unique generated ID.\n\
\n\
The caller is responsible for destroying the interpreter before exiting,\n\
typically by using _interpreters.destroy(). This can be managed \n\
automatically by passing \"reqrefs=True\" and then using _incref() and\n\
_decref() appropriately.\n\
\n\
\"config\" must be a valid interpreter config or the name of a\n\
predefined config (\"isolated\" or \"legacy\"). The default\n\
is \"isolated\".");
/*[clinic input]
_interpreters.destroy
id: object
*
restrict as restricted: bool = False
Destroy the identified interpreter.
Attempting to destroy the current interpreter raises InterpreterError.
So does an unrecognized ID.
[clinic start generated code]*/
static PyObject *
interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
_interpreters_destroy_impl(PyObject *module, PyObject *id, int restricted)
/*[clinic end generated code: output=0bc20da8700ab4dd input=561bdd6537639d40]*/
{
static char *kwlist[] = {"id", "restrict", NULL};
PyObject *id;
int restricted = 0;
// XXX Use "L" for id?
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"O|$p:destroy", kwlist, &id, &restricted))
{
return NULL;
}
// Look up the interpreter.
int reqready = 0;
PyInterpreterState *interp = \
@ -946,27 +952,19 @@ interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
}
PyDoc_STRVAR(destroy_doc,
"destroy(id, *, restrict=False)\n\
\n\
Destroy the identified interpreter.\n\
\n\
Attempting to destroy the current interpreter raises InterpreterError.\n\
So does an unrecognized ID.");
/*[clinic input]
_interpreters.list_all
*
require_ready as reqready: bool = False
Return a list containing the ID of every existing interpreter.
[clinic start generated code]*/
static PyObject *
interp_list_all(PyObject *self, PyObject *args, PyObject *kwargs)
_interpreters_list_all_impl(PyObject *module, int reqready)
/*[clinic end generated code: output=3f21c1a7c78043c0 input=35bae91c381a2cf9]*/
{
static char *kwlist[] = {"require_ready", NULL};
int reqready = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"|$p:" MODULE_NAME_STR ".list_all",
kwlist, &reqready))
{
return NULL;
}
PyObject *ids = PyList_New(0);
if (ids == NULL) {
return NULL;
@ -995,14 +993,16 @@ interp_list_all(PyObject *self, PyObject *args, PyObject *kwargs)
return ids;
}
PyDoc_STRVAR(list_all_doc,
"list_all() -> [(ID, whence)]\n\
\n\
Return a list containing the ID of every existing interpreter.");
/*[clinic input]
_interpreters.get_current
Return (ID, whence) of the current interpreter.
[clinic start generated code]*/
static PyObject *
interp_get_current(PyObject *self, PyObject *Py_UNUSED(ignored))
_interpreters_get_current_impl(PyObject *module)
/*[clinic end generated code: output=03161c8fcc0136eb input=37fb2c067c14d543]*/
{
PyInterpreterState *interp =_get_current_interp();
if (interp == NULL) {
@ -1012,39 +1012,38 @@ interp_get_current(PyObject *self, PyObject *Py_UNUSED(ignored))
return get_summary(interp);
}
PyDoc_STRVAR(get_current_doc,
"get_current() -> (ID, whence)\n\
\n\
Return the ID of current interpreter.");
/*[clinic input]
_interpreters.get_main
Return (ID, whence) of the main interpreter.
[clinic start generated code]*/
static PyObject *
interp_get_main(PyObject *self, PyObject *Py_UNUSED(ignored))
_interpreters_get_main_impl(PyObject *module)
/*[clinic end generated code: output=9647288aff735557 input=b4ace23ca562146f]*/
{
PyInterpreterState *interp = _PyInterpreterState_Main();
assert(_PyInterpreterState_IsReady(interp));
return get_summary(interp);
}
PyDoc_STRVAR(get_main_doc,
"get_main() -> (ID, whence)\n\
\n\
Return the ID of main interpreter.");
/*[clinic input]
_interpreters.set___main___attrs
id: object
updates: object(subclass_of='&PyDict_Type')
*
restrict as restricted: bool = False
Bind the given attributes in the interpreter's __main__ module.
[clinic start generated code]*/
static PyObject *
interp_set___main___attrs(PyObject *self, PyObject *args, PyObject *kwargs)
_interpreters_set___main___attrs_impl(PyObject *module, PyObject *id,
PyObject *updates, int restricted)
/*[clinic end generated code: output=f3803010cb452bf0 input=d16ab8d81371f86a]*/
{
static char *kwlist[] = {"id", "updates", "restrict", NULL};
PyObject *id, *updates;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"OO!|$p:" MODULE_NAME_STR ".set___main___attrs",
kwlist, &id, &PyDict_Type, &updates, &restricted))
{
return NULL;
}
// Look up the interpreter.
int reqready = 1;
PyInterpreterState *interp = \
@ -1091,11 +1090,6 @@ interp_set___main___attrs(PyObject *self, PyObject *args, PyObject *kwargs)
Py_RETURN_NONE;
}
PyDoc_STRVAR(set___main___attrs_doc,
"set___main___attrs(id, ns, *, restrict=False)\n\
\n\
Bind the given attributes in the interpreter's __main__ module.");
static PyObject *
_handle_script_error(struct run_result *runres)
@ -1109,23 +1103,36 @@ _handle_script_error(struct run_result *runres)
return runres->excinfo;
}
static PyObject *
interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
{
#define FUNCNAME MODULE_NAME_STR ".exec"
PyThreadState *tstate = _PyThreadState_GET();
static char *kwlist[] = {"id", "code", "shared", "restrict", NULL};
PyObject *id, *code;
PyObject *shared = NULL;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"OO|O!$p:" FUNCNAME, kwlist,
&id, &code, &PyDict_Type, &shared,
&restricted))
{
return NULL;
}
/*[clinic input]
_interpreters.exec
id: object
code: object
shared: object(subclass_of='&PyDict_Type', c_default='NULL') = {}
*
restrict as restricted: bool = False
Execute the provided code in the identified interpreter.
This is equivalent to running the builtin exec() under the target
interpreter, using the __dict__ of its __main__ module as both
globals and locals.
"code" may be a string containing the text of a Python script.
Functions (and code objects) are also supported, with some restrictions.
The code/function must not take any arguments or be a closure
(i.e. have cell vars). Methods and other callables are not supported.
If a function is provided, its code object is used and all its state
is ignored, including its __globals__ dict.
[clinic start generated code]*/
static PyObject *
_interpreters_exec_impl(PyObject *module, PyObject *id, PyObject *code,
PyObject *shared, int restricted)
/*[clinic end generated code: output=492057c4f10dc304 input=5a22c1ed0c5dbcf3]*/
{
PyThreadState *tstate = _PyThreadState_GET();
int reqready = 1;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "exec code for");
@ -1150,43 +1157,29 @@ interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
}
assert(runres.result == NULL);
Py_RETURN_NONE;
#undef FUNCNAME
}
PyDoc_STRVAR(exec_doc,
"exec(id, code, shared=None, *, restrict=False)\n\
\n\
Execute the provided code in the identified interpreter.\n\
This is equivalent to running the builtin exec() under the target\n\
interpreter, using the __dict__ of its __main__ module as both\n\
globals and locals.\n\
\n\
\"code\" may be a string containing the text of a Python script.\n\
\n\
Functions (and code objects) are also supported, with some restrictions.\n\
The code/function must not take any arguments or be a closure\n\
(i.e. have cell vars). Methods and other callables are not supported.\n\
\n\
If a function is provided, its code object is used and all its state\n\
is ignored, including its __globals__ dict.");
/*[clinic input]
_interpreters.run_string
id: object
script: unicode
shared: object(subclass_of='&PyDict_Type', c_default='NULL') = {}
*
restrict as restricted: bool = False
Execute the provided string in the identified interpreter.
(See _interpreters.exec().)
[clinic start generated code]*/
static PyObject *
interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
_interpreters_run_string_impl(PyObject *module, PyObject *id,
PyObject *script, PyObject *shared,
int restricted)
/*[clinic end generated code: output=a30a64fb9ad396a2 input=51ce549b9a8dbe21]*/
{
#define FUNCNAME MODULE_NAME_STR ".run_string"
PyThreadState *tstate = _PyThreadState_GET();
static char *kwlist[] = {"id", "script", "shared", "restrict", NULL};
PyObject *id, *script;
PyObject *shared = NULL;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"OU|O!$p:" FUNCNAME, kwlist,
&id, &script, &PyDict_Type, &shared,
&restricted))
{
return NULL;
}
int reqready = 1;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "run a string in");
@ -1217,30 +1210,29 @@ interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
#undef FUNCNAME
}
PyDoc_STRVAR(run_string_doc,
"run_string(id, script, shared=None, *, restrict=False)\n\
\n\
Execute the provided string in the identified interpreter.\n\
\n\
(See " MODULE_NAME_STR ".exec().");
/*[clinic input]
_interpreters.run_func
id: object
func: object
shared: object(subclass_of='&PyDict_Type', c_default='NULL') = {}
*
restrict as restricted: bool = False
Execute the body of the provided function in the identified interpreter.
Code objects are also supported. In both cases, closures and args
are not supported. Methods and other callables are not supported either.
(See _interpreters.exec().)
[clinic start generated code]*/
static PyObject *
interp_run_func(PyObject *self, PyObject *args, PyObject *kwds)
_interpreters_run_func_impl(PyObject *module, PyObject *id, PyObject *func,
PyObject *shared, int restricted)
/*[clinic end generated code: output=131f7202ca4a0c5e input=2d62bb9b9eaf4948]*/
{
#define FUNCNAME MODULE_NAME_STR ".run_func"
PyThreadState *tstate = _PyThreadState_GET();
static char *kwlist[] = {"id", "func", "shared", "restrict", NULL};
PyObject *id, *func;
PyObject *shared = NULL;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"OO|O!$p:" FUNCNAME, kwlist,
&id, &func, &PyDict_Type, &shared,
&restricted))
{
return NULL;
}
int reqready = 1;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "run a function in");
@ -1280,37 +1272,28 @@ interp_run_func(PyObject *self, PyObject *args, PyObject *kwds)
#undef FUNCNAME
}
PyDoc_STRVAR(run_func_doc,
"run_func(id, func, shared=None, *, restrict=False)\n\
\n\
Execute the body of the provided function in the identified interpreter.\n\
Code objects are also supported. In both cases, closures and args\n\
are not supported. Methods and other callables are not supported either.\n\
\n\
(See " MODULE_NAME_STR ".exec().");
/*[clinic input]
_interpreters.call
id: object
callable: object
args as args_obj: object(subclass_of='&PyTuple_Type', c_default='NULL') = ()
kwargs as kwargs_obj: object(subclass_of='&PyDict_Type', c_default='NULL') = {}
*
preserve_exc: bool = False
restrict as restricted: bool = False
Call the provided object in the identified interpreter.
Pass the given args and kwargs, if possible.
[clinic start generated code]*/
static PyObject *
interp_call(PyObject *self, PyObject *args, PyObject *kwds)
_interpreters_call_impl(PyObject *module, PyObject *id, PyObject *callable,
PyObject *args_obj, PyObject *kwargs_obj,
int preserve_exc, int restricted)
/*[clinic end generated code: output=983ee27b3c43f6ef input=77590fdb3f519d65]*/
{
#define FUNCNAME MODULE_NAME_STR ".call"
PyThreadState *tstate = _PyThreadState_GET();
static char *kwlist[] = {"id", "callable", "args", "kwargs",
"preserve_exc", "restrict", NULL};
PyObject *id, *callable;
PyObject *args_obj = NULL;
PyObject *kwargs_obj = NULL;
int preserve_exc = 0;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"OO|O!O!$pp:" FUNCNAME, kwlist,
&id, &callable,
&PyTuple_Type, &args_obj,
&PyDict_Type, &kwargs_obj,
&preserve_exc, &restricted))
{
return NULL;
}
int reqready = 1;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "make a call in");
@ -1341,26 +1324,20 @@ finally:
_interp_call_clear(&call);
_run_result_clear(&runres);
return res_and_exc;
#undef FUNCNAME
}
PyDoc_STRVAR(call_doc,
"call(id, callable, args=None, kwargs=None, *, restrict=False)\n\
\n\
Call the provided object in the identified interpreter.\n\
Pass the given args and kwargs, if possible.");
/*[clinic input]
_interpreters.is_shareable
obj: object
Return True if the object's data may be shared between interpreters and False otherwise.
[clinic start generated code]*/
static PyObject *
object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds)
_interpreters_is_shareable_impl(PyObject *module, PyObject *obj)
/*[clinic end generated code: output=227856926a22940b input=72b9a36bdf1d2a53]*/
{
static char *kwlist[] = {"obj", NULL};
PyObject *obj;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"O:is_shareable", kwlist, &obj)) {
return NULL;
}
PyThreadState *tstate = _PyThreadState_GET();
if (_PyObject_CheckXIData(tstate, obj) == 0) {
Py_RETURN_TRUE;
@ -1369,26 +1346,20 @@ object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds)
Py_RETURN_FALSE;
}
PyDoc_STRVAR(is_shareable_doc,
"is_shareable(obj) -> bool\n\
\n\
Return True if the object's data may be shared between interpreters and\n\
False otherwise.");
/*[clinic input]
_interpreters.is_running
id: object
*
restrict as restricted: bool = False
Return whether or not the identified interpreter is running.
[clinic start generated code]*/
static PyObject *
interp_is_running(PyObject *self, PyObject *args, PyObject *kwds)
_interpreters_is_running_impl(PyObject *module, PyObject *id, int restricted)
/*[clinic end generated code: output=32a6225d5ded9bdb input=3291578d04231125]*/
{
static char *kwlist[] = {"id", "restrict", NULL};
PyObject *id;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"O|$p:is_running", kwlist,
&id, &restricted))
{
return NULL;
}
int reqready = 1;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "check if running for");
@ -1402,24 +1373,21 @@ interp_is_running(PyObject *self, PyObject *args, PyObject *kwds)
Py_RETURN_FALSE;
}
PyDoc_STRVAR(is_running_doc,
"is_running(id, *, restrict=False) -> bool\n\
\n\
Return whether or not the identified interpreter is running.");
/*[clinic input]
_interpreters.get_config
id as idobj: object
*
restrict as restricted: bool = False
Return a representation of the config used to initialize the interpreter.
[clinic start generated code]*/
static PyObject *
interp_get_config(PyObject *self, PyObject *args, PyObject *kwds)
_interpreters_get_config_impl(PyObject *module, PyObject *idobj,
int restricted)
/*[clinic end generated code: output=63f81d35c2fe1387 input=aa38d50f534eb3c5]*/
{
static char *kwlist[] = {"id", "restrict", NULL};
PyObject *idobj = NULL;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"O|$p:get_config", kwlist,
&idobj, &restricted))
{
return NULL;
}
if (idobj == Py_None) {
idobj = NULL;
}
@ -1445,23 +1413,18 @@ interp_get_config(PyObject *self, PyObject *args, PyObject *kwds)
return configobj;
}
PyDoc_STRVAR(get_config_doc,
"get_config(id, *, restrict=False) -> types.SimpleNamespace\n\
\n\
Return a representation of the config used to initialize the interpreter.");
/*[clinic input]
_interpreters.whence
id: object
Return an identifier for where the interpreter was created.
[clinic start generated code]*/
static PyObject *
interp_whence(PyObject *self, PyObject *args, PyObject *kwds)
_interpreters_whence_impl(PyObject *module, PyObject *id)
/*[clinic end generated code: output=ef2c21ab106c2c20 input=eeede0a2fbfa2968]*/
{
static char *kwlist[] = {"id", NULL};
PyObject *id;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"O:whence", kwlist, &id))
{
return NULL;
}
PyInterpreterState *interp = look_up_interp(id);
if (interp == NULL) {
return NULL;
@ -1471,26 +1434,21 @@ interp_whence(PyObject *self, PyObject *args, PyObject *kwds)
return PyLong_FromLong(whence);
}
PyDoc_STRVAR(whence_doc,
"whence(id) -> int\n\
\n\
Return an identifier for where the interpreter was created.");
/*[clinic input]
_interpreters.incref
id: object
*
implieslink: bool = False
restrict as restricted: bool = False
[clinic start generated code]*/
static PyObject *
interp_incref(PyObject *self, PyObject *args, PyObject *kwds)
_interpreters_incref_impl(PyObject *module, PyObject *id, int implieslink,
int restricted)
/*[clinic end generated code: output=eccaa4e03fbe8ee2 input=a0a614748f2e348c]*/
{
static char *kwlist[] = {"id", "implieslink", "restrict", NULL};
PyObject *id;
int implieslink = 0;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"O|$pp:incref", kwlist,
&id, &implieslink, &restricted))
{
return NULL;
}
int reqready = 1;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "incref");
@ -1508,18 +1466,18 @@ interp_incref(PyObject *self, PyObject *args, PyObject *kwds)
}
static PyObject *
interp_decref(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"id", "restrict", NULL};
PyObject *id;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"O|$p:decref", kwlist, &id, &restricted))
{
return NULL;
}
/*[clinic input]
_interpreters.decref
id: object
*
restrict as restricted: bool = False
[clinic start generated code]*/
static PyObject *
_interpreters_decref_impl(PyObject *module, PyObject *id, int restricted)
/*[clinic end generated code: output=5c54db4b22086171 input=c4aa34f09c44e62a]*/
{
int reqready = 1;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "decref");
@ -1533,18 +1491,20 @@ interp_decref(PyObject *self, PyObject *args, PyObject *kwds)
}
static PyObject *
capture_exception(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"exc", NULL};
PyObject *exc_arg = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"|O:capture_exception", kwlist,
&exc_arg))
{
return NULL;
}
/*[clinic input]
_interpreters.capture_exception
exc as exc_arg: object = None
Return a snapshot of an exception.
If "exc" is None then the current exception, if any, is used (but not cleared).
The returned snapshot is the same as what _interpreters.exec() returns.
[clinic start generated code]*/
static PyObject *
_interpreters_capture_exception_impl(PyObject *module, PyObject *exc_arg)
/*[clinic end generated code: output=ef3f5393ef9c88a6 input=32045341e979bc9e]*/
{
PyObject *exc = exc_arg;
if (exc == NULL || exc == Py_None) {
exc = PyErr_GetRaisedException();
@ -1592,58 +1552,33 @@ finally:
return captured;
}
PyDoc_STRVAR(capture_exception_doc,
"capture_exception(exc=None) -> types.SimpleNamespace\n\
\n\
Return a snapshot of an exception. If \"exc\" is None\n\
then the current exception, if any, is used (but not cleared).\n\
\n\
The returned snapshot is the same as what _interpreters.exec() returns.");
static PyMethodDef module_functions[] = {
{"new_config", _PyCFunction_CAST(interp_new_config),
METH_VARARGS | METH_KEYWORDS, new_config_doc},
{"create", _PyCFunction_CAST(interp_create),
METH_VARARGS | METH_KEYWORDS, create_doc},
{"destroy", _PyCFunction_CAST(interp_destroy),
METH_VARARGS | METH_KEYWORDS, destroy_doc},
{"list_all", _PyCFunction_CAST(interp_list_all),
METH_VARARGS | METH_KEYWORDS, list_all_doc},
{"get_current", interp_get_current,
METH_NOARGS, get_current_doc},
{"get_main", interp_get_main,
METH_NOARGS, get_main_doc},
_INTERPRETERS_CREATE_METHODDEF
_INTERPRETERS_DESTROY_METHODDEF
_INTERPRETERS_LIST_ALL_METHODDEF
_INTERPRETERS_GET_CURRENT_METHODDEF
_INTERPRETERS_GET_MAIN_METHODDEF
{"is_running", _PyCFunction_CAST(interp_is_running),
METH_VARARGS | METH_KEYWORDS, is_running_doc},
{"get_config", _PyCFunction_CAST(interp_get_config),
METH_VARARGS | METH_KEYWORDS, get_config_doc},
{"whence", _PyCFunction_CAST(interp_whence),
METH_VARARGS | METH_KEYWORDS, whence_doc},
{"exec", _PyCFunction_CAST(interp_exec),
METH_VARARGS | METH_KEYWORDS, exec_doc},
{"call", _PyCFunction_CAST(interp_call),
METH_VARARGS | METH_KEYWORDS, call_doc},
{"run_string", _PyCFunction_CAST(interp_run_string),
METH_VARARGS | METH_KEYWORDS, run_string_doc},
{"run_func", _PyCFunction_CAST(interp_run_func),
METH_VARARGS | METH_KEYWORDS, run_func_doc},
_INTERPRETERS_IS_RUNNING_METHODDEF
_INTERPRETERS_GET_CONFIG_METHODDEF
_INTERPRETERS_WHENCE_METHODDEF
_INTERPRETERS_EXEC_METHODDEF
_INTERPRETERS_CALL_METHODDEF
_INTERPRETERS_RUN_STRING_METHODDEF
_INTERPRETERS_RUN_FUNC_METHODDEF
{"set___main___attrs", _PyCFunction_CAST(interp_set___main___attrs),
METH_VARARGS | METH_KEYWORDS, set___main___attrs_doc},
_INTERPRETERS_SET___MAIN___ATTRS_METHODDEF
{"incref", _PyCFunction_CAST(interp_incref),
METH_VARARGS | METH_KEYWORDS, NULL},
{"decref", _PyCFunction_CAST(interp_decref),
METH_VARARGS | METH_KEYWORDS, NULL},
_INTERPRETERS_INCREF_METHODDEF
_INTERPRETERS_DECREF_METHODDEF
{"is_shareable", _PyCFunction_CAST(object_is_shareable),
METH_VARARGS | METH_KEYWORDS, is_shareable_doc},
_INTERPRETERS_IS_SHAREABLE_METHODDEF
{"capture_exception", _PyCFunction_CAST(capture_exception),
METH_VARARGS | METH_KEYWORDS, capture_exception_doc},
_INTERPRETERS_CAPTURE_EXCEPTION_METHODDEF
{NULL, NULL} /* sentinel */
};

1202
Modules/clinic/_interpretersmodule.c.h generated Normal file

File diff suppressed because it is too large Load diff