]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-132775: Add _PyCode_GetXIData() (gh-133475)
authorEric Snow <ericsnowcurrently@gmail.com>
Mon, 5 May 2025 23:46:03 +0000 (17:46 -0600)
committerGitHub <noreply@github.com>
Mon, 5 May 2025 23:46:03 +0000 (23:46 +0000)
Include/internal/pycore_crossinterp.h
Lib/test/_code_definitions.py
Lib/test/test_code.py
Lib/test/test_crossinterp.py
Modules/_testinternalcapi.c
Python/crossinterp_data_lookup.h

index 4b4617fdbcb2adb63a426710795b556ed3e780fc..9de61ef54125d53d3dc3d161b80683e4ccfe75ca 100644 (file)
@@ -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 */
 
index 0c7b7b03cb3110b663f3c9b1bafe28c158876c10..d64ac45d85f3968d122678a0e5b1e6d47ab588e1 100644 (file)
@@ -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 spam_with_inner_closure():
     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 @@ TOP_FUNCTIONS = [
     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 @@ STATELESS_FUNCTIONS = [
     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,
index e66d7283b18a1d68cda3a314cc2eb5fcf04a4212..6715ee051336a1e74c5b8f97dcfc48550d8580aa 100644 (file)
@@ -687,6 +687,16 @@ class CodeTest(unittest.TestCase):
                 '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 @@ class CodeTest(unittest.TestCase):
                 '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 @@ class CodeTest(unittest.TestCase):
                 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 @@ class CodeTest(unittest.TestCase):
                 othercells=1,
                 purelocals=1,
             ),
+            defs.spam_annotated: new_var_counts(
+                posorkw=3,
+            ),
             defs.spam_full: new_var_counts(
                 posonly=2,
                 posorkw=2,
index 32d6fd4e94bf1be61e4e33fc709e807e85f4ca01..5ac0080db435a82f2b59635078d5e3cb8c23faaa 100644 (file)
@@ -725,6 +725,39 @@ class MarshalTests(_GetXIDataTests):
         ])
 
 
+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 @@ class ShareableTypeTests(_GetXIDataTests):
             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 @@ class ShareableTypeTests(_GetXIDataTests):
         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
index e7f4510b714af3a7bed38e09fbc897f884ed0401..63f1d079d8d3121f8788e2db7c11fea601dcfab2 100644 (file)
@@ -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;
index efef1e06d82f631a5e4a441200cad777a33b053b..231537c66d78f6d1a58eb8e856a1073141e7fcfc 100644 (file)
@@ -654,6 +654,30 @@ error:
     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