[Python-checkins] r62303 - in python/trunk: Doc/library/warnings.rst Include/Python.h Include/pyerrors.h Include/sysmodule.h Include/traceback.h Include/warnings.h Lib/test/test_support.py Lib/test/test_warnings.py Lib/warnings.py Makefile.pre.in Misc/NEWS Modules/config.c.in PC/config.c Python/_warnings.c Python/errors.c Python/pythonrun.c Python/sysmodule.c Python/traceback.c

brett.cannon python-checkins at python.org
Sun Apr 13 01:44:08 CEST 2008


Author: brett.cannon
Date: Sun Apr 13 01:44:07 2008
New Revision: 62303

Log:
Re-implement the 'warnings' module in C. This allows for usage of the
'warnings' code in places where it was previously not possible (e.g., the
parser). It could also potentially lead to a speed-up in interpreter start-up
if the C version of the code (_warnings) is imported over the use of the
Python version in key places.

Closes issue #1631171.


Added:
   python/trunk/Include/warnings.h
   python/trunk/Python/_warnings.c   (contents, props changed)
Modified:
   python/trunk/Doc/library/warnings.rst
   python/trunk/Include/Python.h
   python/trunk/Include/pyerrors.h
   python/trunk/Include/sysmodule.h
   python/trunk/Include/traceback.h
   python/trunk/Lib/test/test_support.py
   python/trunk/Lib/test/test_warnings.py
   python/trunk/Lib/warnings.py
   python/trunk/Makefile.pre.in
   python/trunk/Misc/NEWS
   python/trunk/Modules/config.c.in
   python/trunk/PC/config.c
   python/trunk/Python/errors.c
   python/trunk/Python/pythonrun.c
   python/trunk/Python/sysmodule.c
   python/trunk/Python/traceback.c

Modified: python/trunk/Doc/library/warnings.rst
==============================================================================
--- python/trunk/Doc/library/warnings.rst	(original)
+++ python/trunk/Doc/library/warnings.rst	Sun Apr 13 01:44:07 2008
@@ -211,20 +211,28 @@
    is using :exc:`DeprecationWarning` as default warning class.
 
 
-.. function:: showwarning(message, category, filename, lineno[, file])
+.. function:: showwarning(message, category, filename, lineno[, file[, line]])
 
    Write a warning to a file.  The default implementation calls
-   ``formatwarning(message, category, filename, lineno)`` and writes the resulting
-   string to *file*, which defaults to ``sys.stderr``.  You may replace this
-   function with an alternative implementation by assigning to
+   ``formatwarning(message, category, filename, lineno, line)`` and writes the
+   resulting string to *file*, which defaults to ``sys.stderr``.  You may replace
+   this function with an alternative implementation by assigning to
    ``warnings.showwarning``.
 
+   ..versionchanged:: 2.6
+     Added the `line` argument.
 
-.. function:: formatwarning(message, category, filename, lineno)
+
+
+
+.. function:: formatwarning(message, category, filename, lineno[, line])
 
    Format a warning the standard way.  This returns a string  which may contain
    embedded newlines and ends in a newline.
 
+   ..versionchanged:: 2.6
+     Added the `line` argument.
+
 
 .. function:: filterwarnings(action[, message[, category[, module[, lineno[, append]]]]])
 

Modified: python/trunk/Include/Python.h
==============================================================================
--- python/trunk/Include/Python.h	(original)
+++ python/trunk/Include/Python.h	Sun Apr 13 01:44:07 2008
@@ -110,6 +110,7 @@
 #include "iterobject.h"
 #include "genobject.h"
 #include "descrobject.h"
+#include "warnings.h"
 #include "weakrefobject.h"
 
 #include "codecs.h"

Modified: python/trunk/Include/pyerrors.h
==============================================================================
--- python/trunk/Include/pyerrors.h	(original)
+++ python/trunk/Include/pyerrors.h	Sun Apr 13 01:44:07 2008
@@ -227,16 +227,6 @@
                                          PyObject *dict);
 PyAPI_FUNC(void) PyErr_WriteUnraisable(PyObject *);
 
-/* Issue a warning or exception */
-PyAPI_FUNC(int) PyErr_WarnEx(PyObject *category, const char *msg,
-			     Py_ssize_t stack_level);
-PyAPI_FUNC(int) PyErr_WarnExplicit(PyObject *, const char *,
-				   const char *, int, 
-				   const char *, PyObject *);
-/* PyErr_Warn is only for backwards compatability and will be removed.
-   Use PyErr_WarnEx instead. */
-#define PyErr_Warn(category, msg) PyErr_WarnEx(category, msg, 1)
-
 /* In sigcheck.c or signalmodule.c */
 PyAPI_FUNC(int) PyErr_CheckSignals(void);
 PyAPI_FUNC(void) PyErr_SetInterrupt(void);

Modified: python/trunk/Include/sysmodule.h
==============================================================================
--- python/trunk/Include/sysmodule.h	(original)
+++ python/trunk/Include/sysmodule.h	Sun Apr 13 01:44:07 2008
@@ -23,6 +23,7 @@
 
 PyAPI_FUNC(void) PySys_ResetWarnOptions(void);
 PyAPI_FUNC(void) PySys_AddWarnOption(char *);
+PyAPI_FUNC(int) PySys_HasWarnOptions(void);
 
 #ifdef __cplusplus
 }

Modified: python/trunk/Include/traceback.h
==============================================================================
--- python/trunk/Include/traceback.h	(original)
+++ python/trunk/Include/traceback.h	Sun Apr 13 01:44:07 2008
@@ -19,6 +19,7 @@
 
 PyAPI_FUNC(int) PyTraceBack_Here(struct _frame *);
 PyAPI_FUNC(int) PyTraceBack_Print(PyObject *, PyObject *);
+PyAPI_FUNC(int) Py_DisplaySourceLine(PyObject *, const char *, int);
 
 /* Reveal traceback type so we can typecheck traceback objects */
 PyAPI_DATA(PyTypeObject) PyTraceBack_Type;

Added: python/trunk/Include/warnings.h
==============================================================================
--- (empty file)
+++ python/trunk/Include/warnings.h	Sun Apr 13 01:44:07 2008
@@ -0,0 +1,19 @@
+#ifndef Py_WARNINGS_H
+#define Py_WARNINGS_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+PyAPI_FUNC(void) _PyWarnings_Init(void);
+
+PyAPI_FUNC(int) PyErr_WarnEx(PyObject *, const char *, Py_ssize_t);
+PyAPI_FUNC(int) PyErr_WarnExplicit(PyObject *, const char *, const char *, int,
+                                    const char *, PyObject *);
+
+/* DEPRECATED: Use PyErr_WarnEx() instead. */
+#define PyErr_Warn(category, msg) PyErr_WarnEx(category, msg, 1)
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_WARNINGS_H */
\ No newline at end of file

Modified: python/trunk/Lib/test/test_support.py
==============================================================================
--- python/trunk/Lib/test/test_support.py	(original)
+++ python/trunk/Lib/test/test_support.py	Sun Apr 13 01:44:07 2008
@@ -363,14 +363,26 @@
         self.filename = None
         self.lineno = None
 
-    def _showwarning(self, message, category, filename, lineno, file=None):
+    def _showwarning(self, message, category, filename, lineno, file=None,
+                        line=None):
         self.message = message
         self.category = category
         self.filename = filename
         self.lineno = lineno
+        self.line = line
+
+    def reset(self):
+        self._showwarning(*((None,)*6))
+
+    def __str__(self):
+        return ("{message : %r, category : %r, filename : %r, lineno : %s, "
+                    "line : %r}" % (self.message,
+                            self.category.__name__ if self.category else None,
+                            self.filename, self.lineno, self.line))
+
 
 @contextlib.contextmanager
-def catch_warning():
+def catch_warning(module=warnings):
     """
     Guard the warnings filter from being permanently changed and record the
     data of the last warning that has been issued.
@@ -381,15 +393,15 @@
             warnings.warn("foo")
             assert str(w.message) == "foo"
     """
-    warning = WarningMessage()
-    original_filters = warnings.filters[:]
-    original_showwarning = warnings.showwarning
-    warnings.showwarning = warning._showwarning
+    warning_obj = WarningMessage()
+    original_filters = module.filters[:]
+    original_showwarning = module.showwarning
+    module.showwarning = warning_obj._showwarning
     try:
-        yield warning
+        yield warning_obj
     finally:
-        warnings.showwarning = original_showwarning
-        warnings.filters = original_filters
+        module.showwarning = original_showwarning
+        module.filters = original_filters
 
 class EnvironmentVarGuard(object):
 

Modified: python/trunk/Lib/test/test_warnings.py
==============================================================================
--- python/trunk/Lib/test/test_warnings.py	(original)
+++ python/trunk/Lib/test/test_warnings.py	Sun Apr 13 01:44:07 2008
@@ -1,4 +1,4 @@
-import warnings
+from contextlib import contextmanager
 import linecache
 import os
 import StringIO
@@ -8,112 +8,338 @@
 
 import warning_tests
 
-class TestModule(unittest.TestCase):
-    def setUp(self):
-        self.ignored = [w[2].__name__ for w in warnings.filters
-            if w[0]=='ignore' and w[1] is None and w[3] is None]
+sys.modules['_warnings'] = 0
+if 'warnings' in sys.modules:
+    del sys.modules['warnings']
+
+import warnings as py_warnings
+
+del sys.modules['_warnings']
+del sys.modules['warnings']
+
+import warnings as c_warnings
+
+ at contextmanager
+def warnings_state(module):
+    """Use a specific warnings implementation in warning_tests."""
+    global __warningregistry__
+    for to_clear in (sys, warning_tests):
+        try:
+            to_clear.__warningregistry__.clear()
+        except AttributeError:
+            pass
+    try:
+        __warningregistry__.clear()
+    except NameError:
+        pass
+    original_warnings = warning_tests.warnings
+    try:
+        warning_tests.warnings = module
+        yield
+    finally:
+        warning_tests.warnings = original_warnings
 
-    def test_warn_default_category(self):
-        with test_support.catch_warning() as w:
-            for i in range(4):
-                text = 'multi %d' %i    # Different text on each call
-                warnings.warn(text)
-                self.assertEqual(str(w.message), text)
-                self.assert_(w.category is UserWarning)
 
-    def test_warn_specific_category(self):
-        with test_support.catch_warning() as w:
-            text = 'None'
-            for category in [DeprecationWarning, FutureWarning,
-                        PendingDeprecationWarning, RuntimeWarning,
-                        SyntaxWarning, UserWarning, Warning]:
-                if category.__name__ in self.ignored:
-                    text = 'filtered out' + category.__name__
-                    warnings.warn(text, category)
-                    self.assertNotEqual(w.message, text)
+class FilterTests(unittest.TestCase):
+
+    """Testing the filtering functionality."""
+
+    def setUp(self):
+        global __warningregistry__
+        try:
+            __warningregistry__.clear()
+        except NameError:
+            pass
+
+    def test_error(self):
+        with test_support.catch_warning(self.module) as w:
+            self.module.resetwarnings()
+            self.module.filterwarnings("error", category=UserWarning)
+            self.assertRaises(UserWarning, self.module.warn,
+                                "FilterTests.test_error")
+
+    def test_ignore(self):
+        with test_support.catch_warning(self.module) as w:
+            self.module.resetwarnings()
+            self.module.filterwarnings("ignore", category=UserWarning)
+            self.module.warn("FilterTests.test_ignore", UserWarning)
+            self.assert_(not w.message)
+
+    def test_always(self):
+        with test_support.catch_warning(self.module) as w:
+            self.module.resetwarnings()
+            self.module.filterwarnings("always", category=UserWarning)
+            message = "FilterTests.test_always"
+            self.module.warn(message, UserWarning)
+            self.assert_(message, w.message)
+            w.message = None  # Reset.
+            self.module.warn(message, UserWarning)
+            self.assert_(w.message, message)
+
+    def test_default(self):
+        with test_support.catch_warning(self.module) as w:
+            self.module.resetwarnings()
+            self.module.filterwarnings("default", category=UserWarning)
+            message = UserWarning("FilterTests.test_default")
+            for x in xrange(2):
+                self.module.warn(message, UserWarning)
+                if x == 0:
+                    self.assertEquals(w.message, message)
+                    w.reset()
+                elif x == 1:
+                    self.assert_(not w.message, "unexpected warning: " + str(w))
                 else:
-                    text = 'unfiltered %s' % category.__name__
-                    warnings.warn(text, category)
-                    self.assertEqual(str(w.message), text)
-                    self.assert_(w.category is category)
+                    raise ValueError("loop variant unhandled")
 
-    def test_filtering(self):
+    def test_module(self):
+        with test_support.catch_warning(self.module) as w:
+            self.module.resetwarnings()
+            self.module.filterwarnings("module", category=UserWarning)
+            message = UserWarning("FilterTests.test_module")
+            self.module.warn(message, UserWarning)
+            self.assertEquals(w.message, message)
+            w.reset()
+            self.module.warn(message, UserWarning)
+            self.assert_(not w.message, "unexpected message: " + str(w))
+
+    def test_once(self):
+        with test_support.catch_warning(self.module) as w:
+            self.module.resetwarnings()
+            self.module.filterwarnings("once", category=UserWarning)
+            message = UserWarning("FilterTests.test_once")
+            self.module.warn_explicit(message, UserWarning, "test_warnings.py",
+                                    42)
+            self.assertEquals(w.message, message)
+            w.reset()
+            self.module.warn_explicit(message, UserWarning, "test_warnings.py",
+                                    13)
+            self.assert_(not w.message)
+            self.module.warn_explicit(message, UserWarning, "test_warnings2.py",
+                                    42)
+            self.assert_(not w.message)
+
+    def test_inheritance(self):
+        with test_support.catch_warning(self.module) as w:
+            self.module.resetwarnings()
+            self.module.filterwarnings("error", category=Warning)
+            self.assertRaises(UserWarning, self.module.warn,
+                                "FilterTests.test_inheritance", UserWarning)
+
+    def test_ordering(self):
+        with test_support.catch_warning(self.module) as w:
+            self.module.resetwarnings()
+            self.module.filterwarnings("ignore", category=UserWarning)
+            self.module.filterwarnings("error", category=UserWarning,
+                                        append=True)
+            w.reset()
+            try:
+                self.module.warn("FilterTests.test_ordering", UserWarning)
+            except UserWarning:
+                self.fail("order handling for actions failed")
+            self.assert_(not w.message)
+
+    def test_filterwarnings(self):
         # Test filterwarnings().
         # Implicitly also tests resetwarnings().
-        with test_support.catch_warning() as w:
-            warnings.filterwarnings("error", "", Warning, "", 0)
-            self.assertRaises(UserWarning, warnings.warn, 'convert to error')
+        with test_support.catch_warning(self.module) as w:
+            self.module.filterwarnings("error", "", Warning, "", 0)
+            self.assertRaises(UserWarning, self.module.warn, 'convert to error')
 
-            warnings.resetwarnings()
+            self.module.resetwarnings()
             text = 'handle normally'
-            warnings.warn(text)
+            self.module.warn(text)
             self.assertEqual(str(w.message), text)
             self.assert_(w.category is UserWarning)
 
-            warnings.filterwarnings("ignore", "", Warning, "", 0)
+            self.module.filterwarnings("ignore", "", Warning, "", 0)
             text = 'filtered out'
-            warnings.warn(text)
+            self.module.warn(text)
             self.assertNotEqual(str(w.message), text)
 
-            warnings.resetwarnings()
-            warnings.filterwarnings("error", "hex*", Warning, "", 0)
-            self.assertRaises(UserWarning, warnings.warn, 'hex/oct')
+            self.module.resetwarnings()
+            self.module.filterwarnings("error", "hex*", Warning, "", 0)
+            self.assertRaises(UserWarning, self.module.warn, 'hex/oct')
             text = 'nonmatching text'
-            warnings.warn(text)
+            self.module.warn(text)
             self.assertEqual(str(w.message), text)
             self.assert_(w.category is UserWarning)
 
-    def test_options(self):
-        # Uses the private _setoption() function to test the parsing
-        # of command-line warning arguments
-        with test_support.catch_warning():
-            self.assertRaises(warnings._OptionError,
-                              warnings._setoption, '1:2:3:4:5:6')
-            self.assertRaises(warnings._OptionError,
-                              warnings._setoption, 'bogus::Warning')
-            self.assertRaises(warnings._OptionError,
-                              warnings._setoption, 'ignore:2::4:-5')
-            warnings._setoption('error::Warning::0')
-            self.assertRaises(UserWarning, warnings.warn, 'convert to error')
+class CFilterTests(FilterTests):
+    module = c_warnings
+
+class PyFilterTests(FilterTests):
+    module = py_warnings
+
+
+class WarnTests(unittest.TestCase):
+
+    """Test warnings.warn() and warnings.warn_explicit()."""
+
+    def test_message(self):
+        with test_support.catch_warning(self.module) as w:
+            for i in range(4):
+                text = 'multi %d' %i  # Different text on each call.
+                self.module.warn(text)
+                self.assertEqual(str(w.message), text)
+                self.assert_(w.category is UserWarning)
 
     def test_filename(self):
-        with test_support.catch_warning() as w:
-            warning_tests.inner("spam1")
-            self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
-            warning_tests.outer("spam2")
-            self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
+        with warnings_state(self.module):
+            with test_support.catch_warning(self.module) as w:
+                warning_tests.inner("spam1")
+                self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
+                warning_tests.outer("spam2")
+                self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
 
     def test_stacklevel(self):
         # Test stacklevel argument
         # make sure all messages are different, so the warning won't be skipped
-        with test_support.catch_warning() as w:
-            warning_tests.inner("spam3", stacklevel=1)
-            self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
-            warning_tests.outer("spam4", stacklevel=1)
-            self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
-
-            warning_tests.inner("spam5", stacklevel=2)
-            self.assertEqual(os.path.basename(w.filename), "test_warnings.py")
-            warning_tests.outer("spam6", stacklevel=2)
-            self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
+        with warnings_state(self.module):
+            with test_support.catch_warning(self.module) as w:
+                warning_tests.inner("spam3", stacklevel=1)
+                self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
+                warning_tests.outer("spam4", stacklevel=1)
+                self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
+
+                warning_tests.inner("spam5", stacklevel=2)
+                self.assertEqual(os.path.basename(w.filename), "test_warnings.py")
+                warning_tests.outer("spam6", stacklevel=2)
+                self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
+
+                warning_tests.inner("spam7", stacklevel=9999)
+                self.assertEqual(os.path.basename(w.filename), "sys")
+
+
+class CWarnTests(WarnTests):
+    module = c_warnings
+
+class PyWarnTests(WarnTests):
+    module = py_warnings
+
+
+class WCmdLineTests(unittest.TestCase):
 
-            warning_tests.inner("spam7", stacklevel=9999)
-            self.assertEqual(os.path.basename(w.filename), "sys")
+    def test_improper_input(self):
+        # Uses the private _setoption() function to test the parsing
+        # of command-line warning arguments
+        with test_support.catch_warning(self.module):
+            self.assertRaises(self.module._OptionError,
+                              self.module._setoption, '1:2:3:4:5:6')
+            self.assertRaises(self.module._OptionError,
+                              self.module._setoption, 'bogus::Warning')
+            self.assertRaises(self.module._OptionError,
+                              self.module._setoption, 'ignore:2::4:-5')
+            self.module._setoption('error::Warning::0')
+            self.assertRaises(UserWarning, self.module.warn, 'convert to error')
+
+class CWCmdLineTests(WCmdLineTests):
+    module = c_warnings
+
+class PyWCmdLineTests(WCmdLineTests):
+    module = py_warnings
+
+
+class _WarningsTests(unittest.TestCase):
+
+    """Tests specific to the _warnings module."""
+
+    module = c_warnings
+
+    def test_filter(self):
+        # Everything should function even if 'filters' is not in warnings.
+        with test_support.catch_warning(self.module) as w:
+            self.module.filterwarnings("error", "", Warning, "", 0)
+            self.assertRaises(UserWarning, self.module.warn,
+                                'convert to error')
+            del self.module.filters
+            self.assertRaises(UserWarning, self.module.warn,
+                                'convert to error')
+
+    def test_onceregistry(self):
+        # Replacing or removing the onceregistry should be okay.
+        global __warningregistry__
+        message = UserWarning('onceregistry test')
+        try:
+            original_registry = self.module.onceregistry
+            __warningregistry__ = {}
+            with test_support.catch_warning(self.module) as w:
+                self.module.resetwarnings()
+                self.module.filterwarnings("once", category=UserWarning)
+                self.module.warn_explicit(message, UserWarning, "file", 42)
+                self.failUnlessEqual(w.message, message)
+                w.reset()
+                self.module.warn_explicit(message, UserWarning, "file", 42)
+                self.assert_(not w.message)
+                # Test the resetting of onceregistry.
+                self.module.onceregistry = {}
+                __warningregistry__ = {}
+                self.module.warn('onceregistry test')
+                self.failUnlessEqual(w.message.args, message.args)
+                # Removal of onceregistry is okay.
+                w.reset()
+                del self.module.onceregistry
+                __warningregistry__ = {}
+                self.module.warn_explicit(message, UserWarning, "file", 42)
+                self.failUnless(not w.message)
+        finally:
+            self.module.onceregistry = original_registry
+
+    def test_showwarning_missing(self):
+        # Test that showwarning() missing is okay.
+        text = 'del showwarning test'
+        with test_support.catch_warning(self.module):
+            self.module.filterwarnings("always", category=UserWarning)
+            del self.module.showwarning
+            with test_support.captured_output('stderr') as stream:
+                self.module.warn(text)
+                result = stream.getvalue()
+        self.failUnless(text in result)
+
+    def test_show_warning_output(self):
+        # With showarning() missing, make sure that output is okay.
+        text = 'test show_warning'
+        with test_support.catch_warning(self.module):
+            self.module.filterwarnings("always", category=UserWarning)
+            del self.module.showwarning
+            with test_support.captured_output('stderr') as stream:
+                warning_tests.inner(text)
+                result = stream.getvalue()
+        self.failUnlessEqual(result.count('\n'), 2,
+                             "Too many newlines in %r" % result)
+        first_line, second_line = result.split('\n', 1)
+        expected_file = os.path.splitext(warning_tests.__file__)[0] + '.py'
+        path, line, warning_class, message = first_line.split(':')
+        line = int(line)
+        self.failUnlessEqual(expected_file, path)
+        self.failUnlessEqual(warning_class, ' ' + UserWarning.__name__)
+        self.failUnlessEqual(message, ' ' + text)
+        expected_line = '  ' + linecache.getline(path, line).strip() + '\n'
+        assert expected_line
+        self.failUnlessEqual(second_line, expected_line)
 
 
 class WarningsDisplayTests(unittest.TestCase):
 
+    """Test the displaying of warnings and the ability to overload functions
+    related to displaying warnings."""
+
     def test_formatwarning(self):
         message = "msg"
         category = Warning
         file_name = os.path.splitext(warning_tests.__file__)[0] + '.py'
         line_num = 3
         file_line = linecache.getline(file_name, line_num).strip()
-        expect = "%s:%s: %s: %s\n  %s\n" % (file_name, line_num, category.__name__,
-                                         message, file_line)
-        self.failUnlessEqual(warnings.formatwarning(message, category,
-                                                    file_name, line_num),
-                             expect)
+        format = "%s:%s: %s: %s\n  %s\n"
+        expect = format % (file_name, line_num, category.__name__, message,
+                            file_line)
+        self.failUnlessEqual(expect, self.module.formatwarning(message,
+                                                category, file_name, line_num))
+        # Test the 'line' argument.
+        file_line += " for the win!"
+        expect = format % (file_name, line_num, category.__name__, message,
+                            file_line)
+        self.failUnlessEqual(expect, self.module.formatwarning(message,
+                                    category, file_name, line_num, file_line))
 
     def test_showwarning(self):
         file_name = os.path.splitext(warning_tests.__file__)[0] + '.py'
@@ -122,13 +348,28 @@
         message = 'msg'
         category = Warning
         file_object = StringIO.StringIO()
-        expect = warnings.formatwarning(message, category, file_name, line_num)
-        warnings.showwarning(message, category, file_name, line_num,
+        expect = self.module.formatwarning(message, category, file_name,
+                                            line_num)
+        self.module.showwarning(message, category, file_name, line_num,
                                 file_object)
         self.failUnlessEqual(file_object.getvalue(), expect)
+        # Test 'line' argument.
+        expected_file_line += "for the win!"
+        expect = self.module.formatwarning(message, category, file_name,
+                                            line_num, expected_file_line)
+        file_object = StringIO.StringIO()
+        self.module.showwarning(message, category, file_name, line_num,
+                                file_object, expected_file_line)
+        self.failUnlessEqual(expect, file_object.getvalue())
 
+class CWarningsDisplayTests(WarningsDisplayTests):
+    module = c_warnings
 
-def test_main(verbose=None):
+class PyWarningsDisplayTests(WarningsDisplayTests):
+    module = py_warnings
+
+
+def test_main():
     # Obscure hack so that this test passes after reloads or repeated calls
     # to test_main (regrtest -R).
     if '__warningregistry__' in globals():
@@ -137,7 +378,14 @@
         del warning_tests.__warningregistry__
     if hasattr(sys, '__warningregistry__'):
         del sys.__warningregistry__
-    test_support.run_unittest(TestModule, WarningsDisplayTests)
+    test_support.run_unittest(CFilterTests, PyFilterTests,
+                                CWarnTests, PyWarnTests,
+                                CWCmdLineTests, PyWCmdLineTests,
+                                _WarningsTests,
+                                CWarningsDisplayTests, PyWarningsDisplayTests,
+                             )
+
+
 
 if __name__ == "__main__":
-    test_main(verbose=True)
+    test_main()

Modified: python/trunk/Lib/warnings.py
==============================================================================
--- python/trunk/Lib/warnings.py	(original)
+++ python/trunk/Lib/warnings.py	Sun Apr 13 01:44:07 2008
@@ -3,127 +3,13 @@
 # Note: function level imports should *not* be used
 # in this module as it may cause import lock deadlock.
 # See bug 683658.
-import sys, types
 import linecache
+import sys
+import types
 
 __all__ = ["warn", "showwarning", "formatwarning", "filterwarnings",
            "resetwarnings"]
 
-# filters contains a sequence of filter 5-tuples
-# The components of the 5-tuple are:
-# - an action: error, ignore, always, default, module, or once
-# - a compiled regex that must match the warning message
-# - a class representing the warning category
-# - a compiled regex that must match the module that is being warned
-# - a line number for the line being warning, or 0 to mean any line
-# If either if the compiled regexs are None, match anything.
-filters = []
-defaultaction = "default"
-onceregistry = {}
-
-def warn(message, category=None, stacklevel=1):
-    """Issue a warning, or maybe ignore it or raise an exception."""
-    # Check if message is already a Warning object
-    if isinstance(message, Warning):
-        category = message.__class__
-    # Check category argument
-    if category is None:
-        category = UserWarning
-    assert issubclass(category, Warning)
-    # Get context information
-    try:
-        caller = sys._getframe(stacklevel)
-    except ValueError:
-        globals = sys.__dict__
-        lineno = 1
-    else:
-        globals = caller.f_globals
-        lineno = caller.f_lineno
-    if '__name__' in globals:
-        module = globals['__name__']
-    else:
-        module = "<string>"
-    filename = globals.get('__file__')
-    if filename:
-        fnl = filename.lower()
-        if fnl.endswith((".pyc", ".pyo")):
-            filename = filename[:-1]
-    else:
-        if module == "__main__":
-            try:
-                filename = sys.argv[0]
-            except AttributeError:
-                # embedded interpreters don't have sys.argv, see bug #839151
-                filename = '__main__'
-        if not filename:
-            filename = module
-    registry = globals.setdefault("__warningregistry__", {})
-    warn_explicit(message, category, filename, lineno, module, registry,
-                  globals)
-
-def warn_explicit(message, category, filename, lineno,
-                  module=None, registry=None, module_globals=None):
-    if module is None:
-        module = filename or "<unknown>"
-        if module[-3:].lower() == ".py":
-            module = module[:-3] # XXX What about leading pathname?
-    if registry is None:
-        registry = {}
-    if isinstance(message, Warning):
-        text = str(message)
-        category = message.__class__
-    else:
-        text = message
-        message = category(message)
-    key = (text, category, lineno)
-    # Quick test for common case
-    if registry.get(key):
-        return
-    # Search the filters
-    for item in filters:
-        action, msg, cat, mod, ln = item
-        if ((msg is None or msg.match(text)) and
-            issubclass(category, cat) and
-            (mod is None or mod.match(module)) and
-            (ln == 0 or lineno == ln)):
-            break
-    else:
-        action = defaultaction
-    # Early exit actions
-    if action == "ignore":
-        registry[key] = 1
-        return
-
-    # Prime the linecache for formatting, in case the
-    # "file" is actually in a zipfile or something.
-    linecache.getlines(filename, module_globals)
-
-    if action == "error":
-        raise message
-    # Other actions
-    if action == "once":
-        registry[key] = 1
-        oncekey = (text, category)
-        if onceregistry.get(oncekey):
-            return
-        onceregistry[oncekey] = 1
-    elif action == "always":
-        pass
-    elif action == "module":
-        registry[key] = 1
-        altkey = (text, category, 0)
-        if registry.get(altkey):
-            return
-        registry[altkey] = 1
-    elif action == "default":
-        registry[key] = 1
-    else:
-        # Unrecognized actions are errors
-        raise RuntimeError(
-              "Unrecognized action (%r) in warnings.filters:\n %s" %
-              (action, item))
-    # Print message and context
-    showwarning(message, category, filename, lineno)
 
 def warnpy3k(message, category=None, stacklevel=1):
     """Issue a deprecation warning for Python 3.x related changes.
@@ -135,21 +21,22 @@
             category = DeprecationWarning
         warn(message, category, stacklevel+1)
 
-def showwarning(message, category, filename, lineno, file=None):
+def showwarning(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
     try:
-        file.write(formatwarning(message, category, filename, lineno))
+        file.write(formatwarning(message, category, filename, lineno, line))
     except IOError:
         pass # the file (probably stderr) is invalid - this warning gets lost.
 
-def formatwarning(message, category, filename, lineno):
+def formatwarning(message, category, filename, lineno, line=None):
     """Function to format a warning the standard way."""
     s =  "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message)
-    line = linecache.getline(filename, lineno).strip()
+    line = linecache.getline(filename, lineno) if line is None else line
     if line:
-        s = s + "  " + line + "\n"
+        line = line.strip()
+        s += "  %s\n" % line
     return s
 
 def filterwarnings(action, message="", category=Warning, module="", lineno=0,
@@ -268,7 +155,145 @@
         raise _OptionError("invalid warning category: %r" % (category,))
     return cat
 
+
+# Code typically replaced by _warnings
+def warn(message, category=None, stacklevel=1):
+    """Issue a warning, or maybe ignore it or raise an exception."""
+    # Check if message is already a Warning object
+    if isinstance(message, Warning):
+        category = message.__class__
+    # Check category argument
+    if category is None:
+        category = UserWarning
+    assert issubclass(category, Warning)
+    # Get context information
+    try:
+        caller = sys._getframe(stacklevel)
+    except ValueError:
+        globals = sys.__dict__
+        lineno = 1
+    else:
+        globals = caller.f_globals
+        lineno = caller.f_lineno
+    if '__name__' in globals:
+        module = globals['__name__']
+    else:
+        module = "<string>"
+    filename = globals.get('__file__')
+    if filename:
+        fnl = filename.lower()
+        if fnl.endswith((".pyc", ".pyo")):
+            filename = filename[:-1]
+    else:
+        if module == "__main__":
+            try:
+                filename = sys.argv[0]
+            except AttributeError:
+                # embedded interpreters don't have sys.argv, see bug #839151
+                filename = '__main__'
+        if not filename:
+            filename = module
+    registry = globals.setdefault("__warningregistry__", {})
+    warn_explicit(message, category, filename, lineno, module, registry,
+                  globals)
+
+def warn_explicit(message, category, filename, lineno,
+                  module=None, registry=None, module_globals=None):
+    if module is None:
+        module = filename or "<unknown>"
+        if module[-3:].lower() == ".py":
+            module = module[:-3] # XXX What about leading pathname?
+    if registry is None:
+        registry = {}
+    if isinstance(message, Warning):
+        text = str(message)
+        category = message.__class__
+    else:
+        text = message
+        message = category(message)
+    key = (text, category, lineno)
+    # Quick test for common case
+    if registry.get(key):
+        return
+    # Search the filters
+    for item in filters:
+        action, msg, cat, mod, ln = item
+        if ((msg is None or msg.match(text)) and
+            issubclass(category, cat) and
+            (mod is None or mod.match(module)) and
+            (ln == 0 or lineno == ln)):
+            break
+    else:
+        action = defaultaction
+    # Early exit actions
+    if action == "ignore":
+        registry[key] = 1
+        return
+
+    # Prime the linecache for formatting, in case the
+    # "file" is actually in a zipfile or something.
+    linecache.getlines(filename, module_globals)
+
+    if action == "error":
+        raise message
+    # Other actions
+    if action == "once":
+        registry[key] = 1
+        oncekey = (text, category)
+        if onceregistry.get(oncekey):
+            return
+        onceregistry[oncekey] = 1
+    elif action == "always":
+        pass
+    elif action == "module":
+        registry[key] = 1
+        altkey = (text, category, 0)
+        if registry.get(altkey):
+            return
+        registry[altkey] = 1
+    elif action == "default":
+        registry[key] = 1
+    else:
+        # Unrecognized actions are errors
+        raise RuntimeError(
+              "Unrecognized action (%r) in warnings.filters:\n %s" %
+              (action, item))
+    # Print message and context
+    showwarning(message, category, filename, lineno)
+
+
+# filters contains a sequence of filter 5-tuples
+# The components of the 5-tuple are:
+# - an action: error, ignore, always, default, module, or once
+# - a compiled regex that must match the warning message
+# - a class representing the warning category
+# - a compiled regex that must match the module that is being warned
+# - a line number for the line being warning, or 0 to mean any line
+# If either if the compiled regexs are None, match anything.
+_warnings_defaults = False
+try:
+    from _warnings import (filters, default_action, once_registry,
+                            warn, warn_explicit)
+    defaultaction = default_action
+    onceregistry = once_registry
+    _warnings_defaults = True
+except ImportError:
+    filters = []
+    defaultaction = "default"
+    onceregistry = {}
+
+
 # Module initialization
 _processoptions(sys.warnoptions)
-simplefilter("ignore", category=PendingDeprecationWarning, append=1)
-simplefilter("ignore", category=ImportWarning, append=1)
+if not _warnings_defaults:
+    simplefilter("ignore", category=PendingDeprecationWarning, append=1)
+    simplefilter("ignore", category=ImportWarning, append=1)
+    bytes_warning = sys.flags.bytes_warning
+    if bytes_warning > 1:
+        bytes_action = "error"
+    elif bytes_warning:
+        bytes_action = "default"
+    else:
+        bytes_action = "ignore"
+    simplefilter(bytes_action, category=BytesWarning, append=1)
+del _warnings_defaults

Modified: python/trunk/Makefile.pre.in
==============================================================================
--- python/trunk/Makefile.pre.in	(original)
+++ python/trunk/Makefile.pre.in	Sun Apr 13 01:44:07 2008
@@ -245,6 +245,7 @@
 ##########################################################################
 # Python
 PYTHON_OBJS=	\
+		Python/_warnings.o \
 		Python/Python-ast.o \
 		Python/asdl.o \
 		Python/ast.o \
@@ -621,6 +622,7 @@
 		Include/tupleobject.h \
 		Include/ucnhash.h \
 		Include/unicodeobject.h \
+		Include/warnings.h \
 		Include/weakrefobject.h \
 		pyconfig.h \
 		$(PARSER_HEADERS)

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Sun Apr 13 01:44:07 2008
@@ -21,6 +21,11 @@
 - zlib.decompressobj().flush(value) no longer crashes the interpreter when
   passed a value less than or equal to zero.
 
+- Issue #1631171: Re-implement the 'warnings' module in C (the original Python
+  code has been kept as backup). This will allow for using the 'warning's
+  machinery in such places as the parser where use of pure Python code is not
+  possible.
+
 Library
 -------
 

Modified: python/trunk/Modules/config.c.in
==============================================================================
--- python/trunk/Modules/config.c.in	(original)
+++ python/trunk/Modules/config.c.in	Sun Apr 13 01:44:07 2008
@@ -28,6 +28,7 @@
 extern void initimp(void);
 extern void initgc(void);
 extern void init_ast(void);
+extern void _PyWarnings_Init(void);
 
 struct _inittab _PyImport_Inittab[] = {
 
@@ -51,6 +52,9 @@
 	/* This lives in gcmodule.c */
 	{"gc", initgc},
 
+    /* This lives in _warnings.c */
+    {"_warnings", _PyWarnings_Init},
+
 	/* Sentinel */
 	{0, 0}
 };

Modified: python/trunk/PC/config.c
==============================================================================
--- python/trunk/PC/config.c	(original)
+++ python/trunk/PC/config.c	Sun Apr 13 01:44:07 2008
@@ -66,6 +66,7 @@
 extern void init_subprocess(void);
 extern void init_lsprof(void);
 extern void init_ast(void);
+extern void _PyWarnings_Init(void);
 
 /* tools/freeze/makeconfig.py marker for additional "extern" */
 /* -- ADDMODULE MARKER 1 -- */
@@ -160,6 +161,9 @@
         {"sys", NULL},
 	{"exceptions", NULL},
         
+        {"_types", init_types},
+        {"_warnings", _PyWarnings_Init},
+
         /* Sentinel */
         {0, 0}
 };

Added: python/trunk/Python/_warnings.c
==============================================================================
--- (empty file)
+++ python/trunk/Python/_warnings.c	Sun Apr 13 01:44:07 2008
@@ -0,0 +1,856 @@
+#include "Python.h"
+#include "frameobject.h"
+
+#define MODULE_NAME "_warnings"
+#define DEFAULT_ACTION_NAME "default_action"
+
+PyDoc_STRVAR(warnings__doc__,
+MODULE_NAME " provides basic warning filtering support.\n"
+"It is a helper module to speed up interpreter start-up.");
+
+/* Both 'filters' and 'onceregistry' can be set in warnings.py;
+   get_warnings_attr() will reset these variables accordingly. */
+static PyObject *_filters;  /* List */
+static PyObject *_once_registry;  /* Dict */
+
+
+static int
+check_matched(PyObject *obj, PyObject *arg)
+{
+    PyObject *result;
+    int rc;
+
+    if (obj == Py_None)
+        return 1;
+    result = PyObject_CallMethod(obj, "match", "O", arg);
+    if (result == NULL)
+        return -1;
+
+    rc = PyObject_IsTrue(result);
+    Py_DECREF(result);
+    return rc;
+}
+
+/*
+   Returns a new reference.
+   A NULL return value can mean false or an error.
+*/
+static PyObject *
+get_warnings_attr(const char *attr)
+{
+    static PyObject *warnings_str = NULL;
+    PyObject *all_modules;
+    PyObject *warnings_module;
+    int result;
+
+    if (warnings_str == NULL) {
+        warnings_str = PyString_FromString("warnings");
+        if (warnings_str == NULL)
+            return NULL;
+    }
+
+    all_modules = PyImport_GetModuleDict();
+    result = PyDict_Contains(all_modules, warnings_str);
+    if (result == -1 || result == 0)
+        return NULL;
+
+    warnings_module = PyDict_GetItem(all_modules, warnings_str);
+    if (!PyObject_HasAttrString(warnings_module, attr))
+            return NULL;
+    return PyObject_GetAttrString(warnings_module, attr);
+}
+
+
+PyObject *
+get_once_registry(void)
+{
+    PyObject *registry;
+
+    registry = get_warnings_attr("onceregistry");
+    if (registry == NULL) {
+        if (PyErr_Occurred())
+            return NULL;
+        return _once_registry;
+    }
+    Py_DECREF(_once_registry);
+    _once_registry = registry;
+    return registry;
+}
+
+
+/* The item is a borrowed reference. */
+static const char *
+get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno,
+           PyObject *module, PyObject **item)
+{
+    PyObject *action, *m, *d;
+    Py_ssize_t i;
+    PyObject *warnings_filters;
+
+    warnings_filters = get_warnings_attr("filters");
+    if (warnings_filters == NULL) {
+        if (PyErr_Occurred())
+            return NULL;
+    }
+    else {
+        Py_DECREF(_filters);
+        _filters = warnings_filters;
+    }
+
+    if (!PyList_Check(_filters)) {
+        PyErr_SetString(PyExc_ValueError,
+                        MODULE_NAME ".filters must be a list");
+        return NULL;
+    }
+
+    /* _filters could change while we are iterating over it. */
+    for (i = 0; i < PyList_GET_SIZE(_filters); i++) {
+        PyObject *tmp_item, *action, *msg, *cat, *mod, *ln_obj;
+        Py_ssize_t ln;
+        int is_subclass, good_msg, good_mod;
+
+        tmp_item = *item = PyList_GET_ITEM(_filters, i);
+        if (PyTuple_Size(tmp_item) != 5) {
+            PyErr_Format(PyExc_ValueError,
+                         MODULE_NAME ".filters item %zd isn't a 5-tuple", i);
+            return NULL;
+        }
+
+        /* Python code: action, msg, cat, mod, ln = item */
+        action = PyTuple_GET_ITEM(tmp_item, 0);
+        msg = PyTuple_GET_ITEM(tmp_item, 1);
+        cat = PyTuple_GET_ITEM(tmp_item, 2);
+        mod = PyTuple_GET_ITEM(tmp_item, 3);
+        ln_obj = PyTuple_GET_ITEM(tmp_item, 4);
+
+        good_msg = check_matched(msg, text);
+        good_mod = check_matched(mod, module);
+        is_subclass = PyObject_IsSubclass(category, cat);
+        ln = PyInt_AsSsize_t(ln_obj);
+        if (good_msg == -1 || good_mod == -1 || is_subclass == -1 ||
+            (ln == -1 && PyErr_Occurred()))
+            return NULL;
+
+        if (good_msg && is_subclass && good_mod && (ln == 0 || lineno == ln))
+            return PyString_AsString(action);
+    }
+
+    m = PyImport_ImportModule(MODULE_NAME);
+    if (m == NULL)
+        return NULL;
+    d = PyModule_GetDict(m);
+    Py_DECREF(m);
+    if (d == NULL)
+        return NULL;
+    action = PyDict_GetItemString(d, DEFAULT_ACTION_NAME);
+    if (action != NULL)
+        return PyString_AsString(action);
+
+    PyErr_SetString(PyExc_ValueError,
+                    MODULE_NAME "." DEFAULT_ACTION_NAME " not found");
+    return NULL;
+}
+
+static int
+already_warned(PyObject *registry, PyObject *key, int should_set)
+{
+    PyObject *already_warned;
+
+    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;
+    }
+
+    /* This warning wasn't found in the registry, set it. */
+    if (should_set)
+        return PyDict_SetItem(registry, key, Py_True);
+    return 0;
+}
+
+/* New reference. */
+static PyObject *
+normalize_module(PyObject *filename)
+{
+    PyObject *module;
+    const char *mod_str;
+    Py_ssize_t len;
+
+    int rc = PyObject_IsTrue(filename);
+    if (rc == -1)
+        return NULL;
+    else if (rc == 0)
+        return PyString_FromString("<unknown>");
+
+    mod_str = PyString_AsString(filename);
+    if (mod_str == NULL)
+	    return NULL;
+    len = PyString_Size(filename);
+    if (len < 0)
+        return NULL;
+    if (len >= 3 &&
+	strncmp(mod_str + (len - 3), ".py", 3) == 0) {
+        module = PyString_FromStringAndSize(mod_str, len-3);
+    }
+    else {
+        module = filename;
+        Py_INCREF(module);
+    }
+    return module;
+}
+
+static int
+update_registry(PyObject *registry, PyObject *text, PyObject *category,
+                int add_zero)
+{
+    PyObject *altkey, *zero = NULL;
+    int rc;
+
+    if (add_zero) {
+        zero = PyInt_FromLong(0);
+        if (zero == NULL)
+            return -1;
+        altkey = PyTuple_Pack(3, text, category, zero);
+    }
+    else
+        altkey = PyTuple_Pack(2, text, category);
+
+    rc = already_warned(registry, altkey, 1);
+    Py_XDECREF(zero);
+    Py_XDECREF(altkey);
+    return rc;
+}
+
+static void
+show_warning(PyObject *filename, int lineno, PyObject *text, PyObject
+                *category, PyObject *sourceline)
+{
+    PyObject *f_stderr; 
+    PyObject *name; 
+    char lineno_str[128];
+
+    PyOS_snprintf(lineno_str, sizeof(lineno_str), ":%d: ", lineno);
+
+    name = PyObject_GetAttrString(category, "__name__");
+    if (name == NULL)  /* XXX Can an object lack a '__name__' attribute? */
+	    return;
+
+    f_stderr = PySys_GetObject("stderr");
+    if (f_stderr == NULL) {
+        fprintf(stderr, "lost sys.stderr\n");
+        Py_DECREF(name);
+        return;
+    }
+
+    /* 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);
+
+    /* Print "  source_line\n" */
+    PyFile_WriteString("  ", f_stderr);
+    if (sourceline) {
+        char *source_line_str = PyString_AS_STRING(sourceline);
+        while (*source_line_str == ' ' || *source_line_str == '\t' ||
+                *source_line_str == '\014')
+            source_line_str++;
+
+        PyFile_WriteString(source_line_str, f_stderr);
+        PyFile_WriteString("\n", f_stderr);
+    }
+    else
+        Py_DisplaySourceLine(f_stderr, PyString_AS_STRING(filename), lineno);
+    PyErr_Clear();
+}
+
+static PyObject *
+warn_explicit(PyObject *category, PyObject *message, 
+              PyObject *filename, int lineno,
+              PyObject *module, PyObject *registry, PyObject *sourceline)
+{
+    PyObject *key = NULL, *text = NULL, *result = NULL, *lineno_obj = NULL;
+    PyObject *item = Py_None;
+    const char *action;
+    int rc;
+
+    /* Normalize module. */
+    if (module == NULL) {
+        module = normalize_module(filename);
+        if (module == NULL)
+            return NULL;
+    }
+    else
+        Py_INCREF(module);
+
+    /* Normalize message. */
+    Py_INCREF(message);  /* DECREF'ed in cleanup. */
+    rc = PyObject_IsInstance(message, PyExc_Warning);
+    if (rc == -1) {
+        goto cleanup;
+    }
+    if (rc == 1) {
+        text = PyObject_Str(message);
+        category = (PyObject*)message->ob_type;
+    }
+    else {
+        text = message;
+        message = PyObject_CallFunction(category, "O", message);
+    }
+
+    lineno_obj = PyInt_FromLong(lineno);
+    if (lineno_obj == NULL)
+        goto cleanup;
+
+    /* Create key. */
+    key = PyTuple_Pack(3, text, category, lineno_obj);
+    if (key == NULL)
+        goto cleanup;
+
+    if (registry != NULL) {
+        rc = already_warned(registry, key, 0);
+        if (rc == -1)
+            goto cleanup;
+	else if (rc == 1)
+            goto return_none;
+        /* Else this warning hasn't been generated before. */
+    }
+
+    action = get_filter(category, text, lineno, module, &item);
+    if (action == NULL)
+        goto cleanup;
+
+    if (strcmp(action, "error") == 0) {
+        PyErr_SetObject(category, message);
+        goto cleanup;
+    }
+
+    /* Store in the registry that we've been here, *except* when the action
+       is "always". */
+    rc = 0;
+    if (strcmp(action, "always") != 0) {
+        if (registry != NULL && PyDict_SetItem(registry, key, Py_True) < 0)
+            goto cleanup;
+        else if (strcmp(action, "ignore") == 0)
+            goto return_none;
+        else if (strcmp(action, "once") == 0) {
+            if (registry == NULL) {
+                registry = get_once_registry();
+                if (registry == NULL)
+                    goto cleanup;
+            }
+            /* _once_registry[(text, category)] = 1 */
+            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); 
+        }
+        else if (strcmp(action, "default") != 0) {
+            PyObject *to_str = PyObject_Str(item);
+            const char *err_str = "???";
+
+            if (to_str != NULL)
+                err_str = PyString_AS_STRING(to_str);
+            PyErr_Format(PyExc_RuntimeError,
+                        "Unrecognized action (%s) in warnings.filters:\n %s",
+                        action, err_str);
+            Py_XDECREF(to_str);
+            goto cleanup;
+        }
+    }
+
+    if (rc == 1)  // Already warned for this module. */
+        goto return_none;
+    if (rc == 0) {
+        PyObject *show_fxn = get_warnings_attr("showwarning");
+        if (show_fxn == NULL) {
+            if (PyErr_Occurred())
+                goto cleanup;
+            show_warning(filename, lineno, text, category, sourceline);
+        }
+        else {
+            PyObject *result;
+            
+            result = PyObject_CallFunctionObjArgs(show_fxn, message, category,
+                                                    filename, lineno_obj,
+                                                    Py_None,
+                                                    sourceline ?
+                                                        sourceline: Py_None,
+                                                    NULL);
+            Py_XDECREF(result);
+            if (result == NULL)
+                goto cleanup;
+        }
+    }
+    else /* if (rc == -1) */
+        goto cleanup;
+
+ return_none:
+    result = Py_None;
+    Py_INCREF(result);
+
+ cleanup:
+    Py_XDECREF(key);
+    Py_XDECREF(text);
+    Py_XDECREF(lineno_obj);
+    Py_DECREF(module);
+    Py_DECREF(message);
+    return result;  /* Py_None or NULL. */
+}
+
+/* filename, module, and registry are new refs, globals is borrowed */
+/* Returns 0 on error (no new refs), 1 on success */
+static int
+setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
+              PyObject **module, PyObject **registry)
+{
+    PyObject *globals;
+
+    /* Setup globals and lineno. */
+    PyFrameObject *f = PyThreadState_GET()->frame;
+    while (--stack_level > 0 && f != NULL) {
+        f = f->f_back;
+        --stack_level;
+    }
+
+    if (f == NULL) {
+        globals = PyThreadState_Get()->interp->sysdict;
+        *lineno = 1;
+    }
+    else {
+        globals = f->f_globals;
+        *lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+    }
+
+    *module = NULL;
+
+    /* Setup registry. */
+    assert(globals != NULL);
+    assert(PyDict_Check(globals));
+    *registry = PyDict_GetItemString(globals, "__warningregistry__");
+    if (*registry == NULL) {
+        int rc;
+
+        *registry = PyDict_New();
+        if (*registry == NULL)
+            return 0;
+
+         rc = PyDict_SetItemString(globals, "__warningregistry__", *registry);
+         if (rc < 0)
+            goto handle_error;
+    }
+    else
+        Py_INCREF(*registry);
+
+    /* Setup module. */
+    *module = PyDict_GetItemString(globals, "__name__");
+    if (*module == NULL) {
+        *module = PyString_FromString("<string>");
+        if (*module == NULL)
+            goto handle_error;
+    }
+    else
+        Py_INCREF(*module);
+
+    /* Setup filename. */
+    *filename = PyDict_GetItemString(globals, "__file__");
+    if (*filename != NULL) {
+	Py_ssize_t len = PyString_Size(*filename);
+        const char *file_str = PyString_AsString(*filename);
+	if (file_str == NULL || (len < 0 && PyErr_Occurred()))
+            goto handle_error;
+
+        /* if filename.lower().endswith((".pyc", ".pyo")): */
+        if (len >= 4 &&
+            file_str[len-4] == '.' &&
+            tolower(file_str[len-3]) == 'p' &&
+            tolower(file_str[len-2]) == 'y' &&
+            (tolower(file_str[len-1]) == 'c' ||
+             tolower(file_str[len-1]) == 'o')) {
+            *filename = PyString_FromStringAndSize(file_str, len-1);
+	    if (*filename == NULL)
+		    goto handle_error;
+	}
+	else
+            Py_INCREF(*filename);
+    }
+    else {
+        const char *module_str = PyString_AsString(*module);
+        if (module_str && strcmp(module_str, "__main__") == 0) {
+            PyObject *argv = PySys_GetObject("argv");
+            if (argv != NULL && PyList_Size(argv) > 0) {
+                *filename = PyList_GetItem(argv, 0);
+                Py_INCREF(*filename);
+            }
+            else {
+                /* embedded interpreters don't have sys.argv, see bug #839151 */
+                *filename = PyString_FromString("__main__");
+	        if (*filename == NULL)
+	            goto handle_error;
+            }
+        }
+        if (*filename == NULL) {
+            *filename = *module;
+            Py_INCREF(*filename);
+        }
+    }
+
+    return 1;
+
+ handle_error:
+    /* filename not XDECREF'ed here as there is no way to jump here with a
+       dangling reference. */
+    Py_XDECREF(*registry);
+    Py_XDECREF(*module);
+    return 0;
+}
+
+static PyObject *
+get_category(PyObject *message, PyObject *category)
+{
+    int rc;
+
+    /* Get category. */
+    rc = PyObject_IsInstance(message, PyExc_Warning);
+    if (rc == -1)
+        return NULL;
+
+    if (rc == 1)
+        category = (PyObject*)message->ob_type;
+    else if (category == NULL)
+        category = PyExc_UserWarning;
+
+    /* Validate category. */
+    rc = PyObject_IsSubclass(category, PyExc_Warning);
+    if (rc == -1)
+        return NULL;
+    if (rc == 0) {
+        PyErr_SetString(PyExc_ValueError,
+                        "category is not a subclass of Warning");
+        return NULL;
+    }
+
+    return category;
+}
+
+static PyObject *
+do_warn(PyObject *message, PyObject *category, Py_ssize_t stack_level)
+{
+    PyObject *filename, *module, *registry, *res;
+    int lineno;
+
+    if (!setup_context(stack_level, &filename, &lineno, &module, &registry))
+        return NULL;
+
+    res = warn_explicit(category, message, filename, lineno, module, registry,
+                        NULL);
+    Py_DECREF(filename);
+    Py_DECREF(registry);
+    Py_DECREF(module);
+    return res;
+}
+
+static PyObject *
+warnings_warn(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    static char *kw_list[] = { "message", "category", "stacklevel", 0 };
+    PyObject *message, *category = NULL;
+    Py_ssize_t stack_level = 1;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|On:warn", kw_list, 
+                                     &message, &category, &stack_level))
+        return NULL;
+
+    category = get_category(message, category);
+    if (category == NULL)
+        return NULL;
+    return do_warn(message, category, stack_level);
+}
+
+static PyObject *
+warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    static char *kwd_list[] = {"message", "category", "filename", "lineno",
+                                "module", "registry", "module_globals", 0};
+    PyObject *message;
+    PyObject *category;
+    PyObject *filename;
+    int lineno;
+    PyObject *module = NULL;
+    PyObject *registry = NULL;
+    PyObject *module_globals = NULL;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOi|OOO:warn_explicit",
+                kwd_list, &message, &category, &filename, &lineno, &module,
+                &registry, &module_globals))
+        return NULL;
+
+    if (module_globals) {
+        static PyObject *get_source_name = NULL;
+        static PyObject *splitlines_name = NULL;
+        PyObject *loader;
+        PyObject *module_name;
+        PyObject *source;
+        PyObject *source_list;
+        PyObject *source_line;
+        PyObject *returned;
+
+        if (get_source_name == NULL) {
+            get_source_name = PyString_FromString("get_source");
+            if (!get_source_name)
+                return NULL;
+        }
+        if (splitlines_name == NULL) {
+            splitlines_name = PyString_FromString("splitlines");
+            if (!splitlines_name)
+                return NULL;
+        }
+
+        /* Check/get the requisite pieces needed for the loader. */
+        loader = PyDict_GetItemString(module_globals, "__loader__");
+        module_name = PyDict_GetItemString(module_globals, "__name__");
+
+        if (loader == NULL || module_name == NULL)
+            goto standard_call;
+
+        /* Make sure the loader implements the optional get_source() method. */
+        if (!PyObject_HasAttrString(loader, "get_source"))
+                goto standard_call;
+        /* Call get_source() to get the source code. */
+        source = PyObject_CallMethodObjArgs(loader, get_source_name,
+                                                module_name, NULL);
+        if (!source)
+            return NULL;
+        else if (source == Py_None) {
+            Py_DECREF(Py_None);
+            goto standard_call;
+        }
+
+        /* Split the source into lines. */
+        source_list = PyObject_CallMethodObjArgs(source, splitlines_name,
+                                                    NULL);
+        Py_DECREF(source);
+        if (!source_list)
+            return NULL;
+
+        /* Get the source line. */
+        source_line = PyList_GetItem(source_list, lineno-1);
+        if (!source_line) {
+            Py_DECREF(source_list);
+            return NULL;
+        }
+
+        /* Handle the warning. */
+        returned = warn_explicit(category, message, filename, lineno, module,
+                            registry, source_line);
+        Py_DECREF(source_list);
+        return returned;
+    }
+
+ standard_call:
+    return warn_explicit(category, message, filename, lineno, module,
+                                registry, NULL);
+}
+
+
+/* Function to issue a warning message; may raise an exception. */
+int
+PyErr_WarnEx(PyObject *category, const char *text, Py_ssize_t stack_level)
+{
+    PyObject *res;
+    PyObject *message = PyString_FromString(text);
+    if (message == NULL)
+        return -1;
+
+    if (category == NULL)
+        category = PyExc_RuntimeWarning;
+
+    res = do_warn(message, category, stack_level);
+    Py_DECREF(message);
+    if (res == NULL)
+        return -1;
+    Py_DECREF(res);
+
+    return 0;
+}
+
+/* PyErr_Warn is only for backwards compatability and will be removed.
+   Use PyErr_WarnEx instead. */
+
+#undef PyErr_Warn
+
+PyAPI_FUNC(int)
+PyErr_Warn(PyObject *category, char *text)
+{
+    return PyErr_WarnEx(category, text, 1);
+}
+
+/* Warning with explicit origin */
+int
+PyErr_WarnExplicit(PyObject *category, const char *text,
+                   const char *filename_str, int lineno,
+                   const char *module_str, PyObject *registry)
+{
+    PyObject *res;
+    PyObject *message = PyString_FromString(text);
+    PyObject *filename = PyString_FromString(filename_str);
+    PyObject *module = NULL;
+    int ret = -1;
+
+    if (message == NULL || filename == NULL)
+        goto exit;
+    if (module_str != NULL) {
+        module = PyString_FromString(module_str);
+            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;
+
+ exit:
+    Py_XDECREF(message);
+    Py_XDECREF(module);
+    Py_XDECREF(filename);
+    return ret;
+}
+
+
+PyDoc_STRVAR(warn_doc,
+"Issue a warning, or maybe ignore it or raise an exception.");
+
+PyDoc_STRVAR(warn_explicit_doc,
+"Low-level inferface to warnings functionality.");
+
+static PyMethodDef warnings_functions[] = {
+    {"warn", (PyCFunction)warnings_warn, METH_VARARGS | METH_KEYWORDS,
+        warn_doc},
+    {"warn_explicit", (PyCFunction)warnings_warn_explicit,
+        METH_VARARGS | METH_KEYWORDS, warn_explicit_doc},
+    // XXX(brett.cannon): add showwarning?
+    // XXX(brett.cannon): Reasonable to add formatwarning?
+    {NULL, NULL}	        /* sentinel */
+};
+
+
+static PyObject *
+create_filter(PyObject *category, const char *action)
+{
+    static PyObject *ignore_str = NULL;
+    static PyObject *error_str = NULL;
+    static PyObject *default_str = NULL;
+    PyObject *action_obj = NULL;
+    PyObject *lineno, *result;
+
+    if (!strcmp(action, "ignore")) {
+        if (ignore_str == NULL) {
+            ignore_str = PyString_InternFromString("ignore");
+            if (ignore_str == NULL)
+                return NULL;
+        }
+        action_obj = ignore_str;
+    }
+    else if (!strcmp(action, "error")) {
+        if (error_str == NULL) {
+            error_str = PyString_InternFromString("error");
+            if (error_str == NULL)
+                return NULL;
+        }
+        action_obj = error_str;
+    }
+    else if (!strcmp(action, "default")) {
+        if (default_str == NULL) {
+            default_str = PyString_InternFromString("default");
+            if (default_str == NULL)
+                return NULL;
+        }
+        action_obj = default_str;
+    }
+    else {
+        Py_FatalError("unknown action");
+    }
+
+    /* This assumes the line number is zero for now. */
+    lineno = PyInt_FromLong(0);
+    if (lineno == NULL)
+        return NULL;
+    result = PyTuple_Pack(5, action_obj, Py_None, category, Py_None, lineno);
+    Py_DECREF(lineno);
+    return result;
+}
+
+static PyObject *
+init_filters(void)
+{
+    PyObject *filters = PyList_New(3);
+    const char *bytes_action;
+    if (filters == NULL)
+        return NULL;
+
+    PyList_SET_ITEM(filters, 0,
+                    create_filter(PyExc_PendingDeprecationWarning, "ignore"));
+    PyList_SET_ITEM(filters, 1, create_filter(PyExc_ImportWarning, "ignore"));
+    if (Py_BytesWarningFlag > 1)
+        bytes_action = "error";
+    else if (Py_BytesWarningFlag)
+        bytes_action = "default";
+    else
+        bytes_action = "ignore";
+    PyList_SET_ITEM(filters, 2, create_filter(PyExc_BytesWarning,
+                    bytes_action));
+
+    if (PyList_GET_ITEM(filters, 0) == NULL ||
+        PyList_GET_ITEM(filters, 1) == NULL ||
+        PyList_GET_ITEM(filters, 2) == NULL) {
+        Py_DECREF(filters);
+        return NULL;
+    }
+
+    return filters;
+}
+
+
+PyMODINIT_FUNC
+_PyWarnings_Init(void)
+{
+    PyObject *m, *default_action;
+
+    m = Py_InitModule3(MODULE_NAME, warnings_functions, warnings__doc__);
+    if (m == NULL)
+        return;
+
+    _filters = init_filters();
+    if (_filters == NULL)
+        return;
+    Py_INCREF(_filters);
+    if (PyModule_AddObject(m, "filters", _filters) < 0)
+        return;
+
+    _once_registry = PyDict_New();
+    if (_once_registry == NULL)
+        return;
+    Py_INCREF(_once_registry);
+    if (PyModule_AddObject(m, "once_registry", _once_registry) < 0)
+        return;
+
+    default_action = PyString_InternFromString("default");
+    if (default_action == NULL)
+        return;
+    if (PyModule_AddObject(m, DEFAULT_ACTION_NAME, default_action) < 0)
+        return;
+}

Modified: python/trunk/Python/errors.c
==============================================================================
--- python/trunk/Python/errors.c	(original)
+++ python/trunk/Python/errors.c	Sun Apr 13 01:44:07 2008
@@ -641,81 +641,6 @@
 
 extern PyObject *PyModule_GetWarningsModule(void);
 
-/* Function to issue a warning message; may raise an exception. */
-int
-PyErr_WarnEx(PyObject *category, const char *message, Py_ssize_t stack_level)
-{
-	PyObject *dict, *func = NULL;
-	PyObject *warnings_module = PyModule_GetWarningsModule();
-
-	if (warnings_module != NULL) {
-		dict = PyModule_GetDict(warnings_module);
-		if (dict != NULL)
-			func = PyDict_GetItemString(dict, "warn");
-	}
-	if (func == NULL) {
-		PySys_WriteStderr("warning: %s\n", message);
-		return 0;
-	}
-	else {
-		PyObject *res;
-
-		if (category == NULL)
-			category = PyExc_RuntimeWarning;
-		res = PyObject_CallFunction(func, "sOn",
-					    message, category, stack_level);
-		if (res == NULL)
-			return -1;
-		Py_DECREF(res);
-		return 0;
-	}
-}
-
-/* PyErr_Warn is only for backwards compatability and will be removed.
-   Use PyErr_WarnEx instead. */
-
-#undef PyErr_Warn
-
-PyAPI_FUNC(int)
-PyErr_Warn(PyObject *category, char *message)
-{
-	return PyErr_WarnEx(category, message, 1);
-}
-
-/* Warning with explicit origin */
-int
-PyErr_WarnExplicit(PyObject *category, const char *message,
-		   const char *filename, int lineno,
-		   const char *module, PyObject *registry)
-{
-	PyObject *mod, *dict, *func = NULL;
-
-	mod = PyImport_ImportModuleNoBlock("warnings");
-	if (mod != NULL) {
-		dict = PyModule_GetDict(mod);
-		func = PyDict_GetItemString(dict, "warn_explicit");
-		Py_DECREF(mod);
-	}
-	if (func == NULL) {
-		PySys_WriteStderr("warning: %s\n", message);
-		return 0;
-	}
-	else {
-		PyObject *res;
-
-		if (category == NULL)
-			category = PyExc_RuntimeWarning;
-		if (registry == NULL)
-			registry = Py_None;
-		res = PyObject_CallFunction(func, "sOsizO", message, category,
-					    filename, lineno, module, registry);
-		if (res == NULL)
-			return -1;
-		Py_DECREF(res);
-		return 0;
-	}
-}
-
 
 /* Set file and line information for the current exception.
    If the exception is not a SyntaxError, also sets additional attributes

Modified: python/trunk/Python/pythonrun.c
==============================================================================
--- python/trunk/Python/pythonrun.c	(original)
+++ python/trunk/Python/pythonrun.c	Sun Apr 13 01:44:07 2008
@@ -83,38 +83,12 @@
   true divisions (which they will be in 2.3). */
 int _Py_QnewFlag = 0;
 
-/* Reference to 'warnings' module, to avoid importing it
-   on the fly when the import lock may be held.  See 683658/771097
-*/
-static PyObject *warnings_module = NULL;
-
-/* Returns a borrowed reference to the 'warnings' module, or NULL.
-   If the module is returned, it is guaranteed to have been obtained
-   without acquiring the import lock
-*/
-PyObject *PyModule_GetWarningsModule(void)
+/* PyModule_GetWarningsModule is no longer necessary as of 2.6
+since _warnings is builtin.  This API should not be used. */
+PyObject *
+PyModule_GetWarningsModule(void)
 {
-	PyObject *typ, *val, *tb;
-	PyObject *all_modules;
-	/* If we managed to get the module at init time, just use it */
-	if (warnings_module)
-		return warnings_module;
-	/* If it wasn't available at init time, it may be available
-	   now in sys.modules (common scenario is frozen apps: import
-	   at init time fails, but the frozen init code sets up sys.path
-	   correctly, then does an implicit import of warnings for us
-	*/
-	/* Save and restore any exceptions */
-	PyErr_Fetch(&typ, &val, &tb);
-
-	all_modules = PySys_GetObject("modules");
-	if (all_modules) {
-		warnings_module = PyDict_GetItemString(all_modules, "warnings");
-		/* We keep a ref in the global */
-		Py_XINCREF(warnings_module);
-	}
-	PyErr_Restore(typ, val, tb);
-	return warnings_module;
+	return PyImport_ImportModule("warnings");
 }
 
 static int initialized = 0;
@@ -244,6 +218,15 @@
 
 	if (install_sigs)
 		initsigs(); /* Signal handling stuff, including initintr() */
+		
+    /* Initialize warnings. */
+    _PyWarnings_Init();
+    if (PySys_HasWarnOptions()) {
+        PyObject *warnings_module = PyImport_ImportModule("warnings");
+        if (!warnings_module)
+            PyErr_Clear();
+        Py_XDECREF(warnings_module);
+    }
 
 	initmain(); /* Module __main__ */
 	if (!Py_NoSiteFlag)
@@ -254,30 +237,6 @@
 	_PyGILState_Init(interp, tstate);
 #endif /* WITH_THREAD */
 
-	warnings_module = PyImport_ImportModule("warnings");
-	if (!warnings_module) {
-		PyErr_Clear();
-	}
-	else {
-		PyObject *o;
-		char *action[8];
-
-		if (Py_BytesWarningFlag > 1)
-			*action = "error";
-		else if (Py_BytesWarningFlag)
-			*action = "default";
-		else
-			*action = "ignore";
-
-		o = PyObject_CallMethod(warnings_module,
-					"simplefilter", "sO",
-					*action, PyExc_BytesWarning);
-		if (o == NULL)
-			Py_FatalError("Py_Initialize: can't initialize"
-				      "warning filter for BytesWarning.");
-		Py_DECREF(o);
-        }
-
 #if defined(Py_USING_UNICODE) && defined(HAVE_LANGINFO_H) && defined(CODESET)
 	/* On Unix, set the file system encoding according to the
 	   user's preference, if the CODESET names a well-known
@@ -397,10 +356,6 @@
 	/* Disable signal handling */
 	PyOS_FiniInterrupts();
 
-	/* drop module references we saved */
-	Py_XDECREF(warnings_module);
-	warnings_module = NULL;
-
 	/* Clear type lookup cache */
 	PyType_ClearCache();
 

Modified: python/trunk/Python/sysmodule.c
==============================================================================
--- python/trunk/Python/sysmodule.c	(original)
+++ python/trunk/Python/sysmodule.c	Sun Apr 13 01:44:07 2008
@@ -940,6 +940,12 @@
 	}
 }
 
+int
+PySys_HasWarnOptions(void)
+{
+    return warnoptions ? 1 : 0;
+}
+
 /* XXX This doc string is too long to be a single string literal in VC++ 5.0.
    Two literals concatenated works just fine.  If you have a K&R compiler
    or other abomination that however *does* understand longer strings,
@@ -1165,6 +1171,7 @@
 	/* {"unbuffered",		"-u"}, */
 	{"unicode",		"-U"},
 	/* {"skip_first",		"-x"}, */
+	{"bytes_warning", "-b"},
 	{0}
 };
 
@@ -1211,6 +1218,7 @@
 	/* SetFlag(saw_unbuffered_flag); */
 	SetFlag(Py_UnicodeFlag);
 	/* SetFlag(skipfirstline); */
+    SetFlag(Py_BytesWarningFlag);
 #undef SetFlag
 
 	if (PyErr_Occurred()) {

Modified: python/trunk/Python/traceback.c
==============================================================================
--- python/trunk/Python/traceback.c	(original)
+++ python/trunk/Python/traceback.c	Sun Apr 13 01:44:07 2008
@@ -122,16 +122,16 @@
 	return 0;
 }
 
-static int
-tb_displayline(PyObject *f, char *filename, int lineno, char *name)
+int
+Py_DisplaySourceLine(PyObject *f, const char *filename, int lineno)
 {
 	int err = 0;
-	FILE *xfp;
+	FILE *xfp = NULL;
 	char linebuf[2000];
 	int i;
 	char namebuf[MAXPATHLEN+1];
 
-	if (filename == NULL || name == NULL)
+	if (filename == NULL)
 		return -1;
 	/* This is needed by Emacs' compile command */
 #define FMT "  File \"%.500s\", line %d, in %.500s\n"
@@ -139,7 +139,7 @@
 	if (xfp == NULL) {
 		/* Search tail of filename in sys.path before giving up */
 		PyObject *path;
-		char *tail = strrchr(filename, SEP);
+		const char *tail = strrchr(filename, SEP);
 		if (tail == NULL)
 			tail = filename;
 		else
@@ -175,14 +175,14 @@
 			}
 		}
 	}
-	PyOS_snprintf(linebuf, sizeof(linebuf), FMT, filename, lineno, name);
-	err = PyFile_WriteString(linebuf, f);
-	if (xfp == NULL)
-		return err;
-	else if (err != 0) {
-		fclose(xfp);
-		return err;
-	}
+
+        if (xfp == NULL)
+            return err;
+        if (err != 0) {
+            fclose(xfp);
+            return err;
+        }
+
 	for (i = 0; i < lineno; i++) {
 		char* pLastChar = &linebuf[sizeof(linebuf)-2];
 		do {
@@ -200,22 +200,38 @@
 		char *p = linebuf;
 		while (*p == ' ' || *p == '\t' || *p == '\014')
 			p++;
-		err = PyFile_WriteString("    ", f);
-		if (err == 0) {
-			err = PyFile_WriteString(p, f);
-			if (err == 0 && strchr(p, '\n') == NULL)
-				err = PyFile_WriteString("\n", f);
-		}
+                    err = PyFile_WriteString(p, f);
+                    if (err == 0 && strchr(p, '\n') == NULL)
+                            err = PyFile_WriteString("\n", f);
 	}
 	fclose(xfp);
 	return err;
 }
 
 static int
-tb_printinternal(PyTracebackObject *tb, PyObject *f, int limit)
+tb_displayline(PyObject *f, const char *filename, int lineno, const char *name)
+{
+	int err = 0;
+        char linebuf[2000];
+
+	if (filename == NULL || name == NULL)
+		return -1;
+	/* This is needed by Emacs' compile command */
+#define FMT "  File \"%.500s\", line %d, in %.500s\n"
+	PyOS_snprintf(linebuf, sizeof(linebuf), FMT, filename, lineno, name);
+	err = PyFile_WriteString(linebuf, f);
+	if (err != 0)
+		return err;
+
+        err = PyFile_WriteString("    ", f);
+        return Py_DisplaySourceLine(f, filename, lineno);
+}
+
+static int
+tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
 {
 	int err = 0;
-	int depth = 0;
+	long depth = 0;
 	PyTracebackObject *tb1 = tb;
 	while (tb1 != NULL) {
 		depth++;
@@ -242,7 +258,7 @@
 {
 	int err;
 	PyObject *limitv;
-	int limit = 1000;
+	long limit = 1000;
 	if (v == NULL)
 		return 0;
 	if (!PyTraceBack_Check(v)) {


More information about the Python-checkins mailing list