https://github.com/python/cpython/commit/f717b25712064b88e6dac5a919dbc717e69ebb9c
commit: f717b25712064b88e6dac5a919dbc717e69ebb9c
branch: main
author: Savannah Ostrowski <[email protected]>
committer: savannahostrowski <[email protected]>
date: 2026-07-24T20:33:26Z
summary:
GH-154638: Use lazy imports in argparse (#154639)
Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
files:
A Misc/NEWS.d/next/Library/2026-07-24-17-02-46.gh-issue-154638.7YnFHH.rst
M Lib/argparse.py
M Lib/test/test_argparse.py
diff --git a/Lib/argparse.py b/Lib/argparse.py
index 42891516b3bb2a..f8739d031e01c5 100644
--- a/Lib/argparse.py
+++ b/Lib/argparse.py
@@ -87,12 +87,17 @@
import os as _os
-import re as _re
import sys as _sys
-from gettext import gettext as _
-from gettext import ngettext
lazy import _colorize
+lazy import copy
+lazy import difflib
+lazy import re as _re
+lazy import shutil
+lazy import textwrap
+lazy import warnings
+lazy from gettext import gettext as _
+lazy from gettext import ngettext
SUPPRESS = '==SUPPRESS=='
@@ -143,10 +148,8 @@ def _copy_items(items):
return []
# The copy module is used only in the 'append' and 'append_const'
# actions, and it is needed only when the default value isn't a list.
- # Delay its import for speeding up the common case.
if type(items) is list:
return items[:]
- import copy
return copy.copy(items)
@@ -186,7 +189,6 @@ def __init__(
):
# default setting for width
if width is None:
- import shutil
width = shutil.get_terminal_size().columns
width -= 2
@@ -773,9 +775,6 @@ def _iter_indented_subactions(self, action):
def _split_lines(self, text, width):
text = self._whitespace_matcher.sub(' ', text).strip()
- # The textwrap module is used only for formatting help.
- # Delay its import for speeding up the common usage of argparse.
- import textwrap
decolored = self._decolor(text)
if decolored == text:
return textwrap.wrap(text, width)
@@ -808,7 +807,6 @@ def _split_lines(self, text, width):
def _fill_text(self, text, width, indent):
text = self._whitespace_matcher.sub(' ', text).strip()
- import textwrap
return textwrap.fill(text, width,
initial_indent=indent,
subsequent_indent=indent)
@@ -1486,7 +1484,6 @@ class FileType(object):
"""
def __init__(self, mode='r', bufsize=-1, encoding=None, errors=None):
- import warnings
warnings.warn(
"FileType is deprecated. Simply open files after parsing
arguments.",
category=PendingDeprecationWarning,
@@ -1893,7 +1890,6 @@ class _ArgumentGroup(_ActionsContainer):
def __init__(self, container, title=None, description=None, **kwargs):
if 'prefix_chars' in kwargs:
- import warnings
depr_msg = (
"The use of the undocumented 'prefix_chars' parameter in "
"ArgumentParser.add_argument_group() is deprecated."
@@ -2824,7 +2820,6 @@ def _check_value(self, action, value):
if self.suggest_on_error and isinstance(value, str):
if all(isinstance(choice, str) for choice in action.choices):
- import difflib
suggestions = difflib.get_close_matches(value,
action.choices, 1)
if suggestions:
args['closest'] = suggestions[0]
@@ -2964,8 +2959,6 @@ def _warning(self, message):
def __getattr__(name):
if name == "__version__":
- from warnings import _deprecated
-
- _deprecated("__version__", remove=(3, 20))
+ warnings._deprecated("__version__", remove=(3, 20))
return "1.1" # Do not change
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py
index fbeb933841129e..442cbb1aaadfe3 100644
--- a/Lib/test/test_argparse.py
+++ b/Lib/test/test_argparse.py
@@ -3,7 +3,6 @@
import _colorize
import contextlib
import functools
-import inspect
import io
import operator
import os
@@ -12,6 +11,7 @@
import sys
import textwrap
import tempfile
+import types
import unittest
import argparse
import warnings
@@ -85,6 +85,8 @@ class TestLazyImports(unittest.TestCase):
"_colorize",
"copy",
"difflib",
+ "gettext",
+ "re",
"shutil",
"textwrap",
"warnings",
@@ -99,7 +101,7 @@ def test_create_parser(self):
# Test imports are still unused after
# creating a parser
create_parser = "argparse.ArgumentParser()"
- imported_modules = {"shutil"}
+ imported_modules = {"gettext", "re", "shutil"}
import_helper.ensure_lazy_imports(
"argparse",
@@ -114,7 +116,7 @@ def test_add_subparser(self):
parser.add_subparsers(dest='command', required=False)
"""
)
- imported_modules = {"shutil"}
+ imported_modules = {"gettext", "re", "shutil"}
import_helper.ensure_lazy_imports(
"argparse",
@@ -132,7 +134,7 @@ def test_parse_args(self):
parser.parse_args(['BAR', '--foo', 'FOO'])
"""
)
- imported_modules = {"shutil"}
+ imported_modules = {"gettext", "re", "shutil"}
import_helper.ensure_lazy_imports(
"argparse",
self.LAZY_IMPORTS - imported_modules,
@@ -7098,7 +7100,10 @@ def test_all_exports_everything_but_modules(self):
name
for name, value in vars(argparse).items()
if not (name.startswith("_") or name == 'ngettext')
- if not inspect.ismodule(value)
+ if not isinstance(
+ value,
+ (types.ModuleType, types.LazyImportType),
+ )
]
self.assertEqual(sorted(items), sorted(argparse.__all__))
diff --git
a/Misc/NEWS.d/next/Library/2026-07-24-17-02-46.gh-issue-154638.7YnFHH.rst
b/Misc/NEWS.d/next/Library/2026-07-24-17-02-46.gh-issue-154638.7YnFHH.rst
new file mode 100644
index 00000000000000..91c22640deba6b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-07-24-17-02-46.gh-issue-154638.7YnFHH.rst
@@ -0,0 +1 @@
+Improve import time of :mod:`argparse` by lazily importing several
dependencies.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]