summaryrefslogtreecommitdiffstats
path: root/Python
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 /Python
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.
Diffstat (limited to 'Python')
-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");