Skip to content

Commit 00348be

Browse files
authored
gh-154675: Use lazy imports in pdb, bdb, code (#156567)
1 parent b577a54 commit 00348be

7 files changed

Lines changed: 69 additions & 34 deletions

File tree

‎Lib/bdb.py‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
"""Debugger basics"""
22

3-
import fnmatch
4-
import sys
5-
import threading
63
import os
7-
import weakref
4+
import sys
85
from contextlib import contextmanager
96
from inspect import CO_GENERATOR, CO_COROUTINE, CO_ASYNC_GENERATOR
7+
lazy import fnmatch
8+
lazy import threading
9+
lazy import weakref
1010

1111
__all__ = ["BdbQuit", "Bdb", "Breakpoint"]
1212

‎Lib/code.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
import builtins
99
import sys
10-
import traceback
1110
from codeop import CommandCompiler, compile_command
11+
lazy import traceback
1212

1313
__all__ = ["InteractiveInterpreter", "InteractiveConsole", "interact",
1414
"compile_command"]

‎Lib/pdb.py‎

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -67,46 +67,44 @@
6767

6868
import os
6969
import io
70-
import re
7170
import sys
7271
import cmd
73-
import bdb
7472
import dis
73+
import bdb
7574
import code
76-
import glob
77-
import json
7875
import stat
7976
import token
8077
import types
8178
import atexit
8279
import codeop
83-
import pprint
84-
import signal
85-
import socket
8680
import typing
8781
import inspect
88-
import weakref
8982
import builtins
90-
import tempfile
91-
import textwrap
92-
import tokenize
9383
import itertools
94-
import traceback
9584
import linecache
96-
import selectors
97-
import threading
98-
import _colorize
9985

10086
from contextlib import ExitStack, closing, contextmanager
10187
from types import CodeType
10288
from warnings import deprecated
10389

90+
lazy import _colorize
91+
lazy import argparse
10492
lazy import asyncio
105-
106-
try:
107-
import _pyrepl.utils
108-
except ModuleNotFoundError:
109-
_pyrepl = None
93+
lazy import glob
94+
lazy import json
95+
lazy import pprint
96+
lazy import re
97+
lazy import runpy
98+
lazy import selectors
99+
lazy import shlex
100+
lazy import signal
101+
lazy import socket
102+
lazy import tempfile
103+
lazy import textwrap
104+
lazy import threading
105+
lazy import tokenize
106+
lazy import traceback
107+
lazy import weakref
110108

111109

112110
class Restart(Exception):
@@ -247,7 +245,6 @@ class _ModuleTarget(_ExecutableTarget):
247245
def __init__(self, target):
248246
self._target = target
249247

250-
import runpy
251248
try:
252249
_, self._spec, self._code = runpy._get_module_details(self._target)
253250
except ImportError as e:
@@ -282,8 +279,6 @@ def namespace(self):
282279

283280
class _ZipTarget(_ExecutableTarget):
284281
def __init__(self, target):
285-
import runpy
286-
287282
self._target = os.path.realpath(target)
288283
sys.path.insert(0, self._target)
289284
try:
@@ -466,6 +461,7 @@ def complete(self, text, state):
466461
return None
467462

468463
def gen_colors(self, buffer):
464+
import _pyrepl.utils
469465
from _pyrepl.utils import ColorSpan, Span
470466

471467
if not buffer.strip():
@@ -1271,7 +1267,11 @@ def handle_command_def(self, line):
12711267
return False
12721268

12731269
def _colorize_code(self, code):
1274-
if self.colorize and _pyrepl:
1270+
if self.colorize:
1271+
try:
1272+
import _pyrepl.utils
1273+
except ModuleNotFoundError:
1274+
return code
12751275
colors = list(_pyrepl.utils.gen_colors(code))
12761276
chars, _ = _pyrepl.utils.disp_str(code, colors=colors, force_color=True)
12771277
code = "".join(chars)
@@ -2089,7 +2089,6 @@ def do_run(self, arg):
20892089
'e.g. "python -m pdb myscript.py"')
20902090
return
20912091
if arg:
2092-
import shlex
20932092
argv0 = sys.argv[0:1]
20942093
try:
20952094
sys.argv = shlex.split(arg)
@@ -3787,9 +3786,7 @@ def parse_args():
37873786
# "python -m pdb -m foo -p 1" should pass "-p 1" to "foo".
37883787
# "python -m pdb foo.py -m bar" should pass "-m bar" to "foo.py".
37893788
# "python -m pdb -m foo -m bar" should pass "-m bar" to "foo".
3790-
# This require some customized parsing logic to find the actual debug target.
3791-
3792-
import argparse
3789+
# This requires some customized parsing logic to find the actual debug target.
37933790

37943791
parser = argparse.ArgumentParser(
37953792
usage="%(prog)s [-h] [-c command] (-m module | -p pid | pyfile) [args ...]",

‎Lib/test/test_bdb.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import linecache
5858
from contextlib import contextmanager
5959
from itertools import islice, repeat
60+
from test.support import cpython_only
6061
from test.support import import_helper
6162
from test.support import os_helper
6263
from test.support import patch_list
@@ -1243,6 +1244,10 @@ def test_next_to_botframe(self):
12431244

12441245

12451246
class TestRegressions(unittest.TestCase):
1247+
@cpython_only
1248+
def test_lazy_import(self):
1249+
import_helper.ensure_lazy_imports("bdb", {"fnmatch", "threading", "weakref"})
1250+
12461251
def test_format_stack_entry_no_lineno(self):
12471252
# See gh-101517
12481253
self.assertIn('Warning: lineno is None',

‎Lib/test/test_code_module.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from textwrap import dedent
66
from contextlib import ExitStack
77
from unittest import mock
8+
from test.support import cpython_only
89
from test.support import force_not_colorized_test_class
910
from test.support import import_helper
1011

@@ -38,6 +39,10 @@ def setUp(self):
3839
self.console = code.InteractiveConsole()
3940
self.mock_sys()
4041

42+
@cpython_only
43+
def test_lazy_import(self):
44+
import_helper.ensure_lazy_imports("code", {"traceback"})
45+
4146
def test_ps1(self):
4247
self.infunc.side_effect = [
4348
"import code",

‎Lib/test/test_pdb.py‎

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from io import StringIO
2323
from test import support
2424
from test.support import has_socket_support, os_helper
25-
from test.support.import_helper import import_module
25+
from test.support.import_helper import ensure_lazy_imports, import_module
2626
from test.support.pty_helper import run_pty, FakeInput
2727
from test.support.script_helper import kill_python
2828
from unittest.mock import patch
@@ -3558,6 +3558,32 @@ class PdbTestCase(unittest.TestCase):
35583558
def tearDown(self):
35593559
os_helper.unlink(os_helper.TESTFN)
35603560

3561+
@support.cpython_only
3562+
def test_lazy_import(self):
3563+
ensure_lazy_imports(
3564+
"pdb",
3565+
{
3566+
"_colorize",
3567+
"argparse",
3568+
"asyncio",
3569+
"glob",
3570+
"json",
3571+
"pprint",
3572+
"re",
3573+
"runpy",
3574+
"selectors",
3575+
"shlex",
3576+
"signal",
3577+
"socket",
3578+
"tempfile",
3579+
"textwrap",
3580+
"threading",
3581+
"tokenize",
3582+
"traceback",
3583+
"weakref",
3584+
},
3585+
)
3586+
35613587
@unittest.skipIf(sys.flags.safe_path,
35623588
'PYTHONSAFEPATH changes default sys.path')
35633589
def _run_pdb(self, pdb_args, commands,
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improve import time of :mod:`pdb`, :mod:`bdb` and :mod:`code` by lazily
2+
importing several dependencies.

0 commit comments

Comments
 (0)