summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2016-03-22 23:54:48 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2016-03-22 23:54:48 (GMT)
commite98445a4deb2b2eb97de26e03fc8c4c2a5f256d4 (patch)
treeb768387cfe4ef529994e36d5612e73fede636365
parent7bfa409ff841fd84dfa194dd9052650d0a28585d (diff)
downloadcpython-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.c50
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");