diff options
author | Eric Snow <ericsnowcurrently@gmail.com> | 2022-02-08 20:39:07 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-08 20:39:07 (GMT) |
commit | 81c72044a181dbbfbf689d7a977d0d99090f26a8 (patch) | |
tree | 14329746bd6f179cf2ae7c9818e1ae881eb46360 /Python/sysmodule.c | |
parent | c018d3037b5b62e6d48d5985d1a37b91762fbffb (diff) | |
download | cpython-81c72044a181dbbfbf689d7a977d0d99090f26a8.zip cpython-81c72044a181dbbfbf689d7a977d0d99090f26a8.tar.gz cpython-81c72044a181dbbfbf689d7a977d0d99090f26a8.tar.bz2 |
bpo-46541: Replace core use of _Py_IDENTIFIER() with statically initialized global objects. (gh-30928)
We're no longer using _Py_IDENTIFIER() (or _Py_static_string()) in any core CPython code. It is still used in a number of non-builtin stdlib modules.
The replacement is: PyUnicodeObject (not pointer) fields under _PyRuntimeState, statically initialized as part of _PyRuntime. A new _Py_GET_GLOBAL_IDENTIFIER() macro facilitates lookup of the fields (along with _Py_GET_GLOBAL_STRING() for non-identifier strings).
https://bugs.python.org/issue46541#msg411799 explains the rationale for this change.
The core of the change is in:
* (new) Include/internal/pycore_global_strings.h - the declarations for the global strings, along with the macros
* Include/internal/pycore_runtime_init.h - added the static initializers for the global strings
* Include/internal/pycore_global_objects.h - where the struct in pycore_global_strings.h is hooked into _PyRuntimeState
* Tools/scripts/generate_global_objects.py - added generation of the global string declarations and static initializers
I've also added a --check flag to generate_global_objects.py (along with make check-global-objects) to check for unused global strings. That check is added to the PR CI config.
The remainder of this change updates the core code to use _Py_GET_GLOBAL_IDENTIFIER() instead of _Py_IDENTIFIER() and the related _Py*Id functions (likewise for _Py_GET_GLOBAL_STRING() instead of _Py_static_string()). This includes adding a few functions where there wasn't already an alternative to _Py*Id(), replacing the _Py_Identifier * parameter with PyObject *.
The following are not changed (yet):
* stop using _Py_IDENTIFIER() in the stdlib modules
* (maybe) get rid of _Py_IDENTIFIER(), etc. entirely -- this may not be doable as at least one package on PyPI using this (private) API
* (maybe) intern the strings during runtime init
https://bugs.python.org/issue46541
Diffstat (limited to 'Python/sysmodule.c')
-rw-r--r-- | Python/sysmodule.c | 88 |
1 files changed, 49 insertions, 39 deletions
diff --git a/Python/sysmodule.c b/Python/sysmodule.c index acb0378..57bf04d 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -55,17 +55,21 @@ module sys #include "clinic/sysmodule.c.h" -_Py_IDENTIFIER(_); -_Py_IDENTIFIER(__sizeof__); -_Py_IDENTIFIER(_xoptions); -_Py_IDENTIFIER(buffer); -_Py_IDENTIFIER(builtins); -_Py_IDENTIFIER(encoding); -_Py_IDENTIFIER(path); -_Py_IDENTIFIER(stdout); -_Py_IDENTIFIER(stderr); -_Py_IDENTIFIER(warnoptions); -_Py_IDENTIFIER(write); +PyObject * +_PySys_GetAttr(PyThreadState *tstate, PyObject *name) +{ + PyObject *sd = tstate->interp->sysdict; + if (sd == NULL) { + return NULL; + } + PyObject *exc_type, *exc_value, *exc_tb; + _PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb); + /* XXX Suppress a new exception if it was raised and restore + * the old one. */ + PyObject *value = _PyDict_GetItemWithError(sd, name); + _PyErr_Restore(tstate, exc_type, exc_value, exc_tb); + return value; +} static PyObject * sys_get_object_id(PyThreadState *tstate, _Py_Identifier *key) @@ -147,6 +151,13 @@ _PySys_SetObjectId(_Py_Identifier *key, PyObject *v) return sys_set_object_id(interp, key, v); } +int +_PySys_SetAttr(PyObject *key, PyObject *v) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + return sys_set_object(interp, key, v); +} + static int sys_set_object_str(PyInterpreterState *interp, const char *name, PyObject *v) { @@ -258,9 +269,8 @@ sys_audit_tstate(PyThreadState *ts, const char *event, /* Disallow tracing in hooks unless explicitly enabled */ PyThreadState_EnterTracing(ts); while ((hook = PyIter_Next(hooks)) != NULL) { - _Py_IDENTIFIER(__cantrace__); PyObject *o; - int canTrace = _PyObject_LookupAttrId(hook, &PyId___cantrace__, &o); + int canTrace = _PyObject_LookupAttr(hook, &_Py_ID(__cantrace__), &o); if (o) { canTrace = PyObject_IsTrue(o); Py_DECREF(o); @@ -631,7 +641,7 @@ sys_displayhook_unencodable(PyObject *outf, PyObject *o) const char *stdout_encoding_str; int ret; - stdout_encoding = _PyObject_GetAttrId(outf, &PyId_encoding); + stdout_encoding = PyObject_GetAttr(outf, &_Py_ID(encoding)); if (stdout_encoding == NULL) goto error; stdout_encoding_str = PyUnicode_AsUTF8(stdout_encoding); @@ -648,12 +658,12 @@ sys_displayhook_unencodable(PyObject *outf, PyObject *o) if (encoded == NULL) goto error; - if (_PyObject_LookupAttrId(outf, &PyId_buffer, &buffer) < 0) { + if (_PyObject_LookupAttr(outf, &_Py_ID(buffer), &buffer) < 0) { Py_DECREF(encoded); goto error; } if (buffer) { - result = _PyObject_CallMethodIdOneArg(buffer, &PyId_write, encoded); + result = PyObject_CallMethodOneArg(buffer, &_Py_ID(write), encoded); Py_DECREF(buffer); Py_DECREF(encoded); if (result == NULL) @@ -699,7 +709,7 @@ sys_displayhook(PyObject *module, PyObject *o) static PyObject *newline = NULL; PyThreadState *tstate = _PyThreadState_GET(); - builtins = _PyImport_GetModuleId(&PyId_builtins); + builtins = PyImport_GetModule(&_Py_ID(builtins)); if (builtins == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_SetString(tstate, PyExc_RuntimeError, @@ -715,9 +725,9 @@ sys_displayhook(PyObject *module, PyObject *o) if (o == Py_None) { Py_RETURN_NONE; } - if (_PyObject_SetAttrId(builtins, &PyId__, Py_None) != 0) + if (PyObject_SetAttr(builtins, &_Py_ID(_), Py_None) != 0) return NULL; - outf = sys_get_object_id(tstate, &PyId_stdout); + outf = _PySys_GetAttr(tstate, &_Py_ID(stdout)); if (outf == NULL || outf == Py_None) { _PyErr_SetString(tstate, PyExc_RuntimeError, "lost sys.stdout"); return NULL; @@ -744,7 +754,7 @@ sys_displayhook(PyObject *module, PyObject *o) } if (PyFile_WriteObject(newline, outf, Py_PRINT_RAW) != 0) return NULL; - if (_PyObject_SetAttrId(builtins, &PyId__, o) != 0) + if (PyObject_SetAttr(builtins, &_Py_ID(_), o) != 0) return NULL; Py_RETURN_NONE; } @@ -1676,7 +1686,7 @@ _PySys_GetSizeOf(PyObject *o) return (size_t)-1; } - method = _PyObject_LookupSpecial(o, &PyId___sizeof__); + method = _PyObject_LookupSpecial(o, &_Py_ID(__sizeof__)); if (method == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_Format(tstate, PyExc_TypeError, @@ -2218,7 +2228,7 @@ _PySys_ReadPreinitXOptions(PyConfig *config) static PyObject * get_warnoptions(PyThreadState *tstate) { - PyObject *warnoptions = sys_get_object_id(tstate, &PyId_warnoptions); + PyObject *warnoptions = _PySys_GetAttr(tstate, &_Py_ID(warnoptions)); if (warnoptions == NULL || !PyList_Check(warnoptions)) { /* PEP432 TODO: we can reach this if warnoptions is NULL in the main * interpreter config. When that happens, we need to properly set @@ -2234,7 +2244,7 @@ get_warnoptions(PyThreadState *tstate) if (warnoptions == NULL) { return NULL; } - if (sys_set_object_id(tstate->interp, &PyId_warnoptions, warnoptions)) { + if (sys_set_object(tstate->interp, &_Py_ID(warnoptions), warnoptions)) { Py_DECREF(warnoptions); return NULL; } @@ -2252,7 +2262,7 @@ PySys_ResetWarnOptions(void) return; } - PyObject *warnoptions = sys_get_object_id(tstate, &PyId_warnoptions); + PyObject *warnoptions = _PySys_GetAttr(tstate, &_Py_ID(warnoptions)); if (warnoptions == NULL || !PyList_Check(warnoptions)) return; PyList_SetSlice(warnoptions, 0, PyList_GET_SIZE(warnoptions), NULL); @@ -2306,7 +2316,7 @@ int PySys_HasWarnOptions(void) { PyThreadState *tstate = _PyThreadState_GET(); - PyObject *warnoptions = sys_get_object_id(tstate, &PyId_warnoptions); + PyObject *warnoptions = _PySys_GetAttr(tstate, &_Py_ID(warnoptions)); return (warnoptions != NULL && PyList_Check(warnoptions) && PyList_GET_SIZE(warnoptions) > 0); } @@ -2314,7 +2324,7 @@ PySys_HasWarnOptions(void) static PyObject * get_xoptions(PyThreadState *tstate) { - PyObject *xoptions = sys_get_object_id(tstate, &PyId__xoptions); + PyObject *xoptions = _PySys_GetAttr(tstate, &_Py_ID(_xoptions)); if (xoptions == NULL || !PyDict_Check(xoptions)) { /* PEP432 TODO: we can reach this if xoptions is NULL in the main * interpreter config. When that happens, we need to properly set @@ -2330,7 +2340,7 @@ get_xoptions(PyThreadState *tstate) if (xoptions == NULL) { return NULL; } - if (sys_set_object_id(tstate->interp, &PyId__xoptions, xoptions)) { + if (sys_set_object(tstate->interp, &_Py_ID(_xoptions), xoptions)) { Py_DECREF(xoptions); return NULL; } @@ -3032,7 +3042,7 @@ _PySys_SetPreliminaryStderr(PyObject *sysdict) if (pstderr == NULL) { goto error; } - if (_PyDict_SetItemId(sysdict, &PyId_stderr, pstderr) < 0) { + if (PyDict_SetItem(sysdict, &_Py_ID(stderr), pstderr) < 0) { goto error; } if (PyDict_SetItemString(sysdict, "__stderr__", pstderr) < 0) { @@ -3157,7 +3167,7 @@ PySys_SetPath(const wchar_t *path) if ((v = makepathobject(path, DELIM)) == NULL) Py_FatalError("can't create sys.path"); PyInterpreterState *interp = _PyInterpreterState_GET(); - if (sys_set_object_id(interp, &PyId_path, v) != 0) { + if (sys_set_object(interp, &_Py_ID(path), v) != 0) { Py_FatalError("can't assign sys.path"); } Py_DECREF(v); @@ -3214,7 +3224,7 @@ PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath) Py_FatalError("can't compute path0 from argv"); } - PyObject *sys_path = sys_get_object_id(tstate, &PyId_path); + PyObject *sys_path = _PySys_GetAttr(tstate, &_Py_ID(path)); if (sys_path != NULL) { if (PyList_Insert(sys_path, 0, path0) < 0) { Py_DECREF(path0); @@ -3241,7 +3251,7 @@ sys_pyfile_write_unicode(PyObject *unicode, PyObject *file) if (file == NULL) return -1; assert(unicode != NULL); - PyObject *result = _PyObject_CallMethodIdOneArg(file, &PyId_write, unicode); + PyObject *result = _PyObject_CallMethodOneArg(file, &_Py_ID(write), unicode); if (result == NULL) { return -1; } @@ -3296,7 +3306,7 @@ sys_pyfile_write(const char *text, PyObject *file) */ static void -sys_write(_Py_Identifier *key, FILE *fp, const char *format, va_list va) +sys_write(PyObject *key, FILE *fp, const char *format, va_list va) { PyObject *file; PyObject *error_type, *error_value, *error_traceback; @@ -3305,7 +3315,7 @@ sys_write(_Py_Identifier *key, FILE *fp, const char *format, va_list va) PyThreadState *tstate = _PyThreadState_GET(); _PyErr_Fetch(tstate, &error_type, &error_value, &error_traceback); - file = sys_get_object_id(tstate, key); + file = _PySys_GetAttr(tstate, key); written = PyOS_vsnprintf(buffer, sizeof(buffer), format, va); if (sys_pyfile_write(buffer, file) != 0) { _PyErr_Clear(tstate); @@ -3325,7 +3335,7 @@ PySys_WriteStdout(const char *format, ...) va_list va; va_start(va, format); - sys_write(&PyId_stdout, stdout, format, va); + sys_write(&_Py_ID(stdout), stdout, format, va); va_end(va); } @@ -3335,12 +3345,12 @@ PySys_WriteStderr(const char *format, ...) va_list va; va_start(va, format); - sys_write(&PyId_stderr, stderr, format, va); + sys_write(&_Py_ID(stderr), stderr, format, va); va_end(va); } static void -sys_format(_Py_Identifier *key, FILE *fp, const char *format, va_list va) +sys_format(PyObject *key, FILE *fp, const char *format, va_list va) { PyObject *file, *message; PyObject *error_type, *error_value, *error_traceback; @@ -3348,7 +3358,7 @@ sys_format(_Py_Identifier *key, FILE *fp, const char *format, va_list va) PyThreadState *tstate = _PyThreadState_GET(); _PyErr_Fetch(tstate, &error_type, &error_value, &error_traceback); - file = sys_get_object_id(tstate, key); + file = _PySys_GetAttr(tstate, key); message = PyUnicode_FromFormatV(format, va); if (message != NULL) { if (sys_pyfile_write_unicode(message, file) != 0) { @@ -3368,7 +3378,7 @@ PySys_FormatStdout(const char *format, ...) va_list va; va_start(va, format); - sys_format(&PyId_stdout, stdout, format, va); + sys_format(&_Py_ID(stdout), stdout, format, va); va_end(va); } @@ -3378,6 +3388,6 @@ PySys_FormatStderr(const char *format, ...) va_list va; va_start(va, format); - sys_format(&PyId_stderr, stderr, format, va); + sys_format(&_Py_ID(stderr), stderr, format, va); va_end(va); } |