Skip to content

Commit ae56892

Browse files
authored
1 parent dd73273 commit ae56892

File tree

1 file changed

+263
-1
lines changed

1 file changed

+263
-1
lines changed

mypyc/lib-rt/pythoncapi_compat.h

+263-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ extern "C" {
1919
#endif
2020

2121
#include <Python.h>
22+
#include <stddef.h> // offsetof()
2223

2324
// Python 3.11.0b4 added PyFrame_Back() to Python.h
2425
#if PY_VERSION_HEX < 0x030b00B4 && !defined(PYPY_VERSION)
@@ -583,7 +584,7 @@ static inline int PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
583584
return 0;
584585
}
585586
*pobj = Py_NewRef(obj);
586-
return (*pobj != NULL);
587+
return 1;
587588
}
588589
#endif
589590

@@ -1933,6 +1934,267 @@ PyLongWriter_Finish(PyLongWriter *writer)
19331934
#endif
19341935

19351936

1937+
// gh-127350 added Py_fopen() and Py_fclose() to Python 3.14a4
1938+
#if PY_VERSION_HEX < 0x030E00A4
1939+
static inline FILE* Py_fopen(PyObject *path, const char *mode)
1940+
{
1941+
#if 0x030400A2 <= PY_VERSION_HEX && !defined(PYPY_VERSION)
1942+
extern FILE* _Py_fopen_obj(PyObject *path, const char *mode);
1943+
return _Py_fopen_obj(path, mode);
1944+
#else
1945+
FILE *f;
1946+
PyObject *bytes;
1947+
#if PY_VERSION_HEX >= 0x03000000
1948+
if (!PyUnicode_FSConverter(path, &bytes)) {
1949+
return NULL;
1950+
}
1951+
#else
1952+
if (!PyString_Check(path)) {
1953+
PyErr_SetString(PyExc_TypeError, "except str");
1954+
return NULL;
1955+
}
1956+
bytes = Py_NewRef(path);
1957+
#endif
1958+
const char *path_bytes = PyBytes_AS_STRING(bytes);
1959+
1960+
f = fopen(path_bytes, mode);
1961+
Py_DECREF(bytes);
1962+
1963+
if (f == NULL) {
1964+
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path);
1965+
return NULL;
1966+
}
1967+
return f;
1968+
#endif
1969+
}
1970+
1971+
static inline int Py_fclose(FILE *file)
1972+
{
1973+
return fclose(file);
1974+
}
1975+
#endif
1976+
1977+
1978+
#if 0x03090000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030E0000 && !defined(PYPY_VERSION)
1979+
static inline PyObject*
1980+
PyConfig_Get(const char *name)
1981+
{
1982+
typedef enum {
1983+
_PyConfig_MEMBER_INT,
1984+
_PyConfig_MEMBER_UINT,
1985+
_PyConfig_MEMBER_ULONG,
1986+
_PyConfig_MEMBER_BOOL,
1987+
_PyConfig_MEMBER_WSTR,
1988+
_PyConfig_MEMBER_WSTR_OPT,
1989+
_PyConfig_MEMBER_WSTR_LIST,
1990+
} PyConfigMemberType;
1991+
1992+
typedef struct {
1993+
const char *name;
1994+
size_t offset;
1995+
PyConfigMemberType type;
1996+
const char *sys_attr;
1997+
} PyConfigSpec;
1998+
1999+
#define PYTHONCAPI_COMPAT_SPEC(MEMBER, TYPE, sys_attr) \
2000+
{#MEMBER, offsetof(PyConfig, MEMBER), \
2001+
_PyConfig_MEMBER_##TYPE, sys_attr}
2002+
2003+
static const PyConfigSpec config_spec[] = {
2004+
PYTHONCAPI_COMPAT_SPEC(argv, WSTR_LIST, "argv"),
2005+
PYTHONCAPI_COMPAT_SPEC(base_exec_prefix, WSTR_OPT, "base_exec_prefix"),
2006+
PYTHONCAPI_COMPAT_SPEC(base_executable, WSTR_OPT, "_base_executable"),
2007+
PYTHONCAPI_COMPAT_SPEC(base_prefix, WSTR_OPT, "base_prefix"),
2008+
PYTHONCAPI_COMPAT_SPEC(bytes_warning, UINT, _Py_NULL),
2009+
PYTHONCAPI_COMPAT_SPEC(exec_prefix, WSTR_OPT, "exec_prefix"),
2010+
PYTHONCAPI_COMPAT_SPEC(executable, WSTR_OPT, "executable"),
2011+
PYTHONCAPI_COMPAT_SPEC(inspect, BOOL, _Py_NULL),
2012+
#if 0x030C0000 <= PY_VERSION_HEX
2013+
PYTHONCAPI_COMPAT_SPEC(int_max_str_digits, UINT, _Py_NULL),
2014+
#endif
2015+
PYTHONCAPI_COMPAT_SPEC(interactive, BOOL, _Py_NULL),
2016+
PYTHONCAPI_COMPAT_SPEC(module_search_paths, WSTR_LIST, "path"),
2017+
PYTHONCAPI_COMPAT_SPEC(optimization_level, UINT, _Py_NULL),
2018+
PYTHONCAPI_COMPAT_SPEC(parser_debug, BOOL, _Py_NULL),
2019+
PYTHONCAPI_COMPAT_SPEC(platlibdir, WSTR, "platlibdir"),
2020+
PYTHONCAPI_COMPAT_SPEC(prefix, WSTR_OPT, "prefix"),
2021+
PYTHONCAPI_COMPAT_SPEC(pycache_prefix, WSTR_OPT, "pycache_prefix"),
2022+
PYTHONCAPI_COMPAT_SPEC(quiet, BOOL, _Py_NULL),
2023+
#if 0x030B0000 <= PY_VERSION_HEX
2024+
PYTHONCAPI_COMPAT_SPEC(stdlib_dir, WSTR_OPT, "_stdlib_dir"),
2025+
#endif
2026+
PYTHONCAPI_COMPAT_SPEC(use_environment, BOOL, _Py_NULL),
2027+
PYTHONCAPI_COMPAT_SPEC(verbose, UINT, _Py_NULL),
2028+
PYTHONCAPI_COMPAT_SPEC(warnoptions, WSTR_LIST, "warnoptions"),
2029+
PYTHONCAPI_COMPAT_SPEC(write_bytecode, BOOL, _Py_NULL),
2030+
PYTHONCAPI_COMPAT_SPEC(xoptions, WSTR_LIST, "_xoptions"),
2031+
PYTHONCAPI_COMPAT_SPEC(buffered_stdio, BOOL, _Py_NULL),
2032+
PYTHONCAPI_COMPAT_SPEC(check_hash_pycs_mode, WSTR, _Py_NULL),
2033+
#if 0x030B0000 <= PY_VERSION_HEX
2034+
PYTHONCAPI_COMPAT_SPEC(code_debug_ranges, BOOL, _Py_NULL),
2035+
#endif
2036+
PYTHONCAPI_COMPAT_SPEC(configure_c_stdio, BOOL, _Py_NULL),
2037+
#if 0x030D0000 <= PY_VERSION_HEX
2038+
PYTHONCAPI_COMPAT_SPEC(cpu_count, INT, _Py_NULL),
2039+
#endif
2040+
PYTHONCAPI_COMPAT_SPEC(dev_mode, BOOL, _Py_NULL),
2041+
PYTHONCAPI_COMPAT_SPEC(dump_refs, BOOL, _Py_NULL),
2042+
#if 0x030B0000 <= PY_VERSION_HEX
2043+
PYTHONCAPI_COMPAT_SPEC(dump_refs_file, WSTR_OPT, _Py_NULL),
2044+
#endif
2045+
#ifdef Py_GIL_DISABLED
2046+
PYTHONCAPI_COMPAT_SPEC(enable_gil, INT, _Py_NULL),
2047+
#endif
2048+
PYTHONCAPI_COMPAT_SPEC(faulthandler, BOOL, _Py_NULL),
2049+
PYTHONCAPI_COMPAT_SPEC(filesystem_encoding, WSTR, _Py_NULL),
2050+
PYTHONCAPI_COMPAT_SPEC(filesystem_errors, WSTR, _Py_NULL),
2051+
PYTHONCAPI_COMPAT_SPEC(hash_seed, ULONG, _Py_NULL),
2052+
PYTHONCAPI_COMPAT_SPEC(home, WSTR_OPT, _Py_NULL),
2053+
PYTHONCAPI_COMPAT_SPEC(import_time, BOOL, _Py_NULL),
2054+
PYTHONCAPI_COMPAT_SPEC(install_signal_handlers, BOOL, _Py_NULL),
2055+
PYTHONCAPI_COMPAT_SPEC(isolated, BOOL, _Py_NULL),
2056+
#ifdef MS_WINDOWS
2057+
PYTHONCAPI_COMPAT_SPEC(legacy_windows_stdio, BOOL, _Py_NULL),
2058+
#endif
2059+
PYTHONCAPI_COMPAT_SPEC(malloc_stats, BOOL, _Py_NULL),
2060+
#if 0x030A0000 <= PY_VERSION_HEX
2061+
PYTHONCAPI_COMPAT_SPEC(orig_argv, WSTR_LIST, "orig_argv"),
2062+
#endif
2063+
PYTHONCAPI_COMPAT_SPEC(parse_argv, BOOL, _Py_NULL),
2064+
PYTHONCAPI_COMPAT_SPEC(pathconfig_warnings, BOOL, _Py_NULL),
2065+
#if 0x030C0000 <= PY_VERSION_HEX
2066+
PYTHONCAPI_COMPAT_SPEC(perf_profiling, UINT, _Py_NULL),
2067+
#endif
2068+
PYTHONCAPI_COMPAT_SPEC(program_name, WSTR, _Py_NULL),
2069+
PYTHONCAPI_COMPAT_SPEC(run_command, WSTR_OPT, _Py_NULL),
2070+
PYTHONCAPI_COMPAT_SPEC(run_filename, WSTR_OPT, _Py_NULL),
2071+
PYTHONCAPI_COMPAT_SPEC(run_module, WSTR_OPT, _Py_NULL),
2072+
#if 0x030B0000 <= PY_VERSION_HEX
2073+
PYTHONCAPI_COMPAT_SPEC(safe_path, BOOL, _Py_NULL),
2074+
#endif
2075+
PYTHONCAPI_COMPAT_SPEC(show_ref_count, BOOL, _Py_NULL),
2076+
PYTHONCAPI_COMPAT_SPEC(site_import, BOOL, _Py_NULL),
2077+
PYTHONCAPI_COMPAT_SPEC(skip_source_first_line, BOOL, _Py_NULL),
2078+
PYTHONCAPI_COMPAT_SPEC(stdio_encoding, WSTR, _Py_NULL),
2079+
PYTHONCAPI_COMPAT_SPEC(stdio_errors, WSTR, _Py_NULL),
2080+
PYTHONCAPI_COMPAT_SPEC(tracemalloc, UINT, _Py_NULL),
2081+
#if 0x030B0000 <= PY_VERSION_HEX
2082+
PYTHONCAPI_COMPAT_SPEC(use_frozen_modules, BOOL, _Py_NULL),
2083+
#endif
2084+
PYTHONCAPI_COMPAT_SPEC(use_hash_seed, BOOL, _Py_NULL),
2085+
PYTHONCAPI_COMPAT_SPEC(user_site_directory, BOOL, _Py_NULL),
2086+
#if 0x030A0000 <= PY_VERSION_HEX
2087+
PYTHONCAPI_COMPAT_SPEC(warn_default_encoding, BOOL, _Py_NULL),
2088+
#endif
2089+
};
2090+
2091+
#undef PYTHONCAPI_COMPAT_SPEC
2092+
2093+
const PyConfigSpec *spec;
2094+
int found = 0;
2095+
for (size_t i=0; i < sizeof(config_spec) / sizeof(config_spec[0]); i++) {
2096+
spec = &config_spec[i];
2097+
if (strcmp(spec->name, name) == 0) {
2098+
found = 1;
2099+
break;
2100+
}
2101+
}
2102+
if (found) {
2103+
if (spec->sys_attr != NULL) {
2104+
PyObject *value = PySys_GetObject(spec->sys_attr);
2105+
if (value == NULL) {
2106+
PyErr_Format(PyExc_RuntimeError, "lost sys.%s", spec->sys_attr);
2107+
return NULL;
2108+
}
2109+
return Py_NewRef(value);
2110+
}
2111+
2112+
extern const PyConfig* _Py_GetConfig(void);
2113+
const PyConfig *config = _Py_GetConfig();
2114+
void *member = (char *)config + spec->offset;
2115+
switch (spec->type) {
2116+
case _PyConfig_MEMBER_INT:
2117+
case _PyConfig_MEMBER_UINT:
2118+
{
2119+
int value = *(int *)member;
2120+
return PyLong_FromLong(value);
2121+
}
2122+
case _PyConfig_MEMBER_BOOL:
2123+
{
2124+
int value = *(int *)member;
2125+
return PyBool_FromLong(value != 0);
2126+
}
2127+
case _PyConfig_MEMBER_ULONG:
2128+
{
2129+
unsigned long value = *(unsigned long *)member;
2130+
return PyLong_FromUnsignedLong(value);
2131+
}
2132+
case _PyConfig_MEMBER_WSTR:
2133+
case _PyConfig_MEMBER_WSTR_OPT:
2134+
{
2135+
wchar_t *wstr = *(wchar_t **)member;
2136+
if (wstr != NULL) {
2137+
return PyUnicode_FromWideChar(wstr, -1);
2138+
}
2139+
else {
2140+
return Py_NewRef(Py_None);
2141+
}
2142+
}
2143+
case _PyConfig_MEMBER_WSTR_LIST:
2144+
{
2145+
const PyWideStringList *list = (const PyWideStringList *)member;
2146+
PyObject *tuple = PyTuple_New(list->length);
2147+
if (tuple == NULL) {
2148+
return NULL;
2149+
}
2150+
2151+
for (Py_ssize_t i = 0; i < list->length; i++) {
2152+
PyObject *item = PyUnicode_FromWideChar(list->items[i], -1);
2153+
if (item == NULL) {
2154+
Py_DECREF(tuple);
2155+
return NULL;
2156+
}
2157+
PyTuple_SET_ITEM(tuple, i, item);
2158+
}
2159+
return tuple;
2160+
}
2161+
default:
2162+
Py_UNREACHABLE();
2163+
}
2164+
}
2165+
2166+
PyErr_Format(PyExc_ValueError, "unknown config option name: %s", name);
2167+
return NULL;
2168+
}
2169+
2170+
static inline int
2171+
PyConfig_GetInt(const char *name, int *value)
2172+
{
2173+
PyObject *obj = PyConfig_Get(name);
2174+
if (obj == NULL) {
2175+
return -1;
2176+
}
2177+
2178+
if (!PyLong_Check(obj)) {
2179+
Py_DECREF(obj);
2180+
PyErr_Format(PyExc_TypeError, "config option %s is not an int", name);
2181+
return -1;
2182+
}
2183+
2184+
int as_int = PyLong_AsInt(obj);
2185+
Py_DECREF(obj);
2186+
if (as_int == -1 && PyErr_Occurred()) {
2187+
PyErr_Format(PyExc_OverflowError,
2188+
"config option %s value does not fit into a C int", name);
2189+
return -1;
2190+
}
2191+
2192+
*value = as_int;
2193+
return 0;
2194+
}
2195+
#endif // PY_VERSION_HEX > 0x03090000 && !defined(PYPY_VERSION)
2196+
2197+
19362198
#ifdef __cplusplus
19372199
}
19382200
#endif

0 commit comments

Comments
 (0)