Skip to content

Commit ea59873

Browse files
pythongh-132775: Add _PyCode_GetXIData() (pythongh-133475)
1 parent e961611 commit ea59873

File tree

6 files changed

+116
-6
lines changed

6 files changed

+116
-6
lines changed

Include/internal/pycore_crossinterp.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,13 @@ PyAPI_FUNC(int) _PyMarshal_GetXIData(
185185
PyObject *,
186186
_PyXIData_t *);
187187

188+
// _PyObject_GetXIData() for code objects
189+
PyAPI_FUNC(PyObject *) _PyCode_FromXIData(_PyXIData_t *);
190+
PyAPI_FUNC(int) _PyCode_GetXIData(
191+
PyThreadState *,
192+
PyObject *,
193+
_PyXIData_t *);
194+
188195

189196
/* using cross-interpreter data */
190197

Lib/test/_code_definitions.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ def spam_with_globals_and_builtins():
2929
print(res)
3030

3131

32+
def spam_args_attrs_and_builtins(a, b, /, c, d, *args, e, f, **kwargs):
33+
if args.__len__() > 2:
34+
return None
35+
return a, b, c, d, e, f, args, kwargs
36+
37+
3238
def spam_returns_arg(x):
3339
return x
3440

@@ -46,6 +52,10 @@ def eggs():
4652
eggs()
4753

4854

55+
def spam_annotated(a: int, b: str, c: object) -> tuple:
56+
return a, b, c
57+
58+
4959
def spam_full(a, b, /, c, d:int=1, *args, e, f:object=None, **kwargs) -> tuple:
5060
# arg defaults, kwarg defaults
5161
# annotations
@@ -134,9 +144,11 @@ def ham_C_closure(z):
134144
spam_minimal,
135145
spam_with_builtins,
136146
spam_with_globals_and_builtins,
147+
spam_args_attrs_and_builtins,
137148
spam_returns_arg,
138149
spam_with_inner_not_closure,
139150
spam_with_inner_closure,
151+
spam_annotated,
140152
spam_full,
141153
spam,
142154
# outer func
@@ -170,7 +182,9 @@ def ham_C_closure(z):
170182
spam,
171183
spam_minimal,
172184
spam_with_builtins,
185+
spam_args_attrs_and_builtins,
173186
spam_returns_arg,
187+
spam_annotated,
174188
spam_with_inner_not_closure,
175189
spam_with_inner_closure,
176190
spam_N,

Lib/test/test_code.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,16 @@ def test_local_kinds(self):
687687
'checks': CO_FAST_LOCAL,
688688
'res': CO_FAST_LOCAL,
689689
},
690+
defs.spam_args_attrs_and_builtins: {
691+
'a': POSONLY,
692+
'b': POSONLY,
693+
'c': POSORKW,
694+
'd': POSORKW,
695+
'e': KWONLY,
696+
'f': KWONLY,
697+
'args': VARARGS,
698+
'kwargs': VARKWARGS,
699+
},
690700
defs.spam_returns_arg: {
691701
'x': POSORKW,
692702
},
@@ -697,6 +707,11 @@ def test_local_kinds(self):
697707
'x': CO_FAST_CELL,
698708
'eggs': CO_FAST_LOCAL,
699709
},
710+
defs.spam_annotated: {
711+
'a': POSORKW,
712+
'b': POSORKW,
713+
'c': POSORKW,
714+
},
700715
defs.spam_full: {
701716
'a': POSONLY,
702717
'b': POSONLY,
@@ -892,6 +907,14 @@ def new_var_counts(*,
892907
purelocals=5,
893908
globalvars=6,
894909
),
910+
defs.spam_args_attrs_and_builtins: new_var_counts(
911+
posonly=2,
912+
posorkw=2,
913+
kwonly=2,
914+
varargs=1,
915+
varkwargs=1,
916+
attrs=1,
917+
),
895918
defs.spam_returns_arg: new_var_counts(
896919
posorkw=1,
897920
),
@@ -902,6 +925,9 @@ def new_var_counts(*,
902925
othercells=1,
903926
purelocals=1,
904927
),
928+
defs.spam_annotated: new_var_counts(
929+
posorkw=3,
930+
),
905931
defs.spam_full: new_var_counts(
906932
posonly=2,
907933
posorkw=2,

Lib/test/test_crossinterp.py

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,39 @@ def test_user_exception(self):
725725
])
726726

727727

728+
class CodeTests(_GetXIDataTests):
729+
730+
MODE = 'code'
731+
732+
def test_function_code(self):
733+
self.assert_roundtrip_equal_not_identical([
734+
*(f.__code__ for f in defs.FUNCTIONS),
735+
*(f.__code__ for f in defs.FUNCTION_LIKE),
736+
])
737+
738+
def test_functions(self):
739+
self.assert_not_shareable([
740+
*defs.FUNCTIONS,
741+
*defs.FUNCTION_LIKE,
742+
])
743+
744+
def test_other_objects(self):
745+
self.assert_not_shareable([
746+
None,
747+
True,
748+
False,
749+
Ellipsis,
750+
NotImplemented,
751+
9999,
752+
'spam',
753+
b'spam',
754+
(),
755+
[],
756+
{},
757+
object(),
758+
])
759+
760+
728761
class ShareableTypeTests(_GetXIDataTests):
729762

730763
MODE = 'xidata'
@@ -817,6 +850,13 @@ def test_object(self):
817850
object(),
818851
])
819852

853+
def test_code(self):
854+
# types.CodeType
855+
self.assert_not_shareable([
856+
*(f.__code__ for f in defs.FUNCTIONS),
857+
*(f.__code__ for f in defs.FUNCTION_LIKE),
858+
])
859+
820860
def test_function_object(self):
821861
for func in defs.FUNCTIONS:
822862
assert type(func) is types.FunctionType, func
@@ -935,12 +975,6 @@ def test_builtin_objects(self):
935975
self.assert_not_shareable([
936976
types.MappingProxyType({}),
937977
types.SimpleNamespace(),
938-
# types.CodeType
939-
defs.spam_minimal.__code__,
940-
defs.spam_full.__code__,
941-
defs.spam_CC.__code__,
942-
defs.eggs_closure_C.__code__,
943-
defs.ham_C_closure.__code__,
944978
# types.CellType
945979
types.CellType(),
946980
# types.FrameType

Modules/_testinternalcapi.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1984,6 +1984,11 @@ get_crossinterp_data(PyObject *self, PyObject *args, PyObject *kwargs)
19841984
goto error;
19851985
}
19861986
}
1987+
else if (strcmp(mode, "code") == 0) {
1988+
if (_PyCode_GetXIData(tstate, obj, xidata) != 0) {
1989+
goto error;
1990+
}
1991+
}
19871992
else {
19881993
PyErr_Format(PyExc_ValueError, "unsupported mode %R", modeobj);
19891994
goto error;

Python/crossinterp_data_lookup.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,30 @@ _tuple_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *xidata)
654654
return -1;
655655
}
656656

657+
// code
658+
659+
PyObject *
660+
_PyCode_FromXIData(_PyXIData_t *xidata)
661+
{
662+
return _PyMarshal_ReadObjectFromXIData(xidata);
663+
}
664+
665+
int
666+
_PyCode_GetXIData(PyThreadState *tstate, PyObject *obj, _PyXIData_t *xidata)
667+
{
668+
if (!PyCode_Check(obj)) {
669+
_PyXIData_FormatNotShareableError(tstate, "expected code, got %R", obj);
670+
return -1;
671+
}
672+
if (_PyMarshal_GetXIData(tstate, obj, xidata) < 0) {
673+
return -1;
674+
}
675+
assert(_PyXIData_CHECK_NEW_OBJECT(xidata, _PyMarshal_ReadObjectFromXIData));
676+
_PyXIData_SET_NEW_OBJECT(xidata, _PyCode_FromXIData);
677+
return 0;
678+
}
679+
680+
657681
// registration
658682

659683
static void

0 commit comments

Comments
 (0)