summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2017-09-25 21:55:55 (GMT)
committerGitHub <noreply@github.com>2017-09-25 21:55:55 (GMT)
commit81108375d9b2ccd0add1572da745311d4dfac505 (patch)
tree54632e1d6ec58850f70941452634c4faf1ea7218
parentf1502d097c29b266a5748312ee2451a2d6ac0af6 (diff)
downloadcpython-81108375d9b2ccd0add1572da745311d4dfac505.zip
cpython-81108375d9b2ccd0add1572da745311d4dfac505.tar.gz
cpython-81108375d9b2ccd0add1572da745311d4dfac505.tar.bz2
bpo-30152: Reduce the number of imports for argparse. (#1269)
-rw-r--r--Lib/argparse.py40
-rw-r--r--Lib/enum.py11
-rw-r--r--Lib/gettext.py14
-rw-r--r--Lib/locale.py6
-rw-r--r--Lib/os.py21
-rw-r--r--Lib/pathlib.py2
-rw-r--r--Lib/types.py8
-rw-r--r--Lib/weakref.py6
8 files changed, 59 insertions, 49 deletions
diff --git a/Lib/argparse.py b/Lib/argparse.py
index 98bbed0..d8bbd35 100644
--- a/Lib/argparse.py
+++ b/Lib/argparse.py
@@ -84,15 +84,12 @@ __all__ = [
import collections as _collections
-import copy as _copy
import os as _os
import re as _re
import sys as _sys
-import textwrap as _textwrap
from gettext import gettext as _, ngettext
-
SUPPRESS = '==SUPPRESS=='
OPTIONAL = '?'
@@ -137,10 +134,16 @@ class _AttributeHolder(object):
return []
-def _ensure_value(namespace, name, value):
- if getattr(namespace, name, None) is None:
- setattr(namespace, name, value)
- return getattr(namespace, name)
+def _copy_items(items):
+ if items is None:
+ 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)
# ===============
@@ -619,12 +622,17 @@ class HelpFormatter(object):
def _split_lines(self, text, width):
text = self._whitespace_matcher.sub(' ', text).strip()
- return _textwrap.wrap(text, width)
+ # The textwrap module is used only for formatting help.
+ # Delay its import for speeding up the common usage of argparse.
+ import textwrap
+ return textwrap.wrap(text, width)
def _fill_text(self, text, width, indent):
text = self._whitespace_matcher.sub(' ', text).strip()
- return _textwrap.fill(text, width, initial_indent=indent,
- subsequent_indent=indent)
+ import textwrap
+ return textwrap.fill(text, width,
+ initial_indent=indent,
+ subsequent_indent=indent)
def _get_help_string(self, action):
return action.help
@@ -952,7 +960,8 @@ class _AppendAction(Action):
metavar=metavar)
def __call__(self, parser, namespace, values, option_string=None):
- items = _copy.copy(_ensure_value(namespace, self.dest, []))
+ items = getattr(namespace, self.dest, None)
+ items = _copy_items(items)
items.append(values)
setattr(namespace, self.dest, items)
@@ -978,7 +987,8 @@ class _AppendConstAction(Action):
metavar=metavar)
def __call__(self, parser, namespace, values, option_string=None):
- items = _copy.copy(_ensure_value(namespace, self.dest, []))
+ items = getattr(namespace, self.dest, None)
+ items = _copy_items(items)
items.append(self.const)
setattr(namespace, self.dest, items)
@@ -1000,8 +1010,10 @@ class _CountAction(Action):
help=help)
def __call__(self, parser, namespace, values, option_string=None):
- new_count = _ensure_value(namespace, self.dest, 0) + 1
- setattr(namespace, self.dest, new_count)
+ count = getattr(namespace, self.dest, None)
+ if count is None:
+ count = 0
+ setattr(namespace, self.dest, count + 1)
class _HelpAction(Action):
diff --git a/Lib/enum.py b/Lib/enum.py
index 6d90f7d..fe7cb20 100644
--- a/Lib/enum.py
+++ b/Lib/enum.py
@@ -1,7 +1,5 @@
import sys
from types import MappingProxyType, DynamicClassAttribute
-from functools import reduce
-from operator import or_ as _or_
# try _collections first to reduce startup cost
try:
@@ -744,11 +742,10 @@ class Flag(Enum):
def __invert__(self):
members, uncovered = _decompose(self.__class__, self._value_)
- inverted_members = [
- m for m in self.__class__
- if m not in members and not m._value_ & self._value_
- ]
- inverted = reduce(_or_, inverted_members, self.__class__(0))
+ inverted = self.__class__(0)
+ for m in self.__class__:
+ if m not in members and not (m._value_ & self._value_):
+ inverted = inverted | m
return self.__class__(inverted)
diff --git a/Lib/gettext.py b/Lib/gettext.py
index 5ad7ff6..4c3b80b 100644
--- a/Lib/gettext.py
+++ b/Lib/gettext.py
@@ -46,13 +46,10 @@ internationalized, to the local language and cultural habits.
# find this format documented anywhere.
-import copy
import locale
import os
import re
-import struct
import sys
-from errno import ENOENT
__all__ = ['NullTranslations', 'GNUTranslations', 'Catalog',
@@ -342,7 +339,9 @@ class GNUTranslations(NullTranslations):
def _parse(self, fp):
"""Override this method to support alternative .mo formats."""
- unpack = struct.unpack
+ # Delay struct import for speeding up gettext import when .mo files
+ # are not used.
+ from struct import unpack
filename = getattr(fp, 'name', '')
# Parse the .mo file header, which consists of 5 little endian 32
# bit words.
@@ -520,7 +519,9 @@ def translation(domain, localedir=None, languages=None,
if not mofiles:
if fallback:
return NullTranslations()
- raise OSError(ENOENT, 'No translation file found for domain', domain)
+ from errno import ENOENT
+ raise FileNotFoundError(ENOENT,
+ 'No translation file found for domain', domain)
# Avoid opening, reading, and parsing the .mo file after it's been done
# once.
result = None
@@ -533,6 +534,9 @@ def translation(domain, localedir=None, languages=None,
# Copy the translation object to allow setting fallbacks and
# output charset. All other instance data is shared with the
# cached object.
+ # Delay copy import for speeding up gettext import when .mo files
+ # are not used.
+ import copy
t = copy.copy(t)
if codeset:
t.set_output_charset(codeset)
diff --git a/Lib/locale.py b/Lib/locale.py
index 569fe85..f1d157d 100644
--- a/Lib/locale.py
+++ b/Lib/locale.py
@@ -14,10 +14,9 @@ import sys
import encodings
import encodings.aliases
import re
-import collections.abc
+import _collections_abc
from builtins import str as _builtin_str
import functools
-import warnings
# Try importing the _locale module.
#
@@ -215,7 +214,7 @@ def format_string(f, val, grouping=False, monetary=False):
percents = list(_percent_re.finditer(f))
new_f = _percent_re.sub('%s', f)
- if isinstance(val, collections.abc.Mapping):
+ if isinstance(val, _collections_abc.Mapping):
new_val = []
for perc in percents:
if perc.group()[-1]=='%':
@@ -244,6 +243,7 @@ def format_string(f, val, grouping=False, monetary=False):
def format(percent, value, grouping=False, monetary=False, *additional):
"""Deprecated, use format_string instead."""
+ import warnings
warnings.warn(
"This method will be removed in a future version of Python. "
"Use 'locale.format_string()' instead.",
diff --git a/Lib/os.py b/Lib/os.py
index 807ddb5..4f9fdf5 100644
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -23,7 +23,7 @@ and opendir), and leave all pathname manipulation to os.path
#'
import abc
-import sys, errno
+import sys
import stat as st
_names = sys.builtin_module_names
@@ -590,12 +590,10 @@ def _execvpe(file, args, env=None):
argrest = (args,)
env = environ
- head, tail = path.split(file)
- if head:
+ if path.dirname(file):
exec_func(file, *argrest)
return
- last_exc = saved_exc = None
- saved_tb = None
+ saved_exc = None
path_list = get_exec_path(env)
if name != 'nt':
file = fsencode(file)
@@ -604,16 +602,15 @@ def _execvpe(file, args, env=None):
fullname = path.join(dir, file)
try:
exec_func(fullname, *argrest)
+ except (FileNotFoundError, NotADirectoryError) as e:
+ last_exc = e
except OSError as e:
last_exc = e
- tb = sys.exc_info()[2]
- if (e.errno != errno.ENOENT and e.errno != errno.ENOTDIR
- and saved_exc is None):
+ if saved_exc is None:
saved_exc = e
- saved_tb = tb
- if saved_exc:
- raise saved_exc.with_traceback(saved_tb)
- raise last_exc.with_traceback(tb)
+ if saved_exc is not None:
+ raise saved_exc
+ raise last_exc
def get_exec_path(env=None):
diff --git a/Lib/pathlib.py b/Lib/pathlib.py
index c14ddd0..73dd513 100644
--- a/Lib/pathlib.py
+++ b/Lib/pathlib.py
@@ -6,7 +6,7 @@ import os
import posixpath
import re
import sys
-from collections.abc import Sequence
+from _collections_abc import Sequence
from errno import EINVAL, ENOENT, ENOTDIR
from operator import attrgetter
from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO
diff --git a/Lib/types.py b/Lib/types.py
index 929cba2..336918f 100644
--- a/Lib/types.py
+++ b/Lib/types.py
@@ -172,9 +172,6 @@ class DynamicClassAttribute:
return result
-import functools as _functools
-import collections.abc as _collections_abc
-
class _GeneratorWrapper:
# TODO: Implement this in C.
def __init__(self, gen):
@@ -247,7 +244,10 @@ def coroutine(func):
# return generator-like objects (for instance generators
# compiled with Cython).
- @_functools.wraps(func)
+ # Delay functools and _collections_abc import for speeding up types import.
+ import functools
+ import _collections_abc
+ @functools.wraps(func)
def wrapped(*args, **kwargs):
coro = func(*args, **kwargs)
if (coro.__class__ is CoroutineType or
diff --git a/Lib/weakref.py b/Lib/weakref.py
index 1802f32..99de2ea 100644
--- a/Lib/weakref.py
+++ b/Lib/weakref.py
@@ -21,7 +21,7 @@ from _weakref import (
from _weakrefset import WeakSet, _IterationGuard
-import collections.abc # Import after _weakref to avoid circular import.
+import _collections_abc # Import after _weakref to avoid circular import.
import sys
import itertools
@@ -87,7 +87,7 @@ class WeakMethod(ref):
__hash__ = ref.__hash__
-class WeakValueDictionary(collections.abc.MutableMapping):
+class WeakValueDictionary(_collections_abc.MutableMapping):
"""Mapping class that references values weakly.
Entries in the dictionary will be discarded when no strong
@@ -340,7 +340,7 @@ class KeyedRef(ref):
super().__init__(ob, callback)
-class WeakKeyDictionary(collections.abc.MutableMapping):
+class WeakKeyDictionary(_collections_abc.MutableMapping):
""" Mapping class that references keys weakly.
Entries in the dictionary will be discarded when there is no