Skip to content
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

Update pythoncapi_compat.h #18535

Merged
merged 1 commit into from
Jan 27, 2025
Merged
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
264 changes: 263 additions & 1 deletion mypyc/lib-rt/pythoncapi_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ extern "C" {
#endif

#include <Python.h>
#include <stddef.h> // offsetof()

// Python 3.11.0b4 added PyFrame_Back() to Python.h
#if PY_VERSION_HEX < 0x030b00B4 && !defined(PYPY_VERSION)
Expand Down Expand Up @@ -583,7 +584,7 @@ static inline int PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
return 0;
}
*pobj = Py_NewRef(obj);
return (*pobj != NULL);
return 1;
}
#endif

Expand Down Expand Up @@ -1933,6 +1934,267 @@ PyLongWriter_Finish(PyLongWriter *writer)
#endif


// gh-127350 added Py_fopen() and Py_fclose() to Python 3.14a4
#if PY_VERSION_HEX < 0x030E00A4
static inline FILE* Py_fopen(PyObject *path, const char *mode)
{
#if 0x030400A2 <= PY_VERSION_HEX && !defined(PYPY_VERSION)
extern FILE* _Py_fopen_obj(PyObject *path, const char *mode);
return _Py_fopen_obj(path, mode);
#else
FILE *f;
PyObject *bytes;
#if PY_VERSION_HEX >= 0x03000000
if (!PyUnicode_FSConverter(path, &bytes)) {
return NULL;
}
#else
if (!PyString_Check(path)) {
PyErr_SetString(PyExc_TypeError, "except str");
return NULL;
}
bytes = Py_NewRef(path);
#endif
const char *path_bytes = PyBytes_AS_STRING(bytes);

f = fopen(path_bytes, mode);
Py_DECREF(bytes);

if (f == NULL) {
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path);
return NULL;
}
return f;
#endif
}

static inline int Py_fclose(FILE *file)
{
return fclose(file);
}
#endif


#if 0x03090000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030E0000 && !defined(PYPY_VERSION)
static inline PyObject*
PyConfig_Get(const char *name)
{
typedef enum {
_PyConfig_MEMBER_INT,
_PyConfig_MEMBER_UINT,
_PyConfig_MEMBER_ULONG,
_PyConfig_MEMBER_BOOL,
_PyConfig_MEMBER_WSTR,
_PyConfig_MEMBER_WSTR_OPT,
_PyConfig_MEMBER_WSTR_LIST,
} PyConfigMemberType;

typedef struct {
const char *name;
size_t offset;
PyConfigMemberType type;
const char *sys_attr;
} PyConfigSpec;

#define PYTHONCAPI_COMPAT_SPEC(MEMBER, TYPE, sys_attr) \
{#MEMBER, offsetof(PyConfig, MEMBER), \
_PyConfig_MEMBER_##TYPE, sys_attr}

static const PyConfigSpec config_spec[] = {
PYTHONCAPI_COMPAT_SPEC(argv, WSTR_LIST, "argv"),
PYTHONCAPI_COMPAT_SPEC(base_exec_prefix, WSTR_OPT, "base_exec_prefix"),
PYTHONCAPI_COMPAT_SPEC(base_executable, WSTR_OPT, "_base_executable"),
PYTHONCAPI_COMPAT_SPEC(base_prefix, WSTR_OPT, "base_prefix"),
PYTHONCAPI_COMPAT_SPEC(bytes_warning, UINT, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(exec_prefix, WSTR_OPT, "exec_prefix"),
PYTHONCAPI_COMPAT_SPEC(executable, WSTR_OPT, "executable"),
PYTHONCAPI_COMPAT_SPEC(inspect, BOOL, _Py_NULL),
#if 0x030C0000 <= PY_VERSION_HEX
PYTHONCAPI_COMPAT_SPEC(int_max_str_digits, UINT, _Py_NULL),
#endif
PYTHONCAPI_COMPAT_SPEC(interactive, BOOL, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(module_search_paths, WSTR_LIST, "path"),
PYTHONCAPI_COMPAT_SPEC(optimization_level, UINT, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(parser_debug, BOOL, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(platlibdir, WSTR, "platlibdir"),
PYTHONCAPI_COMPAT_SPEC(prefix, WSTR_OPT, "prefix"),
PYTHONCAPI_COMPAT_SPEC(pycache_prefix, WSTR_OPT, "pycache_prefix"),
PYTHONCAPI_COMPAT_SPEC(quiet, BOOL, _Py_NULL),
#if 0x030B0000 <= PY_VERSION_HEX
PYTHONCAPI_COMPAT_SPEC(stdlib_dir, WSTR_OPT, "_stdlib_dir"),
#endif
PYTHONCAPI_COMPAT_SPEC(use_environment, BOOL, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(verbose, UINT, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(warnoptions, WSTR_LIST, "warnoptions"),
PYTHONCAPI_COMPAT_SPEC(write_bytecode, BOOL, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(xoptions, WSTR_LIST, "_xoptions"),
PYTHONCAPI_COMPAT_SPEC(buffered_stdio, BOOL, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(check_hash_pycs_mode, WSTR, _Py_NULL),
#if 0x030B0000 <= PY_VERSION_HEX
PYTHONCAPI_COMPAT_SPEC(code_debug_ranges, BOOL, _Py_NULL),
#endif
PYTHONCAPI_COMPAT_SPEC(configure_c_stdio, BOOL, _Py_NULL),
#if 0x030D0000 <= PY_VERSION_HEX
PYTHONCAPI_COMPAT_SPEC(cpu_count, INT, _Py_NULL),
#endif
PYTHONCAPI_COMPAT_SPEC(dev_mode, BOOL, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(dump_refs, BOOL, _Py_NULL),
#if 0x030B0000 <= PY_VERSION_HEX
PYTHONCAPI_COMPAT_SPEC(dump_refs_file, WSTR_OPT, _Py_NULL),
#endif
#ifdef Py_GIL_DISABLED
PYTHONCAPI_COMPAT_SPEC(enable_gil, INT, _Py_NULL),
#endif
PYTHONCAPI_COMPAT_SPEC(faulthandler, BOOL, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(filesystem_encoding, WSTR, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(filesystem_errors, WSTR, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(hash_seed, ULONG, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(home, WSTR_OPT, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(import_time, BOOL, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(install_signal_handlers, BOOL, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(isolated, BOOL, _Py_NULL),
#ifdef MS_WINDOWS
PYTHONCAPI_COMPAT_SPEC(legacy_windows_stdio, BOOL, _Py_NULL),
#endif
PYTHONCAPI_COMPAT_SPEC(malloc_stats, BOOL, _Py_NULL),
#if 0x030A0000 <= PY_VERSION_HEX
PYTHONCAPI_COMPAT_SPEC(orig_argv, WSTR_LIST, "orig_argv"),
#endif
PYTHONCAPI_COMPAT_SPEC(parse_argv, BOOL, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(pathconfig_warnings, BOOL, _Py_NULL),
#if 0x030C0000 <= PY_VERSION_HEX
PYTHONCAPI_COMPAT_SPEC(perf_profiling, UINT, _Py_NULL),
#endif
PYTHONCAPI_COMPAT_SPEC(program_name, WSTR, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(run_command, WSTR_OPT, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(run_filename, WSTR_OPT, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(run_module, WSTR_OPT, _Py_NULL),
#if 0x030B0000 <= PY_VERSION_HEX
PYTHONCAPI_COMPAT_SPEC(safe_path, BOOL, _Py_NULL),
#endif
PYTHONCAPI_COMPAT_SPEC(show_ref_count, BOOL, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(site_import, BOOL, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(skip_source_first_line, BOOL, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(stdio_encoding, WSTR, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(stdio_errors, WSTR, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(tracemalloc, UINT, _Py_NULL),
#if 0x030B0000 <= PY_VERSION_HEX
PYTHONCAPI_COMPAT_SPEC(use_frozen_modules, BOOL, _Py_NULL),
#endif
PYTHONCAPI_COMPAT_SPEC(use_hash_seed, BOOL, _Py_NULL),
PYTHONCAPI_COMPAT_SPEC(user_site_directory, BOOL, _Py_NULL),
#if 0x030A0000 <= PY_VERSION_HEX
PYTHONCAPI_COMPAT_SPEC(warn_default_encoding, BOOL, _Py_NULL),
#endif
};

#undef PYTHONCAPI_COMPAT_SPEC

const PyConfigSpec *spec;
int found = 0;
for (size_t i=0; i < sizeof(config_spec) / sizeof(config_spec[0]); i++) {
spec = &config_spec[i];
if (strcmp(spec->name, name) == 0) {
found = 1;
break;
}
}
if (found) {
if (spec->sys_attr != NULL) {
PyObject *value = PySys_GetObject(spec->sys_attr);
if (value == NULL) {
PyErr_Format(PyExc_RuntimeError, "lost sys.%s", spec->sys_attr);
return NULL;
}
return Py_NewRef(value);
}

extern const PyConfig* _Py_GetConfig(void);
const PyConfig *config = _Py_GetConfig();
void *member = (char *)config + spec->offset;
switch (spec->type) {
case _PyConfig_MEMBER_INT:
case _PyConfig_MEMBER_UINT:
{
int value = *(int *)member;
return PyLong_FromLong(value);
}
case _PyConfig_MEMBER_BOOL:
{
int value = *(int *)member;
return PyBool_FromLong(value != 0);
}
case _PyConfig_MEMBER_ULONG:
{
unsigned long value = *(unsigned long *)member;
return PyLong_FromUnsignedLong(value);
}
case _PyConfig_MEMBER_WSTR:
case _PyConfig_MEMBER_WSTR_OPT:
{
wchar_t *wstr = *(wchar_t **)member;
if (wstr != NULL) {
return PyUnicode_FromWideChar(wstr, -1);
}
else {
return Py_NewRef(Py_None);
}
}
case _PyConfig_MEMBER_WSTR_LIST:
{
const PyWideStringList *list = (const PyWideStringList *)member;
PyObject *tuple = PyTuple_New(list->length);
if (tuple == NULL) {
return NULL;
}

for (Py_ssize_t i = 0; i < list->length; i++) {
PyObject *item = PyUnicode_FromWideChar(list->items[i], -1);
if (item == NULL) {
Py_DECREF(tuple);
return NULL;
}
PyTuple_SET_ITEM(tuple, i, item);
}
return tuple;
}
default:
Py_UNREACHABLE();
}
}

PyErr_Format(PyExc_ValueError, "unknown config option name: %s", name);
return NULL;
}

static inline int
PyConfig_GetInt(const char *name, int *value)
{
PyObject *obj = PyConfig_Get(name);
if (obj == NULL) {
return -1;
}

if (!PyLong_Check(obj)) {
Py_DECREF(obj);
PyErr_Format(PyExc_TypeError, "config option %s is not an int", name);
return -1;
}

int as_int = PyLong_AsInt(obj);
Py_DECREF(obj);
if (as_int == -1 && PyErr_Occurred()) {
PyErr_Format(PyExc_OverflowError,
"config option %s value does not fit into a C int", name);
return -1;
}

*value = as_int;
return 0;
}
#endif // PY_VERSION_HEX > 0x03090000 && !defined(PYPY_VERSION)


#ifdef __cplusplus
}
#endif
Expand Down
Loading