Armin Rigo avatar Armin Rigo committed ed5309c

Use sys.stderr.encoding when printing exceptions in PyPy. Done by
adding an '_encoding' argument to some functions in the traceback.py
module, but not changing the default behavior of traceback.py itself.
This avoids as much as possible breaking anything that explicitly uses
traceback.py.

Comments (0)

Files changed (3)

lib-python/2.7/traceback.py

     return list
 
 
-def print_exception(etype, value, tb, limit=None, file=None):
+def print_exception(etype, value, tb, limit=None, file=None, _encoding=None):
     """Print exception up to 'limit' stack trace entries from 'tb' to 'file'.
 
     This differs from print_tb() in the following ways: (1) if
     if tb:
         _print(file, 'Traceback (most recent call last):')
         print_tb(tb, limit, file)
-    lines = format_exception_only(etype, value)
+    lines = format_exception_only(etype, value, _encoding)
     for line in lines:
         _print(file, line, '')
 
     list = list + format_exception_only(etype, value)
     return list
 
-def format_exception_only(etype, value):
+def format_exception_only(etype, value, _encoding=None):
     """Format the exception part of a traceback.
 
     The arguments are the exception type and value such as given by
     if (isinstance(etype, BaseException) or
         isinstance(etype, types.InstanceType) or
         etype is None or type(etype) is str):
-        return [_format_final_exc_line(etype, value)]
+        return [_format_final_exc_line(etype, value, _encoding)]
 
     stype = etype.__name__
 
     if not issubclass(etype, SyntaxError):
-        return [_format_final_exc_line(stype, value)]
+        return [_format_final_exc_line(stype, value, _encoding)]
 
     # It was a syntax error; show exactly where the problem was found.
     lines = []
                 lines.append('   %s^\n' % ''.join(caretspace))
         value = msg
 
-    lines.append(_format_final_exc_line(stype, value))
+    lines.append(_format_final_exc_line(stype, value, _encoding))
     return lines
 
-def _format_final_exc_line(etype, value):
+def _format_final_exc_line(etype, value, _encoding=None):
     """Return a list of a single line -- normal case for format_exception_only"""
-    valuestr = _some_str(value)
+    valuestr = _some_str(value, _encoding)
     if value is None or not valuestr:
         line = "%s\n" % etype
     else:
         line = "%s: %s\n" % (etype, valuestr)
     return line
 
-def _some_str(value):
+def _some_str(value, _encoding=None):
     try:
         return str(value)
     except Exception:
         pass
     try:
         value = unicode(value)
-        return value.encode("ascii", "backslashreplace")
+        return value.encode(_encoding or "ascii", "backslashreplace")
     except Exception:
         pass
     return '<unprintable %s object>' % type(value).__name__

pypy/module/sys/app.py

         pass
 
     try:
+        encoding = sys.stderr.encoding
+    except:
+        encoding = None
+
+    try:
         from traceback import print_exception
-        print_exception(exctype, value, traceback)
+        print_exception(exctype, value, traceback, _encoding=encoding)
     except:
         if not excepthook_failsafe(exctype, value):
             raise

pypy/module/sys/test/test_sysmodule.py

 
         assert err.getvalue() == "ValueError: 42\n"
 
+    def test_original_excepthook_pypy_encoding(self):
+        import sys
+        if '__pypy__' not in sys.builtin_module_names:
+            skip("only on PyPy")
+        savestderr = sys.stderr
+        class MyStringIO(object):
+            def __init__(self):
+                self.output = []
+            def write(self, s):
+                assert isinstance(s, str)
+                self.output.append(s)
+            def getvalue(self):
+                return ''.join(self.output)
+
+        for input, expectedoutput in [(u"\u013a", "\xe5"),
+                                      (u"\u1111", "\\u1111")]:
+            err = MyStringIO()
+            err.encoding = 'iso-8859-2'
+            sys.stderr = err
+
+            eh = sys.__excepthook__
+            try:
+                raise ValueError(input)
+            except ValueError, exc:
+                eh(*sys.exc_info())
+
+            sys.stderr = savestderr
+            print repr(err.getvalue())
+            assert err.getvalue().endswith("ValueError: %s\n" % expectedoutput)
+
     # FIXME: testing the code for a lost or replaced excepthook in
     # Python/pythonrun.c::PyErr_PrintEx() is tricky.
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.