diff options
Diffstat (limited to 'Python/_warnings.c')
-rw-r--r-- | Python/_warnings.c | 245 |
1 files changed, 165 insertions, 80 deletions
diff --git a/Python/_warnings.c b/Python/_warnings.c index f33e477ad7b..6013d7d7d48 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -13,6 +13,8 @@ static PyObject *_filters; /* List */ static PyObject *_once_registry; /* Dict */ static PyObject *_default_action; /* String */ +_Py_IDENTIFIER(argv); +_Py_IDENTIFIER(stderr); static int check_matched(PyObject *obj, PyObject *arg) @@ -99,7 +101,7 @@ get_default_action(void) /* The item is a borrowed reference. */ -static const char * +static PyObject* get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno, PyObject *module, PyObject **item) { @@ -144,21 +146,28 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno, ln_obj = PyTuple_GET_ITEM(tmp_item, 4); good_msg = check_matched(msg, text); + if (good_msg == -1) + return NULL; + good_mod = check_matched(mod, module); + if (good_mod == -1) + return NULL; + is_subclass = PyObject_IsSubclass(category, cat); + if (is_subclass == -1) + return NULL; + ln = PyLong_AsSsize_t(ln_obj); - if (good_msg == -1 || good_mod == -1 || is_subclass == -1 || - (ln == -1 && PyErr_Occurred())) + if (ln == -1 && PyErr_Occurred()) return NULL; if (good_msg && is_subclass && good_mod && (ln == 0 || lineno == ln)) - return _PyUnicode_AsString(action); + return action; } action = get_default_action(); - if (action != NULL) { - return _PyUnicode_AsString(action); - } + if (action != NULL) + return action; PyErr_SetString(PyExc_ValueError, MODULE_NAME ".defaultaction not found"); @@ -192,23 +201,26 @@ static PyObject * normalize_module(PyObject *filename) { PyObject *module; - const char *mod_str; + int kind; + void *data; Py_ssize_t len; - int rc = PyObject_IsTrue(filename); - if (rc == -1) - return NULL; - else if (rc == 0) - return PyUnicode_FromString("<unknown>"); - - mod_str = _PyUnicode_AsString(filename); - if (mod_str == NULL) - return NULL; len = PyUnicode_GetLength(filename); if (len < 0) return NULL; + + if (len == 0) + return PyUnicode_FromString("<unknown>"); + + kind = PyUnicode_KIND(filename); + data = PyUnicode_DATA(filename); + + /* if filename.endswith(".py"): */ if (len >= 3 && - strncmp(mod_str + (len - 3), ".py", 3) == 0) { + PyUnicode_READ(kind, data, len-3) == '.' && + PyUnicode_READ(kind, data, len-2) == 'p' && + PyUnicode_READ(kind, data, len-1) == 'y') + { module = PyUnicode_Substring(filename, 0, len-3); } else { @@ -253,39 +265,63 @@ show_warning(PyObject *filename, int lineno, PyObject *text, PyObject name = _PyObject_GetAttrId(category, &PyId___name__); if (name == NULL) /* XXX Can an object lack a '__name__' attribute? */ - return; + goto error; - f_stderr = PySys_GetObject("stderr"); + f_stderr = _PySys_GetObjectId(&PyId_stderr); if (f_stderr == NULL) { fprintf(stderr, "lost sys.stderr\n"); - Py_DECREF(name); - return; + goto error; } /* Print "filename:lineno: category: text\n" */ - PyFile_WriteObject(filename, f_stderr, Py_PRINT_RAW); - PyFile_WriteString(lineno_str, f_stderr); - PyFile_WriteObject(name, f_stderr, Py_PRINT_RAW); - PyFile_WriteString(": ", f_stderr); - PyFile_WriteObject(text, f_stderr, Py_PRINT_RAW); - PyFile_WriteString("\n", f_stderr); - Py_XDECREF(name); + if (PyFile_WriteObject(filename, f_stderr, Py_PRINT_RAW) < 0) + goto error; + if (PyFile_WriteString(lineno_str, f_stderr) < 0) + goto error; + if (PyFile_WriteObject(name, f_stderr, Py_PRINT_RAW) < 0) + goto error; + if (PyFile_WriteString(": ", f_stderr) < 0) + goto error; + if (PyFile_WriteObject(text, f_stderr, Py_PRINT_RAW) < 0) + goto error; + if (PyFile_WriteString("\n", f_stderr) < 0) + goto error; + Py_CLEAR(name); /* Print " source_line\n" */ if (sourceline) { - char *source_line_str = _PyUnicode_AsString(sourceline); - if (source_line_str == NULL) - return; - while (*source_line_str == ' ' || *source_line_str == '\t' || - *source_line_str == '\014') - source_line_str++; - - PyFile_WriteString(source_line_str, f_stderr); + int kind; + void *data; + Py_ssize_t i, len; + Py_UCS4 ch; + PyObject *truncated; + + if (PyUnicode_READY(sourceline) < 1) + goto error; + + kind = PyUnicode_KIND(sourceline); + data = PyUnicode_DATA(sourceline); + len = PyUnicode_GET_LENGTH(sourceline); + for (i=0; i<len; i++) { + ch = PyUnicode_READ(kind, data, i); + if (ch != ' ' && ch != '\t' && ch != '\014') + break; + } + + truncated = PyUnicode_Substring(sourceline, i, len); + if (truncated == NULL) + goto error; + + PyFile_WriteObject(sourceline, f_stderr, Py_PRINT_RAW); + Py_DECREF(truncated); PyFile_WriteString("\n", f_stderr); } - else - if (_Py_DisplaySourceLine(f_stderr, filename, lineno, 2) < 0) - return; + else { + _Py_DisplaySourceLine(f_stderr, filename, lineno, 2); + } + +error: + Py_XDECREF(name); PyErr_Clear(); } @@ -296,9 +332,16 @@ warn_explicit(PyObject *category, PyObject *message, { PyObject *key = NULL, *text = NULL, *result = NULL, *lineno_obj = NULL; PyObject *item = Py_None; - const char *action; + PyObject *action; int rc; + /* module can be None if a warning is emitted late during Python shutdown. + In this case, the Python warnings module was probably unloaded, filters + are no more available to choose as action. It is safer to ignore the + warning and do nothing. */ + if (module == Py_None) + Py_RETURN_NONE; + if (registry && !PyDict_Check(registry) && (registry != Py_None)) { PyErr_SetString(PyExc_TypeError, "'registry' must be a dict"); return NULL; @@ -354,7 +397,7 @@ warn_explicit(PyObject *category, PyObject *message, if (action == NULL) goto cleanup; - if (strcmp(action, "error") == 0) { + if (PyUnicode_CompareWithASCIIString(action, "error") == 0) { PyErr_SetObject(category, message); goto cleanup; } @@ -362,13 +405,13 @@ warn_explicit(PyObject *category, PyObject *message, /* Store in the registry that we've been here, *except* when the action is "always". */ rc = 0; - if (strcmp(action, "always") != 0) { + if (PyUnicode_CompareWithASCIIString(action, "always") != 0) { if (registry != NULL && registry != Py_None && PyDict_SetItem(registry, key, Py_True) < 0) goto cleanup; - else if (strcmp(action, "ignore") == 0) + else if (PyUnicode_CompareWithASCIIString(action, "ignore") == 0) goto return_none; - else if (strcmp(action, "once") == 0) { + else if (PyUnicode_CompareWithASCIIString(action, "once") == 0) { if (registry == NULL || registry == Py_None) { registry = get_once_registry(); if (registry == NULL) @@ -377,24 +420,15 @@ warn_explicit(PyObject *category, PyObject *message, /* _once_registry[(text, category)] = 1 */ rc = update_registry(registry, text, category, 0); } - else if (strcmp(action, "module") == 0) { + else if (PyUnicode_CompareWithASCIIString(action, "module") == 0) { /* registry[(text, category, 0)] = 1 */ if (registry != NULL && registry != Py_None) rc = update_registry(registry, text, category, 0); } - else if (strcmp(action, "default") != 0) { - PyObject *to_str = PyObject_Str(item); - const char *err_str = "???"; - - if (to_str != NULL) { - err_str = _PyUnicode_AsString(to_str); - if (err_str == NULL) - goto cleanup; - } + else if (PyUnicode_CompareWithASCIIString(action, "default") != 0) { PyErr_Format(PyExc_RuntimeError, - "Unrecognized action (%s) in warnings.filters:\n %s", - action, err_str); - Py_XDECREF(to_str); + "Unrecognized action (%R) in warnings.filters:\n %R", + action, item); goto cleanup; } } @@ -528,13 +562,12 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno, Py_INCREF(*filename); } else { - const char *module_str = _PyUnicode_AsString(*module); *filename = NULL; - if (module_str == NULL) - goto handle_error; - if (strcmp(module_str, "__main__") == 0) { - PyObject *argv = PySys_GetObject("argv"); - if (argv != NULL && PyList_Size(argv) > 0) { + if (*module != Py_None && PyUnicode_CompareWithASCIIString(*module, "__main__") == 0) { + PyObject *argv = _PySys_GetObjectId(&PyId_argv); + /* PyList_Check() is needed because sys.argv is set to None during + Python finalization */ + if (argv != NULL && PyList_Check(argv) && PyList_Size(argv) > 0) { int is_true; *filename = PyList_GetItem(argv, 0); Py_INCREF(*filename); @@ -554,8 +587,8 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno, else { /* embedded interpreters don't have sys.argv, see bug #839151 */ *filename = PyUnicode_FromString("__main__"); - if (*filename == NULL) - goto handle_error; + if (*filename == NULL) + goto handle_error; } } if (*filename == NULL) { @@ -649,7 +682,7 @@ warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds) PyObject *registry = NULL; PyObject *module_globals = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOi|OOO:warn_explicit", + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOUi|OOO:warn_explicit", kwd_list, &message, &category, &filename, &lineno, &module, ®istry, &module_globals)) return NULL; @@ -707,14 +740,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); Py_DECREF(source_list); return returned; } standard_call: return warn_explicit(category, message, filename, lineno, module, - registry, NULL); + registry, NULL); } @@ -786,11 +819,26 @@ PyErr_Warn(PyObject *category, char *text) /* Warning with explicit origin */ int +PyErr_WarnExplicitObject(PyObject *category, PyObject *message, + PyObject *filename, int lineno, + PyObject *module, PyObject *registry) +{ + PyObject *res; + if (category == NULL) + category = PyExc_RuntimeWarning; + res = warn_explicit(category, message, filename, lineno, + module, registry, NULL); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; +} + +int PyErr_WarnExplicit(PyObject *category, const char *text, const char *filename_str, int lineno, const char *module_str, PyObject *registry) { - PyObject *res; PyObject *message = PyUnicode_FromString(text); PyObject *filename = PyUnicode_DecodeFSDefault(filename_str); PyObject *module = NULL; @@ -800,18 +848,12 @@ PyErr_WarnExplicit(PyObject *category, const char *text, goto exit; if (module_str != NULL) { module = PyUnicode_FromString(module_str); - if (module == NULL) - goto exit; + if (module == NULL) + goto exit; } - if (category == NULL) - category = PyExc_RuntimeWarning; - res = warn_explicit(category, message, filename, lineno, module, registry, - NULL); - if (res == NULL) - goto exit; - Py_DECREF(res); - ret = 0; + ret = PyErr_WarnExplicitObject(category, message, filename, lineno, + module, registry); exit: Py_XDECREF(message); @@ -820,6 +862,49 @@ PyErr_WarnExplicit(PyObject *category, const char *text, return ret; } +int +PyErr_WarnExplicitFormat(PyObject *category, + const char *filename_str, int lineno, + const char *module_str, PyObject *registry, + const char *format, ...) +{ + PyObject *message; + PyObject *module = NULL; + PyObject *filename = PyUnicode_DecodeFSDefault(filename_str); + int ret = -1; + va_list vargs; + + if (filename == NULL) + goto exit; + if (module_str != NULL) { + module = PyUnicode_FromString(module_str); + if (module == NULL) + goto exit; + } + +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + message = PyUnicode_FromFormatV(format, vargs); + if (message != NULL) { + PyObject *res; + res = warn_explicit(category, message, filename, lineno, + module, registry, NULL); + Py_DECREF(message); + if (res != NULL) { + Py_DECREF(res); + ret = 0; + } + } + va_end(vargs); +exit: + Py_XDECREF(module); + Py_XDECREF(filename); + return ret; +} + PyDoc_STRVAR(warn_doc, "Issue a warning, or maybe ignore it or raise an exception."); |