test_traceback.py 113 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871
  1. """Test cases for traceback module"""
  2. from collections import namedtuple
  3. from io import StringIO
  4. import linecache
  5. import sys
  6. import types
  7. import inspect
  8. import unittest
  9. import re
  10. from test import support
  11. from test.support import (Error, captured_output, cpython_only, ALWAYS_EQ,
  12. requires_debug_ranges, has_no_debug_ranges,
  13. requires_subprocess)
  14. from test.support.os_helper import TESTFN, unlink
  15. from test.support.script_helper import assert_python_ok, assert_python_failure
  16. import os
  17. import textwrap
  18. import traceback
  19. from functools import partial
  20. MODULE_PREFIX = f'{__name__}.' if __name__ == '__main__' else ''
  21. test_code = namedtuple('code', ['co_filename', 'co_name'])
  22. test_code.co_positions = lambda _: iter([(6, 6, 0, 0)])
  23. test_frame = namedtuple('frame', ['f_code', 'f_globals', 'f_locals'])
  24. test_tb = namedtuple('tb', ['tb_frame', 'tb_lineno', 'tb_next', 'tb_lasti'])
  25. class TracebackCases(unittest.TestCase):
  26. # For now, a very minimal set of tests. I want to be sure that
  27. # formatting of SyntaxErrors works based on changes for 2.1.
  28. def get_exception_format(self, func, exc):
  29. try:
  30. func()
  31. except exc as value:
  32. return traceback.format_exception_only(exc, value)
  33. else:
  34. raise ValueError("call did not raise exception")
  35. def syntax_error_with_caret(self):
  36. compile("def fact(x):\n\treturn x!\n", "?", "exec")
  37. def syntax_error_with_caret_2(self):
  38. compile("1 +\n", "?", "exec")
  39. def syntax_error_with_caret_range(self):
  40. compile("f(x, y for y in range(30), z)", "?", "exec")
  41. def syntax_error_bad_indentation(self):
  42. compile("def spam():\n print(1)\n print(2)", "?", "exec")
  43. def syntax_error_with_caret_non_ascii(self):
  44. compile('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', "?", "exec")
  45. def syntax_error_bad_indentation2(self):
  46. compile(" print(2)", "?", "exec")
  47. def tokenizer_error_with_caret_range(self):
  48. compile("blech ( ", "?", "exec")
  49. def test_caret(self):
  50. err = self.get_exception_format(self.syntax_error_with_caret,
  51. SyntaxError)
  52. self.assertEqual(len(err), 4)
  53. self.assertTrue(err[1].strip() == "return x!")
  54. self.assertIn("^", err[2]) # third line has caret
  55. self.assertEqual(err[1].find("!"), err[2].find("^")) # in the right place
  56. self.assertEqual(err[2].count("^"), 1)
  57. err = self.get_exception_format(self.syntax_error_with_caret_2,
  58. SyntaxError)
  59. self.assertIn("^", err[2]) # third line has caret
  60. self.assertEqual(err[2].count('\n'), 1) # and no additional newline
  61. self.assertEqual(err[1].find("+") + 1, err[2].find("^")) # in the right place
  62. self.assertEqual(err[2].count("^"), 1)
  63. err = self.get_exception_format(self.syntax_error_with_caret_non_ascii,
  64. SyntaxError)
  65. self.assertIn("^", err[2]) # third line has caret
  66. self.assertEqual(err[2].count('\n'), 1) # and no additional newline
  67. self.assertEqual(err[1].find("+") + 1, err[2].find("^")) # in the right place
  68. self.assertEqual(err[2].count("^"), 1)
  69. err = self.get_exception_format(self.syntax_error_with_caret_range,
  70. SyntaxError)
  71. self.assertIn("^", err[2]) # third line has caret
  72. self.assertEqual(err[2].count('\n'), 1) # and no additional newline
  73. self.assertEqual(err[1].find("y"), err[2].find("^")) # in the right place
  74. self.assertEqual(err[2].count("^"), len("y for y in range(30)"))
  75. err = self.get_exception_format(self.tokenizer_error_with_caret_range,
  76. SyntaxError)
  77. self.assertIn("^", err[2]) # third line has caret
  78. self.assertEqual(err[2].count('\n'), 1) # and no additional newline
  79. self.assertEqual(err[1].find("("), err[2].find("^")) # in the right place
  80. self.assertEqual(err[2].count("^"), 1)
  81. def test_nocaret(self):
  82. exc = SyntaxError("error", ("x.py", 23, None, "bad syntax"))
  83. err = traceback.format_exception_only(SyntaxError, exc)
  84. self.assertEqual(len(err), 3)
  85. self.assertEqual(err[1].strip(), "bad syntax")
  86. def test_no_caret_with_no_debug_ranges_flag(self):
  87. # Make sure that if `-X no_debug_ranges` is used, there are no carets
  88. # in the traceback.
  89. try:
  90. with open(TESTFN, 'w') as f:
  91. f.write("x = 1 / 0\n")
  92. _, _, stderr = assert_python_failure(
  93. '-X', 'no_debug_ranges', TESTFN)
  94. lines = stderr.splitlines()
  95. self.assertEqual(len(lines), 4)
  96. self.assertEqual(lines[0], b'Traceback (most recent call last):')
  97. self.assertIn(b'line 1, in <module>', lines[1])
  98. self.assertEqual(lines[2], b' x = 1 / 0')
  99. self.assertEqual(lines[3], b'ZeroDivisionError: division by zero')
  100. finally:
  101. unlink(TESTFN)
  102. def test_no_caret_with_no_debug_ranges_flag_python_traceback(self):
  103. code = textwrap.dedent("""
  104. import traceback
  105. try:
  106. x = 1 / 0
  107. except:
  108. traceback.print_exc()
  109. """)
  110. try:
  111. with open(TESTFN, 'w') as f:
  112. f.write(code)
  113. _, _, stderr = assert_python_ok(
  114. '-X', 'no_debug_ranges', TESTFN)
  115. lines = stderr.splitlines()
  116. self.assertEqual(len(lines), 4)
  117. self.assertEqual(lines[0], b'Traceback (most recent call last):')
  118. self.assertIn(b'line 4, in <module>', lines[1])
  119. self.assertEqual(lines[2], b' x = 1 / 0')
  120. self.assertEqual(lines[3], b'ZeroDivisionError: division by zero')
  121. finally:
  122. unlink(TESTFN)
  123. def test_recursion_error_during_traceback(self):
  124. code = textwrap.dedent("""
  125. import sys
  126. from weakref import ref
  127. sys.setrecursionlimit(15)
  128. def f():
  129. ref(lambda: 0, [])
  130. f()
  131. try:
  132. f()
  133. except RecursionError:
  134. pass
  135. """)
  136. try:
  137. with open(TESTFN, 'w') as f:
  138. f.write(code)
  139. rc, _, _ = assert_python_ok(TESTFN)
  140. self.assertEqual(rc, 0)
  141. finally:
  142. unlink(TESTFN)
  143. def test_bad_indentation(self):
  144. err = self.get_exception_format(self.syntax_error_bad_indentation,
  145. IndentationError)
  146. self.assertEqual(len(err), 4)
  147. self.assertEqual(err[1].strip(), "print(2)")
  148. self.assertIn("^", err[2])
  149. self.assertEqual(err[1].find(")") + 1, err[2].find("^"))
  150. # No caret for "unexpected indent"
  151. err = self.get_exception_format(self.syntax_error_bad_indentation2,
  152. IndentationError)
  153. self.assertEqual(len(err), 3)
  154. self.assertEqual(err[1].strip(), "print(2)")
  155. def test_base_exception(self):
  156. # Test that exceptions derived from BaseException are formatted right
  157. e = KeyboardInterrupt()
  158. lst = traceback.format_exception_only(e.__class__, e)
  159. self.assertEqual(lst, ['KeyboardInterrupt\n'])
  160. def test_format_exception_only_bad__str__(self):
  161. class X(Exception):
  162. def __str__(self):
  163. 1/0
  164. err = traceback.format_exception_only(X, X())
  165. self.assertEqual(len(err), 1)
  166. str_value = '<exception str() failed>'
  167. if X.__module__ in ('__main__', 'builtins'):
  168. str_name = X.__qualname__
  169. else:
  170. str_name = '.'.join([X.__module__, X.__qualname__])
  171. self.assertEqual(err[0], "%s: %s\n" % (str_name, str_value))
  172. @requires_subprocess()
  173. def test_encoded_file(self):
  174. # Test that tracebacks are correctly printed for encoded source files:
  175. # - correct line number (Issue2384)
  176. # - respect file encoding (Issue3975)
  177. import sys, subprocess
  178. # The spawned subprocess has its stdout redirected to a PIPE, and its
  179. # encoding may be different from the current interpreter, on Windows
  180. # at least.
  181. process = subprocess.Popen([sys.executable, "-c",
  182. "import sys; print(sys.stdout.encoding)"],
  183. stdout=subprocess.PIPE,
  184. stderr=subprocess.STDOUT)
  185. stdout, stderr = process.communicate()
  186. output_encoding = str(stdout, 'ascii').splitlines()[0]
  187. def do_test(firstlines, message, charset, lineno):
  188. # Raise the message in a subprocess, and catch the output
  189. try:
  190. with open(TESTFN, "w", encoding=charset) as output:
  191. output.write("""{0}if 1:
  192. import traceback;
  193. raise RuntimeError('{1}')
  194. """.format(firstlines, message))
  195. process = subprocess.Popen([sys.executable, TESTFN],
  196. stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  197. stdout, stderr = process.communicate()
  198. stdout = stdout.decode(output_encoding).splitlines()
  199. finally:
  200. unlink(TESTFN)
  201. # The source lines are encoded with the 'backslashreplace' handler
  202. encoded_message = message.encode(output_encoding,
  203. 'backslashreplace')
  204. # and we just decoded them with the output_encoding.
  205. message_ascii = encoded_message.decode(output_encoding)
  206. err_line = "raise RuntimeError('{0}')".format(message_ascii)
  207. err_msg = "RuntimeError: {0}".format(message_ascii)
  208. self.assertIn(("line %s" % lineno), stdout[1],
  209. "Invalid line number: {0!r} instead of {1}".format(
  210. stdout[1], lineno))
  211. self.assertTrue(stdout[2].endswith(err_line),
  212. "Invalid traceback line: {0!r} instead of {1!r}".format(
  213. stdout[2], err_line))
  214. actual_err_msg = stdout[3]
  215. self.assertTrue(actual_err_msg == err_msg,
  216. "Invalid error message: {0!r} instead of {1!r}".format(
  217. actual_err_msg, err_msg))
  218. do_test("", "foo", "ascii", 3)
  219. for charset in ("ascii", "iso-8859-1", "utf-8", "GBK"):
  220. if charset == "ascii":
  221. text = "foo"
  222. elif charset == "GBK":
  223. text = "\u4E02\u5100"
  224. else:
  225. text = "h\xe9 ho"
  226. do_test("# coding: {0}\n".format(charset),
  227. text, charset, 4)
  228. do_test("#!shebang\n# coding: {0}\n".format(charset),
  229. text, charset, 5)
  230. do_test(" \t\f\n# coding: {0}\n".format(charset),
  231. text, charset, 5)
  232. # Issue #18960: coding spec should have no effect
  233. do_test("x=0\n# coding: GBK\n", "h\xe9 ho", 'utf-8', 5)
  234. def test_print_traceback_at_exit(self):
  235. # Issue #22599: Ensure that it is possible to use the traceback module
  236. # to display an exception at Python exit
  237. code = textwrap.dedent("""
  238. import sys
  239. import traceback
  240. class PrintExceptionAtExit(object):
  241. def __init__(self):
  242. try:
  243. x = 1 / 0
  244. except Exception:
  245. self.exc_info = sys.exc_info()
  246. # self.exc_info[1] (traceback) contains frames:
  247. # explicitly clear the reference to self in the current
  248. # frame to break a reference cycle
  249. self = None
  250. def __del__(self):
  251. traceback.print_exception(*self.exc_info)
  252. # Keep a reference in the module namespace to call the destructor
  253. # when the module is unloaded
  254. obj = PrintExceptionAtExit()
  255. """)
  256. rc, stdout, stderr = assert_python_ok('-c', code)
  257. expected = [b'Traceback (most recent call last):',
  258. b' File "<string>", line 8, in __init__',
  259. b'ZeroDivisionError: division by zero']
  260. self.assertEqual(stderr.splitlines(), expected)
  261. def test_print_exception(self):
  262. output = StringIO()
  263. traceback.print_exception(
  264. Exception, Exception("projector"), None, file=output
  265. )
  266. self.assertEqual(output.getvalue(), "Exception: projector\n")
  267. def test_print_exception_exc(self):
  268. output = StringIO()
  269. traceback.print_exception(Exception("projector"), file=output)
  270. self.assertEqual(output.getvalue(), "Exception: projector\n")
  271. def test_format_exception_exc(self):
  272. e = Exception("projector")
  273. output = traceback.format_exception(e)
  274. self.assertEqual(output, ["Exception: projector\n"])
  275. with self.assertRaisesRegex(ValueError, 'Both or neither'):
  276. traceback.format_exception(e.__class__, e)
  277. with self.assertRaisesRegex(ValueError, 'Both or neither'):
  278. traceback.format_exception(e.__class__, tb=e.__traceback__)
  279. with self.assertRaisesRegex(TypeError, 'positional-only'):
  280. traceback.format_exception(exc=e)
  281. def test_format_exception_only_exc(self):
  282. output = traceback.format_exception_only(Exception("projector"))
  283. self.assertEqual(output, ["Exception: projector\n"])
  284. def test_exception_is_None(self):
  285. NONE_EXC_STRING = 'NoneType: None\n'
  286. excfile = StringIO()
  287. traceback.print_exception(None, file=excfile)
  288. self.assertEqual(excfile.getvalue(), NONE_EXC_STRING)
  289. excfile = StringIO()
  290. traceback.print_exception(None, None, None, file=excfile)
  291. self.assertEqual(excfile.getvalue(), NONE_EXC_STRING)
  292. excfile = StringIO()
  293. traceback.print_exc(None, file=excfile)
  294. self.assertEqual(excfile.getvalue(), NONE_EXC_STRING)
  295. self.assertEqual(traceback.format_exc(None), NONE_EXC_STRING)
  296. self.assertEqual(traceback.format_exception(None), [NONE_EXC_STRING])
  297. self.assertEqual(
  298. traceback.format_exception(None, None, None), [NONE_EXC_STRING])
  299. self.assertEqual(
  300. traceback.format_exception_only(None), [NONE_EXC_STRING])
  301. self.assertEqual(
  302. traceback.format_exception_only(None, None), [NONE_EXC_STRING])
  303. def test_signatures(self):
  304. self.assertEqual(
  305. str(inspect.signature(traceback.print_exception)),
  306. ('(exc, /, value=<implicit>, tb=<implicit>, '
  307. 'limit=None, file=None, chain=True)'))
  308. self.assertEqual(
  309. str(inspect.signature(traceback.format_exception)),
  310. ('(exc, /, value=<implicit>, tb=<implicit>, limit=None, '
  311. 'chain=True)'))
  312. self.assertEqual(
  313. str(inspect.signature(traceback.format_exception_only)),
  314. '(exc, /, value=<implicit>)')
  315. @requires_debug_ranges()
  316. class TracebackErrorLocationCaretTests(unittest.TestCase):
  317. """
  318. Tests for printing code error expressions as part of PEP 657
  319. """
  320. def get_exception(self, callable):
  321. try:
  322. callable()
  323. self.fail("No exception thrown.")
  324. except:
  325. return traceback.format_exc().splitlines()[:-1]
  326. callable_line = get_exception.__code__.co_firstlineno + 2
  327. def test_basic_caret(self):
  328. # NOTE: In caret tests, "if True:" is used as a way to force indicator
  329. # display, since the raising expression spans only part of the line.
  330. def f():
  331. if True: raise ValueError("basic caret tests")
  332. lineno_f = f.__code__.co_firstlineno
  333. expected_f = (
  334. 'Traceback (most recent call last):\n'
  335. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  336. ' callable()\n'
  337. f' File "{__file__}", line {lineno_f+1}, in f\n'
  338. ' if True: raise ValueError("basic caret tests")\n'
  339. ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n'
  340. )
  341. result_lines = self.get_exception(f)
  342. self.assertEqual(result_lines, expected_f.splitlines())
  343. def test_line_with_unicode(self):
  344. # Make sure that even if a line contains multi-byte unicode characters
  345. # the correct carets are printed.
  346. def f_with_unicode():
  347. if True: raise ValueError("Ĥellö Wörld")
  348. lineno_f = f_with_unicode.__code__.co_firstlineno
  349. expected_f = (
  350. 'Traceback (most recent call last):\n'
  351. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  352. ' callable()\n'
  353. f' File "{__file__}", line {lineno_f+1}, in f_with_unicode\n'
  354. ' if True: raise ValueError("Ĥellö Wörld")\n'
  355. ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n'
  356. )
  357. result_lines = self.get_exception(f_with_unicode)
  358. self.assertEqual(result_lines, expected_f.splitlines())
  359. def test_caret_in_type_annotation(self):
  360. def f_with_type():
  361. def foo(a: THIS_DOES_NOT_EXIST ) -> int:
  362. return 0
  363. lineno_f = f_with_type.__code__.co_firstlineno
  364. expected_f = (
  365. 'Traceback (most recent call last):\n'
  366. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  367. ' callable()\n'
  368. f' File "{__file__}", line {lineno_f+1}, in f_with_type\n'
  369. ' def foo(a: THIS_DOES_NOT_EXIST ) -> int:\n'
  370. ' ^^^^^^^^^^^^^^^^^^^\n'
  371. )
  372. result_lines = self.get_exception(f_with_type)
  373. self.assertEqual(result_lines, expected_f.splitlines())
  374. def test_caret_multiline_expression(self):
  375. # Make sure no carets are printed for expressions spanning multiple
  376. # lines.
  377. def f_with_multiline():
  378. if True: raise ValueError(
  379. "error over multiple lines"
  380. )
  381. lineno_f = f_with_multiline.__code__.co_firstlineno
  382. expected_f = (
  383. 'Traceback (most recent call last):\n'
  384. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  385. ' callable()\n'
  386. f' File "{__file__}", line {lineno_f+1}, in f_with_multiline\n'
  387. ' if True: raise ValueError(\n'
  388. ' ^^^^^^^^^^^^^^^^^'
  389. )
  390. result_lines = self.get_exception(f_with_multiline)
  391. self.assertEqual(result_lines, expected_f.splitlines())
  392. def test_caret_multiline_expression_syntax_error(self):
  393. # Make sure an expression spanning multiple lines that has
  394. # a syntax error is correctly marked with carets.
  395. code = textwrap.dedent("""
  396. def foo(*args, **kwargs):
  397. pass
  398. a, b, c = 1, 2, 3
  399. foo(a, z
  400. for z in
  401. range(10), b, c)
  402. """)
  403. def f_with_multiline():
  404. # Need to defer the compilation until in self.get_exception(..)
  405. return compile(code, "?", "exec")
  406. lineno_f = f_with_multiline.__code__.co_firstlineno
  407. expected_f = (
  408. 'Traceback (most recent call last):\n'
  409. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  410. ' callable()\n'
  411. f' File "{__file__}", line {lineno_f+2}, in f_with_multiline\n'
  412. ' return compile(code, "?", "exec")\n'
  413. ' ^^^^^^^^^^^^^^^^^^^^^^^^^^\n'
  414. ' File "?", line 7\n'
  415. ' foo(a, z\n'
  416. ' ^'
  417. )
  418. result_lines = self.get_exception(f_with_multiline)
  419. self.assertEqual(result_lines, expected_f.splitlines())
  420. def test_caret_multiline_expression_bin_op(self):
  421. # Make sure no carets are printed for expressions spanning multiple
  422. # lines.
  423. def f_with_multiline():
  424. return (
  425. 2 + 1 /
  426. 0
  427. )
  428. lineno_f = f_with_multiline.__code__.co_firstlineno
  429. expected_f = (
  430. 'Traceback (most recent call last):\n'
  431. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  432. ' callable()\n'
  433. f' File "{__file__}", line {lineno_f+2}, in f_with_multiline\n'
  434. ' 2 + 1 /\n'
  435. ' ^^^'
  436. )
  437. result_lines = self.get_exception(f_with_multiline)
  438. self.assertEqual(result_lines, expected_f.splitlines())
  439. def test_caret_for_binary_operators(self):
  440. def f_with_binary_operator():
  441. divisor = 20
  442. return 10 + divisor / 0 + 30
  443. lineno_f = f_with_binary_operator.__code__.co_firstlineno
  444. expected_error = (
  445. 'Traceback (most recent call last):\n'
  446. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  447. ' callable()\n'
  448. f' File "{__file__}", line {lineno_f+2}, in f_with_binary_operator\n'
  449. ' return 10 + divisor / 0 + 30\n'
  450. ' ~~~~~~~~^~~\n'
  451. )
  452. result_lines = self.get_exception(f_with_binary_operator)
  453. self.assertEqual(result_lines, expected_error.splitlines())
  454. def test_caret_for_binary_operators_with_unicode(self):
  455. def f_with_binary_operator():
  456. áóí = 20
  457. return 10 + áóí / 0 + 30
  458. lineno_f = f_with_binary_operator.__code__.co_firstlineno
  459. expected_error = (
  460. 'Traceback (most recent call last):\n'
  461. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  462. ' callable()\n'
  463. f' File "{__file__}", line {lineno_f+2}, in f_with_binary_operator\n'
  464. ' return 10 + áóí / 0 + 30\n'
  465. ' ~~~~^~~\n'
  466. )
  467. result_lines = self.get_exception(f_with_binary_operator)
  468. self.assertEqual(result_lines, expected_error.splitlines())
  469. def test_caret_for_binary_operators_two_char(self):
  470. def f_with_binary_operator():
  471. divisor = 20
  472. return 10 + divisor // 0 + 30
  473. lineno_f = f_with_binary_operator.__code__.co_firstlineno
  474. expected_error = (
  475. 'Traceback (most recent call last):\n'
  476. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  477. ' callable()\n'
  478. f' File "{__file__}", line {lineno_f+2}, in f_with_binary_operator\n'
  479. ' return 10 + divisor // 0 + 30\n'
  480. ' ~~~~~~~~^^~~\n'
  481. )
  482. result_lines = self.get_exception(f_with_binary_operator)
  483. self.assertEqual(result_lines, expected_error.splitlines())
  484. def test_caret_for_subscript(self):
  485. def f_with_subscript():
  486. some_dict = {'x': {'y': None}}
  487. return some_dict['x']['y']['z']
  488. lineno_f = f_with_subscript.__code__.co_firstlineno
  489. expected_error = (
  490. 'Traceback (most recent call last):\n'
  491. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  492. ' callable()\n'
  493. f' File "{__file__}", line {lineno_f+2}, in f_with_subscript\n'
  494. " return some_dict['x']['y']['z']\n"
  495. ' ~~~~~~~~~~~~~~~~~~~^^^^^\n'
  496. )
  497. result_lines = self.get_exception(f_with_subscript)
  498. self.assertEqual(result_lines, expected_error.splitlines())
  499. def test_caret_for_subscript_unicode(self):
  500. def f_with_subscript():
  501. some_dict = {'ó': {'á': {'í': {'theta': 1}}}}
  502. return some_dict['ó']['á']['í']['beta']
  503. lineno_f = f_with_subscript.__code__.co_firstlineno
  504. expected_error = (
  505. 'Traceback (most recent call last):\n'
  506. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  507. ' callable()\n'
  508. f' File "{__file__}", line {lineno_f+2}, in f_with_subscript\n'
  509. " return some_dict['ó']['á']['í']['beta']\n"
  510. ' ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^\n'
  511. )
  512. result_lines = self.get_exception(f_with_subscript)
  513. self.assertEqual(result_lines, expected_error.splitlines())
  514. def test_traceback_specialization_with_syntax_error(self):
  515. bytecode = compile("1 / 0 / 1 / 2\n", TESTFN, "exec")
  516. with open(TESTFN, "w") as file:
  517. # make the file's contents invalid
  518. file.write("1 $ 0 / 1 / 2\n")
  519. self.addCleanup(unlink, TESTFN)
  520. func = partial(exec, bytecode)
  521. result_lines = self.get_exception(func)
  522. lineno_f = bytecode.co_firstlineno
  523. expected_error = (
  524. 'Traceback (most recent call last):\n'
  525. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  526. ' callable()\n'
  527. f' File "{TESTFN}", line {lineno_f}, in <module>\n'
  528. " 1 $ 0 / 1 / 2\n"
  529. ' ^^^^^\n'
  530. )
  531. self.assertEqual(result_lines, expected_error.splitlines())
  532. def test_traceback_very_long_line(self):
  533. source = "if True: " + "a" * 256
  534. bytecode = compile(source, TESTFN, "exec")
  535. with open(TESTFN, "w") as file:
  536. file.write(source)
  537. self.addCleanup(unlink, TESTFN)
  538. func = partial(exec, bytecode)
  539. result_lines = self.get_exception(func)
  540. lineno_f = bytecode.co_firstlineno
  541. expected_error = (
  542. 'Traceback (most recent call last):\n'
  543. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  544. ' callable()\n'
  545. f' File "{TESTFN}", line {lineno_f}, in <module>\n'
  546. f' {source}\n'
  547. f' {" "*len("if True: ") + "^"*256}\n'
  548. )
  549. self.assertEqual(result_lines, expected_error.splitlines())
  550. def test_secondary_caret_not_elided(self):
  551. # Always show a line's indicators if they include the secondary character.
  552. def f_with_subscript():
  553. some_dict = {'x': {'y': None}}
  554. some_dict['x']['y']['z']
  555. lineno_f = f_with_subscript.__code__.co_firstlineno
  556. expected_error = (
  557. 'Traceback (most recent call last):\n'
  558. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  559. ' callable()\n'
  560. f' File "{__file__}", line {lineno_f+2}, in f_with_subscript\n'
  561. " some_dict['x']['y']['z']\n"
  562. ' ~~~~~~~~~~~~~~~~~~~^^^^^\n'
  563. )
  564. result_lines = self.get_exception(f_with_subscript)
  565. self.assertEqual(result_lines, expected_error.splitlines())
  566. def test_caret_exception_group(self):
  567. # Notably, this covers whether indicators handle margin strings correctly.
  568. # (Exception groups use margin strings to display vertical indicators.)
  569. # The implementation must account for both "indent" and "margin" offsets.
  570. def exc():
  571. if True: raise ExceptionGroup("eg", [ValueError(1), TypeError(2)])
  572. expected_error = (
  573. f' + Exception Group Traceback (most recent call last):\n'
  574. f' | File "{__file__}", line {self.callable_line}, in get_exception\n'
  575. f' | callable()\n'
  576. f' | File "{__file__}", line {exc.__code__.co_firstlineno + 1}, in exc\n'
  577. f' | if True: raise ExceptionGroup("eg", [ValueError(1), TypeError(2)])\n'
  578. f' | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n'
  579. f' | ExceptionGroup: eg (2 sub-exceptions)\n'
  580. f' +-+---------------- 1 ----------------\n'
  581. f' | ValueError: 1\n'
  582. f' +---------------- 2 ----------------\n'
  583. f' | TypeError: 2\n')
  584. result_lines = self.get_exception(exc)
  585. self.assertEqual(result_lines, expected_error.splitlines())
  586. def assertSpecialized(self, func, expected_specialization):
  587. result_lines = self.get_exception(func)
  588. specialization_line = result_lines[-1]
  589. self.assertEqual(specialization_line.lstrip(), expected_specialization)
  590. def test_specialization_variations(self):
  591. self.assertSpecialized(lambda: 1/0,
  592. "~^~")
  593. self.assertSpecialized(lambda: 1/0/3,
  594. "~^~")
  595. self.assertSpecialized(lambda: 1 / 0,
  596. "~~^~~")
  597. self.assertSpecialized(lambda: 1 / 0 / 3,
  598. "~~^~~")
  599. self.assertSpecialized(lambda: 1/ 0,
  600. "~^~~")
  601. self.assertSpecialized(lambda: 1/ 0/3,
  602. "~^~~")
  603. self.assertSpecialized(lambda: 1 / 0,
  604. "~~~~~^~~~")
  605. self.assertSpecialized(lambda: 1 / 0 / 5,
  606. "~~~~~^~~~")
  607. self.assertSpecialized(lambda: 1 /0,
  608. "~~^~")
  609. self.assertSpecialized(lambda: 1//0,
  610. "~^^~")
  611. self.assertSpecialized(lambda: 1//0//4,
  612. "~^^~")
  613. self.assertSpecialized(lambda: 1 // 0,
  614. "~~^^~~")
  615. self.assertSpecialized(lambda: 1 // 0 // 4,
  616. "~~^^~~")
  617. self.assertSpecialized(lambda: 1 //0,
  618. "~~^^~")
  619. self.assertSpecialized(lambda: 1// 0,
  620. "~^^~~")
  621. def test_decorator_application_lineno_correct(self):
  622. def dec_error(func):
  623. raise TypeError
  624. def dec_fine(func):
  625. return func
  626. def applydecs():
  627. @dec_error
  628. @dec_fine
  629. def g(): pass
  630. result_lines = self.get_exception(applydecs)
  631. lineno_applydescs = applydecs.__code__.co_firstlineno
  632. lineno_dec_error = dec_error.__code__.co_firstlineno
  633. expected_error = (
  634. 'Traceback (most recent call last):\n'
  635. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  636. ' callable()\n'
  637. f' File "{__file__}", line {lineno_applydescs + 1}, in applydecs\n'
  638. ' @dec_error\n'
  639. ' ^^^^^^^^^\n'
  640. f' File "{__file__}", line {lineno_dec_error + 1}, in dec_error\n'
  641. ' raise TypeError\n'
  642. )
  643. self.assertEqual(result_lines, expected_error.splitlines())
  644. def applydecs_class():
  645. @dec_error
  646. @dec_fine
  647. class A: pass
  648. result_lines = self.get_exception(applydecs_class)
  649. lineno_applydescs_class = applydecs_class.__code__.co_firstlineno
  650. expected_error = (
  651. 'Traceback (most recent call last):\n'
  652. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  653. ' callable()\n'
  654. f' File "{__file__}", line {lineno_applydescs_class + 1}, in applydecs_class\n'
  655. ' @dec_error\n'
  656. ' ^^^^^^^^^\n'
  657. f' File "{__file__}", line {lineno_dec_error + 1}, in dec_error\n'
  658. ' raise TypeError\n'
  659. )
  660. self.assertEqual(result_lines, expected_error.splitlines())
  661. def test_multiline_method_call_a(self):
  662. def f():
  663. (None
  664. .method
  665. )()
  666. actual = self.get_exception(f)
  667. expected = [
  668. f"Traceback (most recent call last):",
  669. f" File \"{__file__}\", line {self.callable_line}, in get_exception",
  670. f" callable()",
  671. f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f",
  672. f" .method",
  673. f" ^^^^^^",
  674. ]
  675. self.assertEqual(actual, expected)
  676. def test_multiline_method_call_b(self):
  677. def f():
  678. (None.
  679. method
  680. )()
  681. actual = self.get_exception(f)
  682. expected = [
  683. f"Traceback (most recent call last):",
  684. f" File \"{__file__}\", line {self.callable_line}, in get_exception",
  685. f" callable()",
  686. f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f",
  687. f" method",
  688. ]
  689. self.assertEqual(actual, expected)
  690. def test_multiline_method_call_c(self):
  691. def f():
  692. (None
  693. . method
  694. )()
  695. actual = self.get_exception(f)
  696. expected = [
  697. f"Traceback (most recent call last):",
  698. f" File \"{__file__}\", line {self.callable_line}, in get_exception",
  699. f" callable()",
  700. f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f",
  701. f" . method",
  702. f" ^^^^^^",
  703. ]
  704. self.assertEqual(actual, expected)
  705. def test_wide_characters_unicode_with_problematic_byte_offset(self):
  706. def f():
  707. width
  708. actual = self.get_exception(f)
  709. expected = [
  710. f"Traceback (most recent call last):",
  711. f" File \"{__file__}\", line {self.callable_line}, in get_exception",
  712. f" callable()",
  713. f" File \"{__file__}\", line {f.__code__.co_firstlineno + 1}, in f",
  714. f" width",
  715. ]
  716. self.assertEqual(actual, expected)
  717. def test_byte_offset_with_wide_characters_middle(self):
  718. def f():
  719. width = 1
  720. raise ValueError(width)
  721. actual = self.get_exception(f)
  722. expected = [
  723. f"Traceback (most recent call last):",
  724. f" File \"{__file__}\", line {self.callable_line}, in get_exception",
  725. f" callable()",
  726. f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f",
  727. f" raise ValueError(width)",
  728. ]
  729. self.assertEqual(actual, expected)
  730. def test_byte_offset_multiline(self):
  731. def f():
  732. www = 1
  733. th = 0
  734. print(1, www(
  735. th))
  736. actual = self.get_exception(f)
  737. expected = [
  738. f"Traceback (most recent call last):",
  739. f" File \"{__file__}\", line {self.callable_line}, in get_exception",
  740. f" callable()",
  741. f" File \"{__file__}\", line {f.__code__.co_firstlineno + 4}, in f",
  742. f" print(1, www(",
  743. f" ^^^^",
  744. ]
  745. self.assertEqual(actual, expected)
  746. @cpython_only
  747. @requires_debug_ranges()
  748. class CPythonTracebackErrorCaretTests(TracebackErrorLocationCaretTests):
  749. """
  750. Same set of tests as above but with Python's internal traceback printing.
  751. """
  752. def get_exception(self, callable):
  753. from _testcapi import exception_print
  754. try:
  755. callable()
  756. self.fail("No exception thrown.")
  757. except Exception as e:
  758. with captured_output("stderr") as tbstderr:
  759. exception_print(e)
  760. return tbstderr.getvalue().splitlines()[:-1]
  761. callable_line = get_exception.__code__.co_firstlineno + 3
  762. class TracebackFormatTests(unittest.TestCase):
  763. def some_exception(self):
  764. raise KeyError('blah')
  765. @cpython_only
  766. def check_traceback_format(self, cleanup_func=None):
  767. from _testcapi import traceback_print
  768. try:
  769. self.some_exception()
  770. except KeyError:
  771. type_, value, tb = sys.exc_info()
  772. if cleanup_func is not None:
  773. # Clear the inner frames, not this one
  774. cleanup_func(tb.tb_next)
  775. traceback_fmt = 'Traceback (most recent call last):\n' + \
  776. ''.join(traceback.format_tb(tb))
  777. file_ = StringIO()
  778. traceback_print(tb, file_)
  779. python_fmt = file_.getvalue()
  780. # Call all _tb and _exc functions
  781. with captured_output("stderr") as tbstderr:
  782. traceback.print_tb(tb)
  783. tbfile = StringIO()
  784. traceback.print_tb(tb, file=tbfile)
  785. with captured_output("stderr") as excstderr:
  786. traceback.print_exc()
  787. excfmt = traceback.format_exc()
  788. excfile = StringIO()
  789. traceback.print_exc(file=excfile)
  790. else:
  791. raise Error("unable to create test traceback string")
  792. # Make sure that Python and the traceback module format the same thing
  793. self.assertEqual(traceback_fmt, python_fmt)
  794. # Now verify the _tb func output
  795. self.assertEqual(tbstderr.getvalue(), tbfile.getvalue())
  796. # Now verify the _exc func output
  797. self.assertEqual(excstderr.getvalue(), excfile.getvalue())
  798. self.assertEqual(excfmt, excfile.getvalue())
  799. # Make sure that the traceback is properly indented.
  800. tb_lines = python_fmt.splitlines()
  801. banner = tb_lines[0]
  802. self.assertEqual(len(tb_lines), 5)
  803. location, source_line = tb_lines[-2], tb_lines[-1]
  804. self.assertTrue(banner.startswith('Traceback'))
  805. self.assertTrue(location.startswith(' File'))
  806. self.assertTrue(source_line.startswith(' raise'))
  807. def test_traceback_format(self):
  808. self.check_traceback_format()
  809. def test_traceback_format_with_cleared_frames(self):
  810. # Check that traceback formatting also works with a clear()ed frame
  811. def cleanup_tb(tb):
  812. tb.tb_frame.clear()
  813. self.check_traceback_format(cleanup_tb)
  814. def test_stack_format(self):
  815. # Verify _stack functions. Note we have to use _getframe(1) to
  816. # compare them without this frame appearing in the output
  817. with captured_output("stderr") as ststderr:
  818. traceback.print_stack(sys._getframe(1))
  819. stfile = StringIO()
  820. traceback.print_stack(sys._getframe(1), file=stfile)
  821. self.assertEqual(ststderr.getvalue(), stfile.getvalue())
  822. stfmt = traceback.format_stack(sys._getframe(1))
  823. self.assertEqual(ststderr.getvalue(), "".join(stfmt))
  824. def test_print_stack(self):
  825. def prn():
  826. traceback.print_stack()
  827. with captured_output("stderr") as stderr:
  828. prn()
  829. lineno = prn.__code__.co_firstlineno
  830. self.assertEqual(stderr.getvalue().splitlines()[-4:], [
  831. ' File "%s", line %d, in test_print_stack' % (__file__, lineno+3),
  832. ' prn()',
  833. ' File "%s", line %d, in prn' % (__file__, lineno+1),
  834. ' traceback.print_stack()',
  835. ])
  836. # issue 26823 - Shrink recursive tracebacks
  837. def _check_recursive_traceback_display(self, render_exc):
  838. # Always show full diffs when this test fails
  839. # Note that rearranging things may require adjusting
  840. # the relative line numbers in the expected tracebacks
  841. self.maxDiff = None
  842. # Check hitting the recursion limit
  843. def f():
  844. f()
  845. with captured_output("stderr") as stderr_f:
  846. try:
  847. f()
  848. except RecursionError:
  849. render_exc()
  850. else:
  851. self.fail("no recursion occurred")
  852. lineno_f = f.__code__.co_firstlineno
  853. result_f = (
  854. 'Traceback (most recent call last):\n'
  855. f' File "{__file__}", line {lineno_f+5}, in _check_recursive_traceback_display\n'
  856. ' f()\n'
  857. f' File "{__file__}", line {lineno_f+1}, in f\n'
  858. ' f()\n'
  859. f' File "{__file__}", line {lineno_f+1}, in f\n'
  860. ' f()\n'
  861. f' File "{__file__}", line {lineno_f+1}, in f\n'
  862. ' f()\n'
  863. # XXX: The following line changes depending on whether the tests
  864. # are run through the interactive interpreter or with -m
  865. # It also varies depending on the platform (stack size)
  866. # Fortunately, we don't care about exactness here, so we use regex
  867. r' \[Previous line repeated (\d+) more times\]' '\n'
  868. 'RecursionError: maximum recursion depth exceeded\n'
  869. )
  870. expected = result_f.splitlines()
  871. actual = stderr_f.getvalue().splitlines()
  872. # Check the output text matches expectations
  873. # 2nd last line contains the repetition count
  874. self.assertEqual(actual[:-2], expected[:-2])
  875. self.assertRegex(actual[-2], expected[-2])
  876. # last line can have additional text appended
  877. self.assertIn(expected[-1], actual[-1])
  878. # Check the recursion count is roughly as expected
  879. rec_limit = sys.getrecursionlimit()
  880. self.assertIn(int(re.search(r"\d+", actual[-2]).group()), range(rec_limit-60, rec_limit))
  881. # Check a known (limited) number of recursive invocations
  882. def g(count=10):
  883. if count:
  884. return g(count-1)
  885. raise ValueError
  886. with captured_output("stderr") as stderr_g:
  887. try:
  888. g()
  889. except ValueError:
  890. render_exc()
  891. else:
  892. self.fail("no value error was raised")
  893. lineno_g = g.__code__.co_firstlineno
  894. result_g = (
  895. f' File "{__file__}", line {lineno_g+2}, in g\n'
  896. ' return g(count-1)\n'
  897. ' ^^^^^^^^^^\n'
  898. f' File "{__file__}", line {lineno_g+2}, in g\n'
  899. ' return g(count-1)\n'
  900. ' ^^^^^^^^^^\n'
  901. f' File "{__file__}", line {lineno_g+2}, in g\n'
  902. ' return g(count-1)\n'
  903. ' ^^^^^^^^^^\n'
  904. ' [Previous line repeated 7 more times]\n'
  905. f' File "{__file__}", line {lineno_g+3}, in g\n'
  906. ' raise ValueError\n'
  907. 'ValueError\n'
  908. )
  909. tb_line = (
  910. 'Traceback (most recent call last):\n'
  911. f' File "{__file__}", line {lineno_g+7}, in _check_recursive_traceback_display\n'
  912. ' g()\n'
  913. )
  914. expected = (tb_line + result_g).splitlines()
  915. actual = stderr_g.getvalue().splitlines()
  916. self.assertEqual(actual, expected)
  917. # Check 2 different repetitive sections
  918. def h(count=10):
  919. if count:
  920. return h(count-1)
  921. g()
  922. with captured_output("stderr") as stderr_h:
  923. try:
  924. h()
  925. except ValueError:
  926. render_exc()
  927. else:
  928. self.fail("no value error was raised")
  929. lineno_h = h.__code__.co_firstlineno
  930. result_h = (
  931. 'Traceback (most recent call last):\n'
  932. f' File "{__file__}", line {lineno_h+7}, in _check_recursive_traceback_display\n'
  933. ' h()\n'
  934. f' File "{__file__}", line {lineno_h+2}, in h\n'
  935. ' return h(count-1)\n'
  936. ' ^^^^^^^^^^\n'
  937. f' File "{__file__}", line {lineno_h+2}, in h\n'
  938. ' return h(count-1)\n'
  939. ' ^^^^^^^^^^\n'
  940. f' File "{__file__}", line {lineno_h+2}, in h\n'
  941. ' return h(count-1)\n'
  942. ' ^^^^^^^^^^\n'
  943. ' [Previous line repeated 7 more times]\n'
  944. f' File "{__file__}", line {lineno_h+3}, in h\n'
  945. ' g()\n'
  946. )
  947. expected = (result_h + result_g).splitlines()
  948. actual = stderr_h.getvalue().splitlines()
  949. self.assertEqual(actual, expected)
  950. # Check the boundary conditions. First, test just below the cutoff.
  951. with captured_output("stderr") as stderr_g:
  952. try:
  953. g(traceback._RECURSIVE_CUTOFF)
  954. except ValueError:
  955. render_exc()
  956. else:
  957. self.fail("no error raised")
  958. result_g = (
  959. f' File "{__file__}", line {lineno_g+2}, in g\n'
  960. ' return g(count-1)\n'
  961. ' ^^^^^^^^^^\n'
  962. f' File "{__file__}", line {lineno_g+2}, in g\n'
  963. ' return g(count-1)\n'
  964. ' ^^^^^^^^^^\n'
  965. f' File "{__file__}", line {lineno_g+2}, in g\n'
  966. ' return g(count-1)\n'
  967. ' ^^^^^^^^^^\n'
  968. f' File "{__file__}", line {lineno_g+3}, in g\n'
  969. ' raise ValueError\n'
  970. 'ValueError\n'
  971. )
  972. tb_line = (
  973. 'Traceback (most recent call last):\n'
  974. f' File "{__file__}", line {lineno_g+77}, in _check_recursive_traceback_display\n'
  975. ' g(traceback._RECURSIVE_CUTOFF)\n'
  976. )
  977. expected = (tb_line + result_g).splitlines()
  978. actual = stderr_g.getvalue().splitlines()
  979. self.assertEqual(actual, expected)
  980. # Second, test just above the cutoff.
  981. with captured_output("stderr") as stderr_g:
  982. try:
  983. g(traceback._RECURSIVE_CUTOFF + 1)
  984. except ValueError:
  985. render_exc()
  986. else:
  987. self.fail("no error raised")
  988. result_g = (
  989. f' File "{__file__}", line {lineno_g+2}, in g\n'
  990. ' return g(count-1)\n'
  991. ' ^^^^^^^^^^\n'
  992. f' File "{__file__}", line {lineno_g+2}, in g\n'
  993. ' return g(count-1)\n'
  994. ' ^^^^^^^^^^\n'
  995. f' File "{__file__}", line {lineno_g+2}, in g\n'
  996. ' return g(count-1)\n'
  997. ' ^^^^^^^^^^\n'
  998. ' [Previous line repeated 1 more time]\n'
  999. f' File "{__file__}", line {lineno_g+3}, in g\n'
  1000. ' raise ValueError\n'
  1001. 'ValueError\n'
  1002. )
  1003. tb_line = (
  1004. 'Traceback (most recent call last):\n'
  1005. f' File "{__file__}", line {lineno_g+108}, in _check_recursive_traceback_display\n'
  1006. ' g(traceback._RECURSIVE_CUTOFF + 1)\n'
  1007. )
  1008. expected = (tb_line + result_g).splitlines()
  1009. actual = stderr_g.getvalue().splitlines()
  1010. self.assertEqual(actual, expected)
  1011. @requires_debug_ranges()
  1012. def test_recursive_traceback_python(self):
  1013. self._check_recursive_traceback_display(traceback.print_exc)
  1014. @cpython_only
  1015. @requires_debug_ranges()
  1016. def test_recursive_traceback_cpython_internal(self):
  1017. from _testcapi import exception_print
  1018. def render_exc():
  1019. exc_type, exc_value, exc_tb = sys.exc_info()
  1020. exception_print(exc_value)
  1021. self._check_recursive_traceback_display(render_exc)
  1022. def test_format_stack(self):
  1023. def fmt():
  1024. return traceback.format_stack()
  1025. result = fmt()
  1026. lineno = fmt.__code__.co_firstlineno
  1027. self.assertEqual(result[-2:], [
  1028. ' File "%s", line %d, in test_format_stack\n'
  1029. ' result = fmt()\n' % (__file__, lineno+2),
  1030. ' File "%s", line %d, in fmt\n'
  1031. ' return traceback.format_stack()\n' % (__file__, lineno+1),
  1032. ])
  1033. @cpython_only
  1034. def test_unhashable(self):
  1035. from _testcapi import exception_print
  1036. class UnhashableException(Exception):
  1037. def __eq__(self, other):
  1038. return True
  1039. ex1 = UnhashableException('ex1')
  1040. ex2 = UnhashableException('ex2')
  1041. try:
  1042. raise ex2 from ex1
  1043. except UnhashableException:
  1044. try:
  1045. raise ex1
  1046. except UnhashableException:
  1047. exc_type, exc_val, exc_tb = sys.exc_info()
  1048. with captured_output("stderr") as stderr_f:
  1049. exception_print(exc_val)
  1050. tb = stderr_f.getvalue().strip().splitlines()
  1051. self.assertEqual(11, len(tb))
  1052. self.assertEqual(context_message.strip(), tb[5])
  1053. self.assertIn('UnhashableException: ex2', tb[3])
  1054. self.assertIn('UnhashableException: ex1', tb[10])
  1055. def deep_eg(self):
  1056. e = TypeError(1)
  1057. for i in range(2000):
  1058. e = ExceptionGroup('eg', [e])
  1059. return e
  1060. @cpython_only
  1061. def test_exception_group_deep_recursion_capi(self):
  1062. from _testcapi import exception_print
  1063. LIMIT = 75
  1064. eg = self.deep_eg()
  1065. with captured_output("stderr") as stderr_f:
  1066. with support.infinite_recursion(max_depth=LIMIT):
  1067. exception_print(eg)
  1068. output = stderr_f.getvalue()
  1069. self.assertIn('ExceptionGroup', output)
  1070. self.assertLessEqual(output.count('ExceptionGroup'), LIMIT)
  1071. def test_exception_group_deep_recursion_traceback(self):
  1072. LIMIT = 75
  1073. eg = self.deep_eg()
  1074. with captured_output("stderr") as stderr_f:
  1075. with support.infinite_recursion(max_depth=LIMIT):
  1076. traceback.print_exception(type(eg), eg, eg.__traceback__)
  1077. output = stderr_f.getvalue()
  1078. self.assertIn('ExceptionGroup', output)
  1079. self.assertLessEqual(output.count('ExceptionGroup'), LIMIT)
  1080. @cpython_only
  1081. def test_print_exception_bad_type_capi(self):
  1082. from _testcapi import exception_print
  1083. with captured_output("stderr") as stderr:
  1084. exception_print(42)
  1085. self.assertEqual(
  1086. stderr.getvalue(),
  1087. ('TypeError: print_exception(): '
  1088. 'Exception expected for value, int found\n')
  1089. )
  1090. def test_print_exception_bad_type_python(self):
  1091. msg = "Exception expected for value, int found"
  1092. with self.assertRaisesRegex(TypeError, msg):
  1093. traceback.print_exception(42)
  1094. cause_message = (
  1095. "\nThe above exception was the direct cause "
  1096. "of the following exception:\n\n")
  1097. context_message = (
  1098. "\nDuring handling of the above exception, "
  1099. "another exception occurred:\n\n")
  1100. boundaries = re.compile(
  1101. '(%s|%s)' % (re.escape(cause_message), re.escape(context_message)))
  1102. class BaseExceptionReportingTests:
  1103. def get_exception(self, exception_or_callable):
  1104. if isinstance(exception_or_callable, BaseException):
  1105. return exception_or_callable
  1106. try:
  1107. exception_or_callable()
  1108. except Exception as e:
  1109. return e
  1110. callable_line = get_exception.__code__.co_firstlineno + 4
  1111. def zero_div(self):
  1112. 1/0 # In zero_div
  1113. def check_zero_div(self, msg):
  1114. lines = msg.splitlines()
  1115. if has_no_debug_ranges():
  1116. self.assertTrue(lines[-3].startswith(' File'))
  1117. self.assertIn('1/0 # In zero_div', lines[-2])
  1118. else:
  1119. self.assertTrue(lines[-4].startswith(' File'))
  1120. self.assertIn('1/0 # In zero_div', lines[-3])
  1121. self.assertTrue(lines[-1].startswith('ZeroDivisionError'), lines[-1])
  1122. def test_simple(self):
  1123. try:
  1124. 1/0 # Marker
  1125. except ZeroDivisionError as _:
  1126. e = _
  1127. lines = self.get_report(e).splitlines()
  1128. if has_no_debug_ranges():
  1129. self.assertEqual(len(lines), 4)
  1130. self.assertTrue(lines[3].startswith('ZeroDivisionError'))
  1131. else:
  1132. self.assertEqual(len(lines), 5)
  1133. self.assertTrue(lines[4].startswith('ZeroDivisionError'))
  1134. self.assertTrue(lines[0].startswith('Traceback'))
  1135. self.assertTrue(lines[1].startswith(' File'))
  1136. self.assertIn('1/0 # Marker', lines[2])
  1137. def test_cause(self):
  1138. def inner_raise():
  1139. try:
  1140. self.zero_div()
  1141. except ZeroDivisionError as e:
  1142. raise KeyError from e
  1143. def outer_raise():
  1144. inner_raise() # Marker
  1145. blocks = boundaries.split(self.get_report(outer_raise))
  1146. self.assertEqual(len(blocks), 3)
  1147. self.assertEqual(blocks[1], cause_message)
  1148. self.check_zero_div(blocks[0])
  1149. self.assertIn('inner_raise() # Marker', blocks[2])
  1150. def test_context(self):
  1151. def inner_raise():
  1152. try:
  1153. self.zero_div()
  1154. except ZeroDivisionError:
  1155. raise KeyError
  1156. def outer_raise():
  1157. inner_raise() # Marker
  1158. blocks = boundaries.split(self.get_report(outer_raise))
  1159. self.assertEqual(len(blocks), 3)
  1160. self.assertEqual(blocks[1], context_message)
  1161. self.check_zero_div(blocks[0])
  1162. self.assertIn('inner_raise() # Marker', blocks[2])
  1163. def test_context_suppression(self):
  1164. try:
  1165. try:
  1166. raise Exception
  1167. except:
  1168. raise ZeroDivisionError from None
  1169. except ZeroDivisionError as _:
  1170. e = _
  1171. lines = self.get_report(e).splitlines()
  1172. self.assertEqual(len(lines), 4)
  1173. self.assertTrue(lines[3].startswith('ZeroDivisionError'))
  1174. self.assertTrue(lines[0].startswith('Traceback'))
  1175. self.assertTrue(lines[1].startswith(' File'))
  1176. self.assertIn('ZeroDivisionError from None', lines[2])
  1177. def test_cause_and_context(self):
  1178. # When both a cause and a context are set, only the cause should be
  1179. # displayed and the context should be muted.
  1180. def inner_raise():
  1181. try:
  1182. self.zero_div()
  1183. except ZeroDivisionError as _e:
  1184. e = _e
  1185. try:
  1186. xyzzy
  1187. except NameError:
  1188. raise KeyError from e
  1189. def outer_raise():
  1190. inner_raise() # Marker
  1191. blocks = boundaries.split(self.get_report(outer_raise))
  1192. self.assertEqual(len(blocks), 3)
  1193. self.assertEqual(blocks[1], cause_message)
  1194. self.check_zero_div(blocks[0])
  1195. self.assertIn('inner_raise() # Marker', blocks[2])
  1196. def test_cause_recursive(self):
  1197. def inner_raise():
  1198. try:
  1199. try:
  1200. self.zero_div()
  1201. except ZeroDivisionError as e:
  1202. z = e
  1203. raise KeyError from e
  1204. except KeyError as e:
  1205. raise z from e
  1206. def outer_raise():
  1207. inner_raise() # Marker
  1208. blocks = boundaries.split(self.get_report(outer_raise))
  1209. self.assertEqual(len(blocks), 3)
  1210. self.assertEqual(blocks[1], cause_message)
  1211. # The first block is the KeyError raised from the ZeroDivisionError
  1212. self.assertIn('raise KeyError from e', blocks[0])
  1213. self.assertNotIn('1/0', blocks[0])
  1214. # The second block (apart from the boundary) is the ZeroDivisionError
  1215. # re-raised from the KeyError
  1216. self.assertIn('inner_raise() # Marker', blocks[2])
  1217. self.check_zero_div(blocks[2])
  1218. def test_syntax_error_offset_at_eol(self):
  1219. # See #10186.
  1220. def e():
  1221. raise SyntaxError('', ('', 0, 5, 'hello'))
  1222. msg = self.get_report(e).splitlines()
  1223. self.assertEqual(msg[-2], " ^")
  1224. def e():
  1225. exec("x = 5 | 4 |")
  1226. msg = self.get_report(e).splitlines()
  1227. self.assertEqual(msg[-2], ' ^')
  1228. def test_syntax_error_no_lineno(self):
  1229. # See #34463.
  1230. # Without filename
  1231. e = SyntaxError('bad syntax')
  1232. msg = self.get_report(e).splitlines()
  1233. self.assertEqual(msg,
  1234. ['SyntaxError: bad syntax'])
  1235. e.lineno = 100
  1236. msg = self.get_report(e).splitlines()
  1237. self.assertEqual(msg,
  1238. [' File "<string>", line 100', 'SyntaxError: bad syntax'])
  1239. # With filename
  1240. e = SyntaxError('bad syntax')
  1241. e.filename = 'myfile.py'
  1242. msg = self.get_report(e).splitlines()
  1243. self.assertEqual(msg,
  1244. ['SyntaxError: bad syntax (myfile.py)'])
  1245. e.lineno = 100
  1246. msg = self.get_report(e).splitlines()
  1247. self.assertEqual(msg,
  1248. [' File "myfile.py", line 100', 'SyntaxError: bad syntax'])
  1249. def test_message_none(self):
  1250. # A message that looks like "None" should not be treated specially
  1251. err = self.get_report(Exception(None))
  1252. self.assertIn('Exception: None\n', err)
  1253. err = self.get_report(Exception('None'))
  1254. self.assertIn('Exception: None\n', err)
  1255. err = self.get_report(Exception())
  1256. self.assertIn('Exception\n', err)
  1257. err = self.get_report(Exception(''))
  1258. self.assertIn('Exception\n', err)
  1259. def test_syntax_error_various_offsets(self):
  1260. for offset in range(-5, 10):
  1261. for add in [0, 2]:
  1262. text = " "*add + "text%d" % offset
  1263. expected = [' File "file.py", line 1']
  1264. if offset < 1:
  1265. expected.append(" %s" % text.lstrip())
  1266. elif offset <= 6:
  1267. expected.append(" %s" % text.lstrip())
  1268. expected.append(" %s^" % (" "*(offset-1)))
  1269. else:
  1270. expected.append(" %s" % text.lstrip())
  1271. expected.append(" %s^" % (" "*5))
  1272. expected.append("SyntaxError: msg")
  1273. expected.append("")
  1274. err = self.get_report(SyntaxError("msg", ("file.py", 1, offset+add, text)))
  1275. exp = "\n".join(expected)
  1276. self.assertEqual(exp, err)
  1277. def test_exception_with_note(self):
  1278. e = ValueError(123)
  1279. vanilla = self.get_report(e)
  1280. e.add_note('My Note')
  1281. self.assertEqual(self.get_report(e), vanilla + 'My Note\n')
  1282. del e.__notes__
  1283. e.add_note('')
  1284. self.assertEqual(self.get_report(e), vanilla + '\n')
  1285. del e.__notes__
  1286. e.add_note('Your Note')
  1287. self.assertEqual(self.get_report(e), vanilla + 'Your Note\n')
  1288. del e.__notes__
  1289. self.assertEqual(self.get_report(e), vanilla)
  1290. def test_exception_with_invalid_notes(self):
  1291. e = ValueError(123)
  1292. vanilla = self.get_report(e)
  1293. # non-sequence __notes__
  1294. class BadThing:
  1295. def __str__(self):
  1296. return 'bad str'
  1297. def __repr__(self):
  1298. return 'bad repr'
  1299. # unprintable, non-sequence __notes__
  1300. class Unprintable:
  1301. def __repr__(self):
  1302. raise ValueError('bad value')
  1303. e.__notes__ = BadThing()
  1304. notes_repr = 'bad repr'
  1305. self.assertEqual(self.get_report(e), vanilla + notes_repr)
  1306. e.__notes__ = Unprintable()
  1307. err_msg = '<__notes__ repr() failed>'
  1308. self.assertEqual(self.get_report(e), vanilla + err_msg)
  1309. # non-string item in the __notes__ sequence
  1310. e.__notes__ = [BadThing(), 'Final Note']
  1311. bad_note = 'bad str'
  1312. self.assertEqual(self.get_report(e), vanilla + bad_note + '\nFinal Note\n')
  1313. # unprintable, non-string item in the __notes__ sequence
  1314. e.__notes__ = [Unprintable(), 'Final Note']
  1315. err_msg = '<note str() failed>'
  1316. self.assertEqual(self.get_report(e), vanilla + err_msg + '\nFinal Note\n')
  1317. def test_exception_with_note_with_multiple_notes(self):
  1318. e = ValueError(42)
  1319. vanilla = self.get_report(e)
  1320. e.add_note('Note 1')
  1321. e.add_note('Note 2')
  1322. e.add_note('Note 3')
  1323. self.assertEqual(
  1324. self.get_report(e),
  1325. vanilla + 'Note 1\n' + 'Note 2\n' + 'Note 3\n')
  1326. del e.__notes__
  1327. e.add_note('Note 4')
  1328. del e.__notes__
  1329. e.add_note('Note 5')
  1330. e.add_note('Note 6')
  1331. self.assertEqual(
  1332. self.get_report(e),
  1333. vanilla + 'Note 5\n' + 'Note 6\n')
  1334. def test_exception_qualname(self):
  1335. class A:
  1336. class B:
  1337. class X(Exception):
  1338. def __str__(self):
  1339. return "I am X"
  1340. err = self.get_report(A.B.X())
  1341. str_value = 'I am X'
  1342. str_name = '.'.join([A.B.X.__module__, A.B.X.__qualname__])
  1343. exp = "%s: %s\n" % (str_name, str_value)
  1344. self.assertEqual(exp, MODULE_PREFIX + err)
  1345. def test_exception_modulename(self):
  1346. class X(Exception):
  1347. def __str__(self):
  1348. return "I am X"
  1349. for modulename in '__main__', 'builtins', 'some_module':
  1350. X.__module__ = modulename
  1351. with self.subTest(modulename=modulename):
  1352. err = self.get_report(X())
  1353. str_value = 'I am X'
  1354. if modulename in ['builtins', '__main__']:
  1355. str_name = X.__qualname__
  1356. else:
  1357. str_name = '.'.join([X.__module__, X.__qualname__])
  1358. exp = "%s: %s\n" % (str_name, str_value)
  1359. self.assertEqual(exp, err)
  1360. def test_exception_modulename_not_unicode(self):
  1361. class X(Exception):
  1362. def __str__(self):
  1363. return "I am X"
  1364. X.__module__ = 42
  1365. err = self.get_report(X())
  1366. exp = f'<unknown>.{X.__qualname__}: I am X\n'
  1367. self.assertEqual(exp, err)
  1368. def test_exception_bad__str__(self):
  1369. class X(Exception):
  1370. def __str__(self):
  1371. 1/0
  1372. err = self.get_report(X())
  1373. str_value = '<exception str() failed>'
  1374. str_name = '.'.join([X.__module__, X.__qualname__])
  1375. self.assertEqual(MODULE_PREFIX + err, f"{str_name}: {str_value}\n")
  1376. # #### Exception Groups ####
  1377. def test_exception_group_basic(self):
  1378. def exc():
  1379. raise ExceptionGroup("eg", [ValueError(1), TypeError(2)])
  1380. expected = (
  1381. f' + Exception Group Traceback (most recent call last):\n'
  1382. f' | File "{__file__}", line {self.callable_line}, in get_exception\n'
  1383. f' | exception_or_callable()\n'
  1384. f' | File "{__file__}", line {exc.__code__.co_firstlineno + 1}, in exc\n'
  1385. f' | raise ExceptionGroup("eg", [ValueError(1), TypeError(2)])\n'
  1386. f' | ExceptionGroup: eg (2 sub-exceptions)\n'
  1387. f' +-+---------------- 1 ----------------\n'
  1388. f' | ValueError: 1\n'
  1389. f' +---------------- 2 ----------------\n'
  1390. f' | TypeError: 2\n'
  1391. f' +------------------------------------\n')
  1392. report = self.get_report(exc)
  1393. self.assertEqual(report, expected)
  1394. def test_exception_group_cause(self):
  1395. def exc():
  1396. EG = ExceptionGroup
  1397. try:
  1398. raise EG("eg1", [ValueError(1), TypeError(2)])
  1399. except Exception as e:
  1400. raise EG("eg2", [ValueError(3), TypeError(4)]) from e
  1401. expected = (f' + Exception Group Traceback (most recent call last):\n'
  1402. f' | File "{__file__}", line {exc.__code__.co_firstlineno + 3}, in exc\n'
  1403. f' | raise EG("eg1", [ValueError(1), TypeError(2)])\n'
  1404. f' | ExceptionGroup: eg1 (2 sub-exceptions)\n'
  1405. f' +-+---------------- 1 ----------------\n'
  1406. f' | ValueError: 1\n'
  1407. f' +---------------- 2 ----------------\n'
  1408. f' | TypeError: 2\n'
  1409. f' +------------------------------------\n'
  1410. f'\n'
  1411. f'The above exception was the direct cause of the following exception:\n'
  1412. f'\n'
  1413. f' + Exception Group Traceback (most recent call last):\n'
  1414. f' | File "{__file__}", line {self.callable_line}, in get_exception\n'
  1415. f' | exception_or_callable()\n'
  1416. f' | File "{__file__}", line {exc.__code__.co_firstlineno + 5}, in exc\n'
  1417. f' | raise EG("eg2", [ValueError(3), TypeError(4)]) from e\n'
  1418. f' | ExceptionGroup: eg2 (2 sub-exceptions)\n'
  1419. f' +-+---------------- 1 ----------------\n'
  1420. f' | ValueError: 3\n'
  1421. f' +---------------- 2 ----------------\n'
  1422. f' | TypeError: 4\n'
  1423. f' +------------------------------------\n')
  1424. report = self.get_report(exc)
  1425. self.assertEqual(report, expected)
  1426. def test_exception_group_context_with_context(self):
  1427. def exc():
  1428. EG = ExceptionGroup
  1429. try:
  1430. try:
  1431. raise EG("eg1", [ValueError(1), TypeError(2)])
  1432. except:
  1433. raise EG("eg2", [ValueError(3), TypeError(4)])
  1434. except:
  1435. raise ImportError(5)
  1436. expected = (
  1437. f' + Exception Group Traceback (most recent call last):\n'
  1438. f' | File "{__file__}", line {exc.__code__.co_firstlineno + 4}, in exc\n'
  1439. f' | raise EG("eg1", [ValueError(1), TypeError(2)])\n'
  1440. f' | ExceptionGroup: eg1 (2 sub-exceptions)\n'
  1441. f' +-+---------------- 1 ----------------\n'
  1442. f' | ValueError: 1\n'
  1443. f' +---------------- 2 ----------------\n'
  1444. f' | TypeError: 2\n'
  1445. f' +------------------------------------\n'
  1446. f'\n'
  1447. f'During handling of the above exception, another exception occurred:\n'
  1448. f'\n'
  1449. f' + Exception Group Traceback (most recent call last):\n'
  1450. f' | File "{__file__}", line {exc.__code__.co_firstlineno + 6}, in exc\n'
  1451. f' | raise EG("eg2", [ValueError(3), TypeError(4)])\n'
  1452. f' | ExceptionGroup: eg2 (2 sub-exceptions)\n'
  1453. f' +-+---------------- 1 ----------------\n'
  1454. f' | ValueError: 3\n'
  1455. f' +---------------- 2 ----------------\n'
  1456. f' | TypeError: 4\n'
  1457. f' +------------------------------------\n'
  1458. f'\n'
  1459. f'During handling of the above exception, another exception occurred:\n'
  1460. f'\n'
  1461. f'Traceback (most recent call last):\n'
  1462. f' File "{__file__}", line {self.callable_line}, in get_exception\n'
  1463. f' exception_or_callable()\n'
  1464. f' File "{__file__}", line {exc.__code__.co_firstlineno + 8}, in exc\n'
  1465. f' raise ImportError(5)\n'
  1466. f'ImportError: 5\n')
  1467. report = self.get_report(exc)
  1468. self.assertEqual(report, expected)
  1469. def test_exception_group_nested(self):
  1470. def exc():
  1471. EG = ExceptionGroup
  1472. VE = ValueError
  1473. TE = TypeError
  1474. try:
  1475. try:
  1476. raise EG("nested", [TE(2), TE(3)])
  1477. except Exception as e:
  1478. exc = e
  1479. raise EG("eg", [VE(1), exc, VE(4)])
  1480. except:
  1481. raise EG("top", [VE(5)])
  1482. expected = (f' + Exception Group Traceback (most recent call last):\n'
  1483. f' | File "{__file__}", line {exc.__code__.co_firstlineno + 9}, in exc\n'
  1484. f' | raise EG("eg", [VE(1), exc, VE(4)])\n'
  1485. f' | ExceptionGroup: eg (3 sub-exceptions)\n'
  1486. f' +-+---------------- 1 ----------------\n'
  1487. f' | ValueError: 1\n'
  1488. f' +---------------- 2 ----------------\n'
  1489. f' | Exception Group Traceback (most recent call last):\n'
  1490. f' | File "{__file__}", line {exc.__code__.co_firstlineno + 6}, in exc\n'
  1491. f' | raise EG("nested", [TE(2), TE(3)])\n'
  1492. f' | ExceptionGroup: nested (2 sub-exceptions)\n'
  1493. f' +-+---------------- 1 ----------------\n'
  1494. f' | TypeError: 2\n'
  1495. f' +---------------- 2 ----------------\n'
  1496. f' | TypeError: 3\n'
  1497. f' +------------------------------------\n'
  1498. f' +---------------- 3 ----------------\n'
  1499. f' | ValueError: 4\n'
  1500. f' +------------------------------------\n'
  1501. f'\n'
  1502. f'During handling of the above exception, another exception occurred:\n'
  1503. f'\n'
  1504. f' + Exception Group Traceback (most recent call last):\n'
  1505. f' | File "{__file__}", line {self.callable_line}, in get_exception\n'
  1506. f' | exception_or_callable()\n'
  1507. f' | File "{__file__}", line {exc.__code__.co_firstlineno + 11}, in exc\n'
  1508. f' | raise EG("top", [VE(5)])\n'
  1509. f' | ExceptionGroup: top (1 sub-exception)\n'
  1510. f' +-+---------------- 1 ----------------\n'
  1511. f' | ValueError: 5\n'
  1512. f' +------------------------------------\n')
  1513. report = self.get_report(exc)
  1514. self.assertEqual(report, expected)
  1515. def test_exception_group_width_limit(self):
  1516. excs = []
  1517. for i in range(1000):
  1518. excs.append(ValueError(i))
  1519. eg = ExceptionGroup('eg', excs)
  1520. expected = (' | ExceptionGroup: eg (1000 sub-exceptions)\n'
  1521. ' +-+---------------- 1 ----------------\n'
  1522. ' | ValueError: 0\n'
  1523. ' +---------------- 2 ----------------\n'
  1524. ' | ValueError: 1\n'
  1525. ' +---------------- 3 ----------------\n'
  1526. ' | ValueError: 2\n'
  1527. ' +---------------- 4 ----------------\n'
  1528. ' | ValueError: 3\n'
  1529. ' +---------------- 5 ----------------\n'
  1530. ' | ValueError: 4\n'
  1531. ' +---------------- 6 ----------------\n'
  1532. ' | ValueError: 5\n'
  1533. ' +---------------- 7 ----------------\n'
  1534. ' | ValueError: 6\n'
  1535. ' +---------------- 8 ----------------\n'
  1536. ' | ValueError: 7\n'
  1537. ' +---------------- 9 ----------------\n'
  1538. ' | ValueError: 8\n'
  1539. ' +---------------- 10 ----------------\n'
  1540. ' | ValueError: 9\n'
  1541. ' +---------------- 11 ----------------\n'
  1542. ' | ValueError: 10\n'
  1543. ' +---------------- 12 ----------------\n'
  1544. ' | ValueError: 11\n'
  1545. ' +---------------- 13 ----------------\n'
  1546. ' | ValueError: 12\n'
  1547. ' +---------------- 14 ----------------\n'
  1548. ' | ValueError: 13\n'
  1549. ' +---------------- 15 ----------------\n'
  1550. ' | ValueError: 14\n'
  1551. ' +---------------- ... ----------------\n'
  1552. ' | and 985 more exceptions\n'
  1553. ' +------------------------------------\n')
  1554. report = self.get_report(eg)
  1555. self.assertEqual(report, expected)
  1556. def test_exception_group_depth_limit(self):
  1557. exc = TypeError('bad type')
  1558. for i in range(1000):
  1559. exc = ExceptionGroup(
  1560. f'eg{i}',
  1561. [ValueError(i), exc, ValueError(-i)])
  1562. expected = (' | ExceptionGroup: eg999 (3 sub-exceptions)\n'
  1563. ' +-+---------------- 1 ----------------\n'
  1564. ' | ValueError: 999\n'
  1565. ' +---------------- 2 ----------------\n'
  1566. ' | ExceptionGroup: eg998 (3 sub-exceptions)\n'
  1567. ' +-+---------------- 1 ----------------\n'
  1568. ' | ValueError: 998\n'
  1569. ' +---------------- 2 ----------------\n'
  1570. ' | ExceptionGroup: eg997 (3 sub-exceptions)\n'
  1571. ' +-+---------------- 1 ----------------\n'
  1572. ' | ValueError: 997\n'
  1573. ' +---------------- 2 ----------------\n'
  1574. ' | ExceptionGroup: eg996 (3 sub-exceptions)\n'
  1575. ' +-+---------------- 1 ----------------\n'
  1576. ' | ValueError: 996\n'
  1577. ' +---------------- 2 ----------------\n'
  1578. ' | ExceptionGroup: eg995 (3 sub-exceptions)\n'
  1579. ' +-+---------------- 1 ----------------\n'
  1580. ' | ValueError: 995\n'
  1581. ' +---------------- 2 ----------------\n'
  1582. ' | ExceptionGroup: eg994 (3 sub-exceptions)\n'
  1583. ' +-+---------------- 1 ----------------\n'
  1584. ' | ValueError: 994\n'
  1585. ' +---------------- 2 ----------------\n'
  1586. ' | ExceptionGroup: eg993 (3 sub-exceptions)\n'
  1587. ' +-+---------------- 1 ----------------\n'
  1588. ' | ValueError: 993\n'
  1589. ' +---------------- 2 ----------------\n'
  1590. ' | ExceptionGroup: eg992 (3 sub-exceptions)\n'
  1591. ' +-+---------------- 1 ----------------\n'
  1592. ' | ValueError: 992\n'
  1593. ' +---------------- 2 ----------------\n'
  1594. ' | ExceptionGroup: eg991 (3 sub-exceptions)\n'
  1595. ' +-+---------------- 1 ----------------\n'
  1596. ' | ValueError: 991\n'
  1597. ' +---------------- 2 ----------------\n'
  1598. ' | ExceptionGroup: eg990 (3 sub-exceptions)\n'
  1599. ' +-+---------------- 1 ----------------\n'
  1600. ' | ValueError: 990\n'
  1601. ' +---------------- 2 ----------------\n'
  1602. ' | ... (max_group_depth is 10)\n'
  1603. ' +---------------- 3 ----------------\n'
  1604. ' | ValueError: -990\n'
  1605. ' +------------------------------------\n'
  1606. ' +---------------- 3 ----------------\n'
  1607. ' | ValueError: -991\n'
  1608. ' +------------------------------------\n'
  1609. ' +---------------- 3 ----------------\n'
  1610. ' | ValueError: -992\n'
  1611. ' +------------------------------------\n'
  1612. ' +---------------- 3 ----------------\n'
  1613. ' | ValueError: -993\n'
  1614. ' +------------------------------------\n'
  1615. ' +---------------- 3 ----------------\n'
  1616. ' | ValueError: -994\n'
  1617. ' +------------------------------------\n'
  1618. ' +---------------- 3 ----------------\n'
  1619. ' | ValueError: -995\n'
  1620. ' +------------------------------------\n'
  1621. ' +---------------- 3 ----------------\n'
  1622. ' | ValueError: -996\n'
  1623. ' +------------------------------------\n'
  1624. ' +---------------- 3 ----------------\n'
  1625. ' | ValueError: -997\n'
  1626. ' +------------------------------------\n'
  1627. ' +---------------- 3 ----------------\n'
  1628. ' | ValueError: -998\n'
  1629. ' +------------------------------------\n'
  1630. ' +---------------- 3 ----------------\n'
  1631. ' | ValueError: -999\n'
  1632. ' +------------------------------------\n')
  1633. report = self.get_report(exc)
  1634. self.assertEqual(report, expected)
  1635. def test_exception_group_with_notes(self):
  1636. def exc():
  1637. try:
  1638. excs = []
  1639. for msg in ['bad value', 'terrible value']:
  1640. try:
  1641. raise ValueError(msg)
  1642. except ValueError as e:
  1643. e.add_note(f'the {msg}')
  1644. excs.append(e)
  1645. raise ExceptionGroup("nested", excs)
  1646. except ExceptionGroup as e:
  1647. e.add_note(('>> Multi line note\n'
  1648. '>> Because I am such\n'
  1649. '>> an important exception.\n'
  1650. '>> empty lines work too\n'
  1651. '\n'
  1652. '(that was an empty line)'))
  1653. raise
  1654. expected = (f' + Exception Group Traceback (most recent call last):\n'
  1655. f' | File "{__file__}", line {self.callable_line}, in get_exception\n'
  1656. f' | exception_or_callable()\n'
  1657. f' | File "{__file__}", line {exc.__code__.co_firstlineno + 9}, in exc\n'
  1658. f' | raise ExceptionGroup("nested", excs)\n'
  1659. f' | ExceptionGroup: nested (2 sub-exceptions)\n'
  1660. f' | >> Multi line note\n'
  1661. f' | >> Because I am such\n'
  1662. f' | >> an important exception.\n'
  1663. f' | >> empty lines work too\n'
  1664. f' | \n'
  1665. f' | (that was an empty line)\n'
  1666. f' +-+---------------- 1 ----------------\n'
  1667. f' | Traceback (most recent call last):\n'
  1668. f' | File "{__file__}", line {exc.__code__.co_firstlineno + 5}, in exc\n'
  1669. f' | raise ValueError(msg)\n'
  1670. f' | ValueError: bad value\n'
  1671. f' | the bad value\n'
  1672. f' +---------------- 2 ----------------\n'
  1673. f' | Traceback (most recent call last):\n'
  1674. f' | File "{__file__}", line {exc.__code__.co_firstlineno + 5}, in exc\n'
  1675. f' | raise ValueError(msg)\n'
  1676. f' | ValueError: terrible value\n'
  1677. f' | the terrible value\n'
  1678. f' +------------------------------------\n')
  1679. report = self.get_report(exc)
  1680. self.assertEqual(report, expected)
  1681. def test_exception_group_with_multiple_notes(self):
  1682. def exc():
  1683. try:
  1684. excs = []
  1685. for msg in ['bad value', 'terrible value']:
  1686. try:
  1687. raise ValueError(msg)
  1688. except ValueError as e:
  1689. e.add_note(f'the {msg}')
  1690. e.add_note(f'Goodbye {msg}')
  1691. excs.append(e)
  1692. raise ExceptionGroup("nested", excs)
  1693. except ExceptionGroup as e:
  1694. e.add_note(('>> Multi line note\n'
  1695. '>> Because I am such\n'
  1696. '>> an important exception.\n'
  1697. '>> empty lines work too\n'
  1698. '\n'
  1699. '(that was an empty line)'))
  1700. e.add_note('Goodbye!')
  1701. raise
  1702. expected = (f' + Exception Group Traceback (most recent call last):\n'
  1703. f' | File "{__file__}", line {self.callable_line}, in get_exception\n'
  1704. f' | exception_or_callable()\n'
  1705. f' | File "{__file__}", line {exc.__code__.co_firstlineno + 10}, in exc\n'
  1706. f' | raise ExceptionGroup("nested", excs)\n'
  1707. f' | ExceptionGroup: nested (2 sub-exceptions)\n'
  1708. f' | >> Multi line note\n'
  1709. f' | >> Because I am such\n'
  1710. f' | >> an important exception.\n'
  1711. f' | >> empty lines work too\n'
  1712. f' | \n'
  1713. f' | (that was an empty line)\n'
  1714. f' | Goodbye!\n'
  1715. f' +-+---------------- 1 ----------------\n'
  1716. f' | Traceback (most recent call last):\n'
  1717. f' | File "{__file__}", line {exc.__code__.co_firstlineno + 5}, in exc\n'
  1718. f' | raise ValueError(msg)\n'
  1719. f' | ValueError: bad value\n'
  1720. f' | the bad value\n'
  1721. f' | Goodbye bad value\n'
  1722. f' +---------------- 2 ----------------\n'
  1723. f' | Traceback (most recent call last):\n'
  1724. f' | File "{__file__}", line {exc.__code__.co_firstlineno + 5}, in exc\n'
  1725. f' | raise ValueError(msg)\n'
  1726. f' | ValueError: terrible value\n'
  1727. f' | the terrible value\n'
  1728. f' | Goodbye terrible value\n'
  1729. f' +------------------------------------\n')
  1730. report = self.get_report(exc)
  1731. self.assertEqual(report, expected)
  1732. def test_KeyboardInterrupt_at_first_line_of_frame(self):
  1733. # see GH-93249
  1734. def f():
  1735. return sys._getframe()
  1736. tb_next = None
  1737. frame = f()
  1738. lasti = 0
  1739. lineno = f.__code__.co_firstlineno
  1740. tb = types.TracebackType(tb_next, frame, lasti, lineno)
  1741. exc = KeyboardInterrupt()
  1742. exc.__traceback__ = tb
  1743. expected = (f'Traceback (most recent call last):\n'
  1744. f' File "{__file__}", line {lineno}, in f\n'
  1745. f' def f():\n'
  1746. f'\n'
  1747. f'KeyboardInterrupt\n')
  1748. report = self.get_report(exc)
  1749. # remove trailing writespace:
  1750. report = '\n'.join([l.rstrip() for l in report.split('\n')])
  1751. self.assertEqual(report, expected)
  1752. class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
  1753. #
  1754. # This checks reporting through the 'traceback' module, with both
  1755. # format_exception() and print_exception().
  1756. #
  1757. def get_report(self, e):
  1758. e = self.get_exception(e)
  1759. s = ''.join(
  1760. traceback.format_exception(type(e), e, e.__traceback__))
  1761. with captured_output("stderr") as sio:
  1762. traceback.print_exception(type(e), e, e.__traceback__)
  1763. self.assertEqual(sio.getvalue(), s)
  1764. return s
  1765. class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
  1766. #
  1767. # This checks built-in reporting by the interpreter.
  1768. #
  1769. @cpython_only
  1770. def get_report(self, e):
  1771. from _testcapi import exception_print
  1772. e = self.get_exception(e)
  1773. with captured_output("stderr") as s:
  1774. exception_print(e)
  1775. return s.getvalue()
  1776. class LimitTests(unittest.TestCase):
  1777. ''' Tests for limit argument.
  1778. It's enough to test extact_tb, extract_stack and format_exception '''
  1779. def last_raises1(self):
  1780. raise Exception('Last raised')
  1781. def last_raises2(self):
  1782. self.last_raises1()
  1783. def last_raises3(self):
  1784. self.last_raises2()
  1785. def last_raises4(self):
  1786. self.last_raises3()
  1787. def last_raises5(self):
  1788. self.last_raises4()
  1789. def last_returns_frame1(self):
  1790. return sys._getframe()
  1791. def last_returns_frame2(self):
  1792. return self.last_returns_frame1()
  1793. def last_returns_frame3(self):
  1794. return self.last_returns_frame2()
  1795. def last_returns_frame4(self):
  1796. return self.last_returns_frame3()
  1797. def last_returns_frame5(self):
  1798. return self.last_returns_frame4()
  1799. def test_extract_stack(self):
  1800. frame = self.last_returns_frame5()
  1801. def extract(**kwargs):
  1802. return traceback.extract_stack(frame, **kwargs)
  1803. def assertEqualExcept(actual, expected, ignore):
  1804. self.assertEqual(actual[:ignore], expected[:ignore])
  1805. self.assertEqual(actual[ignore+1:], expected[ignore+1:])
  1806. self.assertEqual(len(actual), len(expected))
  1807. with support.swap_attr(sys, 'tracebacklimit', 1000):
  1808. nolim = extract()
  1809. self.assertGreater(len(nolim), 5)
  1810. self.assertEqual(extract(limit=2), nolim[-2:])
  1811. assertEqualExcept(extract(limit=100), nolim[-100:], -5-1)
  1812. self.assertEqual(extract(limit=-2), nolim[:2])
  1813. assertEqualExcept(extract(limit=-100), nolim[:100], len(nolim)-5-1)
  1814. self.assertEqual(extract(limit=0), [])
  1815. del sys.tracebacklimit
  1816. assertEqualExcept(extract(), nolim, -5-1)
  1817. sys.tracebacklimit = 2
  1818. self.assertEqual(extract(), nolim[-2:])
  1819. self.assertEqual(extract(limit=3), nolim[-3:])
  1820. self.assertEqual(extract(limit=-3), nolim[:3])
  1821. sys.tracebacklimit = 0
  1822. self.assertEqual(extract(), [])
  1823. sys.tracebacklimit = -1
  1824. self.assertEqual(extract(), [])
  1825. def test_extract_tb(self):
  1826. try:
  1827. self.last_raises5()
  1828. except Exception:
  1829. exc_type, exc_value, tb = sys.exc_info()
  1830. def extract(**kwargs):
  1831. return traceback.extract_tb(tb, **kwargs)
  1832. with support.swap_attr(sys, 'tracebacklimit', 1000):
  1833. nolim = extract()
  1834. self.assertEqual(len(nolim), 5+1)
  1835. self.assertEqual(extract(limit=2), nolim[:2])
  1836. self.assertEqual(extract(limit=10), nolim)
  1837. self.assertEqual(extract(limit=-2), nolim[-2:])
  1838. self.assertEqual(extract(limit=-10), nolim)
  1839. self.assertEqual(extract(limit=0), [])
  1840. del sys.tracebacklimit
  1841. self.assertEqual(extract(), nolim)
  1842. sys.tracebacklimit = 2
  1843. self.assertEqual(extract(), nolim[:2])
  1844. self.assertEqual(extract(limit=3), nolim[:3])
  1845. self.assertEqual(extract(limit=-3), nolim[-3:])
  1846. sys.tracebacklimit = 0
  1847. self.assertEqual(extract(), [])
  1848. sys.tracebacklimit = -1
  1849. self.assertEqual(extract(), [])
  1850. def test_format_exception(self):
  1851. try:
  1852. self.last_raises5()
  1853. except Exception:
  1854. exc_type, exc_value, tb = sys.exc_info()
  1855. # [1:-1] to exclude "Traceback (...)" header and
  1856. # exception type and value
  1857. def extract(**kwargs):
  1858. return traceback.format_exception(exc_type, exc_value, tb, **kwargs)[1:-1]
  1859. with support.swap_attr(sys, 'tracebacklimit', 1000):
  1860. nolim = extract()
  1861. self.assertEqual(len(nolim), 5+1)
  1862. self.assertEqual(extract(limit=2), nolim[:2])
  1863. self.assertEqual(extract(limit=10), nolim)
  1864. self.assertEqual(extract(limit=-2), nolim[-2:])
  1865. self.assertEqual(extract(limit=-10), nolim)
  1866. self.assertEqual(extract(limit=0), [])
  1867. del sys.tracebacklimit
  1868. self.assertEqual(extract(), nolim)
  1869. sys.tracebacklimit = 2
  1870. self.assertEqual(extract(), nolim[:2])
  1871. self.assertEqual(extract(limit=3), nolim[:3])
  1872. self.assertEqual(extract(limit=-3), nolim[-3:])
  1873. sys.tracebacklimit = 0
  1874. self.assertEqual(extract(), [])
  1875. sys.tracebacklimit = -1
  1876. self.assertEqual(extract(), [])
  1877. class MiscTracebackCases(unittest.TestCase):
  1878. #
  1879. # Check non-printing functions in traceback module
  1880. #
  1881. def test_clear(self):
  1882. def outer():
  1883. middle()
  1884. def middle():
  1885. inner()
  1886. def inner():
  1887. i = 1
  1888. 1/0
  1889. try:
  1890. outer()
  1891. except:
  1892. type_, value, tb = sys.exc_info()
  1893. # Initial assertion: there's one local in the inner frame.
  1894. inner_frame = tb.tb_next.tb_next.tb_next.tb_frame
  1895. self.assertEqual(len(inner_frame.f_locals), 1)
  1896. # Clear traceback frames
  1897. traceback.clear_frames(tb)
  1898. # Local variable dict should now be empty.
  1899. self.assertEqual(len(inner_frame.f_locals), 0)
  1900. def test_extract_stack(self):
  1901. def extract():
  1902. return traceback.extract_stack()
  1903. result = extract()
  1904. lineno = extract.__code__.co_firstlineno
  1905. self.assertEqual(result[-2:], [
  1906. (__file__, lineno+2, 'test_extract_stack', 'result = extract()'),
  1907. (__file__, lineno+1, 'extract', 'return traceback.extract_stack()'),
  1908. ])
  1909. self.assertEqual(len(result[0]), 4)
  1910. class TestFrame(unittest.TestCase):
  1911. def test_basics(self):
  1912. linecache.clearcache()
  1913. linecache.lazycache("f", globals())
  1914. f = traceback.FrameSummary("f", 1, "dummy")
  1915. self.assertEqual(f,
  1916. ("f", 1, "dummy", '"""Test cases for traceback module"""'))
  1917. self.assertEqual(tuple(f),
  1918. ("f", 1, "dummy", '"""Test cases for traceback module"""'))
  1919. self.assertEqual(f, traceback.FrameSummary("f", 1, "dummy"))
  1920. self.assertEqual(f, tuple(f))
  1921. # Since tuple.__eq__ doesn't support FrameSummary, the equality
  1922. # operator fallbacks to FrameSummary.__eq__.
  1923. self.assertEqual(tuple(f), f)
  1924. self.assertIsNone(f.locals)
  1925. self.assertNotEqual(f, object())
  1926. self.assertEqual(f, ALWAYS_EQ)
  1927. def test_lazy_lines(self):
  1928. linecache.clearcache()
  1929. f = traceback.FrameSummary("f", 1, "dummy", lookup_line=False)
  1930. self.assertEqual(None, f._line)
  1931. linecache.lazycache("f", globals())
  1932. self.assertEqual(
  1933. '"""Test cases for traceback module"""',
  1934. f.line)
  1935. def test_no_line(self):
  1936. f = traceback.FrameSummary("f", None, "dummy")
  1937. self.assertEqual(f.line, None)
  1938. def test_explicit_line(self):
  1939. f = traceback.FrameSummary("f", 1, "dummy", line="line")
  1940. self.assertEqual("line", f.line)
  1941. def test_len(self):
  1942. f = traceback.FrameSummary("f", 1, "dummy", line="line")
  1943. self.assertEqual(len(f), 4)
  1944. class TestStack(unittest.TestCase):
  1945. def test_walk_stack(self):
  1946. def deeper():
  1947. return list(traceback.walk_stack(None))
  1948. s1 = list(traceback.walk_stack(None))
  1949. s2 = deeper()
  1950. self.assertEqual(len(s2) - len(s1), 1)
  1951. self.assertEqual(s2[1:], s1)
  1952. def test_walk_tb(self):
  1953. try:
  1954. 1/0
  1955. except Exception:
  1956. _, _, tb = sys.exc_info()
  1957. s = list(traceback.walk_tb(tb))
  1958. self.assertEqual(len(s), 1)
  1959. def test_extract_stack(self):
  1960. s = traceback.StackSummary.extract(traceback.walk_stack(None))
  1961. self.assertIsInstance(s, traceback.StackSummary)
  1962. def test_extract_stack_limit(self):
  1963. s = traceback.StackSummary.extract(traceback.walk_stack(None), limit=5)
  1964. self.assertEqual(len(s), 5)
  1965. def test_extract_stack_lookup_lines(self):
  1966. linecache.clearcache()
  1967. linecache.updatecache('/foo.py', globals())
  1968. c = test_code('/foo.py', 'method')
  1969. f = test_frame(c, None, None)
  1970. s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=True)
  1971. linecache.clearcache()
  1972. self.assertEqual(s[0].line, "import sys")
  1973. def test_extract_stackup_deferred_lookup_lines(self):
  1974. linecache.clearcache()
  1975. c = test_code('/foo.py', 'method')
  1976. f = test_frame(c, None, None)
  1977. s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=False)
  1978. self.assertEqual({}, linecache.cache)
  1979. linecache.updatecache('/foo.py', globals())
  1980. self.assertEqual(s[0].line, "import sys")
  1981. def test_from_list(self):
  1982. s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
  1983. self.assertEqual(
  1984. [' File "foo.py", line 1, in fred\n line\n'],
  1985. s.format())
  1986. def test_from_list_edited_stack(self):
  1987. s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
  1988. s[0] = ('foo.py', 2, 'fred', 'line')
  1989. s2 = traceback.StackSummary.from_list(s)
  1990. self.assertEqual(
  1991. [' File "foo.py", line 2, in fred\n line\n'],
  1992. s2.format())
  1993. def test_format_smoke(self):
  1994. # For detailed tests see the format_list tests, which consume the same
  1995. # code.
  1996. s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
  1997. self.assertEqual(
  1998. [' File "foo.py", line 1, in fred\n line\n'],
  1999. s.format())
  2000. def test_locals(self):
  2001. linecache.updatecache('/foo.py', globals())
  2002. c = test_code('/foo.py', 'method')
  2003. f = test_frame(c, globals(), {'something': 1})
  2004. s = traceback.StackSummary.extract(iter([(f, 6)]), capture_locals=True)
  2005. self.assertEqual(s[0].locals, {'something': '1'})
  2006. def test_no_locals(self):
  2007. linecache.updatecache('/foo.py', globals())
  2008. c = test_code('/foo.py', 'method')
  2009. f = test_frame(c, globals(), {'something': 1})
  2010. s = traceback.StackSummary.extract(iter([(f, 6)]))
  2011. self.assertEqual(s[0].locals, None)
  2012. def test_format_locals(self):
  2013. def some_inner(k, v):
  2014. a = 1
  2015. b = 2
  2016. return traceback.StackSummary.extract(
  2017. traceback.walk_stack(None), capture_locals=True, limit=1)
  2018. s = some_inner(3, 4)
  2019. self.assertEqual(
  2020. [' File "%s", line %d, in some_inner\n'
  2021. ' return traceback.StackSummary.extract(\n'
  2022. ' a = 1\n'
  2023. ' b = 2\n'
  2024. ' k = 3\n'
  2025. ' v = 4\n' % (__file__, some_inner.__code__.co_firstlineno + 3)
  2026. ], s.format())
  2027. def test_custom_format_frame(self):
  2028. class CustomStackSummary(traceback.StackSummary):
  2029. def format_frame_summary(self, frame_summary):
  2030. return f'{frame_summary.filename}:{frame_summary.lineno}'
  2031. def some_inner():
  2032. return CustomStackSummary.extract(
  2033. traceback.walk_stack(None), limit=1)
  2034. s = some_inner()
  2035. self.assertEqual(
  2036. s.format(),
  2037. [f'{__file__}:{some_inner.__code__.co_firstlineno + 1}'])
  2038. def test_dropping_frames(self):
  2039. def f():
  2040. 1/0
  2041. def g():
  2042. try:
  2043. f()
  2044. except:
  2045. return sys.exc_info()
  2046. exc_info = g()
  2047. class Skip_G(traceback.StackSummary):
  2048. def format_frame_summary(self, frame_summary):
  2049. if frame_summary.name == 'g':
  2050. return None
  2051. return super().format_frame_summary(frame_summary)
  2052. stack = Skip_G.extract(
  2053. traceback.walk_tb(exc_info[2])).format()
  2054. self.assertEqual(len(stack), 1)
  2055. lno = f.__code__.co_firstlineno + 1
  2056. self.assertEqual(
  2057. stack[0],
  2058. f' File "{__file__}", line {lno}, in f\n 1/0\n'
  2059. )
  2060. class TestTracebackException(unittest.TestCase):
  2061. def test_smoke(self):
  2062. try:
  2063. 1/0
  2064. except Exception:
  2065. exc_info = sys.exc_info()
  2066. exc = traceback.TracebackException(*exc_info)
  2067. expected_stack = traceback.StackSummary.extract(
  2068. traceback.walk_tb(exc_info[2]))
  2069. self.assertEqual(None, exc.__cause__)
  2070. self.assertEqual(None, exc.__context__)
  2071. self.assertEqual(False, exc.__suppress_context__)
  2072. self.assertEqual(expected_stack, exc.stack)
  2073. self.assertEqual(exc_info[0], exc.exc_type)
  2074. self.assertEqual(str(exc_info[1]), str(exc))
  2075. def test_from_exception(self):
  2076. # Check all the parameters are accepted.
  2077. def foo():
  2078. 1/0
  2079. try:
  2080. foo()
  2081. except Exception as e:
  2082. exc_info = sys.exc_info()
  2083. self.expected_stack = traceback.StackSummary.extract(
  2084. traceback.walk_tb(exc_info[2]), limit=1, lookup_lines=False,
  2085. capture_locals=True)
  2086. self.exc = traceback.TracebackException.from_exception(
  2087. e, limit=1, lookup_lines=False, capture_locals=True)
  2088. expected_stack = self.expected_stack
  2089. exc = self.exc
  2090. self.assertEqual(None, exc.__cause__)
  2091. self.assertEqual(None, exc.__context__)
  2092. self.assertEqual(False, exc.__suppress_context__)
  2093. self.assertEqual(expected_stack, exc.stack)
  2094. self.assertEqual(exc_info[0], exc.exc_type)
  2095. self.assertEqual(str(exc_info[1]), str(exc))
  2096. def test_cause(self):
  2097. try:
  2098. try:
  2099. 1/0
  2100. finally:
  2101. exc_info_context = sys.exc_info()
  2102. exc_context = traceback.TracebackException(*exc_info_context)
  2103. cause = Exception("cause")
  2104. raise Exception("uh oh") from cause
  2105. except Exception:
  2106. exc_info = sys.exc_info()
  2107. exc = traceback.TracebackException(*exc_info)
  2108. expected_stack = traceback.StackSummary.extract(
  2109. traceback.walk_tb(exc_info[2]))
  2110. exc_cause = traceback.TracebackException(Exception, cause, None)
  2111. self.assertEqual(exc_cause, exc.__cause__)
  2112. self.assertEqual(exc_context, exc.__context__)
  2113. self.assertEqual(True, exc.__suppress_context__)
  2114. self.assertEqual(expected_stack, exc.stack)
  2115. self.assertEqual(exc_info[0], exc.exc_type)
  2116. self.assertEqual(str(exc_info[1]), str(exc))
  2117. def test_context(self):
  2118. try:
  2119. try:
  2120. 1/0
  2121. finally:
  2122. exc_info_context = sys.exc_info()
  2123. exc_context = traceback.TracebackException(*exc_info_context)
  2124. raise Exception("uh oh")
  2125. except Exception:
  2126. exc_info = sys.exc_info()
  2127. exc = traceback.TracebackException(*exc_info)
  2128. expected_stack = traceback.StackSummary.extract(
  2129. traceback.walk_tb(exc_info[2]))
  2130. self.assertEqual(None, exc.__cause__)
  2131. self.assertEqual(exc_context, exc.__context__)
  2132. self.assertEqual(False, exc.__suppress_context__)
  2133. self.assertEqual(expected_stack, exc.stack)
  2134. self.assertEqual(exc_info[0], exc.exc_type)
  2135. self.assertEqual(str(exc_info[1]), str(exc))
  2136. def test_long_context_chain(self):
  2137. def f():
  2138. try:
  2139. 1/0
  2140. except:
  2141. f()
  2142. try:
  2143. f()
  2144. except RecursionError:
  2145. exc_info = sys.exc_info()
  2146. else:
  2147. self.fail("Exception not raised")
  2148. te = traceback.TracebackException(*exc_info)
  2149. res = list(te.format())
  2150. # many ZeroDiv errors followed by the RecursionError
  2151. self.assertGreater(len(res), sys.getrecursionlimit())
  2152. self.assertGreater(
  2153. len([l for l in res if 'ZeroDivisionError:' in l]),
  2154. sys.getrecursionlimit() * 0.5)
  2155. self.assertIn(
  2156. "RecursionError: maximum recursion depth exceeded", res[-1])
  2157. def test_compact_with_cause(self):
  2158. try:
  2159. try:
  2160. 1/0
  2161. finally:
  2162. cause = Exception("cause")
  2163. raise Exception("uh oh") from cause
  2164. except Exception:
  2165. exc_info = sys.exc_info()
  2166. exc = traceback.TracebackException(*exc_info, compact=True)
  2167. expected_stack = traceback.StackSummary.extract(
  2168. traceback.walk_tb(exc_info[2]))
  2169. exc_cause = traceback.TracebackException(Exception, cause, None)
  2170. self.assertEqual(exc_cause, exc.__cause__)
  2171. self.assertEqual(None, exc.__context__)
  2172. self.assertEqual(True, exc.__suppress_context__)
  2173. self.assertEqual(expected_stack, exc.stack)
  2174. self.assertEqual(exc_info[0], exc.exc_type)
  2175. self.assertEqual(str(exc_info[1]), str(exc))
  2176. def test_compact_no_cause(self):
  2177. try:
  2178. try:
  2179. 1/0
  2180. finally:
  2181. exc_info_context = sys.exc_info()
  2182. exc_context = traceback.TracebackException(*exc_info_context)
  2183. raise Exception("uh oh")
  2184. except Exception:
  2185. exc_info = sys.exc_info()
  2186. exc = traceback.TracebackException(*exc_info, compact=True)
  2187. expected_stack = traceback.StackSummary.extract(
  2188. traceback.walk_tb(exc_info[2]))
  2189. self.assertEqual(None, exc.__cause__)
  2190. self.assertEqual(exc_context, exc.__context__)
  2191. self.assertEqual(False, exc.__suppress_context__)
  2192. self.assertEqual(expected_stack, exc.stack)
  2193. self.assertEqual(exc_info[0], exc.exc_type)
  2194. self.assertEqual(str(exc_info[1]), str(exc))
  2195. def test_no_refs_to_exception_and_traceback_objects(self):
  2196. try:
  2197. 1/0
  2198. except Exception:
  2199. exc_info = sys.exc_info()
  2200. refcnt1 = sys.getrefcount(exc_info[1])
  2201. refcnt2 = sys.getrefcount(exc_info[2])
  2202. exc = traceback.TracebackException(*exc_info)
  2203. self.assertEqual(sys.getrefcount(exc_info[1]), refcnt1)
  2204. self.assertEqual(sys.getrefcount(exc_info[2]), refcnt2)
  2205. def test_comparison_basic(self):
  2206. try:
  2207. 1/0
  2208. except Exception:
  2209. exc_info = sys.exc_info()
  2210. exc = traceback.TracebackException(*exc_info)
  2211. exc2 = traceback.TracebackException(*exc_info)
  2212. self.assertIsNot(exc, exc2)
  2213. self.assertEqual(exc, exc2)
  2214. self.assertNotEqual(exc, object())
  2215. self.assertEqual(exc, ALWAYS_EQ)
  2216. def test_comparison_params_variations(self):
  2217. def raise_exc():
  2218. try:
  2219. raise ValueError('bad value')
  2220. except:
  2221. raise
  2222. def raise_with_locals():
  2223. x, y = 1, 2
  2224. raise_exc()
  2225. try:
  2226. raise_with_locals()
  2227. except Exception:
  2228. exc_info = sys.exc_info()
  2229. exc = traceback.TracebackException(*exc_info)
  2230. exc1 = traceback.TracebackException(*exc_info, limit=10)
  2231. exc2 = traceback.TracebackException(*exc_info, limit=2)
  2232. self.assertEqual(exc, exc1) # limit=10 gets all frames
  2233. self.assertNotEqual(exc, exc2) # limit=2 truncates the output
  2234. # locals change the output
  2235. exc3 = traceback.TracebackException(*exc_info, capture_locals=True)
  2236. self.assertNotEqual(exc, exc3)
  2237. # there are no locals in the innermost frame
  2238. exc4 = traceback.TracebackException(*exc_info, limit=-1)
  2239. exc5 = traceback.TracebackException(*exc_info, limit=-1, capture_locals=True)
  2240. self.assertEqual(exc4, exc5)
  2241. # there are locals in the next-to-innermost frame
  2242. exc6 = traceback.TracebackException(*exc_info, limit=-2)
  2243. exc7 = traceback.TracebackException(*exc_info, limit=-2, capture_locals=True)
  2244. self.assertNotEqual(exc6, exc7)
  2245. def test_comparison_equivalent_exceptions_are_equal(self):
  2246. excs = []
  2247. for _ in range(2):
  2248. try:
  2249. 1/0
  2250. except:
  2251. excs.append(traceback.TracebackException(*sys.exc_info()))
  2252. self.assertEqual(excs[0], excs[1])
  2253. self.assertEqual(list(excs[0].format()), list(excs[1].format()))
  2254. def test_unhashable(self):
  2255. class UnhashableException(Exception):
  2256. def __eq__(self, other):
  2257. return True
  2258. ex1 = UnhashableException('ex1')
  2259. ex2 = UnhashableException('ex2')
  2260. try:
  2261. raise ex2 from ex1
  2262. except UnhashableException:
  2263. try:
  2264. raise ex1
  2265. except UnhashableException:
  2266. exc_info = sys.exc_info()
  2267. exc = traceback.TracebackException(*exc_info)
  2268. formatted = list(exc.format())
  2269. self.assertIn('UnhashableException: ex2\n', formatted[2])
  2270. self.assertIn('UnhashableException: ex1\n', formatted[6])
  2271. def test_limit(self):
  2272. def recurse(n):
  2273. if n:
  2274. recurse(n-1)
  2275. else:
  2276. 1/0
  2277. try:
  2278. recurse(10)
  2279. except Exception:
  2280. exc_info = sys.exc_info()
  2281. exc = traceback.TracebackException(*exc_info, limit=5)
  2282. expected_stack = traceback.StackSummary.extract(
  2283. traceback.walk_tb(exc_info[2]), limit=5)
  2284. self.assertEqual(expected_stack, exc.stack)
  2285. def test_lookup_lines(self):
  2286. linecache.clearcache()
  2287. e = Exception("uh oh")
  2288. c = test_code('/foo.py', 'method')
  2289. f = test_frame(c, None, None)
  2290. tb = test_tb(f, 6, None, 0)
  2291. exc = traceback.TracebackException(Exception, e, tb, lookup_lines=False)
  2292. self.assertEqual(linecache.cache, {})
  2293. linecache.updatecache('/foo.py', globals())
  2294. self.assertEqual(exc.stack[0].line, "import sys")
  2295. def test_locals(self):
  2296. linecache.updatecache('/foo.py', globals())
  2297. e = Exception("uh oh")
  2298. c = test_code('/foo.py', 'method')
  2299. f = test_frame(c, globals(), {'something': 1, 'other': 'string'})
  2300. tb = test_tb(f, 6, None, 0)
  2301. exc = traceback.TracebackException(
  2302. Exception, e, tb, capture_locals=True)
  2303. self.assertEqual(
  2304. exc.stack[0].locals, {'something': '1', 'other': "'string'"})
  2305. def test_no_locals(self):
  2306. linecache.updatecache('/foo.py', globals())
  2307. e = Exception("uh oh")
  2308. c = test_code('/foo.py', 'method')
  2309. f = test_frame(c, globals(), {'something': 1})
  2310. tb = test_tb(f, 6, None, 0)
  2311. exc = traceback.TracebackException(Exception, e, tb)
  2312. self.assertEqual(exc.stack[0].locals, None)
  2313. def test_traceback_header(self):
  2314. # do not print a traceback header if exc_traceback is None
  2315. # see issue #24695
  2316. exc = traceback.TracebackException(Exception, Exception("haven"), None)
  2317. self.assertEqual(list(exc.format()), ["Exception: haven\n"])
  2318. @requires_debug_ranges()
  2319. def test_print(self):
  2320. def f():
  2321. x = 12
  2322. try:
  2323. x/0
  2324. except Exception:
  2325. return sys.exc_info()
  2326. exc = traceback.TracebackException(*f(), capture_locals=True)
  2327. output = StringIO()
  2328. exc.print(file=output)
  2329. self.assertEqual(
  2330. output.getvalue().split('\n')[-5:],
  2331. [' x/0',
  2332. ' ~^~',
  2333. ' x = 12',
  2334. 'ZeroDivisionError: division by zero',
  2335. ''])
  2336. class TestTracebackException_ExceptionGroups(unittest.TestCase):
  2337. def setUp(self):
  2338. super().setUp()
  2339. self.eg_info = self._get_exception_group()
  2340. def _get_exception_group(self):
  2341. def f():
  2342. 1/0
  2343. def g(v):
  2344. raise ValueError(v)
  2345. self.lno_f = f.__code__.co_firstlineno
  2346. self.lno_g = g.__code__.co_firstlineno
  2347. try:
  2348. try:
  2349. try:
  2350. f()
  2351. except Exception as e:
  2352. exc1 = e
  2353. try:
  2354. g(42)
  2355. except Exception as e:
  2356. exc2 = e
  2357. raise ExceptionGroup("eg1", [exc1, exc2])
  2358. except ExceptionGroup as e:
  2359. exc3 = e
  2360. try:
  2361. g(24)
  2362. except Exception as e:
  2363. exc4 = e
  2364. raise ExceptionGroup("eg2", [exc3, exc4])
  2365. except ExceptionGroup:
  2366. return sys.exc_info()
  2367. self.fail('Exception Not Raised')
  2368. def test_exception_group_construction(self):
  2369. eg_info = self.eg_info
  2370. teg1 = traceback.TracebackException(*eg_info)
  2371. teg2 = traceback.TracebackException.from_exception(eg_info[1])
  2372. self.assertIsNot(teg1, teg2)
  2373. self.assertEqual(teg1, teg2)
  2374. def test_exception_group_format_exception_only(self):
  2375. teg = traceback.TracebackException(*self.eg_info)
  2376. formatted = ''.join(teg.format_exception_only()).split('\n')
  2377. expected = "ExceptionGroup: eg2 (2 sub-exceptions)\n".split('\n')
  2378. self.assertEqual(formatted, expected)
  2379. def test_exception_group_format(self):
  2380. teg = traceback.TracebackException(*self.eg_info)
  2381. formatted = ''.join(teg.format()).split('\n')
  2382. lno_f = self.lno_f
  2383. lno_g = self.lno_g
  2384. expected = [
  2385. f' + Exception Group Traceback (most recent call last):',
  2386. f' | File "{__file__}", line {lno_g+23}, in _get_exception_group',
  2387. f' | raise ExceptionGroup("eg2", [exc3, exc4])',
  2388. f' | ExceptionGroup: eg2 (2 sub-exceptions)',
  2389. f' +-+---------------- 1 ----------------',
  2390. f' | Exception Group Traceback (most recent call last):',
  2391. f' | File "{__file__}", line {lno_g+16}, in _get_exception_group',
  2392. f' | raise ExceptionGroup("eg1", [exc1, exc2])',
  2393. f' | ExceptionGroup: eg1 (2 sub-exceptions)',
  2394. f' +-+---------------- 1 ----------------',
  2395. f' | Traceback (most recent call last):',
  2396. f' | File "{__file__}", line {lno_g+9}, in _get_exception_group',
  2397. f' | f()',
  2398. f' | File "{__file__}", line {lno_f+1}, in f',
  2399. f' | 1/0',
  2400. f' | ~^~',
  2401. f' | ZeroDivisionError: division by zero',
  2402. f' +---------------- 2 ----------------',
  2403. f' | Traceback (most recent call last):',
  2404. f' | File "{__file__}", line {lno_g+13}, in _get_exception_group',
  2405. f' | g(42)',
  2406. f' | File "{__file__}", line {lno_g+1}, in g',
  2407. f' | raise ValueError(v)',
  2408. f' | ValueError: 42',
  2409. f' +------------------------------------',
  2410. f' +---------------- 2 ----------------',
  2411. f' | Traceback (most recent call last):',
  2412. f' | File "{__file__}", line {lno_g+20}, in _get_exception_group',
  2413. f' | g(24)',
  2414. f' | File "{__file__}", line {lno_g+1}, in g',
  2415. f' | raise ValueError(v)',
  2416. f' | ValueError: 24',
  2417. f' +------------------------------------',
  2418. f'']
  2419. self.assertEqual(formatted, expected)
  2420. def test_max_group_width(self):
  2421. excs1 = []
  2422. excs2 = []
  2423. for i in range(3):
  2424. excs1.append(ValueError(i))
  2425. for i in range(10):
  2426. excs2.append(TypeError(i))
  2427. EG = ExceptionGroup
  2428. eg = EG('eg', [EG('eg1', excs1), EG('eg2', excs2)])
  2429. teg = traceback.TracebackException.from_exception(eg, max_group_width=2)
  2430. formatted = ''.join(teg.format()).split('\n')
  2431. expected = [
  2432. f' | ExceptionGroup: eg (2 sub-exceptions)',
  2433. f' +-+---------------- 1 ----------------',
  2434. f' | ExceptionGroup: eg1 (3 sub-exceptions)',
  2435. f' +-+---------------- 1 ----------------',
  2436. f' | ValueError: 0',
  2437. f' +---------------- 2 ----------------',
  2438. f' | ValueError: 1',
  2439. f' +---------------- ... ----------------',
  2440. f' | and 1 more exception',
  2441. f' +------------------------------------',
  2442. f' +---------------- 2 ----------------',
  2443. f' | ExceptionGroup: eg2 (10 sub-exceptions)',
  2444. f' +-+---------------- 1 ----------------',
  2445. f' | TypeError: 0',
  2446. f' +---------------- 2 ----------------',
  2447. f' | TypeError: 1',
  2448. f' +---------------- ... ----------------',
  2449. f' | and 8 more exceptions',
  2450. f' +------------------------------------',
  2451. f'']
  2452. self.assertEqual(formatted, expected)
  2453. def test_max_group_depth(self):
  2454. exc = TypeError('bad type')
  2455. for i in range(3):
  2456. exc = ExceptionGroup('exc', [ValueError(-i), exc, ValueError(i)])
  2457. teg = traceback.TracebackException.from_exception(exc, max_group_depth=2)
  2458. formatted = ''.join(teg.format()).split('\n')
  2459. expected = [
  2460. f' | ExceptionGroup: exc (3 sub-exceptions)',
  2461. f' +-+---------------- 1 ----------------',
  2462. f' | ValueError: -2',
  2463. f' +---------------- 2 ----------------',
  2464. f' | ExceptionGroup: exc (3 sub-exceptions)',
  2465. f' +-+---------------- 1 ----------------',
  2466. f' | ValueError: -1',
  2467. f' +---------------- 2 ----------------',
  2468. f' | ... (max_group_depth is 2)',
  2469. f' +---------------- 3 ----------------',
  2470. f' | ValueError: 1',
  2471. f' +------------------------------------',
  2472. f' +---------------- 3 ----------------',
  2473. f' | ValueError: 2',
  2474. f' +------------------------------------',
  2475. f'']
  2476. self.assertEqual(formatted, expected)
  2477. def test_comparison(self):
  2478. try:
  2479. raise self.eg_info[1]
  2480. except ExceptionGroup:
  2481. exc_info = sys.exc_info()
  2482. for _ in range(5):
  2483. try:
  2484. raise exc_info[1]
  2485. except:
  2486. exc_info = sys.exc_info()
  2487. exc = traceback.TracebackException(*exc_info)
  2488. exc2 = traceback.TracebackException(*exc_info)
  2489. exc3 = traceback.TracebackException(*exc_info, limit=300)
  2490. ne = traceback.TracebackException(*exc_info, limit=3)
  2491. self.assertIsNot(exc, exc2)
  2492. self.assertEqual(exc, exc2)
  2493. self.assertEqual(exc, exc3)
  2494. self.assertNotEqual(exc, ne)
  2495. self.assertNotEqual(exc, object())
  2496. self.assertEqual(exc, ALWAYS_EQ)
  2497. class MiscTest(unittest.TestCase):
  2498. def test_all(self):
  2499. expected = set()
  2500. denylist = {'print_list'}
  2501. for name in dir(traceback):
  2502. if name.startswith('_') or name in denylist:
  2503. continue
  2504. module_object = getattr(traceback, name)
  2505. if getattr(module_object, '__module__', None) == 'traceback':
  2506. expected.add(name)
  2507. self.assertCountEqual(traceback.__all__, expected)
  2508. if __name__ == "__main__":
  2509. unittest.main()