diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2016-03-22 23:54:48 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2016-03-22 23:54:48 (GMT) |
commit | e98445a4deb2b2eb97de26e03fc8c4c2a5f256d4 (patch) | |
tree | b768387cfe4ef529994e36d5612e73fede636365 | |
parent | 7bfa409ff841fd84dfa194dd9052650d0a28585d (diff) | |
download | cpython-e98445a4deb2b2eb97de26e03fc8c4c2a5f256d4.zip cpython-e98445a4deb2b2eb97de26e03fc8c4c2a5f256d4.tar.gz cpython-e98445a4deb2b2eb97de26e03fc8c4c2a5f256d4.tar.bz2 |
_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.
-rw-r--r-- | Python/_warnings.c | 50 |
1 files changed, 36 insertions, 14 deletions
diff --git a/Python/_warnings.c b/Python/_warnings.c index dcac57b..41eaf53 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -40,11 +40,11 @@ check_matched(PyObject *obj, PyObject *arg) A NULL return value can mean false or an error. */ static PyObject * -get_warnings_attr(const char *attr) +get_warnings_attr(const char *attr, int try_import) { static PyObject *warnings_str = NULL; PyObject *all_modules; - PyObject *warnings_module; + PyObject *warnings_module, *obj; int result; if (warnings_str == NULL) { @@ -53,15 +53,34 @@ get_warnings_attr(const char *attr) return NULL; } - all_modules = PyImport_GetModuleDict(); - result = PyDict_Contains(all_modules, warnings_str); - if (result == -1 || result == 0) + /* don't try to import after the start of the Python finallization */ + if (try_import && _Py_Finalizing == NULL) { + warnings_module = PyImport_Import(warnings_str); + if (warnings_module == NULL) { + /* Fallback to the C implementation if we cannot get + the Python implementation */ + PyErr_Clear(); + return NULL; + } + } + else { + all_modules = PyImport_GetModuleDict(); + result = PyDict_Contains(all_modules, warnings_str); + if (result == -1 || result == 0) + return NULL; + + warnings_module = PyDict_GetItem(all_modules, warnings_str); + Py_INCREF(warnings_module); + } + + if (!PyObject_HasAttrString(warnings_module, attr)) { + Py_DECREF(warnings_module); return NULL; + } - warnings_module = PyDict_GetItem(all_modules, warnings_str); - if (!PyObject_HasAttrString(warnings_module, attr)) - return NULL; - return PyObject_GetAttrString(warnings_module, attr); + obj = PyObject_GetAttrString(warnings_module, attr); + Py_DECREF(warnings_module); + return obj; } @@ -70,7 +89,7 @@ get_once_registry(void) { PyObject *registry; - registry = get_warnings_attr("onceregistry"); + registry = get_warnings_attr("onceregistry", 0); if (registry == NULL) { if (PyErr_Occurred()) return NULL; @@ -87,7 +106,7 @@ get_default_action(void) { PyObject *default_action; - default_action = get_warnings_attr("defaultaction"); + default_action = get_warnings_attr("defaultaction", 0); if (default_action == NULL) { if (PyErr_Occurred()) { return NULL; @@ -110,7 +129,7 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno, Py_ssize_t i; PyObject *warnings_filters; - warnings_filters = get_warnings_attr("filters"); + warnings_filters = get_warnings_attr("filters", 0); if (warnings_filters == NULL) { if (PyErr_Occurred()) return NULL; @@ -366,7 +385,10 @@ call_show_warning(PyObject *category, PyObject *text, PyObject *message, { PyObject *show_fn, *msg, *res, *warnmsg_cls = NULL; - show_fn = get_warnings_attr("_showwarnmsg"); + /* If the source parameter is set, try to get the Python implementation. + The Python implementation is able to log the traceback where the source + was allocated, whereas the C implementation doesnt. */ + show_fn = get_warnings_attr("_showwarnmsg", source != NULL); if (show_fn == NULL) { if (PyErr_Occurred()) return -1; @@ -380,7 +402,7 @@ call_show_warning(PyObject *category, PyObject *text, PyObject *message, goto error; } - warnmsg_cls = get_warnings_attr("WarningMessage"); + warnmsg_cls = get_warnings_attr("WarningMessage", 0); if (warnmsg_cls == NULL) { PyErr_SetString(PyExc_RuntimeError, "unable to get warnings.WarningMessage"); |