diff options
Diffstat (limited to 'Python/_warnings.c')
-rw-r--r-- | Python/_warnings.c | 221 |
1 files changed, 152 insertions, 69 deletions
diff --git a/Python/_warnings.c b/Python/_warnings.c index 978bad1..40f5c8e 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -40,12 +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; - int result; + PyObject *warnings_module, *obj; if (warnings_str == NULL) { warnings_str = PyUnicode_InternFromString("warnings"); @@ -53,15 +52,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) - return NULL; + /* 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(); - warnings_module = PyDict_GetItem(all_modules, warnings_str); - if (!PyObject_HasAttrString(warnings_module, attr)) + warnings_module = PyDict_GetItem(all_modules, warnings_str); + if (warnings_module == NULL) return NULL; - return PyObject_GetAttrString(warnings_module, attr); + + Py_INCREF(warnings_module); + } + + if (!PyObject_HasAttrString(warnings_module, attr)) { + Py_DECREF(warnings_module); + return NULL; + } + + obj = PyObject_GetAttrString(warnings_module, attr); + Py_DECREF(warnings_module); + return obj; } @@ -70,7 +88,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 +105,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 +128,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; @@ -287,8 +305,8 @@ update_registry(PyObject *registry, PyObject *text, PyObject *category, } static void -show_warning(PyObject *filename, int lineno, PyObject *text, PyObject - *category, PyObject *sourceline) +show_warning(PyObject *filename, int lineno, PyObject *text, + PyObject *category, PyObject *sourceline) { PyObject *f_stderr; PyObject *name; @@ -359,10 +377,64 @@ error: PyErr_Clear(); } +static int +call_show_warning(PyObject *category, PyObject *text, PyObject *message, + PyObject *filename, int lineno, PyObject *lineno_obj, + PyObject *sourceline, PyObject *source) +{ + PyObject *show_fn, *msg, *res, *warnmsg_cls = NULL; + + /* 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; + show_warning(filename, lineno, text, category, sourceline); + return 0; + } + + if (!PyCallable_Check(show_fn)) { + PyErr_SetString(PyExc_TypeError, + "warnings._showwarnmsg() must be set to a callable"); + goto error; + } + + warnmsg_cls = get_warnings_attr("WarningMessage", 0); + if (warnmsg_cls == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "unable to get warnings.WarningMessage"); + goto error; + } + + msg = PyObject_CallFunctionObjArgs(warnmsg_cls, message, category, + filename, lineno_obj, Py_None, Py_None, source, + NULL); + Py_DECREF(warnmsg_cls); + if (msg == NULL) + goto error; + + res = PyObject_CallFunctionObjArgs(show_fn, msg, NULL); + Py_DECREF(show_fn); + Py_DECREF(msg); + + if (res == NULL) + return -1; + + Py_DECREF(res); + return 0; + +error: + Py_XDECREF(show_fn); + return -1; +} + static PyObject * warn_explicit(PyObject *category, PyObject *message, PyObject *filename, int lineno, - PyObject *module, PyObject *registry, PyObject *sourceline) + PyObject *module, PyObject *registry, PyObject *sourceline, + PyObject *source) { PyObject *key = NULL, *text = NULL, *result = NULL, *lineno_obj = NULL; PyObject *item = NULL; @@ -470,31 +542,9 @@ warn_explicit(PyObject *category, PyObject *message, if (rc == 1) /* Already warned for this module. */ goto return_none; if (rc == 0) { - PyObject *show_fxn = get_warnings_attr("showwarning"); - if (show_fxn == NULL) { - if (PyErr_Occurred()) - goto cleanup; - show_warning(filename, lineno, text, category, sourceline); - } - else { - PyObject *res; - - if (!PyCallable_Check(show_fxn)) { - PyErr_SetString(PyExc_TypeError, - "warnings.showwarning() must be set to a " - "callable"); - Py_DECREF(show_fxn); - goto cleanup; - } - - res = PyObject_CallFunctionObjArgs(show_fxn, message, category, - filename, lineno_obj, - NULL); - Py_DECREF(show_fxn); - Py_XDECREF(res); - if (res == NULL) - goto cleanup; - } + if (call_show_warning(category, text, message, filename, lineno, + lineno_obj, sourceline, source) < 0) + goto cleanup; } else /* if (rc == -1) */ goto cleanup; @@ -738,7 +788,8 @@ get_category(PyObject *message, PyObject *category) } static PyObject * -do_warn(PyObject *message, PyObject *category, Py_ssize_t stack_level) +do_warn(PyObject *message, PyObject *category, Py_ssize_t stack_level, + PyObject *source) { PyObject *filename, *module, *registry, *res; int lineno; @@ -747,7 +798,7 @@ do_warn(PyObject *message, PyObject *category, Py_ssize_t stack_level) return NULL; res = warn_explicit(category, message, filename, lineno, module, registry, - NULL); + NULL, source); Py_DECREF(filename); Py_DECREF(registry); Py_DECREF(module); @@ -757,25 +808,27 @@ do_warn(PyObject *message, PyObject *category, Py_ssize_t stack_level) static PyObject * warnings_warn(PyObject *self, PyObject *args, PyObject *kwds) { - static char *kw_list[] = { "message", "category", "stacklevel", 0 }; - PyObject *message, *category = NULL; + static char *kw_list[] = {"message", "category", "stacklevel", + "source", NULL}; + PyObject *message, *category = NULL, *source = NULL; Py_ssize_t stack_level = 1; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|On:warn", kw_list, - &message, &category, &stack_level)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OnO:warn", kw_list, + &message, &category, &stack_level, &source)) return NULL; category = get_category(message, category); if (category == NULL) return NULL; - return do_warn(message, category, stack_level); + return do_warn(message, category, stack_level, source); } static PyObject * warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwd_list[] = {"message", "category", "filename", "lineno", - "module", "registry", "module_globals", 0}; + "module", "registry", "module_globals", + "source", 0}; PyObject *message; PyObject *category; PyObject *filename; @@ -783,10 +836,11 @@ warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds) PyObject *module = NULL; PyObject *registry = NULL; PyObject *module_globals = NULL; + PyObject *sourceobj = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOUi|OOO:warn_explicit", + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOUi|OOOO:warn_explicit", kwd_list, &message, &category, &filename, &lineno, &module, - ®istry, &module_globals)) + ®istry, &module_globals, &sourceobj)) return NULL; if (module_globals) { @@ -842,14 +896,14 @@ warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds) /* Handle the warning. */ returned = warn_explicit(category, message, filename, lineno, module, - registry, source_line); + registry, source_line, sourceobj); Py_DECREF(source_list); return returned; } standard_call: return warn_explicit(category, message, filename, lineno, module, - registry, NULL); + registry, NULL, sourceobj); } static PyObject * @@ -864,14 +918,14 @@ warnings_filters_mutated(PyObject *self, PyObject *args) static int warn_unicode(PyObject *category, PyObject *message, - Py_ssize_t stack_level) + Py_ssize_t stack_level, PyObject *source) { PyObject *res; if (category == NULL) category = PyExc_RuntimeWarning; - res = do_warn(message, category, stack_level); + res = do_warn(message, category, stack_level, source); if (res == NULL) return -1; Py_DECREF(res); @@ -879,12 +933,28 @@ warn_unicode(PyObject *category, PyObject *message, return 0; } +static int +_PyErr_WarnFormatV(PyObject *source, + PyObject *category, Py_ssize_t stack_level, + const char *format, va_list vargs) +{ + PyObject *message; + int res; + + message = PyUnicode_FromFormatV(format, vargs); + if (message == NULL) + return -1; + + res = warn_unicode(category, message, stack_level, source); + Py_DECREF(message); + return res; +} + int PyErr_WarnFormat(PyObject *category, Py_ssize_t stack_level, const char *format, ...) { - int ret; - PyObject *message; + int res; va_list vargs; #ifdef HAVE_STDARG_PROTOTYPES @@ -892,25 +962,38 @@ PyErr_WarnFormat(PyObject *category, Py_ssize_t stack_level, #else va_start(vargs); #endif - message = PyUnicode_FromFormatV(format, vargs); - if (message != NULL) { - ret = warn_unicode(category, message, stack_level); - Py_DECREF(message); - } - else - ret = -1; + res = _PyErr_WarnFormatV(NULL, category, stack_level, format, vargs); va_end(vargs); - return ret; + return res; } int +PyErr_ResourceWarning(PyObject *source, Py_ssize_t stack_level, + const char *format, ...) +{ + int res; + va_list vargs; + +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + res = _PyErr_WarnFormatV(source, PyExc_ResourceWarning, + stack_level, format, vargs); + va_end(vargs); + return res; +} + + +int PyErr_WarnEx(PyObject *category, const char *text, Py_ssize_t stack_level) { int ret; PyObject *message = PyUnicode_FromString(text); if (message == NULL) return -1; - ret = warn_unicode(category, message, stack_level); + ret = warn_unicode(category, message, stack_level, NULL); Py_DECREF(message); return ret; } @@ -921,7 +1004,7 @@ PyErr_WarnEx(PyObject *category, const char *text, Py_ssize_t stack_level) #undef PyErr_Warn PyAPI_FUNC(int) -PyErr_Warn(PyObject *category, char *text) +PyErr_Warn(PyObject *category, const char *text) { return PyErr_WarnEx(category, text, 1); } @@ -936,7 +1019,7 @@ PyErr_WarnExplicitObject(PyObject *category, PyObject *message, if (category == NULL) category = PyExc_RuntimeWarning; res = warn_explicit(category, message, filename, lineno, - module, registry, NULL); + module, registry, NULL, NULL); if (res == NULL) return -1; Py_DECREF(res); @@ -1000,7 +1083,7 @@ PyErr_WarnExplicitFormat(PyObject *category, if (message != NULL) { PyObject *res; res = warn_explicit(category, message, filename, lineno, - module, registry, NULL); + module, registry, NULL, NULL); Py_DECREF(message); if (res != NULL) { Py_DECREF(res); |