Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e98445a

Browse files
committed
_warnings.warn_explicit(): try to import warnings
Issue #26592: _warnings.warn_explicit() now tries to import the warnings module (Python implementation) if the source parameter is set to be able to log the traceback where the source was allocated.
1 parent 7bfa409 commit e98445a

1 file changed

Lines changed: 36 additions & 14 deletions

File tree

Python/_warnings.c

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ check_matched(PyObject *obj, PyObject *arg)
4040
A NULL return value can mean false or an error.
4141
*/
4242
static PyObject *
43-
get_warnings_attr(const char *attr)
43+
get_warnings_attr(const char *attr, int try_import)
4444
{
4545
static PyObject *warnings_str = NULL;
4646
PyObject *all_modules;
47-
PyObject *warnings_module;
47+
PyObject *warnings_module, *obj;
4848
int result;
4949

5050
if (warnings_str == NULL) {
@@ -53,15 +53,34 @@ get_warnings_attr(const char *attr)
5353
return NULL;
5454
}
5555

56-
all_modules = PyImport_GetModuleDict();
57-
result = PyDict_Contains(all_modules, warnings_str);
58-
if (result == -1 || result == 0)
56+
/* don't try to import after the start of the Python finallization */
57+
if (try_import && _Py_Finalizing == NULL) {
58+
warnings_module = PyImport_Import(warnings_str);
59+
if (warnings_module == NULL) {
60+
/* Fallback to the C implementation if we cannot get
61+
the Python implementation */
62+
PyErr_Clear();
63+
return NULL;
64+
}
65+
}
66+
else {
67+
all_modules = PyImport_GetModuleDict();
68+
result = PyDict_Contains(all_modules, warnings_str);
69+
if (result == -1 || result == 0)
70+
return NULL;
71+
72+
warnings_module = PyDict_GetItem(all_modules, warnings_str);
73+
Py_INCREF(warnings_module);
74+
}
75+
76+
if (!PyObject_HasAttrString(warnings_module, attr)) {
77+
Py_DECREF(warnings_module);
5978
return NULL;
79+
}
6080

61-
warnings_module = PyDict_GetItem(all_modules, warnings_str);
62-
if (!PyObject_HasAttrString(warnings_module, attr))
63-
return NULL;
64-
return PyObject_GetAttrString(warnings_module, attr);
81+
obj = PyObject_GetAttrString(warnings_module, attr);
82+
Py_DECREF(warnings_module);
83+
return obj;
6584
}
6685

6786

@@ -70,7 +89,7 @@ get_once_registry(void)
7089
{
7190
PyObject *registry;
7291

73-
registry = get_warnings_attr("onceregistry");
92+
registry = get_warnings_attr("onceregistry", 0);
7493
if (registry == NULL) {
7594
if (PyErr_Occurred())
7695
return NULL;
@@ -87,7 +106,7 @@ get_default_action(void)
87106
{
88107
PyObject *default_action;
89108

90-
default_action = get_warnings_attr("defaultaction");
109+
default_action = get_warnings_attr("defaultaction", 0);
91110
if (default_action == NULL) {
92111
if (PyErr_Occurred()) {
93112
return NULL;
@@ -110,7 +129,7 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno,
110129
Py_ssize_t i;
111130
PyObject *warnings_filters;
112131

113-
warnings_filters = get_warnings_attr("filters");
132+
warnings_filters = get_warnings_attr("filters", 0);
114133
if (warnings_filters == NULL) {
115134
if (PyErr_Occurred())
116135
return NULL;
@@ -366,7 +385,10 @@ call_show_warning(PyObject *category, PyObject *text, PyObject *message,
366385
{
367386
PyObject *show_fn, *msg, *res, *warnmsg_cls = NULL;
368387

369-
show_fn = get_warnings_attr("_showwarnmsg");
388+
/* If the source parameter is set, try to get the Python implementation.
389+
The Python implementation is able to log the traceback where the source
390+
was allocated, whereas the C implementation doesnt. */
391+
show_fn = get_warnings_attr("_showwarnmsg", source != NULL);
370392
if (show_fn == NULL) {
371393
if (PyErr_Occurred())
372394
return -1;
@@ -380,7 +402,7 @@ call_show_warning(PyObject *category, PyObject *text, PyObject *message,
380402
goto error;
381403
}
382404

383-
warnmsg_cls = get_warnings_attr("WarningMessage");
405+
warnmsg_cls = get_warnings_attr("WarningMessage", 0);
384406
if (warnmsg_cls == NULL) {
385407
PyErr_SetString(PyExc_RuntimeError,
386408
"unable to get warnings.WarningMessage");

0 commit comments

Comments
 (0)