summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrett Cannon <bcannon@gmail.com>2008-05-05 05:32:07 (GMT)
committerBrett Cannon <bcannon@gmail.com>2008-05-05 05:32:07 (GMT)
commit8a232cc385343c17d9f615f0aff49fc378bdebae (patch)
tree35dbd69774e9a32275293638dcfaeb322dc8790b
parent9ae080ee5acad3c6207db75843cf1a27f868c540 (diff)
downloadcpython-8a232cc385343c17d9f615f0aff49fc378bdebae.zip
cpython-8a232cc385343c17d9f615f0aff49fc378bdebae.tar.gz
cpython-8a232cc385343c17d9f615f0aff49fc378bdebae.tar.bz2
Add a DeprecationWarning for when warnings.showwarning() is set to a function
that lacks support for the new 'line' argument.
-rw-r--r--Doc/library/warnings.rst3
-rw-r--r--Lib/test/test_warnings.py28
-rw-r--r--Lib/warnings.py15
-rw-r--r--Misc/NEWS4
-rw-r--r--Python/_warnings.c56
5 files changed, 90 insertions, 16 deletions
diff --git a/Doc/library/warnings.rst b/Doc/library/warnings.rst
index 94d4738..87c4fd6 100644
--- a/Doc/library/warnings.rst
+++ b/Doc/library/warnings.rst
@@ -220,7 +220,8 @@ Available Functions
``warnings.showwarning``.
.. versionchanged:: 2.6
- Added the *line* argument.
+ Added the *line* argument. Implementations that lack the new argument
+ will trigger a :exc:`DeprecationWarning`.
.. function:: formatwarning(message, category, filename, lineno[, line])
diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py
index 5df0b90..c854d7a 100644
--- a/Lib/test/test_warnings.py
+++ b/Lib/test/test_warnings.py
@@ -461,6 +461,32 @@ class PyWarningsDisplayTests(BaseTest, WarningsDisplayTests):
module = py_warnings
+class ShowwarningDeprecationTests(BaseTest):
+
+ """Test the deprecation of the old warnings.showwarning() API works."""
+
+ @staticmethod
+ def bad_showwarning(message, category, filename, lineno, file=None):
+ pass
+
+ def test_deprecation(self):
+ # message, category, filename, lineno[, file[, line]]
+ args = ("message", UserWarning, "file name", 42)
+ with test_support.catch_warning(self.module):
+ self.module.filterwarnings("error", category=DeprecationWarning)
+ self.module.showwarning = self.bad_showwarning
+ self.assertRaises(DeprecationWarning, self.module.warn_explicit,
+ *args)
+
+class CShowwarningDeprecationTests(ShowwarningDeprecationTests):
+ module = c_warnings
+
+
+class PyShowwarningDeprecationTests(ShowwarningDeprecationTests):
+ module = py_warnings
+
+
+
def test_main():
py_warnings.onceregistry.clear()
c_warnings.onceregistry.clear()
@@ -471,6 +497,8 @@ def test_main():
CWCmdLineTests, PyWCmdLineTests,
_WarningsTests,
CWarningsDisplayTests, PyWarningsDisplayTests,
+ CShowwarningDeprecationTests,
+ PyShowwarningDeprecationTests,
)
diff --git a/Lib/warnings.py b/Lib/warnings.py
index 3c7357b..cefa961 100644
--- a/Lib/warnings.py
+++ b/Lib/warnings.py
@@ -3,6 +3,7 @@
# Note: function level imports should *not* be used
# in this module as it may cause import lock deadlock.
# See bug 683658.
+import inspect
import linecache
import sys
import types
@@ -21,7 +22,7 @@ def warnpy3k(message, category=None, stacklevel=1):
category = DeprecationWarning
warn(message, category, stacklevel+1)
-def showwarning(message, category, filename, lineno, file=None, line=None):
+def _show_warning(message, category, filename, lineno, file=None, line=None):
"""Hook to write a warning to a file; replace if you like."""
if file is None:
file = sys.stderr
@@ -29,6 +30,9 @@ def showwarning(message, category, filename, lineno, file=None, line=None):
file.write(formatwarning(message, category, filename, lineno, line))
except IOError:
pass # the file (probably stderr) is invalid - this warning gets lost.
+# Keep a worrking version around in case the deprecation of the old API is
+# triggered.
+showwarning = _show_warning
def formatwarning(message, category, filename, lineno, line=None):
"""Function to format a warning the standard way."""
@@ -259,6 +263,15 @@ def warn_explicit(message, category, filename, lineno,
"Unrecognized action (%r) in warnings.filters:\n %s" %
(action, item))
# Print message and context
+ if inspect.isfunction(showwarning):
+ arg_spec = inspect.getargspec(showwarning)
+ if 'line' not in arg_spec.args:
+ showwarning_msg = ("functions overriding warnings.showwarning() "
+ "must support the 'line' argument")
+ if message == showwarning_msg:
+ _show_warning(message, category, filename, lineno)
+ else:
+ warn(showwarning_msg, DeprecationWarning)
showwarning(message, category, filename, lineno)
diff --git a/Misc/NEWS b/Misc/NEWS
index 8515238..9c3743f 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -42,7 +42,9 @@ Extension Modules
machinery in such places as the parser where use of pure Python code is not
possible. Both the ``showarning()`` and ``formatwarning()`` gain an
optional 'line' argument which is not called by default for
- backwards-compatibility reasons.
+ backwards-compatibility reasons. Setting ``warnings.showwarning()`` to
+ an implementation that lacks support for the ``line`` argument will raise a
+ DeprecationWarning.
Library
-------
diff --git a/Python/_warnings.c b/Python/_warnings.c
index d843af6..3e7dda7 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -229,8 +229,8 @@ static void
show_warning(PyObject *filename, int lineno, PyObject *text, PyObject
*category, PyObject *sourceline)
{
- PyObject *f_stderr;
- PyObject *name;
+ PyObject *f_stderr;
+ PyObject *name;
char lineno_str[128];
PyOS_snprintf(lineno_str, sizeof(lineno_str), ":%d: ", lineno);
@@ -272,7 +272,7 @@ show_warning(PyObject *filename, int lineno, PyObject *text, PyObject
}
static PyObject *
-warn_explicit(PyObject *category, PyObject *message,
+warn_explicit(PyObject *category, PyObject *message,
PyObject *filename, int lineno,
PyObject *module, PyObject *registry, PyObject *sourceline)
{
@@ -347,12 +347,12 @@ warn_explicit(PyObject *category, PyObject *message,
goto cleanup;
}
/* _once_registry[(text, category)] = 1 */
- rc = update_registry(registry, text, category, 0);
+ rc = update_registry(registry, text, category, 0);
}
else if (strcmp(action, "module") == 0) {
/* registry[(text, category, 0)] = 1 */
if (registry != NULL)
- rc = update_registry(registry, text, category, 0);
+ rc = update_registry(registry, text, category, 0);
}
else if (strcmp(action, "default") != 0) {
PyObject *to_str = PyObject_Str(item);
@@ -378,15 +378,45 @@ warn_explicit(PyObject *category, PyObject *message,
show_warning(filename, lineno, text, category, sourceline);
}
else {
- PyObject *res;
-
- res = PyObject_CallFunctionObjArgs(show_fxn, message, category,
+ const char *msg = "functions overriding warnings.showwarning() "
+ "must support the 'line' argument";
+ const char *text_char = PyString_AS_STRING(text);
+
+ if (strcmp(msg, text_char) == 0) {
+ /* Prevent infinite recursion by using built-in implementation
+ of showwarning(). */
+ show_warning(filename, lineno, text, category, sourceline);
+ }
+ else {
+ PyObject *check_fxn;
+ PyObject *defaults;
+ PyObject *res;
+
+ if (PyMethod_Check(show_fxn))
+ check_fxn = PyMethod_Function(show_fxn);
+ else if (PyFunction_Check(show_fxn))
+ check_fxn = show_fxn;
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "warnings.showwarning() must be set to a "
+ "function or method");
+ }
+
+ defaults = PyFunction_GetDefaults(check_fxn);
+ /* A proper implementation of warnings.showwarning() should
+ have at least two default arguments. */
+ if ((defaults == NULL) || (PyTuple_Size(defaults) < 2)) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning, msg, 1) < 0)
+ 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;
+ Py_DECREF(show_fxn);
+ Py_XDECREF(res);
+ if (res == NULL)
+ goto cleanup;
+ }
}
}
else /* if (rc == -1) */
@@ -578,7 +608,7 @@ warnings_warn(PyObject *self, PyObject *args, PyObject *kwds)
PyObject *message, *category = NULL;
Py_ssize_t stack_level = 1;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|On:warn", kw_list,
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|On:warn", kw_list,
&message, &category, &stack_level))
return NULL;