Skip to content

Commit 8110837

Browse files
bpo-30152: Reduce the number of imports for argparse. (#1269)
1 parent f1502d0 commit 8110837

File tree

8 files changed

+59
-49
lines changed

8 files changed

+59
-49
lines changed

Lib/argparse.py

+26-14
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,12 @@
8484

8585

8686
import collections as _collections
87-
import copy as _copy
8887
import os as _os
8988
import re as _re
9089
import sys as _sys
91-
import textwrap as _textwrap
9290

9391
from gettext import gettext as _, ngettext
9492

95-
9693
SUPPRESS = '==SUPPRESS=='
9794

9895
OPTIONAL = '?'
@@ -137,10 +134,16 @@ def _get_args(self):
137134
return []
138135

139136

140-
def _ensure_value(namespace, name, value):
141-
if getattr(namespace, name, None) is None:
142-
setattr(namespace, name, value)
143-
return getattr(namespace, name)
137+
def _copy_items(items):
138+
if items is None:
139+
return []
140+
# The copy module is used only in the 'append' and 'append_const'
141+
# actions, and it is needed only when the default value isn't a list.
142+
# Delay its import for speeding up the common case.
143+
if type(items) is list:
144+
return items[:]
145+
import copy
146+
return copy.copy(items)
144147

145148

146149
# ===============
@@ -619,12 +622,17 @@ def _iter_indented_subactions(self, action):
619622

620623
def _split_lines(self, text, width):
621624
text = self._whitespace_matcher.sub(' ', text).strip()
622-
return _textwrap.wrap(text, width)
625+
# The textwrap module is used only for formatting help.
626+
# Delay its import for speeding up the common usage of argparse.
627+
import textwrap
628+
return textwrap.wrap(text, width)
623629

624630
def _fill_text(self, text, width, indent):
625631
text = self._whitespace_matcher.sub(' ', text).strip()
626-
return _textwrap.fill(text, width, initial_indent=indent,
627-
subsequent_indent=indent)
632+
import textwrap
633+
return textwrap.fill(text, width,
634+
initial_indent=indent,
635+
subsequent_indent=indent)
628636

629637
def _get_help_string(self, action):
630638
return action.help
@@ -952,7 +960,8 @@ def __init__(self,
952960
metavar=metavar)
953961

954962
def __call__(self, parser, namespace, values, option_string=None):
955-
items = _copy.copy(_ensure_value(namespace, self.dest, []))
963+
items = getattr(namespace, self.dest, None)
964+
items = _copy_items(items)
956965
items.append(values)
957966
setattr(namespace, self.dest, items)
958967

@@ -978,7 +987,8 @@ def __init__(self,
978987
metavar=metavar)
979988

980989
def __call__(self, parser, namespace, values, option_string=None):
981-
items = _copy.copy(_ensure_value(namespace, self.dest, []))
990+
items = getattr(namespace, self.dest, None)
991+
items = _copy_items(items)
982992
items.append(self.const)
983993
setattr(namespace, self.dest, items)
984994

@@ -1000,8 +1010,10 @@ def __init__(self,
10001010
help=help)
10011011

10021012
def __call__(self, parser, namespace, values, option_string=None):
1003-
new_count = _ensure_value(namespace, self.dest, 0) + 1
1004-
setattr(namespace, self.dest, new_count)
1013+
count = getattr(namespace, self.dest, None)
1014+
if count is None:
1015+
count = 0
1016+
setattr(namespace, self.dest, count + 1)
10051017

10061018

10071019
class _HelpAction(Action):

Lib/enum.py

+4-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import sys
22
from types import MappingProxyType, DynamicClassAttribute
3-
from functools import reduce
4-
from operator import or_ as _or_
53

64
# try _collections first to reduce startup cost
75
try:
@@ -744,11 +742,10 @@ def __xor__(self, other):
744742

745743
def __invert__(self):
746744
members, uncovered = _decompose(self.__class__, self._value_)
747-
inverted_members = [
748-
m for m in self.__class__
749-
if m not in members and not m._value_ & self._value_
750-
]
751-
inverted = reduce(_or_, inverted_members, self.__class__(0))
745+
inverted = self.__class__(0)
746+
for m in self.__class__:
747+
if m not in members and not (m._value_ & self._value_):
748+
inverted = inverted | m
752749
return self.__class__(inverted)
753750

754751

Lib/gettext.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,10 @@
4646
# find this format documented anywhere.
4747

4848

49-
import copy
5049
import locale
5150
import os
5251
import re
53-
import struct
5452
import sys
55-
from errno import ENOENT
5653

5754

5855
__all__ = ['NullTranslations', 'GNUTranslations', 'Catalog',
@@ -342,7 +339,9 @@ def _get_versions(self, version):
342339

343340
def _parse(self, fp):
344341
"""Override this method to support alternative .mo formats."""
345-
unpack = struct.unpack
342+
# Delay struct import for speeding up gettext import when .mo files
343+
# are not used.
344+
from struct import unpack
346345
filename = getattr(fp, 'name', '')
347346
# Parse the .mo file header, which consists of 5 little endian 32
348347
# bit words.
@@ -520,7 +519,9 @@ def translation(domain, localedir=None, languages=None,
520519
if not mofiles:
521520
if fallback:
522521
return NullTranslations()
523-
raise OSError(ENOENT, 'No translation file found for domain', domain)
522+
from errno import ENOENT
523+
raise FileNotFoundError(ENOENT,
524+
'No translation file found for domain', domain)
524525
# Avoid opening, reading, and parsing the .mo file after it's been done
525526
# once.
526527
result = None
@@ -533,6 +534,9 @@ def translation(domain, localedir=None, languages=None,
533534
# Copy the translation object to allow setting fallbacks and
534535
# output charset. All other instance data is shared with the
535536
# cached object.
537+
# Delay copy import for speeding up gettext import when .mo files
538+
# are not used.
539+
import copy
536540
t = copy.copy(t)
537541
if codeset:
538542
t.set_output_charset(codeset)

Lib/locale.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@
1414
import encodings
1515
import encodings.aliases
1616
import re
17-
import collections.abc
17+
import _collections_abc
1818
from builtins import str as _builtin_str
1919
import functools
20-
import warnings
2120

2221
# Try importing the _locale module.
2322
#
@@ -215,7 +214,7 @@ def format_string(f, val, grouping=False, monetary=False):
215214
percents = list(_percent_re.finditer(f))
216215
new_f = _percent_re.sub('%s', f)
217216

218-
if isinstance(val, collections.abc.Mapping):
217+
if isinstance(val, _collections_abc.Mapping):
219218
new_val = []
220219
for perc in percents:
221220
if perc.group()[-1]=='%':
@@ -244,6 +243,7 @@ def format_string(f, val, grouping=False, monetary=False):
244243

245244
def format(percent, value, grouping=False, monetary=False, *additional):
246245
"""Deprecated, use format_string instead."""
246+
import warnings
247247
warnings.warn(
248248
"This method will be removed in a future version of Python. "
249249
"Use 'locale.format_string()' instead.",

Lib/os.py

+9-12
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
#'
2525
import abc
26-
import sys, errno
26+
import sys
2727
import stat as st
2828

2929
_names = sys.builtin_module_names
@@ -590,12 +590,10 @@ def _execvpe(file, args, env=None):
590590
argrest = (args,)
591591
env = environ
592592

593-
head, tail = path.split(file)
594-
if head:
593+
if path.dirname(file):
595594
exec_func(file, *argrest)
596595
return
597-
last_exc = saved_exc = None
598-
saved_tb = None
596+
saved_exc = None
599597
path_list = get_exec_path(env)
600598
if name != 'nt':
601599
file = fsencode(file)
@@ -604,16 +602,15 @@ def _execvpe(file, args, env=None):
604602
fullname = path.join(dir, file)
605603
try:
606604
exec_func(fullname, *argrest)
605+
except (FileNotFoundError, NotADirectoryError) as e:
606+
last_exc = e
607607
except OSError as e:
608608
last_exc = e
609-
tb = sys.exc_info()[2]
610-
if (e.errno != errno.ENOENT and e.errno != errno.ENOTDIR
611-
and saved_exc is None):
609+
if saved_exc is None:
612610
saved_exc = e
613-
saved_tb = tb
614-
if saved_exc:
615-
raise saved_exc.with_traceback(saved_tb)
616-
raise last_exc.with_traceback(tb)
611+
if saved_exc is not None:
612+
raise saved_exc
613+
raise last_exc
617614

618615

619616
def get_exec_path(env=None):

Lib/pathlib.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import posixpath
77
import re
88
import sys
9-
from collections.abc import Sequence
9+
from _collections_abc import Sequence
1010
from errno import EINVAL, ENOENT, ENOTDIR
1111
from operator import attrgetter
1212
from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO

Lib/types.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,6 @@ def deleter(self, fdel):
172172
return result
173173

174174

175-
import functools as _functools
176-
import collections.abc as _collections_abc
177-
178175
class _GeneratorWrapper:
179176
# TODO: Implement this in C.
180177
def __init__(self, gen):
@@ -247,7 +244,10 @@ def coroutine(func):
247244
# return generator-like objects (for instance generators
248245
# compiled with Cython).
249246

250-
@_functools.wraps(func)
247+
# Delay functools and _collections_abc import for speeding up types import.
248+
import functools
249+
import _collections_abc
250+
@functools.wraps(func)
251251
def wrapped(*args, **kwargs):
252252
coro = func(*args, **kwargs)
253253
if (coro.__class__ is CoroutineType or

Lib/weakref.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
from _weakrefset import WeakSet, _IterationGuard
2323

24-
import collections.abc # Import after _weakref to avoid circular import.
24+
import _collections_abc # Import after _weakref to avoid circular import.
2525
import sys
2626
import itertools
2727

@@ -87,7 +87,7 @@ def __ne__(self, other):
8787
__hash__ = ref.__hash__
8888

8989

90-
class WeakValueDictionary(collections.abc.MutableMapping):
90+
class WeakValueDictionary(_collections_abc.MutableMapping):
9191
"""Mapping class that references values weakly.
9292
9393
Entries in the dictionary will be discarded when no strong
@@ -340,7 +340,7 @@ def __init__(self, ob, callback, key):
340340
super().__init__(ob, callback)
341341

342342

343-
class WeakKeyDictionary(collections.abc.MutableMapping):
343+
class WeakKeyDictionary(_collections_abc.MutableMapping):
344344
""" Mapping class that references keys weakly.
345345
346346
Entries in the dictionary will be discarded when there is no

0 commit comments

Comments
 (0)