]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
(Merge 3.4) Issue #22599: Enhance tokenize.open() to be able to call it during
authorVictor Stinner <victor.stinner@gmail.com>
Fri, 5 Dec 2014 09:18:30 +0000 (10:18 +0100)
committerVictor Stinner <victor.stinner@gmail.com>
Fri, 5 Dec 2014 09:18:30 +0000 (10:18 +0100)
Python finalization.

Before the module kept a reference to the builtins module, but the module
attributes are cleared during Python finalization. Instead, keep directly a
reference to the open() function.

This enhancement is not perfect, calling tokenize.open() can still fail if
called very late during Python finalization.  Usually, the function is called
by the linecache module which is called to display a traceback or emit a
warning.

1  2 
Lib/test/test_traceback.py
Lib/tokenize.py

index e3b28bd5515646e129f15a631356e850c834a3be,c29556354ef49d1b73b6e1793cee1281f3839191..6bd6fa6303300fdad30dedd2ed523f6f1ca8e6a2
@@@ -6,6 -6,6 +6,8 @@@ import unittes
  import re
  from test.support import run_unittest, Error, captured_output
  from test.support import TESTFN, unlink, cpython_only
++from test.script_helper import assert_python_ok
++import textwrap
  
  import traceback
  
@@@ -169,6 -169,6 +171,37 @@@ class SyntaxTracebackCases(unittest.Tes
          # Issue #18960: coding spec should has no effect
          do_test("0\n# coding: GBK\n", "h\xe9 ho", 'utf-8', 5)
  
++    def test_print_traceback_at_exit(self):
++        # Issue #22599: Ensure that it is possible to use the traceback module
++        # to display an exception at Python exit
++        code = textwrap.dedent("""
++            import sys
++            import traceback
++
++            class PrintExceptionAtExit(object):
++                def __init__(self):
++                    try:
++                        x = 1 / 0
++                    except Exception:
++                        self.exc_info = sys.exc_info()
++                        # self.exc_info[1] (traceback) contains frames:
++                        # explicitly clear the reference to self in the current
++                        # frame to break a reference cycle
++                        self = None
++
++                def __del__(self):
++                    traceback.print_exception(*self.exc_info)
++
++            # Keep a reference in the module namespace to call the destructor
++            # when the module is unloaded
++            obj = PrintExceptionAtExit()
++        """)
++        rc, stdout, stderr = assert_python_ok('-c', code)
++        expected = [b'Traceback (most recent call last):',
++                    b'  File "<string>", line 8, in __init__',
++                    b'ZeroDivisionError: division by zero']
++        self.assertEqual(stderr.splitlines(), expected)
++
  
  class TracebackFormatTests(unittest.TestCase):
  
diff --cc Lib/tokenize.py
Simple merge