Skip to content

gh-132775: Cleanup Related to crossinterp.c Before Further Changes #132974

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 33 additions & 33 deletions Include/internal/pycore_crossinterp.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ struct _xidata {
// likely a registered "xidatafunc", is responsible for
// ensuring it owns the reference (i.e. incref).
PyObject *obj;
// interp is the ID of the owning interpreter of the original
// interpid is the ID of the owning interpreter of the original
// object. It corresponds to the active interpreter when
// _PyObject_GetXIData() was called. This should only
// be set by the cross-interpreter machinery.
Expand Down Expand Up @@ -93,37 +93,6 @@ PyAPI_FUNC(void) _PyXIData_Free(_PyXIData_t *data);
// Users should not need getters for "new_object" or "free".


/* getting cross-interpreter data */

typedef int (*xidatafunc)(PyThreadState *tstate, PyObject *, _PyXIData_t *);

PyAPI_FUNC(PyObject *) _PyXIData_GetNotShareableErrorType(PyThreadState *);
PyAPI_FUNC(void) _PyXIData_SetNotShareableError(PyThreadState *, const char *);
PyAPI_FUNC(void) _PyXIData_FormatNotShareableError(
PyThreadState *,
const char *,
...);

PyAPI_FUNC(xidatafunc) _PyXIData_Lookup(
PyThreadState *,
PyObject *);
PyAPI_FUNC(int) _PyObject_CheckXIData(
PyThreadState *,
PyObject *);

PyAPI_FUNC(int) _PyObject_GetXIData(
PyThreadState *,
PyObject *,
_PyXIData_t *);


/* using cross-interpreter data */

PyAPI_FUNC(PyObject *) _PyXIData_NewObject(_PyXIData_t *);
PyAPI_FUNC(int) _PyXIData_Release(_PyXIData_t *);
PyAPI_FUNC(int) _PyXIData_ReleaseAndRawFree(_PyXIData_t *);


/* defining cross-interpreter data */

PyAPI_FUNC(void) _PyXIData_Init(
Expand All @@ -134,7 +103,7 @@ PyAPI_FUNC(int) _PyXIData_InitWithSize(
_PyXIData_t *,
PyInterpreterState *interp, const size_t, PyObject *,
xid_newobjfunc);
PyAPI_FUNC(void) _PyXIData_Clear( PyInterpreterState *, _PyXIData_t *);
PyAPI_FUNC(void) _PyXIData_Clear(PyInterpreterState *, _PyXIData_t *);

// Normally the Init* functions are sufficient. The only time
// additional initialization might be needed is to set the "free" func,
Expand All @@ -156,6 +125,37 @@ PyAPI_FUNC(void) _PyXIData_Clear( PyInterpreterState *, _PyXIData_t *);
} while (0)


/* getting cross-interpreter data */

typedef int (*xidatafunc)(PyThreadState *tstate, PyObject *, _PyXIData_t *);

PyAPI_FUNC(PyObject *) _PyXIData_GetNotShareableErrorType(PyThreadState *);
PyAPI_FUNC(void) _PyXIData_SetNotShareableError(PyThreadState *, const char *);
PyAPI_FUNC(void) _PyXIData_FormatNotShareableError(
PyThreadState *,
const char *,
...);

PyAPI_FUNC(xidatafunc) _PyXIData_Lookup(
PyThreadState *,
PyObject *);
PyAPI_FUNC(int) _PyObject_CheckXIData(
PyThreadState *,
PyObject *);

PyAPI_FUNC(int) _PyObject_GetXIData(
PyThreadState *,
PyObject *,
_PyXIData_t *);


/* using cross-interpreter data */

PyAPI_FUNC(PyObject *) _PyXIData_NewObject(_PyXIData_t *);
PyAPI_FUNC(int) _PyXIData_Release(_PyXIData_t *);
PyAPI_FUNC(int) _PyXIData_ReleaseAndRawFree(_PyXIData_t *);


/* cross-interpreter data registry */

#define Py_CORE_CROSSINTERP_DATA_REGISTRY_H
Expand Down
230 changes: 230 additions & 0 deletions Lib/test/_crossinterp_definitions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
# This may be loaded as a module, in the current __main__ module,
# or in another __main__ module.


#######################################
# functions

def spam_minimal():
# no arg defaults or kwarg defaults
# no annotations
# no local vars
# no free vars
# no globals
# no builtins
# no attr access (names)
# no code
return


def spam_full(a, b, /, c, d:int=1, *args, e, f:object=None, **kwargs) -> tuple:
# arg defaults, kwarg defaults
# annotations
# all kinds of local vars, except cells
# no free vars
# some globals
# some builtins
# some attr access (names)
x = args
y = kwargs
z = (a, b, c, d)
kwargs['e'] = e
kwargs['f'] = f
extras = list((x, y, z, spam, spam.__name__))
return tuple(a, b, c, d, e, f, args, kwargs), extras


def spam(x):
return x, None


def spam_N(x):
def eggs_nested(y):
return None, y
return eggs_nested, x


def spam_C(x):
a = 1
def eggs_closure(y):
return None, y, a, x
return eggs_closure, a, x


def spam_NN(x):
def eggs_nested_N(y):
def ham_nested(z):
return None, z
return ham_nested, y
return eggs_nested_N, x


def spam_NC(x):
a = 1
def eggs_nested_C(y):
def ham_closure(z):
return None, z, y, a, x
return ham_closure, y
return eggs_nested_C, a, x


def spam_CN(x):
a = 1
def eggs_closure_N(y):
def ham_C_nested(z):
return None, z
return ham_C_nested, y, a, x
return eggs_closure_N, a, x


def spam_CC(x):
a = 1
def eggs_closure_C(y):
b = 2
def ham_C_closure(z):
return None, z, b, y, a, x
return ham_C_closure, b, y, a, x
return eggs_closure_N, a, x


eggs_nested, *_ = spam_N(1)
eggs_closure, *_ = spam_C(1)
eggs_nested_N, *_ = spam_NN(1)
eggs_nested_C, *_ = spam_NC(1)
eggs_closure_N, *_ = spam_CN(1)
eggs_closure_C, *_ = spam_CC(1)

ham_nested, *_ = eggs_nested_N(2)
ham_closure, *_ = eggs_nested_C(2)
ham_C_nested, *_ = eggs_closure_N(2)
ham_C_closure, *_ = eggs_closure_C(2)


FUNCTIONS = [
# shallow
spam_minimal,
spam_full,
spam,
# outer func
spam_N,
spam_C,
spam_NN,
spam_NC,
spam_CN,
spam_CC,
# inner func
eggs_nested,
eggs_closure,
eggs_nested_N,
eggs_nested_C,
eggs_closure_N,
eggs_closure_C,
# inner inner func
ham_nested,
ham_closure,
ham_C_nested,
ham_C_closure,
]


#######################################
# function-like

# generators

def gen_spam_1(*args):
for arg in args:
yield arg


def gen_spam_2(*args):
yield from args


async def async_spam():
pass
coro_spam = async_spam()
coro_spam.close()


async def asyncgen_spam(*args):
for arg in args:
yield arg
asynccoro_spam = asyncgen_spam(1, 2, 3)


FUNCTION_LIKE = [
gen_spam_1,
gen_spam_2,
async_spam,
coro_spam, # actually FunctionType?
asyncgen_spam,
asynccoro_spam, # actually FunctionType?
]


#######################################
# classes

class Spam:
# minimal
pass


class SpamOkay:
def okay(self):
return True


class SpamFull:

a: object
b: object
c: object

@staticmethod
def staticmeth(cls):
return True

@classmethod
def classmeth(cls):
return True

def __new__(cls, *args, **kwargs):
return super().__new__(cls)

def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c

# __repr__
# __str__
# ...

@property
def prop(self):
return True


class SubSpamFull(SpamFull):
...


class SubTuple(tuple):
...


def class_eggs_inner():
class EggsNested:
...
return EggsNested
EggsNested = class_eggs_inner()



#######################################
# exceptions

class MimimalError(Exception):
pass
Loading
Loading