https://github.com/python/cpython/commit/ea598730ef810d48a7d890457ba89330d2996e49
commit: ea598730ef810d48a7d890457ba89330d2996e49
branch: main
author: Eric Snow <ericsnowcurren...@gmail.com>
committer: ericsnowcurrently <ericsnowcurren...@gmail.com>
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 -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to