https://github.com/python/cpython/commit/ea598730ef810d48a7d890457ba89330d2996e49
commit: ea598730ef810d48a7d890457ba89330d2996e49
branch: main
author: Eric Snow <[email protected]>
committer: ericsnowcurrently <[email protected]>
date: 2025-05-05T23:46:03Z
summary:
gh-132775: Add _PyCode_GetXIData() (gh-133475)
files:
M Include/internal/pycore_crossinterp.h
M Lib/test/_code_definitions.py
M Lib/test/test_code.py
M Lib/test/test_crossinterp.py
M Modules/_testinternalcapi.c
M Python/crossinterp_data_lookup.h
diff --git a/Include/internal/pycore_crossinterp.h
b/Include/internal/pycore_crossinterp.h
index 4b4617fdbcb2ad..9de61ef54125d5 100644
--- a/Include/internal/pycore_crossinterp.h
+++ b/Include/internal/pycore_crossinterp.h
@@ -185,6 +185,13 @@ PyAPI_FUNC(int) _PyMarshal_GetXIData(
PyObject *,
_PyXIData_t *);
+// _PyObject_GetXIData() for code objects
+PyAPI_FUNC(PyObject *) _PyCode_FromXIData(_PyXIData_t *);
+PyAPI_FUNC(int) _PyCode_GetXIData(
+ PyThreadState *,
+ PyObject *,
+ _PyXIData_t *);
+
/* using cross-interpreter data */
diff --git a/Lib/test/_code_definitions.py b/Lib/test/_code_definitions.py
index 0c7b7b03cb3110..d64ac45d85f396 100644
--- a/Lib/test/_code_definitions.py
+++ b/Lib/test/_code_definitions.py
@@ -29,6 +29,12 @@ def spam_with_globals_and_builtins():
print(res)
+def spam_args_attrs_and_builtins(a, b, /, c, d, *args, e, f, **kwargs):
+ if args.__len__() > 2:
+ return None
+ return a, b, c, d, e, f, args, kwargs
+
+
def spam_returns_arg(x):
return x
@@ -46,6 +52,10 @@ def eggs():
eggs()
+def spam_annotated(a: int, b: str, c: object) -> tuple:
+ return a, b, c
+
+
def spam_full(a, b, /, c, d:int=1, *args, e, f:object=None, **kwargs) -> tuple:
# arg defaults, kwarg defaults
# annotations
@@ -134,9 +144,11 @@ def ham_C_closure(z):
spam_minimal,
spam_with_builtins,
spam_with_globals_and_builtins,
+ spam_args_attrs_and_builtins,
spam_returns_arg,
spam_with_inner_not_closure,
spam_with_inner_closure,
+ spam_annotated,
spam_full,
spam,
# outer func
@@ -170,7 +182,9 @@ def ham_C_closure(z):
spam,
spam_minimal,
spam_with_builtins,
+ spam_args_attrs_and_builtins,
spam_returns_arg,
+ spam_annotated,
spam_with_inner_not_closure,
spam_with_inner_closure,
spam_N,
diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py
index e66d7283b18a1d..6715ee051336a1 100644
--- a/Lib/test/test_code.py
+++ b/Lib/test/test_code.py
@@ -687,6 +687,16 @@ def test_local_kinds(self):
'checks': CO_FAST_LOCAL,
'res': CO_FAST_LOCAL,
},
+ defs.spam_args_attrs_and_builtins: {
+ 'a': POSONLY,
+ 'b': POSONLY,
+ 'c': POSORKW,
+ 'd': POSORKW,
+ 'e': KWONLY,
+ 'f': KWONLY,
+ 'args': VARARGS,
+ 'kwargs': VARKWARGS,
+ },
defs.spam_returns_arg: {
'x': POSORKW,
},
@@ -697,6 +707,11 @@ def test_local_kinds(self):
'x': CO_FAST_CELL,
'eggs': CO_FAST_LOCAL,
},
+ defs.spam_annotated: {
+ 'a': POSORKW,
+ 'b': POSORKW,
+ 'c': POSORKW,
+ },
defs.spam_full: {
'a': POSONLY,
'b': POSONLY,
@@ -892,6 +907,14 @@ def new_var_counts(*,
purelocals=5,
globalvars=6,
),
+ defs.spam_args_attrs_and_builtins: new_var_counts(
+ posonly=2,
+ posorkw=2,
+ kwonly=2,
+ varargs=1,
+ varkwargs=1,
+ attrs=1,
+ ),
defs.spam_returns_arg: new_var_counts(
posorkw=1,
),
@@ -902,6 +925,9 @@ def new_var_counts(*,
othercells=1,
purelocals=1,
),
+ defs.spam_annotated: new_var_counts(
+ posorkw=3,
+ ),
defs.spam_full: new_var_counts(
posonly=2,
posorkw=2,
diff --git a/Lib/test/test_crossinterp.py b/Lib/test/test_crossinterp.py
index 32d6fd4e94bf1b..5ac0080db435a8 100644
--- a/Lib/test/test_crossinterp.py
+++ b/Lib/test/test_crossinterp.py
@@ -725,6 +725,39 @@ def test_user_exception(self):
])
+class CodeTests(_GetXIDataTests):
+
+ MODE = 'code'
+
+ def test_function_code(self):
+ self.assert_roundtrip_equal_not_identical([
+ *(f.__code__ for f in defs.FUNCTIONS),
+ *(f.__code__ for f in defs.FUNCTION_LIKE),
+ ])
+
+ def test_functions(self):
+ self.assert_not_shareable([
+ *defs.FUNCTIONS,
+ *defs.FUNCTION_LIKE,
+ ])
+
+ def test_other_objects(self):
+ self.assert_not_shareable([
+ None,
+ True,
+ False,
+ Ellipsis,
+ NotImplemented,
+ 9999,
+ 'spam',
+ b'spam',
+ (),
+ [],
+ {},
+ object(),
+ ])
+
+
class ShareableTypeTests(_GetXIDataTests):
MODE = 'xidata'
@@ -817,6 +850,13 @@ def test_object(self):
object(),
])
+ def test_code(self):
+ # types.CodeType
+ self.assert_not_shareable([
+ *(f.__code__ for f in defs.FUNCTIONS),
+ *(f.__code__ for f in defs.FUNCTION_LIKE),
+ ])
+
def test_function_object(self):
for func in defs.FUNCTIONS:
assert type(func) is types.FunctionType, func
@@ -935,12 +975,6 @@ def test_builtin_objects(self):
self.assert_not_shareable([
types.MappingProxyType({}),
types.SimpleNamespace(),
- # types.CodeType
- defs.spam_minimal.__code__,
- defs.spam_full.__code__,
- defs.spam_CC.__code__,
- defs.eggs_closure_C.__code__,
- defs.ham_C_closure.__code__,
# types.CellType
types.CellType(),
# types.FrameType
diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index e7f4510b714af3..63f1d079d8d312 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -1984,6 +1984,11 @@ get_crossinterp_data(PyObject *self, PyObject *args,
PyObject *kwargs)
goto error;
}
}
+ else if (strcmp(mode, "code") == 0) {
+ if (_PyCode_GetXIData(tstate, obj, xidata) != 0) {
+ goto error;
+ }
+ }
else {
PyErr_Format(PyExc_ValueError, "unsupported mode %R", modeobj);
goto error;
diff --git a/Python/crossinterp_data_lookup.h b/Python/crossinterp_data_lookup.h
index efef1e06d82f63..231537c66d78f6 100644
--- a/Python/crossinterp_data_lookup.h
+++ b/Python/crossinterp_data_lookup.h
@@ -654,6 +654,30 @@ _tuple_shared(PyThreadState *tstate, PyObject *obj,
_PyXIData_t *xidata)
return -1;
}
+// code
+
+PyObject *
+_PyCode_FromXIData(_PyXIData_t *xidata)
+{
+ return _PyMarshal_ReadObjectFromXIData(xidata);
+}
+
+int
+_PyCode_GetXIData(PyThreadState *tstate, PyObject *obj, _PyXIData_t *xidata)
+{
+ if (!PyCode_Check(obj)) {
+ _PyXIData_FormatNotShareableError(tstate, "expected code, got %R",
obj);
+ return -1;
+ }
+ if (_PyMarshal_GetXIData(tstate, obj, xidata) < 0) {
+ return -1;
+ }
+ assert(_PyXIData_CHECK_NEW_OBJECT(xidata,
_PyMarshal_ReadObjectFromXIData));
+ _PyXIData_SET_NEW_OBJECT(xidata, _PyCode_FromXIData);
+ return 0;
+}
+
+
// registration
static void
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]