Skip to content

gh-118761: Improve import time by lazy import of traceback #129811

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Lib/_pyrepl/_threading_handler.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import annotations

from dataclasses import dataclass, field
import traceback


TYPE_CHECKING = False
Expand Down Expand Up @@ -55,6 +54,7 @@ def add(self, s: str) -> None:
self.messages.append(s)

def exception(self, args: ExceptHookArgs) -> None:
import traceback
lines = traceback.format_exception(
args.exc_type,
args.exc_value,
Expand Down
2 changes: 1 addition & 1 deletion Lib/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import builtins
import sys
import traceback
from codeop import CommandCompiler, compile_command

__all__ = ["InteractiveInterpreter", "InteractiveConsole", "interact",
Expand Down Expand Up @@ -161,6 +160,7 @@ def _showtraceback(self, typ, value, tb, source):
def _excepthook(self, typ, value, tb):
# This method is being overwritten in
# _pyrepl.console.InteractiveColoredConsole
import traceback
lines = traceback.format_exception(typ, value, tb)
self.write(''.join(lines))

Expand Down
3 changes: 2 additions & 1 deletion Lib/doctest.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ def _test():
import pdb
import re
import sys
import traceback
import unittest
from io import StringIO, IncrementalNewlineDecoder
from collections import namedtuple
Expand Down Expand Up @@ -273,6 +272,7 @@ def _exception_traceback(exc_info):
# Get a traceback message.
excout = StringIO()
exc_type, exc_val, exc_tb = exc_info
import traceback
traceback.print_exception(exc_type, exc_val, exc_tb, file=excout)
return excout.getvalue()

Expand Down Expand Up @@ -1414,6 +1414,7 @@ def __run(self, test, compileflags, out):

# The example raised an exception: check if it was expected.
else:
import traceback
formatted_ex = traceback.format_exception_only(*exception[:2])
if issubclass(exception[0], SyntaxError):
# SyntaxError / IndentationError is special:
Expand Down
2 changes: 1 addition & 1 deletion Lib/logging/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import re
import struct
import threading
import traceback

from socketserver import ThreadingTCPServer, StreamRequestHandler

Expand Down Expand Up @@ -994,6 +993,7 @@ def handle(self):
try:
fileConfig(file)
except Exception:
import traceback
traceback.print_exc()
if self.server.ready:
self.server.ready.set()
Expand Down
5 changes: 4 additions & 1 deletion Lib/pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@
import textwrap
import tokenize
import itertools
import traceback
import linecache
import _colorize

Expand Down Expand Up @@ -219,6 +218,7 @@ def __init__(self, target):
print(f"ImportError: {e}")
sys.exit(1)
except Exception:
import traceback
traceback.print_exc()
sys.exit(1)

Expand Down Expand Up @@ -257,6 +257,7 @@ def __init__(self, target):
print(f"ImportError: {e}")
sys.exit(1)
except Exception:
import traceback
traceback.print_exc()
sys.exit(1)

Expand Down Expand Up @@ -2262,6 +2263,7 @@ def _run(self, target: _ExecutableTarget):
self.run(target.code)

def _format_exc(self, exc: BaseException):
import traceback
return traceback.format_exception_only(exc)[-1].strip()

def _compile_error_message(self, expr):
Expand Down Expand Up @@ -2531,6 +2533,7 @@ def main():
print("The program exited via sys.exit(). Exit status:", end=' ')
print(e)
except BaseException as e:
import traceback
traceback.print_exception(e, colorize=_colorize.can_colorize())
print("Uncaught exception. Entering post mortem debugging")
print("Running 'cont' or 'step' will restart the program")
Expand Down
2 changes: 1 addition & 1 deletion Lib/py_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import os
import os.path
import sys
import traceback

__all__ = ["compile", "main", "PyCompileError", "PycInvalidationMode"]

Expand Down Expand Up @@ -46,6 +45,7 @@ class PyCompileError(Exception):
def __init__(self, exc_type, exc_value, file, msg=''):
exc_type_name = exc_type.__name__
if exc_type is SyntaxError:
import traceback
tbtext = ''.join(traceback.format_exception_only(
exc_type, exc_value))
errmsg = tbtext.replace('File "<string>"', 'File "%s"' % file)
Expand Down
2 changes: 1 addition & 1 deletion Lib/pydoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ class or function within a module or module in a package. If the
from annotationlib import Format
from collections import deque
from reprlib import Repr
from traceback import format_exception_only

from _pyrepl.pager import (get_pager, pipe_pager,
plain_pager, tempfile_pager, tty_pager)
Expand Down Expand Up @@ -2628,6 +2627,7 @@ def html_getobj(url):
return title, content

def html_error(url, exc):
from traceback import format_exception_only
heading = html.heading(
'<strong class="title">Error</strong>',
)
Expand Down
2 changes: 1 addition & 1 deletion Lib/unittest/case.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import warnings
import collections
import contextlib
import traceback
import time
import types

Expand Down Expand Up @@ -262,6 +261,7 @@ def __exit__(self, exc_type, exc_value, tb):
else:
self._raiseFailure("{} not raised".format(exc_name))
else:
import traceback
traceback.clear_frames(tb)
if not issubclass(exc_type, self.expected):
# let unexpected exceptions pass through
Expand Down
4 changes: 3 additions & 1 deletion Lib/unittest/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import os
import re
import sys
import traceback
import types
import functools

Expand Down Expand Up @@ -35,11 +34,13 @@ def testFailure():


def _make_failed_import_test(name, suiteClass):
import traceback
message = 'Failed to import test module: %s\n%s' % (
name, traceback.format_exc())
return _make_failed_test(name, ImportError(message), suiteClass, message)

def _make_failed_load_tests(name, exception, suiteClass):
import traceback
message = 'Failed to call load_tests:\n%s' % (traceback.format_exc(),)
return _make_failed_test(
name, exception, suiteClass, message)
Expand Down Expand Up @@ -163,6 +164,7 @@ def loadTestsFromName(self, name, module=None):
return error_case
else:
# Otherwise, we signal that an AttributeError has occurred.
import traceback
error_case, error_message = _make_failed_test(
part, e, self.suiteClass,
'Failed to access attribute:\n%s' % (
Expand Down
2 changes: 1 addition & 1 deletion Lib/unittest/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import io
import sys
import traceback

from . import util
from functools import wraps
Expand Down Expand Up @@ -186,6 +185,7 @@ def _exc_info_to_string(self, err, test):
"""Converts a sys.exc_info()-style tuple of values into a string."""
exctype, value, tb = err
tb = self._clean_tracebacks(exctype, value, tb, test)
import traceback
tb_e = traceback.TracebackException(
exctype, value, tb,
capture_locals=self.tb_locals, compact=True)
Expand Down
7 changes: 2 additions & 5 deletions Lib/xmlrpc/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,7 @@ def export_add(self, x, y):
import os
import re
import pydoc
import traceback
try:
import fcntl
except ImportError:
fcntl = None


def resolve_dotted_attribute(obj, attr, allow_dotted_names=True):
"""resolve_dotted_attribute(a, 'b.c.d') => a.b.c.d
Expand Down Expand Up @@ -512,6 +508,7 @@ def do_POST(self):
if hasattr(self.server, '_send_traceback_header') and \
self.server._send_traceback_header:
self.send_header("X-exception", str(e))
import traceback
trace = traceback.format_exc()
trace = str(trace.encode('ASCII', 'backslashreplace'), 'ASCII')
self.send_header("X-traceback", trace)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Improve the import time of several modules by lazy importing :mod:`traceback`.
Patch by Semyon Moroz.
Loading