diff options
author | Benjamin Peterson <benjamin@python.org> | 2015-05-03 11:28:46 -0400 |
---|---|---|
committer | Benjamin Peterson <benjamin@python.org> | 2015-05-03 11:28:46 -0400 |
commit | b2358aa45fed9e4bffc61e34c302444f88298d60 (patch) | |
tree | 536d3a3fb22e2b31bc31940b6c6fc4361aae2f17 /Python/_warnings.c | |
parent | e32c96ca2e0152bd6c120d9bac00b94d3fa11567 (diff) | |
parent | 132828c038aed51ffb548acfd849314e3f0f87a5 (diff) | |
download | cpython-b2358aa45fed9e4bffc61e34c302444f88298d60.tar.gz |
merge 3.3 (#24096)
Diffstat (limited to 'Python/_warnings.c')
-rw-r--r-- | Python/_warnings.c | 289 |
1 files changed, 205 insertions, 84 deletions
diff --git a/Python/_warnings.c b/Python/_warnings.c index d274789f4a..6dff0a2c11 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -12,7 +12,10 @@ MODULE_NAME " provides basic warning filtering support.\n" static PyObject *_filters; /* List */ static PyObject *_once_registry; /* Dict */ static PyObject *_default_action; /* String */ +static long _filters_version; +_Py_IDENTIFIER(argv); +_Py_IDENTIFIER(stderr); static int check_matched(PyObject *obj, PyObject *arg) @@ -99,7 +102,7 @@ get_default_action(void) /* The item is a new reference. */ -static const char * +static PyObject* get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno, PyObject *module, PyObject **item) { @@ -145,18 +148,32 @@ 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) { + Py_DECREF(tmp_item); + return NULL; + } + good_mod = check_matched(mod, module); + if (good_mod == -1) { + Py_DECREF(tmp_item); + return NULL; + } + is_subclass = PyObject_IsSubclass(category, cat); + if (is_subclass == -1) { + Py_DECREF(tmp_item); + 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()) { Py_DECREF(tmp_item); return NULL; } if (good_msg && is_subclass && good_mod && (ln == 0 || lineno == ln)) { *item = tmp_item; - return _PyUnicode_AsString(action); + return action; } Py_DECREF(tmp_item); @@ -166,7 +183,7 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno, if (action != NULL) { Py_INCREF(Py_None); *item = Py_None; - return _PyUnicode_AsString(action); + return action; } PyErr_SetString(PyExc_ValueError, @@ -178,16 +195,33 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno, static int already_warned(PyObject *registry, PyObject *key, int should_set) { - PyObject *already_warned; + PyObject *version_obj, *already_warned; + _Py_IDENTIFIER(version); if (key == NULL) return -1; - already_warned = PyDict_GetItem(registry, key); - if (already_warned != NULL) { - int rc = PyObject_IsTrue(already_warned); - if (rc != 0) - return rc; + version_obj = _PyDict_GetItemId(registry, &PyId_version); + if (version_obj == NULL + || !PyLong_CheckExact(version_obj) + || PyLong_AsLong(version_obj) != _filters_version) { + PyDict_Clear(registry); + version_obj = PyLong_FromLong(_filters_version); + if (version_obj == NULL) + return -1; + if (_PyDict_SetItemId(registry, &PyId_version, version_obj) < 0) { + Py_DECREF(version_obj); + return -1; + } + Py_DECREF(version_obj); + } + else { + already_warned = PyDict_GetItem(registry, key); + if (already_warned != NULL) { + int rc = PyObject_IsTrue(already_warned); + if (rc != 0) + return rc; + } } /* This warning wasn't found in the registry, set it. */ @@ -201,23 +235,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 { @@ -262,39 +299,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(); } @@ -305,9 +366,16 @@ warn_explicit(PyObject *category, PyObject *message, { PyObject *key = NULL, *text = NULL, *result = NULL, *lineno_obj = NULL; PyObject *item = NULL; - 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; @@ -363,7 +431,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; } @@ -371,13 +439,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) @@ -386,24 +454,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; } } @@ -538,13 +597,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); @@ -564,8 +622,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) { @@ -659,7 +717,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; @@ -717,14 +775,21 @@ 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); +} + +static PyObject * +warnings_filters_mutated(PyObject *self, PyObject *args) +{ + _filters_version++; + Py_RETURN_NONE; } @@ -796,11 +861,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; @@ -810,18 +890,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); @@ -830,6 +904,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."); @@ -842,6 +959,8 @@ static PyMethodDef warnings_functions[] = { warn_doc}, {"warn_explicit", (PyCFunction)warnings_warn_explicit, METH_VARARGS | METH_KEYWORDS, warn_explicit_doc}, + {"_filters_mutated", (PyCFunction)warnings_filters_mutated, METH_NOARGS, + NULL}, /* XXX(brett.cannon): add showwarning? */ /* XXX(brett.cannon): Reasonable to add formatwarning? */ {NULL, NULL} /* sentinel */ @@ -994,5 +1113,7 @@ _PyWarnings_Init(void) Py_INCREF(_default_action); if (PyModule_AddObject(m, "_defaultaction", _default_action) < 0) return NULL; + + _filters_version = 0; return m; } |