diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2017-09-25 21:55:55 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-25 21:55:55 (GMT) |
commit | 81108375d9b2ccd0add1572da745311d4dfac505 (patch) | |
tree | 54632e1d6ec58850f70941452634c4faf1ea7218 | |
parent | f1502d097c29b266a5748312ee2451a2d6ac0af6 (diff) | |
download | cpython-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.py | 40 | ||||
-rw-r--r-- | Lib/enum.py | 11 | ||||
-rw-r--r-- | Lib/gettext.py | 14 | ||||
-rw-r--r-- | Lib/locale.py | 6 | ||||
-rw-r--r-- | Lib/os.py | 21 | ||||
-rw-r--r-- | Lib/pathlib.py | 2 | ||||
-rw-r--r-- | Lib/types.py | 8 | ||||
-rw-r--r-- | Lib/weakref.py | 6 |
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.", @@ -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 |