mirror of
https://github.com/python/cpython.git
synced 2025-07-23 11:15:24 +00:00
bpo-37467: Fix PyErr_Display() for bytes filename (GH-14504)
Fix sys.excepthook() and PyErr_Display() if a filename is a bytes
string. For example, for a SyntaxError exception where the filename
attribute is a bytes string.
Cleanup also test_sys:
* Sort imports.
* Rename numruns global var to INTERN_NUMRUNS.
* Add DisplayHookTest and ExceptHookTest test case classes.
* Don't save/restore sys.stdout and sys.displayhook using
setUp()/tearDown(): do it in each test method.
* Test error case (call hook with no argument) after the success case.
(cherry picked from commit f9b7457bd7
)
Co-authored-by: Victor Stinner <vstinner@redhat.com>
This commit is contained in:
parent
e224d2865a
commit
2683ded568
3 changed files with 83 additions and 51 deletions
|
@ -1,81 +1,104 @@
|
||||||
import unittest, test.support
|
from test import support
|
||||||
from test.support.script_helper import assert_python_ok, assert_python_failure
|
from test.support.script_helper import assert_python_ok, assert_python_failure
|
||||||
import sys, io, os
|
import builtins
|
||||||
import struct
|
|
||||||
import subprocess
|
|
||||||
import textwrap
|
|
||||||
import warnings
|
|
||||||
import operator
|
|
||||||
import codecs
|
import codecs
|
||||||
import gc
|
import gc
|
||||||
import sysconfig
|
import io
|
||||||
import locale
|
import locale
|
||||||
|
import operator
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import sysconfig
|
||||||
|
import test.support
|
||||||
|
import textwrap
|
||||||
|
import unittest
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
|
||||||
# count the number of test runs, used to create unique
|
# count the number of test runs, used to create unique
|
||||||
# strings to intern in test_intern()
|
# strings to intern in test_intern()
|
||||||
numruns = 0
|
INTERN_NUMRUNS = 0
|
||||||
|
|
||||||
|
|
||||||
class SysModuleTest(unittest.TestCase):
|
class DisplayHookTest(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.orig_stdout = sys.stdout
|
|
||||||
self.orig_stderr = sys.stderr
|
|
||||||
self.orig_displayhook = sys.displayhook
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
sys.stdout = self.orig_stdout
|
|
||||||
sys.stderr = self.orig_stderr
|
|
||||||
sys.displayhook = self.orig_displayhook
|
|
||||||
test.support.reap_children()
|
|
||||||
|
|
||||||
def test_original_displayhook(self):
|
def test_original_displayhook(self):
|
||||||
import builtins
|
|
||||||
out = io.StringIO()
|
|
||||||
sys.stdout = out
|
|
||||||
|
|
||||||
dh = sys.__displayhook__
|
dh = sys.__displayhook__
|
||||||
|
|
||||||
self.assertRaises(TypeError, dh)
|
with support.captured_stdout() as out:
|
||||||
if hasattr(builtins, "_"):
|
dh(42)
|
||||||
del builtins._
|
|
||||||
|
|
||||||
dh(None)
|
|
||||||
self.assertEqual(out.getvalue(), "")
|
|
||||||
self.assertTrue(not hasattr(builtins, "_"))
|
|
||||||
dh(42)
|
|
||||||
self.assertEqual(out.getvalue(), "42\n")
|
self.assertEqual(out.getvalue(), "42\n")
|
||||||
self.assertEqual(builtins._, 42)
|
self.assertEqual(builtins._, 42)
|
||||||
|
|
||||||
del sys.stdout
|
del builtins._
|
||||||
self.assertRaises(RuntimeError, dh, 42)
|
|
||||||
|
with support.captured_stdout() as out:
|
||||||
|
dh(None)
|
||||||
|
|
||||||
|
self.assertEqual(out.getvalue(), "")
|
||||||
|
self.assertTrue(not hasattr(builtins, "_"))
|
||||||
|
|
||||||
|
# sys.displayhook() requires arguments
|
||||||
|
self.assertRaises(TypeError, dh)
|
||||||
|
|
||||||
|
stdout = sys.stdout
|
||||||
|
try:
|
||||||
|
del sys.stdout
|
||||||
|
self.assertRaises(RuntimeError, dh, 42)
|
||||||
|
finally:
|
||||||
|
sys.stdout = stdout
|
||||||
|
|
||||||
def test_lost_displayhook(self):
|
def test_lost_displayhook(self):
|
||||||
del sys.displayhook
|
displayhook = sys.displayhook
|
||||||
code = compile("42", "<string>", "single")
|
try:
|
||||||
self.assertRaises(RuntimeError, eval, code)
|
del sys.displayhook
|
||||||
|
code = compile("42", "<string>", "single")
|
||||||
|
self.assertRaises(RuntimeError, eval, code)
|
||||||
|
finally:
|
||||||
|
sys.displayhook = displayhook
|
||||||
|
|
||||||
def test_custom_displayhook(self):
|
def test_custom_displayhook(self):
|
||||||
def baddisplayhook(obj):
|
def baddisplayhook(obj):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
sys.displayhook = baddisplayhook
|
|
||||||
code = compile("42", "<string>", "single")
|
with support.swap_attr(sys, 'displayhook', baddisplayhook):
|
||||||
self.assertRaises(ValueError, eval, code)
|
code = compile("42", "<string>", "single")
|
||||||
|
self.assertRaises(ValueError, eval, code)
|
||||||
|
|
||||||
|
|
||||||
|
class ExceptHookTest(unittest.TestCase):
|
||||||
|
|
||||||
def test_original_excepthook(self):
|
def test_original_excepthook(self):
|
||||||
err = io.StringIO()
|
|
||||||
sys.stderr = err
|
|
||||||
|
|
||||||
eh = sys.__excepthook__
|
|
||||||
|
|
||||||
self.assertRaises(TypeError, eh)
|
|
||||||
try:
|
try:
|
||||||
raise ValueError(42)
|
raise ValueError(42)
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
eh(*sys.exc_info())
|
with support.captured_stderr() as err:
|
||||||
|
sys.__excepthook__(*sys.exc_info())
|
||||||
|
|
||||||
self.assertTrue(err.getvalue().endswith("ValueError: 42\n"))
|
self.assertTrue(err.getvalue().endswith("ValueError: 42\n"))
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, sys.__excepthook__)
|
||||||
|
|
||||||
|
def test_excepthook_bytes_filename(self):
|
||||||
|
# bpo-37467: sys.excepthook() must not crash if a filename
|
||||||
|
# is a bytes string
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter('ignore', BytesWarning)
|
||||||
|
|
||||||
|
try:
|
||||||
|
raise SyntaxError("msg", (b"bytes_filename", 123, 0, "text"))
|
||||||
|
except SyntaxError as exc:
|
||||||
|
with support.captured_stderr() as err:
|
||||||
|
sys.__excepthook__(*sys.exc_info())
|
||||||
|
|
||||||
|
err = err.getvalue()
|
||||||
|
self.assertIn(""" File "b'bytes_filename'", line 123\n""", err)
|
||||||
|
self.assertIn(""" text\n""", err)
|
||||||
|
self.assertTrue(err.endswith("SyntaxError: msg\n"))
|
||||||
|
|
||||||
def test_excepthook(self):
|
def test_excepthook(self):
|
||||||
with test.support.captured_output("stderr") as stderr:
|
with test.support.captured_output("stderr") as stderr:
|
||||||
sys.excepthook(1, '1', 1)
|
sys.excepthook(1, '1', 1)
|
||||||
|
@ -85,6 +108,12 @@ class SysModuleTest(unittest.TestCase):
|
||||||
# FIXME: testing the code for a lost or replaced excepthook in
|
# FIXME: testing the code for a lost or replaced excepthook in
|
||||||
# Python/pythonrun.c::PyErr_PrintEx() is tricky.
|
# Python/pythonrun.c::PyErr_PrintEx() is tricky.
|
||||||
|
|
||||||
|
|
||||||
|
class SysModuleTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
test.support.reap_children()
|
||||||
|
|
||||||
def test_exit(self):
|
def test_exit(self):
|
||||||
# call with two arguments
|
# call with two arguments
|
||||||
self.assertRaises(TypeError, sys.exit, 42, 42)
|
self.assertRaises(TypeError, sys.exit, 42, 42)
|
||||||
|
@ -501,10 +530,10 @@ class SysModuleTest(unittest.TestCase):
|
||||||
self.assertEqual(sys.__stdout__.encoding, sys.__stderr__.encoding)
|
self.assertEqual(sys.__stdout__.encoding, sys.__stderr__.encoding)
|
||||||
|
|
||||||
def test_intern(self):
|
def test_intern(self):
|
||||||
global numruns
|
global INTERN_NUMRUNS
|
||||||
numruns += 1
|
INTERN_NUMRUNS += 1
|
||||||
self.assertRaises(TypeError, sys.intern)
|
self.assertRaises(TypeError, sys.intern)
|
||||||
s = "never interned before" + str(numruns)
|
s = "never interned before" + str(INTERN_NUMRUNS)
|
||||||
self.assertTrue(sys.intern(s) is s)
|
self.assertTrue(sys.intern(s) is s)
|
||||||
s2 = s.swapcase().swapcase()
|
s2 = s.swapcase().swapcase()
|
||||||
self.assertTrue(sys.intern(s2) is s)
|
self.assertTrue(sys.intern(s2) is s)
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Fix :func:`sys.excepthook` and :c:func:`PyErr_Display` if a filename is a
|
||||||
|
bytes string. For example, for a SyntaxError exception where the filename
|
||||||
|
attribute is a bytes string.
|
|
@ -797,7 +797,7 @@ print_exception(PyObject *f, PyObject *value)
|
||||||
Py_DECREF(value);
|
Py_DECREF(value);
|
||||||
value = message;
|
value = message;
|
||||||
|
|
||||||
line = PyUnicode_FromFormat(" File \"%U\", line %d\n",
|
line = PyUnicode_FromFormat(" File \"%S\", line %d\n",
|
||||||
filename, lineno);
|
filename, lineno);
|
||||||
Py_DECREF(filename);
|
Py_DECREF(filename);
|
||||||
if (line != NULL) {
|
if (line != NULL) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue