| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -177,11 +177,17 @@ Python 3.14 | |||
| 177 | 177 | ||
| 178 | 178 | See `Py_fclose() documentation <https://docs.python.org/dev/c-api/sys.html#c.Py_fclose>`__. | |
| 179 | 179 | ||
| 180 | + .. c:function:: PyObject* PyConfig_Get(const char *name) | ||
| 181 | + | ||
| 182 | + See `PyConfig_Get() documentation <https://docs.python.org/dev/c-api/init_config.html#c.PyConfig_Get>`__. | ||
| 183 | + | ||
| 184 | + .. c:function:: int PyConfig_GetInt(const char *name, int *value) | ||
| 185 | + | ||
| 186 | + See `PyConfig_GetInt() documentation <https://docs.python.org/dev/c-api/init_config.html#c.PyConfig_GetInt>`__. | ||
| 187 | + | ||
| 180 | 188 | ||
| 181 | 189 | Not supported: | |
| 182 | 190 | ||
| 183 | - * ``PyConfig_Get()`` | ||
| 184 | - * ``PyConfig_GetInt()`` | ||
| 185 | 191 | * ``PyConfig_Names()`` | |
| 186 | 192 | * ``PyConfig_Set()`` | |
| 187 | 193 | * ``PyInitConfig_AddModule()`` | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,6 +1,7 @@ | |||
| 1 | 1 | Changelog | |
| 2 | 2 | ========= | |
| 3 | 3 | ||
| 4 | + * 2025-01-19: Add ``PyConfig_Get()`` functions. | ||
| 4 | 5 | * 2025-01-06: Add ``Py_fopen()`` and ``Py_fclose()`` functions. | |
| 5 | 6 | * 2024-12-16: Add ``structmember.h`` constants: | |
| 6 | 7 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -19,6 +19,7 @@ extern "C" { | |||
| 19 | 19 | #endif | |
| 20 | 20 | ||
| 21 | 21 | #include <Python.h> | |
| 22 | + #include <stddef.h> // offsetof() | ||
| 22 | 23 | ||
| 23 | 24 | // Python 3.11.0b4 added PyFrame_Back() to Python.h | |
| 24 | 25 | #if PY_VERSION_HEX < 0x030b00B4 && !defined(PYPY_VERSION) | |
@@ -1974,6 +1975,229 @@ int Py_fclose(FILE *file) | |||
| 1974 | 1975 | #endif | |
| 1975 | 1976 | ||
| 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 | + #if 0x030D0000 <= PY_VERSION_HEX && defined(__APPLE__) | ||
| 2086 | + PYTHONCAPI_COMPAT_SPEC(use_system_logger, BOOL, _Py_NULL), | ||
| 2087 | + #endif | ||
| 2088 | + PYTHONCAPI_COMPAT_SPEC(user_site_directory, BOOL, _Py_NULL), | ||
| 2089 | + #if 0x030A0000 <= PY_VERSION_HEX | ||
| 2090 | + PYTHONCAPI_COMPAT_SPEC(warn_default_encoding, BOOL, _Py_NULL), | ||
| 2091 | + #endif | ||
| 2092 | + }; | ||
| 2093 | + | ||
| 2094 | + #undef PYTHONCAPI_COMPAT_SPEC | ||
| 2095 | + | ||
| 2096 | + const PyConfigSpec *spec; | ||
| 2097 | + int found = 0; | ||
| 2098 | + for (size_t i=0; i < Py_ARRAY_LENGTH(config_spec); i++) { | ||
| 2099 | + spec = &config_spec[i]; | ||
| 2100 | + if (strcmp(spec->name, name) == 0) { | ||
| 2101 | + found = 1; | ||
| 2102 | + break; | ||
| 2103 | + } | ||
| 2104 | + } | ||
| 2105 | + if (found) { | ||
| 2106 | + if (spec->sys_attr != NULL) { | ||
| 2107 | + PyObject *value = PySys_GetObject(spec->sys_attr); | ||
| 2108 | + if (value == NULL) { | ||
| 2109 | + PyErr_Format(PyExc_RuntimeError, "lost sys.%s", spec->sys_attr); | ||
| 2110 | + return NULL; | ||
| 2111 | + } | ||
| 2112 | + return Py_NewRef(value); | ||
| 2113 | + } | ||
| 2114 | + | ||
| 2115 | + extern const PyConfig* _Py_GetConfig(void); | ||
| 2116 | + const PyConfig *config = _Py_GetConfig(); | ||
| 2117 | + void *member = (char *)config + spec->offset; | ||
| 2118 | + switch (spec->type) { | ||
| 2119 | + case _PyConfig_MEMBER_INT: | ||
| 2120 | + case _PyConfig_MEMBER_UINT: | ||
| 2121 | + { | ||
| 2122 | + int value = *(int *)member; | ||
| 2123 | + return PyLong_FromLong(value); | ||
| 2124 | + } | ||
| 2125 | + case _PyConfig_MEMBER_BOOL: | ||
| 2126 | + { | ||
| 2127 | + int value = *(int *)member; | ||
| 2128 | + return PyBool_FromLong(value != 0); | ||
| 2129 | + } | ||
| 2130 | + case _PyConfig_MEMBER_ULONG: | ||
| 2131 | + { | ||
| 2132 | + unsigned long value = *(unsigned long *)member; | ||
| 2133 | + return PyLong_FromUnsignedLong(value); | ||
| 2134 | + } | ||
| 2135 | + case _PyConfig_MEMBER_WSTR: | ||
| 2136 | + case _PyConfig_MEMBER_WSTR_OPT: | ||
| 2137 | + { | ||
| 2138 | + wchar_t *wstr = *(wchar_t **)member; | ||
| 2139 | + if (wstr != NULL) { | ||
| 2140 | + return PyUnicode_FromWideChar(wstr, -1); | ||
| 2141 | + } | ||
| 2142 | + else { | ||
| 2143 | + return Py_NewRef(Py_None); | ||
| 2144 | + } | ||
| 2145 | + } | ||
| 2146 | + case _PyConfig_MEMBER_WSTR_LIST: | ||
| 2147 | + { | ||
| 2148 | + const PyWideStringList *list = (const PyWideStringList *)member; | ||
| 2149 | + PyObject *tuple = PyTuple_New(list->length); | ||
| 2150 | + if (tuple == NULL) { | ||
| 2151 | + return NULL; | ||
| 2152 | + } | ||
| 2153 | + | ||
| 2154 | + for (Py_ssize_t i = 0; i < list->length; i++) { | ||
| 2155 | + PyObject *item = PyUnicode_FromWideChar(list->items[i], -1); | ||
| 2156 | + if (item == NULL) { | ||
| 2157 | + Py_DECREF(tuple); | ||
| 2158 | + return NULL; | ||
| 2159 | + } | ||
| 2160 | + PyTuple_SET_ITEM(tuple, i, item); | ||
| 2161 | + } | ||
| 2162 | + return tuple; | ||
| 2163 | + } | ||
| 2164 | + default: | ||
| 2165 | + Py_UNREACHABLE(); | ||
| 2166 | + } | ||
| 2167 | + } | ||
| 2168 | + | ||
| 2169 | + PyErr_Format(PyExc_ValueError, "unknown config option name: %s", name); | ||
| 2170 | + return NULL; | ||
| 2171 | + } | ||
| 2172 | + | ||
| 2173 | + static inline int | ||
| 2174 | + PyConfig_GetInt(const char *name, int *value) | ||
| 2175 | + { | ||
| 2176 | + PyObject *obj = PyConfig_Get(name); | ||
| 2177 | + if (obj == NULL) { | ||
| 2178 | + return -1; | ||
| 2179 | + } | ||
| 2180 | + | ||
| 2181 | + if (!PyLong_Check(obj)) { | ||
| 2182 | + Py_DECREF(obj); | ||
| 2183 | + PyErr_Format(PyExc_TypeError, "config option %s is not an int", name); | ||
| 2184 | + return -1; | ||
| 2185 | + } | ||
| 2186 | + | ||
| 2187 | + int as_int = PyLong_AsInt(obj); | ||
| 2188 | + Py_DECREF(obj); | ||
| 2189 | + if (as_int == -1 && PyErr_Occurred()) { | ||
| 2190 | + PyErr_Format(PyExc_OverflowError, | ||
| 2191 | + "config option %s value does not fit into a C int", name); | ||
| 2192 | + return -1; | ||
| 2193 | + } | ||
| 2194 | + | ||
| 2195 | + *value = as_int; | ||
| 2196 | + return 0; | ||
| 2197 | + } | ||
| 2198 | + #endif // PY_VERSION_HEX > 0x03090000 && !defined(PYPY_VERSION) | ||
| 2199 | + | ||
| 2200 | + | ||
| 1977 | 2201 | #ifdef __cplusplus | |
| 1978 | 2202 | } | |
| 1979 | 2203 | #endif | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2112,6 +2112,66 @@ test_file(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) | |||
| 2112 | 2112 | } | |
| 2113 | 2113 | ||
| 2114 | 2114 | ||
| 2115 | + #if 0x03090000 <= PY_VERSION_HEX && !defined(PYPY_VERSION) | ||
| 2116 | + static PyObject * | ||
| 2117 | + test_config(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) | ||
| 2118 | + { | ||
| 2119 | + // Test PyConfig_Get() | ||
| 2120 | + PyObject *sys = PyImport_ImportModule("sys"); | ||
| 2121 | + if (sys == _Py_NULL) { | ||
| 2122 | + return _Py_NULL; | ||
| 2123 | + } | ||
| 2124 | + | ||
| 2125 | + PyObject *obj = PyConfig_Get("argv"); | ||
| 2126 | + PyObject *sys_attr = PyObject_GetAttrString(sys, "argv"); | ||
| 2127 | + assert(obj == sys_attr); | ||
| 2128 | + Py_DECREF(obj); | ||
| 2129 | + Py_DECREF(sys_attr); | ||
| 2130 | + | ||
| 2131 | + obj = PyConfig_Get("module_search_paths"); | ||
| 2132 | + sys_attr = PyObject_GetAttrString(sys, "path"); | ||
| 2133 | + assert(obj == sys_attr); | ||
| 2134 | + Py_DECREF(obj); | ||
| 2135 | + Py_DECREF(sys_attr); | ||
| 2136 | + | ||
| 2137 | + obj = PyConfig_Get("xoptions"); | ||
| 2138 | + sys_attr = PyObject_GetAttrString(sys, "_xoptions"); | ||
| 2139 | + assert(obj == sys_attr); | ||
| 2140 | + Py_DECREF(obj); | ||
| 2141 | + Py_DECREF(sys_attr); | ||
| 2142 | + | ||
| 2143 | + obj = PyConfig_Get("use_environment"); | ||
| 2144 | + assert(PyBool_Check(obj)); | ||
| 2145 | + Py_DECREF(obj); | ||
| 2146 | + | ||
| 2147 | + obj = PyConfig_Get("verbose"); | ||
| 2148 | + assert(PyLong_Check(obj)); | ||
| 2149 | + Py_DECREF(obj); | ||
| 2150 | + | ||
| 2151 | + assert(PyConfig_Get("nonexistent") == NULL); | ||
| 2152 | + assert(PyErr_ExceptionMatches(PyExc_ValueError)); | ||
| 2153 | + PyErr_Clear(); | ||
| 2154 | + | ||
| 2155 | + // Test PyConfig_GetInt() | ||
| 2156 | + int value = -3; | ||
| 2157 | + | ||
| 2158 | + assert(PyConfig_GetInt("verbose", &value) == 0); | ||
| 2159 | + assert(value >= 0); | ||
| 2160 | + | ||
| 2161 | + assert(PyConfig_GetInt("argv", &value) == -1); | ||
| 2162 | + assert(PyErr_ExceptionMatches(PyExc_TypeError)); | ||
| 2163 | + PyErr_Clear(); | ||
| 2164 | + | ||
| 2165 | + assert(PyConfig_GetInt("nonexistent", &value) == -1); | ||
| 2166 | + assert(PyErr_ExceptionMatches(PyExc_ValueError)); | ||
| 2167 | + PyErr_Clear(); | ||
| 2168 | + | ||
| 2169 | + Py_DECREF(sys); | ||
| 2170 | + Py_RETURN_NONE; | ||
| 2171 | + } | ||
| 2172 | + #endif | ||
| 2173 | + | ||
| 2174 | + | ||
| 2115 | 2175 | static struct PyMethodDef methods[] = { | |
| 2116 | 2176 | {"test_object", test_object, METH_NOARGS, _Py_NULL}, | |
| 2117 | 2177 | {"test_py_is", test_py_is, METH_NOARGS, _Py_NULL}, | |
@@ -2160,6 +2220,9 @@ static struct PyMethodDef methods[] = { | |||
| 2160 | 2220 | {"test_long_stdint", test_long_stdint, METH_NOARGS, _Py_NULL}, | |
| 2161 | 2221 | {"test_structmember", test_structmember, METH_NOARGS, _Py_NULL}, | |
| 2162 | 2222 | {"test_file", test_file, METH_NOARGS, _Py_NULL}, | |
| 2223 | + #if 0x03090000 <= PY_VERSION_HEX && !defined(PYPY_VERSION) | ||
| 2224 | + {"test_config", test_config, METH_NOARGS, _Py_NULL}, | ||
| 2225 | + #endif | ||
| 2163 | 2226 | {_Py_NULL, _Py_NULL, 0, _Py_NULL} | |
| 2164 | 2227 | }; | |
| 2165 | 2228 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments