summaryrefslogtreecommitdiff
path: root/Python/_warnings.c
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2015-05-03 11:28:46 -0400
committerBenjamin Peterson <benjamin@python.org>2015-05-03 11:28:46 -0400
commitb2358aa45fed9e4bffc61e34c302444f88298d60 (patch)
tree536d3a3fb22e2b31bc31940b6c6fc4361aae2f17 /Python/_warnings.c
parente32c96ca2e0152bd6c120d9bac00b94d3fa11567 (diff)
parent132828c038aed51ffb548acfd849314e3f0f87a5 (diff)
downloadcpython-b2358aa45fed9e4bffc61e34c302444f88298d60.tar.gz
merge 3.3 (#24096)
Diffstat (limited to 'Python/_warnings.c')
-rw-r--r--Python/_warnings.c289
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,
&registry, &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;
}