[Python-checkins] r62720 - in python/trunk: Doc/library/warnings.rst Lib/test/test_warnings.py Lib/warnings.py Misc/NEWS Python/_warnings.c

brett.cannon python-checkins at python.org
Mon May 5 07:32:08 CEST 2008


Author: brett.cannon
Date: Mon May  5 07:32:07 2008
New Revision: 62720

Log:
Add a DeprecationWarning for when warnings.showwarning() is set to a function
that lacks support for the new 'line' argument.


Modified:
   python/trunk/Doc/library/warnings.rst
   python/trunk/Lib/test/test_warnings.py
   python/trunk/Lib/warnings.py
   python/trunk/Misc/NEWS
   python/trunk/Python/_warnings.c

Modified: python/trunk/Doc/library/warnings.rst
==============================================================================
--- python/trunk/Doc/library/warnings.rst	(original)
+++ python/trunk/Doc/library/warnings.rst	Mon May  5 07:32:07 2008
@@ -220,7 +220,8 @@
    ``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])

Modified: python/trunk/Lib/test/test_warnings.py
==============================================================================
--- python/trunk/Lib/test/test_warnings.py	(original)
+++ python/trunk/Lib/test/test_warnings.py	Mon May  5 07:32:07 2008
@@ -461,6 +461,32 @@
     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 @@
                                 CWCmdLineTests, PyWCmdLineTests,
                                 _WarningsTests,
                                 CWarningsDisplayTests, PyWarningsDisplayTests,
+                                CShowwarningDeprecationTests,
+                                PyShowwarningDeprecationTests,
                              )
 
 

Modified: python/trunk/Lib/warnings.py
==============================================================================
--- python/trunk/Lib/warnings.py	(original)
+++ python/trunk/Lib/warnings.py	Mon May  5 07:32:07 2008
@@ -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 @@
             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 @@
         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 @@
               "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)
 
 

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Mon May  5 07:32:07 2008
@@ -42,7 +42,9 @@
   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
 -------

Modified: python/trunk/Python/_warnings.c
==============================================================================
--- python/trunk/Python/_warnings.c	(original)
+++ python/trunk/Python/_warnings.c	Mon May  5 07:32:07 2008
@@ -229,8 +229,8 @@
 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 @@
 }
 
 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 @@
                     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 @@
             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 @@
     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;
 


More information about the Python-checkins mailing list