Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb0d9a03

Browse files
committed
gh-112730: Use color to highlight error locations
1 parentc27b09c commitb0d9a03

File tree

2 files changed

+186
-27
lines changed

2 files changed

+186
-27
lines changed

‎Lib/test/test_traceback.py

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
importinspect
99
importbuiltins
1010
importunittest
11+
importunittest.mock
1112
importre
1213
importtempfile
1314
importrandom
@@ -41,6 +42,14 @@
4142
classTracebackCases(unittest.TestCase):
4243
# For now, a very minimal set of tests. I want to be sure that
4344
# formatting of SyntaxErrors works based on changes for 2.1.
45+
defsetUp(self):
46+
super().setUp()
47+
self.colorize=traceback._COLORIZE
48+
traceback._COLORIZE=False
49+
50+
deftearDown(self):
51+
super().tearDown()
52+
traceback._COLORIZE=self.colorize
4453

4554
defget_exception_format(self,func,exc):
4655
try:
@@ -521,7 +530,7 @@ def test_signatures(self):
521530
self.assertEqual(
522531
str(inspect.signature(traceback.print_exception)),
523532
('(exc, /, value=<implicit>, tb=<implicit>, '
524-
'limit=None, file=None, chain=True)'))
533+
'limit=None, file=None, chain=True, **kwargs)'))
525534

526535
self.assertEqual(
527536
str(inspect.signature(traceback.format_exception)),
@@ -3031,7 +3040,7 @@ def some_inner(k, v):
30313040

30323041
deftest_custom_format_frame(self):
30333042
classCustomStackSummary(traceback.StackSummary):
3034-
defformat_frame_summary(self,frame_summary):
3043+
defformat_frame_summary(self,frame_summary,colorize=False):
30353044
returnf'{frame_summary.filename}:{frame_summary.lineno}'
30363045

30373046
defsome_inner():
@@ -3056,7 +3065,7 @@ def g():
30563065
tb=g()
30573066

30583067
classSkip_G(traceback.StackSummary):
3059-
defformat_frame_summary(self,frame_summary):
3068+
defformat_frame_summary(self,frame_summary,colorize=False):
30603069
ifframe_summary.name=='g':
30613070
returnNone
30623071
returnsuper().format_frame_summary(frame_summary)
@@ -3076,7 +3085,6 @@ def __repr__(self) -> str:
30763085
raiseException("Unrepresentable")
30773086

30783087
classTestTracebackException(unittest.TestCase):
3079-
30803088
defdo_test_smoke(self,exc,expected_type_str):
30813089
try:
30823090
raiseexc
@@ -4245,6 +4253,85 @@ def test_levenshtein_distance_short_circuit(self):
42454253
res3=traceback._levenshtein_distance(a,b,threshold)
42464254
self.assertGreater(res3,threshold,msg=(a,b,threshold))
42474255

4256+
classTestColorizedTraceback(unittest.TestCase):
4257+
deftest_colorized_traceback(self):
4258+
deffoo(*args):
4259+
x= {'a':{'b':None}}
4260+
y=x['a']['b']['c']
4261+
4262+
defbaz(*args):
4263+
returnfoo(1,2,3,4)
4264+
4265+
defbar():
4266+
returnbaz(1,
4267+
2,3
4268+
,4)
4269+
try:
4270+
bar()
4271+
exceptExceptionase:
4272+
exc=traceback.TracebackException.from_exception(
4273+
e,capture_locals=True
4274+
)
4275+
lines="".join(exc.format(colorize=True))
4276+
red=traceback._ANSIColors.RED
4277+
boldr=traceback._ANSIColors.BOLD_RED
4278+
reset=traceback._ANSIColors.RESET
4279+
self.assertIn("y = "+red+"x['a']['b']"+reset+boldr+"['c']"+reset,lines)
4280+
self.assertIn("return "+red+"foo"+reset+boldr+"(1,2,3,4)"+reset,lines)
4281+
self.assertIn("return "+red+"baz"+reset+boldr+"(1,"+reset,lines)
4282+
self.assertIn(boldr+"2,3"+reset,lines)
4283+
self.assertIn(boldr+",4)"+reset,lines)
4284+
self.assertIn(red+"bar"+reset+boldr+"()"+reset,lines)
4285+
4286+
deftest_colorized_traceback_is_the_default(self):
4287+
deffoo():
4288+
1/0
4289+
4290+
from_testcapiimportexception_print
4291+
try:
4292+
foo()
4293+
self.fail("No exception thrown.")
4294+
exceptExceptionase:
4295+
withcaptured_output("stderr")astbstderr:
4296+
withunittest.mock.patch('traceback._can_colorize',return_value=True):
4297+
exception_print(e)
4298+
actual=tbstderr.getvalue().splitlines()
4299+
4300+
red=traceback._ANSIColors.RED
4301+
boldr=traceback._ANSIColors.BOLD_RED
4302+
reset=traceback._ANSIColors.RESET
4303+
lno_foo=foo.__code__.co_firstlineno
4304+
expected= ['Traceback (most recent call last):',
4305+
f' File "{__file__}", '
4306+
f'line{lno_foo+5}, in test_colorized_traceback_is_the_default',
4307+
f'{red}foo{reset+boldr}(){reset}',
4308+
f'{red}~~~{reset+boldr}^^{reset}',
4309+
f' File "{__file__}", '
4310+
f'line{lno_foo+1}, in foo',
4311+
f'{red}1{reset+boldr}/{reset+red}0{reset}',
4312+
f'{red}~{reset+boldr}^{reset+red}~{reset}',
4313+
'ZeroDivisionError: division by zero']
4314+
self.assertEqual(actual,expected)
4315+
4316+
deftest_colorized_detection_checks_for_environment_variables(self):
4317+
withunittest.mock.patch("sys.stderr")asstderr_mock:
4318+
stderr_mock.isatty.return_value=True
4319+
withunittest.mock.patch("os.environ", {'TERM':'dumb'}):
4320+
self.assertEqual(traceback._can_colorize(),False)
4321+
withunittest.mock.patch("os.environ", {'PY_COLORS':'1'}):
4322+
self.assertEqual(traceback._can_colorize(),True)
4323+
withunittest.mock.patch("os.environ", {'PY_COLORS':'0'}):
4324+
self.assertEqual(traceback._can_colorize(),False)
4325+
withunittest.mock.patch("os.environ", {'NO_COLOR':'1'}):
4326+
self.assertEqual(traceback._can_colorize(),False)
4327+
withunittest.mock.patch("os.environ", {'NO_COLOR':'1',"PY_COLORS":'1'}):
4328+
self.assertEqual(traceback._can_colorize(),True)
4329+
withunittest.mock.patch("os.environ", {'FORCE_COLOR':'1'}):
4330+
self.assertEqual(traceback._can_colorize(),True)
4331+
withunittest.mock.patch("os.environ", {'FORCE_COLOR':'1','NO_COLOR':'1'}):
4332+
self.assertEqual(traceback._can_colorize(),False)
4333+
stderr_mock.isatty.return_value=False
4334+
self.assertEqual(traceback._can_colorize(),False)
42484335

42494336
if__name__=="__main__":
42504337
unittest.main()

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp