diff --git a/Lib/_aix_support.py b/Lib/_aix_support.py index dadc75c2bf4200..e0142fe029a4bd 100644 --- a/Lib/_aix_support.py +++ b/Lib/_aix_support.py @@ -1,5 +1,8 @@ """Shared AIX support functions.""" +lazy import os +lazy import contextlib + import sys import sysconfig @@ -10,8 +13,6 @@ def _read_cmd_output(commandstring, capture_stderr=False): # Similar to os.popen(commandstring, "r").read(), # but without actually using os.popen because that # function is not usable during python bootstrap. - import os - import contextlib fp = open("/tmp/_aix_support.%s"%( os.getpid(),), "w+b") diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index 60b471317ce97c..5674a37a4b7245 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -32,6 +32,9 @@ # ####################################################################### +lazy from annotationlib import type_repr +lazy import warnings + from abc import ABCMeta, abstractmethod import sys @@ -485,7 +488,6 @@ def __new__(cls, origin, args): def __repr__(self): if len(self.__args__) == 2 and _is_param_expr(self.__args__[0]): return super().__repr__() - from annotationlib import type_repr return (f'collections.abc.Callable' f'[[{", ".join([type_repr(a) for a in self.__args__[:-1]])}], ' f'{type_repr(self.__args__[-1])}]') @@ -1064,7 +1066,6 @@ def count(self, value): class _DeprecateByteStringMeta(ABCMeta): def __new__(cls, name, bases, namespace, **kwargs): if name != "ByteString": - import warnings warnings._deprecated( "collections.abc.ByteString", @@ -1073,7 +1074,6 @@ def __new__(cls, name, bases, namespace, **kwargs): return super().__new__(cls, name, bases, namespace, **kwargs) def __instancecheck__(cls, instance): - import warnings warnings._deprecated( "collections.abc.ByteString", @@ -1170,7 +1170,6 @@ def __iadd__(self, values): def __getattr__(attr): if attr == "ByteString": - import warnings warnings._deprecated("collections.abc.ByteString", remove=(3, 17)) globals()["ByteString"] = _deprecated_ByteString return _deprecated_ByteString diff --git a/Lib/_osx_support.py b/Lib/_osx_support.py index 0cb064fcd791be..11d169dd041897 100644 --- a/Lib/_osx_support.py +++ b/Lib/_osx_support.py @@ -1,5 +1,7 @@ """Shared OS X support functions.""" +lazy import contextlib + import os import re import sys @@ -58,7 +60,6 @@ def _read_output(commandstring, capture_stderr=False): # but without actually using os.popen because that # function is not usable during python bootstrap. # tempfile is also not available then. - import contextlib try: import tempfile fp = tempfile.NamedTemporaryFile() diff --git a/Lib/_pydatetime.py b/Lib/_pydatetime.py index b6d68f2372850a..cb1d9a9d070687 100644 --- a/Lib/_pydatetime.py +++ b/Lib/_pydatetime.py @@ -1,5 +1,8 @@ """Pure Python implementation of the datetime module.""" +lazy import _strptime +lazy import warnings + __all__ = ("date", "datetime", "time", "timedelta", "timezone", "tzinfo", "MINYEAR", "MAXYEAR", "UTC") @@ -1077,7 +1080,6 @@ def strptime(cls, date_string, format): For a list of supported format codes, see the documentation: https://docs.python.org/3/library/datetime.html#format-codes """ - import _strptime return _strptime._strptime_datetime_date(cls, date_string, format) # Conversions to string @@ -1469,7 +1471,6 @@ def strptime(cls, date_string, format): For a list of supported format codes, see the documentation: https://docs.python.org/3/library/datetime.html#format-codes """ - import _strptime return _strptime._strptime_datetime_time(cls, date_string, format) # Read-only field accessors @@ -1908,7 +1909,6 @@ def fromtimestamp(cls, timestamp, tz=None): @classmethod def utcfromtimestamp(cls, t): """Construct a naive UTC datetime from a POSIX timestamp.""" - import warnings warnings.warn("datetime.datetime.utcfromtimestamp() is deprecated and scheduled " "for removal in a future version. Use timezone-aware " "objects to represent datetimes in UTC: " @@ -1926,7 +1926,6 @@ def now(cls, tz=None): @classmethod def utcnow(cls): "Construct a UTC datetime from time.time()." - import warnings warnings.warn("datetime.datetime.utcnow() is deprecated and scheduled for " "removal in a future version. Use timezone-aware " "objects to represent datetimes in UTC: " @@ -2217,7 +2216,6 @@ def strptime(cls, date_string, format): For a list of supported format codes, see the documentation: https://docs.python.org/3/library/datetime.html#format-codes """ - import _strptime return _strptime._strptime_datetime_datetime(cls, date_string, format) def utcoffset(self): diff --git a/Lib/_pydecimal.py b/Lib/_pydecimal.py index ef889ea0cc834c..467f26c1eee2af 100644 --- a/Lib/_pydecimal.py +++ b/Lib/_pydecimal.py @@ -15,6 +15,9 @@ """Python decimal arithmetic module""" +lazy from itertools import chain as _chain, repeat as _repeat +lazy from warnings import _deprecated as _warnings_deprecated + __all__ = [ # Two major classes 'Decimal', 'Context', @@ -6279,11 +6282,10 @@ def _group_lengths(grouping): # (2) nonempty list of positive integers + [0] # (3) list of positive integers + [locale.CHAR_MAX], or - from itertools import chain, repeat if not grouping: return [] elif grouping[-1] == 0 and len(grouping) >= 2: - return chain(grouping[:-1], repeat(grouping[-2])) + return _chain(grouping[:-1], _repeat(grouping[-2])) elif grouping[-1] == _locale.CHAR_MAX: return grouping[:-1] else: @@ -6405,8 +6407,7 @@ def _format_number(is_negative, intpart, fracpart, exp, spec): def __getattr__(name): if name == "__version__": - from warnings import _deprecated - _deprecated("__version__", remove=(3, 20)) + _warnings_deprecated("__version__", remove=(3, 20)) return SPEC_VERSION raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/_pyio.py b/Lib/_pyio.py index 3306c8a274760b..46e13893de6f69 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -2,6 +2,8 @@ Python implementation of the io module. """ +lazy import warnings + import os import abc import codecs @@ -59,7 +61,6 @@ def text_encoding(encoding, stacklevel=2): else: encoding = "locale" if sys.flags.warn_default_encoding: - import warnings warnings.warn("'encoding' argument not specified.", EncodingWarning, stacklevel + 1) return encoding @@ -225,7 +226,6 @@ def open(file, mode="r", buffering=-1, encoding=None, errors=None, if binary and newline is not None: raise ValueError("binary mode doesn't take a newline argument") if binary and buffering == 1: - import warnings warnings.warn("line buffering (buffering=1) isn't supported in binary " "mode, the default buffer size will be used", RuntimeWarning, 2) @@ -283,7 +283,6 @@ def _open_code_with_warning(path): in order to allow embedders more control over code files. This functionality is not supported on the current runtime. """ - import warnings warnings.warn("_pyio.open_code() may not be using hooks", RuntimeWarning, 2) return open(path, "rb") @@ -1530,7 +1529,6 @@ def __init__(self, file, mode='r', closefd=True, opener=None): raise TypeError('integer argument expected, got float') if isinstance(file, int): if isinstance(file, bool): - import warnings warnings.warn("bool is used as a file descriptor", RuntimeWarning, stacklevel=2) file = int(file) @@ -1633,7 +1631,6 @@ def __init__(self, file, mode='r', closefd=True, opener=None): def _dealloc_warn(self, source): if self._fd >= 0 and self._closefd and not self.closed: - import warnings warnings.warn(f'unclosed file {source!r}', ResourceWarning, stacklevel=2, source=self) diff --git a/Lib/_pylong.py b/Lib/_pylong.py index be1acd17ce3592..7fcc9798ab2485 100644 --- a/Lib/_pylong.py +++ b/Lib/_pylong.py @@ -12,6 +12,8 @@ tricky or non-obvious code is not worth it. For people looking for maximum performance, they should use something like gmpy2.""" +lazy from decimal import Decimal as D + import re import decimal try: @@ -149,7 +151,6 @@ def int_to_decimal(n): # "clever" recursive way. If we want a string representation, we # apply str to _that_. - from decimal import Decimal as D BITLIM = 200 # Don't bother caching the "lo" mask in this; the time to compute it is diff --git a/Lib/_pyrepl/_threading_handler.py b/Lib/_pyrepl/_threading_handler.py index 82f5e8650a2072..234a8e7a44c0f1 100644 --- a/Lib/_pyrepl/_threading_handler.py +++ b/Lib/_pyrepl/_threading_handler.py @@ -1,5 +1,7 @@ from __future__ import annotations +lazy import threading + from dataclasses import dataclass, field import traceback @@ -28,7 +30,6 @@ def add(self, s: str) -> None: ... def install_threading_hook(reader: Reader) -> None: - import threading @dataclass class ExceptHookHandler: diff --git a/Lib/_pyrepl/commands.py b/Lib/_pyrepl/commands.py index 10127e58897a58..2ddbce48b77d2c 100644 --- a/Lib/_pyrepl/commands.py +++ b/Lib/_pyrepl/commands.py @@ -20,6 +20,11 @@ # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. from __future__ import annotations +lazy import signal +lazy import _sitebuiltins +lazy from .pager import get_pager +lazy from site import gethistoryfile + import os import time @@ -215,7 +220,6 @@ def do(self) -> None: class interrupt(FinishCommand): def do(self) -> None: - import signal self.reader.console.finish() self.reader.finish() @@ -231,7 +235,6 @@ def do(self) -> None: class suspend(Command): def do(self) -> None: - import signal r = self.reader p = r.pos @@ -446,7 +449,6 @@ def do(self) -> None: class help(Command): def do(self) -> None: - import _sitebuiltins with self.reader.suspend(): self.reader.msg = _sitebuiltins._Helper()() # type: ignore[assignment] @@ -467,8 +469,6 @@ def do(self) -> None: class show_history(Command): def do(self) -> None: - from .pager import get_pager - from site import gethistoryfile history = os.linesep.join(self.reader.history[:]) self.reader.console.restore() diff --git a/Lib/_pyrepl/console.py b/Lib/_pyrepl/console.py index e0535d50396316..691b9c47a92a3b 100644 --- a/Lib/_pyrepl/console.py +++ b/Lib/_pyrepl/console.py @@ -19,6 +19,8 @@ from __future__ import annotations +lazy import traceback + import _colorize from abc import ABC, abstractmethod @@ -170,7 +172,6 @@ def showsyntaxerror(self, filename=None, **kwargs): super().showsyntaxerror(filename=filename, **kwargs) def _excepthook(self, typ, value, tb): - import traceback lines = traceback.format_exception( typ, value, tb, colorize=self.can_colorize, diff --git a/Lib/_pyrepl/input.py b/Lib/_pyrepl/input.py index 21c24eb5cde3e3..ae3fb52e0ab62f 100644 --- a/Lib/_pyrepl/input.py +++ b/Lib/_pyrepl/input.py @@ -35,6 +35,8 @@ from __future__ import annotations +lazy from .keymap import compile_keymap, parse_keys + from abc import ABC, abstractmethod import unicodedata from collections import deque @@ -62,7 +64,6 @@ def empty(self) -> bool: class KeymapTranslator(InputTranslator): def __init__(self, keymap, verbose=False, invalid_cls=None, character_cls=None): self.verbose = verbose - from .keymap import compile_keymap, parse_keys self.keymap = keymap self.invalid_cls = invalid_cls diff --git a/Lib/_pyrepl/main.py b/Lib/_pyrepl/main.py index 447eb1e551e774..880babc5f293bc 100644 --- a/Lib/_pyrepl/main.py +++ b/Lib/_pyrepl/main.py @@ -1,3 +1,8 @@ +lazy from .trace import trace +lazy import tokenize +lazy from .console import InteractiveColoredConsole +lazy from .simple_interact import run_multiline_interactive_console + import errno import os import sys @@ -25,7 +30,6 @@ def interactive_console(mainmodule=None, quiet=False, pythonstartup=False): if not CAN_USE_PYREPL: if not os.getenv('PYTHON_BASIC_REPL') and FAIL_REASON: - from .trace import trace trace(FAIL_REASON) print(FAIL_REASON, file=sys.stderr) return sys._baserepl() @@ -40,7 +44,6 @@ def interactive_console(mainmodule=None, quiet=False, pythonstartup=False): if pythonstartup and startup_path: sys.audit("cpython.run_startup", startup_path) - import tokenize with tokenize.open(startup_path) as f: startup_code = compile(f.read(), startup_path, "exec") exec(startup_code, namespace) @@ -52,7 +55,5 @@ def interactive_console(mainmodule=None, quiet=False, pythonstartup=False): if not hasattr(sys, "ps2"): sys.ps2 = "... " - from .console import InteractiveColoredConsole - from .simple_interact import run_multiline_interactive_console console = InteractiveColoredConsole(namespace, filename="") run_multiline_interactive_console(console) diff --git a/Lib/_pyrepl/pager.py b/Lib/_pyrepl/pager.py index 1fddc63e3ee3ad..139516d075d0ea 100644 --- a/Lib/_pyrepl/pager.py +++ b/Lib/_pyrepl/pager.py @@ -1,5 +1,8 @@ from __future__ import annotations +lazy import tempfile +lazy import subprocess + import io import os import re @@ -41,7 +44,6 @@ def get_pager() -> Pager: if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0: return lambda text, title='': pipe_pager(text, 'less', title) - import tempfile (fd, filename) = tempfile.mkstemp() os.close(fd) try: @@ -126,7 +128,6 @@ def plain_pager(text: str, title: str = '') -> None: def pipe_pager(text: str, cmd: str, title: str = '') -> None: """Page through text by feeding it to another program.""" - import subprocess env = os.environ.copy() if title: title += ' ' @@ -164,7 +165,6 @@ def pipe_pager(text: str, cmd: str, title: str = '') -> None: def tempfile_pager(text: str, cmd: str, title: str = '') -> None: """Page through text by invoking a program on a temporary file.""" - import tempfile with tempfile.TemporaryDirectory() as tempdir: filename = os.path.join(tempdir, 'pydoc.out') with open(filename, 'w', errors='backslashreplace', diff --git a/Lib/_pyrepl/reader.py b/Lib/_pyrepl/reader.py index 9ab92f64d1ef63..1045bd4cbd5765 100644 --- a/Lib/_pyrepl/reader.py +++ b/Lib/_pyrepl/reader.py @@ -21,6 +21,8 @@ from __future__ import annotations +lazy from ._threading_handler import install_threading_hook + import sys import _colorize @@ -683,7 +685,6 @@ def do_cmd(self, cmd: tuple[str, list[str]]) -> None: def run_hooks(self) -> None: threading_hook = self.threading_hook if threading_hook is None and 'threading' in sys.modules: - from ._threading_handler import install_threading_hook install_threading_hook(self) if threading_hook is not None: try: diff --git a/Lib/_pyrepl/readline.py b/Lib/_pyrepl/readline.py index 23b8fa6b9c7625..d04f4d0c926f4a 100644 --- a/Lib/_pyrepl/readline.py +++ b/Lib/_pyrepl/readline.py @@ -28,6 +28,9 @@ from __future__ import annotations +lazy import warnings +lazy import builtins + import warnings from dataclasses import dataclass, field @@ -570,7 +573,6 @@ def insert_text(self, text: str) -> None: def _make_stub(_name: str, _ret: object) -> None: def stub(*args: object, **kwds: object) -> None: - import warnings warnings.warn("readline.%s() not implemented" % _name, stacklevel=2) @@ -612,7 +614,6 @@ def _setup(namespace: Mapping[str, Any]) -> None: _wrapper.config.readline_completer = RLCompleter(namespace).complete # this is not really what readline.c does. Better than nothing I guess - import builtins raw_input = builtins.input builtins.input = _wrapper.input diff --git a/Lib/_pyrepl/simple_interact.py b/Lib/_pyrepl/simple_interact.py index 0da9f91baf6cfc..da612fdf512919 100644 --- a/Lib/_pyrepl/simple_interact.py +++ b/Lib/_pyrepl/simple_interact.py @@ -25,6 +25,8 @@ from __future__ import annotations +lazy from .readline import _setup + import _sitebuiltins import functools import os @@ -102,7 +104,6 @@ def run_multiline_interactive_console( *, future_flags: int = 0, ) -> None: - from .readline import _setup _setup(console.locals) if future_flags: console.compile.compiler.flags |= future_flags diff --git a/Lib/_sitebuiltins.py b/Lib/_sitebuiltins.py index 81b36efc6c285f..c616168577f726 100644 --- a/Lib/_sitebuiltins.py +++ b/Lib/_sitebuiltins.py @@ -8,6 +8,10 @@ # Note this means this module should also avoid keep things alive in its # globals. +lazy import os +lazy from _pyrepl.pager import get_pager +lazy import pydoc + import sys class Quitter(object): @@ -33,7 +37,6 @@ class _Printer(object): MAXLINES = 23 def __init__(self, name, data, files=(), dirs=()): - import os self.__name = name self.__data = data self.__lines = [] @@ -65,7 +68,6 @@ def __repr__(self): return "Type %s() to see the full %s text" % ((self.__name,)*2) def __call__(self): - from _pyrepl.pager import get_pager self.__setup() pager = get_pager() @@ -87,5 +89,4 @@ def __repr__(self): return "Type help() for interactive help, " \ "or help(object) for help about object." def __call__(self, *args, **kwds): - import pydoc return pydoc.help(*args, **kwds) diff --git a/Lib/_strptime.py b/Lib/_strptime.py index 8b62ea734b7d11..2be7f946183d98 100644 --- a/Lib/_strptime.py +++ b/Lib/_strptime.py @@ -10,6 +10,8 @@ strptime -- Calculates the time struct represented by the passed-in string """ +lazy import warnings + import os import time import locale @@ -473,7 +475,6 @@ def repl(m): return self[directive] format = re_sub(r'%[-_0^#]*[0-9]*([OE]?[:\\]?.?)', repl, format) if day_of_month_in_format and not year_in_format: - import warnings warnings.warn("""\ Parsing dates involving a day of month without a year specified is ambiguous and fails to parse leap day. The default behavior will change in Python 3.15 diff --git a/Lib/annotationlib.py b/Lib/annotationlib.py index 832d160de7f4e5..cea765781f1679 100644 --- a/Lib/annotationlib.py +++ b/Lib/annotationlib.py @@ -1,5 +1,8 @@ """Helpers for introspecting and wrapping annotations.""" +lazy import typing +lazy import warnings + import ast import builtins import enum @@ -225,8 +228,6 @@ def evaluate( return result def _evaluate(self, globalns, localns, type_params=_sentinel, *, recursive_guard): - import typing - import warnings if type_params is _sentinel: typing._deprecation_warning_for_no_type_params_passed( diff --git a/Lib/argparse.py b/Lib/argparse.py index 0494b545f2f1d3..c06f40602fd431 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -193,7 +193,6 @@ def __init__( def _set_color(self, color, *, file=None): from _colorize import can_colorize, decolor, get_theme - if color and can_colorize(file=file): self._theme = get_theme(force_color=True).argparse self._decolor = decolor @@ -1821,6 +1820,7 @@ def _check_help(self, action): try: formatter._expand_help(action) except (ValueError, TypeError, KeyError) as exc: + import warnings raise ValueError('badly formed help string') from exc @@ -2855,7 +2855,6 @@ def _print_message(self, message, file=None): def _get_theme(self, file=None): from _colorize import can_colorize, get_theme - if self.color and can_colorize(file=file): return get_theme(force_color=True).argparse else: @@ -2899,7 +2898,6 @@ def _warning(self, message): def __getattr__(name): if name == "__version__": from warnings import _deprecated - _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/ast.py b/Lib/ast.py index d9743ba7ab40b1..17b4b0f017b652 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -20,6 +20,12 @@ :copyright: Copyright 2008 by Armin Ronacher. :license: Python License. """ +lazy import inspect +lazy import re +lazy from collections import deque +lazy import argparse +lazy import sys + from _ast import * @@ -324,7 +330,6 @@ def get_docstring(node, clean=True): else: return None if clean: - import inspect text = inspect.cleandoc(text) return text @@ -338,7 +343,6 @@ def _splitlines_no_ff(source, maxlines=None): global _line_pattern if _line_pattern is None: # lazily computed to speedup import time of `ast` - import re _line_pattern = re.compile(r"(.*?(?:\r\n|\n|\r|$))") lines = [] @@ -403,7 +407,6 @@ def walk(node): (including *node* itself), in no specified order. This is useful if you only want to modify nodes in place and don't care about the context. """ - from collections import deque todo = deque([node]) while todo: node = todo.popleft() @@ -639,8 +642,6 @@ def unparse(ast_obj): def main(args=None): - import argparse - import sys parser = argparse.ArgumentParser(color=True) parser.add_argument('infile', nargs='?', default='-', diff --git a/Lib/asyncio/__init__.py b/Lib/asyncio/__init__.py index 32a5dbae03af21..1506ef357f391c 100644 --- a/Lib/asyncio/__init__.py +++ b/Lib/asyncio/__init__.py @@ -2,6 +2,8 @@ # flake8: noqa +lazy import warnings + import sys # This relies on each of the submodules having an __all__ variable. @@ -49,7 +51,6 @@ __all__ += unix_events.__all__ def __getattr__(name: str): - import warnings match name: case "AbstractEventLoopPolicy": diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py index 44667efc522556..43ccea7d57f746 100644 --- a/Lib/asyncio/__main__.py +++ b/Lib/asyncio/__main__.py @@ -1,3 +1,5 @@ +lazy from _pyrepl.simple_interact import _get_reader + import argparse import ast import asyncio @@ -142,7 +144,6 @@ def interrupt(self) -> None: if not CAN_USE_PYREPL: return - from _pyrepl.simple_interact import _get_reader r = _get_reader() if r.threading_hook is not None: r.threading_hook.add("") # type: ignore diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py index a51319cb72a6a9..b175561bcc262a 100644 --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -1,3 +1,5 @@ +lazy import warnings + __all__ = 'iscoroutinefunction', 'iscoroutine' import collections.abc @@ -18,7 +20,6 @@ def _is_debug_mode(): def iscoroutinefunction(func): - import warnings """Return True if func is a decorated coroutine function.""" warnings._deprecated("asyncio.iscoroutinefunction", f"{warnings._DEPRECATED_MSG}; " diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py index a7fb55982abe9c..64ccedcf848c7b 100644 --- a/Lib/asyncio/events.py +++ b/Lib/asyncio/events.py @@ -4,6 +4,9 @@ # SPDX-License-Identifier: PSF-2.0 AND (MIT OR Apache-2.0) # SPDX-FileCopyrightText: Copyright (c) 2015-2021 MagicStack Inc. http://magic.io +lazy from .windows_events import _DefaultEventLoopPolicy +lazy from .unix_events import _DefaultEventLoopPolicy + __all__ = ( "AbstractEventLoop", "AbstractServer", @@ -788,10 +791,6 @@ def _init_event_loop_policy(): global _event_loop_policy with _lock: if _event_loop_policy is None: # pragma: no branch - if sys.platform == 'win32': - from .windows_events import _DefaultEventLoopPolicy - else: - from .unix_events import _DefaultEventLoopPolicy _event_loop_policy = _DefaultEventLoopPolicy() diff --git a/Lib/base64.py b/Lib/base64.py index 36688ce43917ce..81f5b6deaace01 100644 --- a/Lib/base64.py +++ b/Lib/base64.py @@ -4,6 +4,10 @@ # Modified 30-Dec-2003 by Barry Warsaw to add full RFC 3548 support # Modified 22-May-2007 by Guido van Rossum to use bytes everywhere +lazy import warnings +lazy import sys, getopt +lazy import io + import binascii @@ -108,7 +112,6 @@ def b64decode(s, altchars=None, validate=_NOT_SPECIFIED, *, ignorechars=_NOT_SPE result = binascii.a2b_base64(s, strict_mode=validate, ignorechars=ignorechars) if badchar is not None: - import warnings if validate: warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data ' f'with altchars={altchars!r} and validate=True ' @@ -172,7 +175,6 @@ def urlsafe_b64decode(s): s = s.translate(_urlsafe_decode_translation) result = binascii.a2b_base64(s, strict_mode=False) if badchar is not None: - import warnings warnings.warn(f'invalid character {chr(badchar)!a} in URL-safe Base64 data ' f'will be discarded in future Python versions', FutureWarning, stacklevel=2) @@ -459,7 +461,6 @@ def decodebytes(s): # Usable as a script... def main(): """Small main program""" - import sys, getopt usage = f"""usage: {sys.argv[0]} [-h|-d|-e|-u] [file|-] -h: print this help message and exit -d, -u: decode @@ -483,7 +484,6 @@ def main(): else: if sys.stdin.isatty(): # gh-138775: read terminal input data all at once to detect EOF - import io data = sys.stdin.buffer.read() buffer = io.BytesIO(data) else: diff --git a/Lib/bdb.py b/Lib/bdb.py index 50cf2b3f5b3e45..7af0a034bc0efd 100644 --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -1,5 +1,11 @@ """Debugger basics""" +lazy import functools +lazy import dis +lazy import linecache +lazy import linecache, reprlib +lazy import __main__ + import fnmatch import sys import threading @@ -83,7 +89,6 @@ def restart_events(self): sys.monitoring.restart_events() def callback_wrapper(self, func, event): - import functools @functools.wraps(func) def wrapper(*args): @@ -168,7 +173,6 @@ def update_local_events(self, frame=None): frame = frame.f_back def _get_lineno(self, code, offset): - import dis last_lineno = None for start, lineno in dis.findlinestarts(code): if offset < start: @@ -243,7 +247,6 @@ def stop_trace(self): def reset(self): """Set values of attributes as ready to start debugging.""" - import linecache linecache.checkcache() self.botframe = None self._set_stopinfo(None, None) @@ -667,7 +670,6 @@ def set_break(self, filename, lineno, temporary=False, cond=None, The filename should be in canonical form. """ filename = self.canonic(filename) - import linecache # Import as late as possible line = linecache.getline(filename, lineno) if not line: return 'Line %s:%d does not exist' % (filename, lineno) @@ -851,7 +853,6 @@ def format_stack_entry(self, frame_lineno, lprefix=': '): line of code (if it exists). """ - import linecache, reprlib frame, lineno = frame_lineno filename = self.canonic(frame.f_code.co_filename) s = '%s(%r)' % (filename, lineno) @@ -892,7 +893,6 @@ def run(self, cmd, globals=None, locals=None): globals defaults to __main__.dict; locals defaults to globals. """ if globals is None: - import __main__ globals = __main__.__dict__ if locals is None: locals = globals @@ -914,7 +914,6 @@ def runeval(self, expr, globals=None, locals=None): globals defaults to __main__.dict; locals defaults to globals. """ if globals is None: - import __main__ globals = __main__.__dict__ if locals is None: locals = globals @@ -1171,7 +1170,6 @@ def user_call(self, frame, args): if not name: name = '???' print('+++ call', name, args) def user_line(self, frame): - import linecache name = frame.f_code.co_name if not name: name = '???' fn = self.canonic(frame.f_code.co_filename) diff --git a/Lib/calendar.py b/Lib/calendar.py index d80c3fd9524776..66770156ea7cbf 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -5,6 +5,10 @@ Sunday as the last (the European convention). Use setfirstweekday() to set the first day of the week (0=Monday, 6=Sunday).""" +lazy import warnings +lazy from _colorize import get_colors +lazy import argparse + import sys import datetime from enum import IntEnum, global_enum @@ -46,7 +50,6 @@ def __str__(self): def __getattr__(name): if name in ('January', 'February'): - import warnings warnings.warn(f"The '{name}' attribute is deprecated, use '{name.upper()}' instead", DeprecationWarning, stacklevel=2) if name == 'January': @@ -691,7 +694,6 @@ def formatweek(self, theweek, width, *, highlight_day=None): Returns a single week in a string (no newline). """ if highlight_day: - from _colorize import get_colors ansi = get_colors() highlight = f"{ansi.BLACK}{ansi.BACKGROUND_YELLOW}" @@ -842,7 +844,6 @@ def timegm(tuple): def main(args=None): - import argparse parser = argparse.ArgumentParser(color=True) textgroup = parser.add_argument_group('text only arguments') htmlgroup = parser.add_argument_group('html only arguments') diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index 55ffc36ea5b0c7..24ea21f8ce6a3c 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -14,6 +14,9 @@ ''' +lazy import heapq +lazy import copy + __all__ = [ 'ChainMap', 'Counter', @@ -634,11 +637,9 @@ def most_common(self, n=None): if n is None: return sorted(self.items(), key=_itemgetter(1), reverse=True) - # Lazy import to speedup Python startup time global heapq if heapq is None: import heapq - return heapq.nlargest(n, self.items(), key=_itemgetter(1)) def elements(self): @@ -1249,7 +1250,6 @@ def __copy__(self): def copy(self): if self.__class__ is UserDict: return UserDict(self.data.copy()) - import copy data = self.data try: self.data = {} diff --git a/Lib/compileall.py b/Lib/compileall.py index c452aed135838f..c8de0d18ed3467 100644 --- a/Lib/compileall.py +++ b/Lib/compileall.py @@ -10,6 +10,11 @@ See module py_compile for details of the actual byte-compilation. """ +lazy from concurrent.futures.process import _check_system_limits +lazy import multiprocessing +lazy import argparse +lazy import re + import os import sys import importlib.util @@ -85,7 +90,6 @@ def compile_dir(dir, maxlevels=None, ddir=None, force=False, raise ValueError('workers must be greater or equal to 0') if workers != 1: # Check if this is a system where ProcessPoolExecutor can function. - from concurrent.futures.process import _check_system_limits try: _check_system_limits() except NotImplementedError: @@ -97,7 +101,6 @@ def compile_dir(dir, maxlevels=None, ddir=None, force=False, files = _walk_dir(dir, quiet=quiet, maxlevels=maxlevels) success = True if workers != 1 and ProcessPoolExecutor is not None: - import multiprocessing if multiprocessing.get_start_method() == 'fork': mp_context = multiprocessing.get_context('forkserver') else: @@ -322,7 +325,6 @@ def compile_path(skip_curdir=1, maxlevels=0, force=False, quiet=0, def main(): """Script main program.""" - import argparse parser = argparse.ArgumentParser( description='Utilities to support installing Python libraries.', @@ -397,7 +399,6 @@ def main(): compile_dests = args.compile_dest if args.rx: - import re args.rx = re.compile(args.rx) if args.limit_sl_dest == "": diff --git a/Lib/concurrent/futures/__init__.py b/Lib/concurrent/futures/__init__.py index d6ac4b3e0b675f..de1f7b8703fb9b 100644 --- a/Lib/concurrent/futures/__init__.py +++ b/Lib/concurrent/futures/__init__.py @@ -3,6 +3,9 @@ """Execute computations asynchronously using threads or processes.""" +lazy from .process import ProcessPoolExecutor +lazy from .thread import ThreadPoolExecutor + __author__ = 'Brian Quinlan (brian@sweetapp.com)' from concurrent.futures._base import (FIRST_COMPLETED, @@ -48,14 +51,12 @@ def __dir__(): def __getattr__(name): - global ProcessPoolExecutor, ThreadPoolExecutor, InterpreterPoolExecutor + global ProcessPoolExecutor, ThreadPoolExecutor if name == 'ProcessPoolExecutor': - from .process import ProcessPoolExecutor return ProcessPoolExecutor if name == 'ThreadPoolExecutor': - from .thread import ThreadPoolExecutor return ThreadPoolExecutor if _interpreters and name == 'InterpreterPoolExecutor': diff --git a/Lib/contextlib.py b/Lib/contextlib.py index cac3e39eba8b52..1bdd1a7bdbdeec 100644 --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -1,4 +1,6 @@ """Utilities for with-statement contexts. See PEP 343.""" +lazy from inspect import getattr_static, _descriptor_get + import abc import os import sys @@ -471,7 +473,6 @@ def __exit__(self, exctype, excinst, exctb): def _lookup_special(obj, name, default): # Follow the standard lookup behaviour for special methods. - from inspect import getattr_static, _descriptor_get cls = type(obj) try: descr = getattr_static(cls, name) diff --git a/Lib/copyreg.py b/Lib/copyreg.py index a5e8add4a554d7..c0c7773bec9f38 100644 --- a/Lib/copyreg.py +++ b/Lib/copyreg.py @@ -4,6 +4,8 @@ C, not for instances of user-defined classes. """ +lazy import typing, operator + __all__ = ["pickle", "constructor", "add_extension", "remove_extension", "clear_extension_cache"] @@ -31,7 +33,6 @@ def pickle_complex(c): pickle(complex, pickle_complex, complex) def pickle_union(obj): - import typing, operator return operator.getitem, (typing.Union, obj.__args__) pickle(type(int | str), pickle_union) diff --git a/Lib/csv.py b/Lib/csv.py index b2aaf5fd9fa91e..872c5f8990e1f8 100644 --- a/Lib/csv.py +++ b/Lib/csv.py @@ -63,6 +63,10 @@ class excel: written as two quotes """ +lazy import re +lazy from collections import Counter, defaultdict +lazy from warnings import _deprecated + import types from _csv import Error, writer, reader, register_dialect, \ unregister_dialect, get_dialect, list_dialects, \ @@ -278,7 +282,6 @@ def _guess_quote_and_delimiter(self, data, delimiters): If there is no quotechar the delimiter can't be determined this way. """ - import re matches = [] for restr in (r'(?P[^\w\n"\'])(?P ?)(?P["\']).*?(?P=quote)(?P=delim)', # ,".*?", @@ -362,7 +365,6 @@ def _guess_delimiter(self, data, delimiters): try and evaluate the smallest portion of the data possible, evaluating additional chunks as necessary. """ - from collections import Counter, defaultdict data = list(filter(None, data.split('\n'))) @@ -515,7 +517,6 @@ def has_header(self, sample): def __getattr__(name): if name == "__version__": - from warnings import _deprecated _deprecated("__version__", remove=(3, 20)) return "1.0" # Do not change diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py index aec92f3aee2472..d6384b553e200a 100644 --- a/Lib/ctypes/__init__.py +++ b/Lib/ctypes/__init__.py @@ -1,5 +1,10 @@ """create and manipulate C data types in Python""" +lazy from struct import calcsize +lazy import warnings +lazy import nt as _nt +lazy from warnings import _deprecated + import os as _os import sys as _sys import sysconfig as _sysconfig @@ -142,7 +147,6 @@ class WinFunctionType(_CFuncPtr): def _check_size(typ, typecode=None): # Check if sizeof(ctypes_type) against struct.calcsize. This # should protect somewhat against a misconfigured libffi. - from struct import calcsize if typecode is None: # Most _type_ codes are the same as used in struct typecode = typ._type_ @@ -276,7 +280,6 @@ def POINTER(cls): pass if isinstance(cls, str): # handle old-style incomplete types (see test_ctypes.test_incomplete) - import warnings warnings._deprecated("ctypes.POINTER with string", remove=(3, 19)) try: return _pointer_type_cache_fallback[cls] @@ -300,7 +303,6 @@ def pointer(obj): class _PointerTypeCache: def __setitem__(self, cls, pointer_type): - import warnings warnings._deprecated("ctypes._pointer_type_cache", remove=(3, 19)) try: cls.__pointer_type__ = pointer_type @@ -308,7 +310,6 @@ def __setitem__(self, cls, pointer_type): _pointer_type_cache_fallback[cls] = pointer_type def __getitem__(self, cls): - import warnings warnings._deprecated("ctypes._pointer_type_cache", remove=(3, 19)) try: return cls.__pointer_type__ @@ -316,7 +317,6 @@ def __getitem__(self, cls): return _pointer_type_cache_fallback[cls] def get(self, cls, default=None): - import warnings warnings._deprecated("ctypes._pointer_type_cache", remove=(3, 19)) try: return cls.__pointer_type__ @@ -423,7 +423,6 @@ class _FuncPtr(_CFuncPtr): if _os.name == "nt": def _load_library(self, name, mode, handle, winmode): if winmode is None: - import nt as _nt winmode = _nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS # WINAPI LoadLibrary searches for a DLL if the given name # is not fully qualified with an explicit drive. For POSIX @@ -671,7 +670,6 @@ def DllCanUnloadNow(): def __getattr__(name): if name == "__version__": - from warnings import _deprecated _deprecated("__version__", remove=(3, 20)) return "1.1.0" # Do not change diff --git a/Lib/ctypes/macholib/__init__.py b/Lib/ctypes/macholib/__init__.py index f00e55f8131c9d..b684c4c285b490 100644 --- a/Lib/ctypes/macholib/__init__.py +++ b/Lib/ctypes/macholib/__init__.py @@ -6,9 +6,10 @@ And also Apple's documentation. """ +lazy from warnings import _deprecated + def __getattr__(name): if name == "__version__": - from warnings import _deprecated _deprecated("__version__", remove=(3, 20)) return "1.0" # Do not change diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py index 378f12167c6842..0d33c4533cc46b 100644 --- a/Lib/ctypes/util.py +++ b/Lib/ctypes/util.py @@ -1,3 +1,8 @@ +lazy import importlib.machinery +lazy import struct +lazy from ctypes import cdll +lazy from ctypes import CDLL + import os import shutil import subprocess @@ -47,7 +52,6 @@ def find_msvcrt(): return None # If python was built with in debug mode - import importlib.machinery if '_d.pyd' in importlib.machinery.EXTENSION_SUFFIXES: clibname += 'd' return clibname+'.dll' @@ -374,7 +378,6 @@ def find_library(name, is64 = False): else: def _findSoname_ldconfig(name): - import struct if struct.calcsize('l') == 4: machine = os.uname().machine + '-32' else: @@ -488,7 +491,6 @@ def dllist(): # test code def test(): - from ctypes import cdll if os.name == "nt": print(cdll.msvcrt) print(cdll.load("msvcrt")) @@ -508,7 +510,6 @@ def test(): print(cdll.LoadLibrary("System.framework/System")) # issue-26439 - fix broken test call for AIX elif sys.platform.startswith("aix"): - from ctypes import CDLL if sys.maxsize < 2**32: print(f"Using CDLL(name, os.RTLD_MEMBER): {CDLL('libc.a(shr.o)', os.RTLD_MEMBER)}") print(f"Using cdll.LoadLibrary(): {cdll.LoadLibrary('libc.a(shr.o)')}") diff --git a/Lib/curses/__init__.py b/Lib/curses/__init__.py index 605d5fcbec5499..f06e1edea233f6 100644 --- a/Lib/curses/__init__.py +++ b/Lib/curses/__init__.py @@ -10,6 +10,8 @@ """ +lazy import _curses, curses + from _curses import * import os as _os import sys as _sys @@ -23,7 +25,6 @@ # curses import *' if you'll be needing the ACS_* constants. def initscr(): - import _curses, curses # we call setupterm() here because it raises an error # instead of calling exit() in error cases. setupterm(term=_os.environ.get("TERM", "unknown"), @@ -39,7 +40,6 @@ def initscr(): # called. def start_color(): - import _curses, curses _curses.start_color() curses.COLORS = _curses.COLORS curses.COLOR_PAIRS = _curses.COLOR_PAIRS diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 730ced7299865e..c9d6ffe3c70731 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1,3 +1,5 @@ +lazy from typing import Any + import re import sys import copy @@ -1705,7 +1707,6 @@ def get_any(): case annotationlib.Format.VALUE: if value_blocked: raise NotImplementedError - from typing import Any return Any case _: raise NotImplementedError diff --git a/Lib/difflib.py b/Lib/difflib.py index 7c7e233b013a76..e95787c02909b0 100644 --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -26,6 +26,8 @@ For producing HTML side by side comparison with change highlights. """ +lazy import re + __all__ = ['get_close_matches', 'ndiff', 'restore', 'SequenceMatcher', 'Differ','IS_CHARACTER_JUNK', 'IS_LINE_JUNK', 'context_diff', 'unified_diff', 'diff_bytes', 'HtmlDiff', 'Match'] @@ -1390,7 +1392,6 @@ def _mdiff(fromlines, tolines, context=None, linejunk=None, side difference markup. Optional ndiff arguments may be passed to this function and they in turn will be passed to ndiff. """ - import re # regular expression for finding intraline change indices change_re = re.compile(r'(\++|\-+|\^+)') diff --git a/Lib/dis.py b/Lib/dis.py index 58c7f6419032c6..73ddb4f9eb15a0 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -1,5 +1,7 @@ """Disassembler of Python byte code into mnemonics.""" +lazy import argparse + import sys import types import collections @@ -1137,7 +1139,6 @@ def dis(self): def main(args=None): - import argparse parser = argparse.ArgumentParser(color=True) parser.add_argument('-C', '--show-caches', action='store_true', diff --git a/Lib/doctest.py b/Lib/doctest.py index 0fcfa1e3e97144..c1570e91d20973 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -45,6 +45,9 @@ def _test(): details. """ +lazy import pdb +lazy import argparse + __docformat__ = 'reStructuredText en' __all__ = [ @@ -2821,7 +2824,6 @@ def debug_src(src, pm=False, globs=None): def debug_script(src, pm=False, globs=None): "Debug a test script. `src` is the script, as a string." - import pdb if globs: globs = globs.copy() @@ -2949,7 +2951,6 @@ def get(self): def _test(): - import argparse parser = argparse.ArgumentParser(description="doctest runner", color=True) parser.add_argument('-v', '--verbose', action='store_true', default=False, diff --git a/Lib/email/__init__.py b/Lib/email/__init__.py index 6d597006e5eefe..ca95e594c453b5 100644 --- a/Lib/email/__init__.py +++ b/Lib/email/__init__.py @@ -4,6 +4,9 @@ """A package for parsing, handling, and generating email messages.""" +lazy from email.parser import Parser +lazy from email.parser import BytesParser + __all__ = [ 'base64mime', 'charset', @@ -33,7 +36,6 @@ def message_from_string(s, *args, **kws): Optional _class and strict are passed to the Parser constructor. """ - from email.parser import Parser return Parser(*args, **kws).parsestr(s) def message_from_bytes(s, *args, **kws): @@ -41,7 +43,6 @@ def message_from_bytes(s, *args, **kws): Optional _class and strict are passed to the Parser constructor. """ - from email.parser import BytesParser return BytesParser(*args, **kws).parsebytes(s) def message_from_file(fp, *args, **kws): @@ -49,7 +50,6 @@ def message_from_file(fp, *args, **kws): Optional _class and strict are passed to the Parser constructor. """ - from email.parser import Parser return Parser(*args, **kws).parse(fp) def message_from_binary_file(fp, *args, **kws): @@ -57,5 +57,4 @@ def message_from_binary_file(fp, *args, **kws): Optional _class and strict are passed to the Parser constructor. """ - from email.parser import BytesParser return BytesParser(*args, **kws).parse(fp) diff --git a/Lib/email/_parseaddr.py b/Lib/email/_parseaddr.py index 6a7c5fa06d20b6..3ca1598ce6ef6f 100644 --- a/Lib/email/_parseaddr.py +++ b/Lib/email/_parseaddr.py @@ -6,6 +6,8 @@ Lifted directly from rfc822.py. This should eventually be rewritten. """ +lazy import calendar + __all__ = [ 'mktime_tz', 'parsedate', @@ -196,7 +198,6 @@ def mktime_tz(data): return time.mktime(data[:8] + (-1,)) else: # Delay the import, since mktime_tz is rarely used - import calendar t = calendar.timegm(data) return t - data[9] diff --git a/Lib/email/feedparser.py b/Lib/email/feedparser.py index ae8ef32792b3e9..26dbd8e2f72aa5 100644 --- a/Lib/email/feedparser.py +++ b/Lib/email/feedparser.py @@ -19,6 +19,8 @@ object's .defects attribute. """ +lazy from email.message import Message + __all__ = ['FeedParser', 'BytesFeedParser'] import re @@ -148,7 +150,6 @@ def __init__(self, _factory=None, *, policy=compat32): self._old_style_factory = False if _factory is None: if policy.message_factory is None: - from email.message import Message self._factory = Message else: self._factory = policy.message_factory diff --git a/Lib/email/message.py b/Lib/email/message.py index 641fb2e944d431..f050b4e3dfe1a8 100644 --- a/Lib/email/message.py +++ b/Lib/email/message.py @@ -4,6 +4,10 @@ """Basic message object for the email package object model.""" +lazy from email.generator import Generator +lazy from email.generator import BytesGenerator +lazy from email.policy import default + __all__ = ['Message', 'EmailMessage'] import binascii @@ -184,7 +188,6 @@ def as_string(self, unixfrom=False, maxheaderlen=0, policy=None): according to RFC standards, the non-compliant data will be replaced by unicode "unknown character" code points. """ - from email.generator import Generator policy = self.policy if policy is None else policy fp = StringIO() g = Generator(fp, @@ -207,7 +210,6 @@ def as_bytes(self, unixfrom=False, policy=None): serialize the message; if not specified the policy associated with the message instance is used. """ - from email.generator import BytesGenerator policy = self.policy if policy is None else policy fp = BytesIO() g = BytesGenerator(fp, mangle_from_=False, policy=policy) @@ -990,7 +992,6 @@ class MIMEPart(Message): def __init__(self, policy=None): if policy is None: - from email.policy import default policy = default super().__init__(policy) diff --git a/Lib/email/utils.py b/Lib/email/utils.py index d4824dc3601b2d..63e9a58543a9ee 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -4,6 +4,9 @@ """Miscellaneous utilities.""" +lazy import random +lazy import socket + __all__ = [ 'collapse_rfc2231_value', 'decode_params', @@ -296,8 +299,6 @@ def make_msgid(idstring=None, domain=None): """ # Lazy imports to speedup module import time # (no other functions in email.utils need these modules) - import random - import socket timeval = int(time.time()*100) pid = os.getpid() diff --git a/Lib/encodings/_win_cp_codecs.py b/Lib/encodings/_win_cp_codecs.py index 4f8eb886794404..902d349c605564 100644 --- a/Lib/encodings/_win_cp_codecs.py +++ b/Lib/encodings/_win_cp_codecs.py @@ -1,7 +1,8 @@ +lazy from codecs import code_page_encode, code_page_decode + import codecs def create_win32_code_page_codec(cp): - from codecs import code_page_encode, code_page_decode def encode(input, errors='strict'): return code_page_encode(cp, input, errors) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 6164ea62324cce..158344da84e3bb 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -1,3 +1,5 @@ +lazy import argparse + import os import subprocess import sys @@ -215,7 +217,6 @@ def _uninstall_helper(*, verbosity=0): def _main(argv=None): - import argparse parser = argparse.ArgumentParser(color=True) parser.add_argument( "--version", diff --git a/Lib/enum.py b/Lib/enum.py index 025e973446d88d..f125c0b358c8ee 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1,3 +1,5 @@ +lazy from inspect import Parameter, Signature + import sys import builtins as bltns from types import MappingProxyType, DynamicClassAttribute @@ -1115,7 +1117,6 @@ def _add_member_(cls, name, member): @property def __signature__(cls): - from inspect import Parameter, Signature if cls._member_names_: return Signature([Parameter('values', Parameter.VAR_POSITIONAL)]) else: diff --git a/Lib/filecmp.py b/Lib/filecmp.py index c5b8d854d77de3..81c8507f9ab189 100644 --- a/Lib/filecmp.py +++ b/Lib/filecmp.py @@ -10,6 +10,9 @@ """ +lazy import sys +lazy import getopt + import os import stat from itertools import filterfalse @@ -305,8 +308,6 @@ def _filter(flist, skip): # Demonstration and testing. # def demo(): - import sys - import getopt options, args = getopt.getopt(sys.argv[1:], 'r') if len(args) != 2: raise getopt.GetoptError('need exactly two args', None) diff --git a/Lib/fileinput.py b/Lib/fileinput.py index 3dba3d2fbfa967..6b953c692e3dca 100644 --- a/Lib/fileinput.py +++ b/Lib/fileinput.py @@ -65,6 +65,11 @@ does not work for MS-DOS 8+3 filesystems. """ +lazy import warnings +lazy import gzip +lazy import bz2 +lazy import getopt + import io import sys, os from types import GenericAlias @@ -212,7 +217,6 @@ def __init__(self, files=None, inplace=False, backup="", *, # take encoding parameter. if (sys.flags.warn_default_encoding and "b" not in mode and encoding is None and openhook is None): - import warnings warnings.warn("'encoding' argument not specified.", EncodingWarning, 2) @@ -403,10 +407,8 @@ def hook_compressed(filename, mode, *, encoding=None, errors=None): encoding = "locale" ext = os.path.splitext(filename)[1] if ext == '.gz': - import gzip stream = gzip.open(filename, mode) elif ext == '.bz2': - import bz2 stream = bz2.BZ2File(filename, mode) else: return open(filename, mode, encoding=encoding, errors=errors) @@ -424,7 +426,6 @@ def openhook(filename, mode): def _test(): - import getopt inplace = False backup = False opts, args = getopt.getopt(sys.argv[1:], "ib:") diff --git a/Lib/fractions.py b/Lib/fractions.py index c1b12e7a1c091c..76c9c2b060f6d8 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -3,6 +3,8 @@ """Fraction, infinite-precision, rational numbers.""" +lazy from decimal import Decimal + import functools import math import numbers @@ -349,7 +351,6 @@ def from_float(cls, f): @classmethod def from_decimal(cls, dec): """Converts a finite Decimal instance to a rational number, exactly.""" - from decimal import Decimal if isinstance(dec, numbers.Integral): dec = Decimal(int(dec)) elif not isinstance(dec, Decimal): diff --git a/Lib/ftplib.py b/Lib/ftplib.py index 640acc64f620cc..74352b8c853833 100644 --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -36,6 +36,9 @@ # Modified by Giampaolo Rodola' to add TLS support. # +lazy import re +lazy import netrc + import sys import socket from socket import _GLOBAL_DEFAULT_TIMEOUT @@ -798,7 +801,6 @@ def parse150(resp): raise error_reply(resp) global _150_re if _150_re is None: - import re _150_re = re.compile( r"150 .* \((\d+) bytes\)", re.IGNORECASE | re.ASCII) m = _150_re.match(resp) @@ -817,7 +819,6 @@ def parse227(resp): raise error_reply(resp) global _227_re if _227_re is None: - import re _227_re = re.compile(r'(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)', re.ASCII) m = _227_re.search(resp) if not m: @@ -917,7 +918,6 @@ def test(): print(test.__doc__) sys.exit(0) - import netrc debugging = 0 rcfile = None diff --git a/Lib/functools.py b/Lib/functools.py index 59fc2a8fbf6219..54d726f13602ee 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -9,6 +9,12 @@ # Copyright (C) 2006 Python Software Foundation. # See C source code for _functools credits/copyright +lazy import weakref +lazy from typing import get_type_hints +lazy from annotationlib import Format, ForwardRef +lazy import os +lazy import warnings + __all__ = ['update_wrapper', 'wraps', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES', 'total_ordering', 'cache', 'cmp_to_key', 'lru_cache', 'reduce', 'partial', 'partialmethod', 'singledispatch', 'singledispatchmethod', @@ -905,7 +911,6 @@ def singledispatch(func): # There are many programs that use functools without singledispatch, so we # trade-off making singledispatch marginally slower for the benefit of # making start-up of such applications slightly faster. - import weakref registry = {} dispatch_cache = weakref.WeakKeyDictionary() @@ -966,8 +971,6 @@ def register(cls, func=None): func = cls # only import typing if annotation parsing is necessary - from typing import get_type_hints - from annotationlib import Format, ForwardRef argname, cls = next(iter(get_type_hints(func, format=Format.FORWARDREF).items())) if not _is_valid_dispatch_type(cls): if isinstance(cls, UnionType): @@ -1165,8 +1168,6 @@ def _warn_python_reduce_kwargs(py_reduce): @wraps(py_reduce) def wrapper(*args, **kwargs): if 'function' in kwargs or 'sequence' in kwargs: - import os - import warnings warnings.warn( 'Calling functools.reduce with keyword arguments ' '"function" or "sequence" ' diff --git a/Lib/genericpath.py b/Lib/genericpath.py index 71ae19190839ae..8f5e886ce29f77 100644 --- a/Lib/genericpath.py +++ b/Lib/genericpath.py @@ -3,6 +3,8 @@ Do not use directly. The OS specific modules import the appropriate functions from this module themselves. """ +lazy import warnings + import os import stat @@ -105,7 +107,6 @@ def getctime(filename, /): # Return the longest prefix of all list elements. def commonprefix(m, /): "Given a list of pathnames, returns the longest common leading component" - import warnings warnings.warn('os.path.commonprefix() is deprecated. Use ' 'os.path.commonpath() for longest path prefix.', category=DeprecationWarning, diff --git a/Lib/getpass.py b/Lib/getpass.py index 3d9bb1f0d146a4..dade793b8f5eab 100644 --- a/Lib/getpass.py +++ b/Lib/getpass.py @@ -15,6 +15,8 @@ # Guido van Rossum (Windows support and cleanup) # Gregory P. Smith (tty support & GetPassWarning) +lazy import warnings + import contextlib import io import os @@ -134,7 +136,6 @@ def win_getpass(prompt='Password: ', stream=None, *, echo_char=None): def fallback_getpass(prompt='Password: ', stream=None, *, echo_char=None): _check_echo_char(echo_char) - import warnings warnings.warn("Can not control echo on the terminal.", GetPassWarning, stacklevel=2) if not stream: diff --git a/Lib/gettext.py b/Lib/gettext.py index 6c11ab2b1eb570..b747c44b20fc0e 100644 --- a/Lib/gettext.py +++ b/Lib/gettext.py @@ -43,6 +43,14 @@ # you'll need to study the GNU gettext code to do this. +lazy import re +lazy import warnings +lazy import locale +lazy import builtins +lazy from struct import unpack +lazy from errno import ENOENT +lazy import copy + import operator import os import sys @@ -71,7 +79,6 @@ def _tokenize(plural): global _token_pattern if _token_pattern is None: - import re _token_pattern = re.compile(r""" (?P[ \t]+) | # spaces and horizontal tabs (?P[0-9]+\b) | # decimal integer @@ -179,7 +186,6 @@ def _as_int2(n): except TypeError: pass - import warnings frame = sys._getframe(1) stacklevel = 2 while frame.f_back is not None and frame.f_globals.get('__name__') == __name__: @@ -229,7 +235,6 @@ def func(n): def _expand_lang(loc): - import locale loc = locale.normalize(loc) COMPONENT_CODESET = 1 << 0 COMPONENT_TERRITORY = 1 << 1 @@ -322,7 +327,6 @@ def charset(self): return self._charset def install(self, names=None): - import builtins builtins.__dict__['_'] = self.gettext if names is not None: allowed = {'gettext', 'ngettext', 'npgettext', 'pgettext'} @@ -350,7 +354,6 @@ def _parse(self, fp): """Override this method to support alternative .mo formats.""" # 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. @@ -533,7 +536,6 @@ def translation(domain, localedir=None, languages=None, if not mofiles: if fallback: return NullTranslations() - 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 @@ -550,7 +552,6 @@ def translation(domain, localedir=None, languages=None, # cached object. # Delay copy import for speeding up gettext import when .mo files # are not used. - import copy t = copy.copy(t) if result is None: result = t diff --git a/Lib/gzip.py b/Lib/gzip.py index 8a2faf846bf894..7dea47e1f4177c 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -5,6 +5,10 @@ # based on Andrew Kuchling's minigzip.py distributed with the zlib module +lazy import errno +lazy import warnings +lazy from argparse import ArgumentParser + import builtins import io import os @@ -310,7 +314,6 @@ def _write_gzip_header(self, compresslevel): def write(self,data): self._check_not_closed() if self.mode != WRITE: - import errno raise OSError(errno.EBADF, "write() on read-only GzipFile object") if self.fileobj is None: @@ -337,7 +340,6 @@ def _write_raw(self, data): def _check_read(self, caller): if self.mode != READ: - import errno msg = f"{caller}() on write-only GzipFile object" raise OSError(errno.EBADF, msg) @@ -462,7 +464,6 @@ def readline(self, size=-1): def __del__(self): if self.mode == WRITE and not self.closed: - import warnings warnings.warn("unclosed GzipFile", ResourceWarning, source=self, stacklevel=2) @@ -662,7 +663,6 @@ def decompress(data): def main(): - from argparse import ArgumentParser parser = ArgumentParser(description= "A simple command line interface for the gzip module: act like gzip, " "but do not delete the input file.", diff --git a/Lib/hmac.py b/Lib/hmac.py index e0c040bcd5fe3d..8924ba93055aee 100644 --- a/Lib/hmac.py +++ b/Lib/hmac.py @@ -3,6 +3,9 @@ Implements the HMAC algorithm as described by RFC 2104. """ +lazy import hashlib +lazy import warnings + try: import _hashlib as _hashopenssl except ImportError: @@ -41,7 +44,6 @@ def _get_digest_constructor(digest_like): return digest_like if isinstance(digest_like, str): def digest_wrapper(d=b''): - import hashlib return hashlib.new(digest_like, d) else: def digest_wrapper(d=b''): @@ -116,7 +118,6 @@ def _init_builtin_hmac(self, key, msg, digestmod): self.block_size = self._hmac.block_size def _init_old(self, key, msg, digestmod): - import warnings digest_cons = _get_digest_constructor(digestmod) if _is_shake_constructor(digest_cons): diff --git a/Lib/http/cookiejar.py b/Lib/http/cookiejar.py index 68cf16c93cc1c8..14980ab3f13d37 100644 --- a/Lib/http/cookiejar.py +++ b/Lib/http/cookiejar.py @@ -25,6 +25,9 @@ """ +lazy import logging +lazy import io, warnings, traceback + __all__ = ['Cookie', 'CookieJar', 'CookiePolicy', 'DefaultCookiePolicy', 'FileCookieJar', 'LWPCookieJar', 'LoadError', 'MozillaCookieJar'] @@ -46,7 +49,6 @@ def _debug(*args): return global logger if not logger: - import logging logger = logging.getLogger("http.cookiejar") return logger.debug(*args) @@ -67,7 +69,6 @@ def _warn_unhandled_exception(): # There are a few catch-all except: statements in this module, for # catching input that's bad in unexpected ways. Warn if any # exceptions are caught there. - import io, warnings, traceback f = io.StringIO() traceback.print_exc(None, f) msg = f.getvalue() diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py index 917280037d4dbb..1fe9953bf66a4d 100644 --- a/Lib/http/cookies.py +++ b/Lib/http/cookies.py @@ -129,6 +129,8 @@ # # Import our required modules # +lazy from time import gmtime, time + import re import string import types @@ -235,7 +237,6 @@ def _unquote(str): 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname): - from time import gmtime, time now = time() year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future) return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % \ diff --git a/Lib/http/server.py b/Lib/http/server.py index 9c9cfbce421343..b5e74c5ab84f80 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -61,6 +61,10 @@ # (Actually, the latter is only true if you know the server configuration # at the time the request was made!) +lazy import argparse +lazy import contextlib +lazy from warnings import _deprecated + __all__ = [ "HTTPServer", "ThreadingHTTPServer", "HTTPSServer", "ThreadingHTTPSServer", @@ -1006,8 +1010,6 @@ def test(HandlerClass=BaseHTTPRequestHandler, def _main(args=None): - import argparse - import contextlib parser = argparse.ArgumentParser(color=True) parser.add_argument('-b', '--bind', metavar='ADDRESS', @@ -1080,7 +1082,6 @@ class HTTPSDualStackServer(DualStackServerMixin, ThreadingHTTPSServer): def __getattr__(name): if name == "__version__": - from warnings import _deprecated _deprecated("__version__", remove=(3, 20)) return "0.6" # Do not change diff --git a/Lib/idlelib/calltip_w.py b/Lib/idlelib/calltip_w.py index 9386376058c791..a4a2ea86627f85 100644 --- a/Lib/idlelib/calltip_w.py +++ b/Lib/idlelib/calltip_w.py @@ -3,6 +3,8 @@ After tooltip.py, which uses ideas gleaned from PySol. Used by calltip.py. """ +lazy from tkinter import Toplevel, Text, LEFT, BOTH + from tkinter import Label, LEFT, SOLID, TclError from idlelib.tooltip import TooltipBase @@ -170,7 +172,6 @@ def _unbind_events(self): def _calltip_window(parent): # htest # - from tkinter import Toplevel, Text, LEFT, BOTH top = Toplevel(parent) top.title("Test call-tips") diff --git a/Lib/idlelib/colorizer.py b/Lib/idlelib/colorizer.py index 6db38de3aa6cb9..619ceadfc1de3a 100644 --- a/Lib/idlelib/colorizer.py +++ b/Lib/idlelib/colorizer.py @@ -1,3 +1,7 @@ +lazy from tkinter import Toplevel, Text +lazy from idlelib.idle_test.test_colorizer import source +lazy from idlelib.percolator import Percolator + import builtins import keyword import re @@ -362,9 +366,6 @@ def removecolors(self): def _color_delegator(parent): # htest # - from tkinter import Toplevel, Text - from idlelib.idle_test.test_colorizer import source - from idlelib.percolator import Percolator top = Toplevel(parent) top.title("Test ColorDelegator") diff --git a/Lib/idlelib/config.py b/Lib/idlelib/config.py index d10c88a43f9231..edaba5e8f3fc24 100644 --- a/Lib/idlelib/config.py +++ b/Lib/idlelib/config.py @@ -25,6 +25,8 @@ """ # TODOs added Oct 2014, tjr +lazy from zlib import crc32 + from configparser import ConfigParser import os import sys @@ -879,7 +881,6 @@ def clear(self): # TODO Revise test output, write expanded unittest def _dump(): # htest # (not really, but ignore in coverage) - from zlib import crc32 line, crc = 0, 0 def sprint(obj): diff --git a/Lib/idlelib/debugger.py b/Lib/idlelib/debugger.py index 1fae1d4b0adbd7..4035f0341cc82e 100644 --- a/Lib/idlelib/debugger.py +++ b/Lib/idlelib/debugger.py @@ -15,6 +15,9 @@ for more. """ +lazy import linecache +lazy import reprlib + import bdb import os @@ -448,7 +451,6 @@ def load_stack(self, stack, index=None): code = frame.f_code filename = code.co_filename funcname = code.co_name - import linecache sourceline = linecache.getline(filename, lineno) sourceline = sourceline.strip() if funcname in ("?", "", None): @@ -515,7 +517,6 @@ def __init__(self, master, title, odict=None): # XXX odict never passed. height = 20*len(odict) # XXX 20 == observed height of Entry widget self.master = master self.title = title - import reprlib self.repr = reprlib.Repr() self.repr.maxstring = 60 self.repr.maxother = 60 diff --git a/Lib/idlelib/debugger_r.py b/Lib/idlelib/debugger_r.py index ad3355d9f82765..000ec602fcac88 100644 --- a/Lib/idlelib/debugger_r.py +++ b/Lib/idlelib/debugger_r.py @@ -19,6 +19,8 @@ barrier, in particular frame and traceback objects. """ +lazy import __main__ + import reprlib import types from idlelib import debugger @@ -102,7 +104,6 @@ def get_stack(self, fid, tbid): return stack, i def run(self, cmd): - import __main__ self.idb.run(cmd, __main__.__dict__) def set_break(self, filename, lineno): diff --git a/Lib/idlelib/debugobj.py b/Lib/idlelib/debugobj.py index fb448ece2fa25e..290c74d75dc041 100644 --- a/Lib/idlelib/debugobj.py +++ b/Lib/idlelib/debugobj.py @@ -10,6 +10,9 @@ # XXX TO DO: # - for classes/modules, add "open source" to object browser +lazy import sys +lazy from tkinter import Toplevel + from reprlib import Repr from idlelib.tree import TreeItem, TreeNode, ScrolledCanvas @@ -123,8 +126,6 @@ def make_objecttreeitem(labeltext, object_, setfunction=None): def _debug_object_browser(parent): # htest # - import sys - from tkinter import Toplevel top = Toplevel(parent) top.title("Test debug object browser") x, y = map(int, parent.geometry().split('+')[1:]) diff --git a/Lib/idlelib/dynoption.py b/Lib/idlelib/dynoption.py index b8937f7106ca75..eeb398d96f5c31 100644 --- a/Lib/idlelib/dynoption.py +++ b/Lib/idlelib/dynoption.py @@ -2,6 +2,8 @@ OptionMenu widget modified to allow dynamic menu reconfiguration and setting of highlightthickness """ +lazy from tkinter import Toplevel + from tkinter import OptionMenu, _setit, StringVar, Button class DynOptionMenu(OptionMenu): @@ -31,7 +33,6 @@ def SetMenu(self,valueList,value=None): def _dyn_option_menu(parent): # htest # - from tkinter import Toplevel # + StringVar, Button top = Toplevel(parent) top.title("Test dynamic option menu") diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 3128934763a1c0..ed05307a4e2d74 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1,3 +1,8 @@ +lazy from idlelib.runscript import ScriptBinding +lazy from idlelib import browser +lazy from idlelib import pathbrowser +lazy import subprocess + import importlib.abc import importlib.util import os @@ -60,7 +65,6 @@ class EditorWindow: def __init__(self, flist=None, filename=None, key=None, root=None): # Delay import: runscript imports pyshell imports EditorWindow. - from idlelib.runscript import ScriptBinding if EditorWindow.help_url is None: EditorWindow.help_url = _get_dochome() @@ -728,17 +732,14 @@ def open_module_browser(self, event=None): filename = self.open_module() if filename is None: return "break" - from idlelib import browser browser.ModuleBrowser(self.root, filename) return "break" def open_path_browser(self, event=None): - from idlelib import pathbrowser pathbrowser.PathBrowser(self.root) return "break" def open_turtle_demo(self, event = None): - import subprocess cmd = [sys.executable, '-c', diff --git a/Lib/idlelib/filelist.py b/Lib/idlelib/filelist.py index e27e5d32a0ff63..844d326b551cde 100644 --- a/Lib/idlelib/filelist.py +++ b/Lib/idlelib/filelist.py @@ -1,5 +1,9 @@ "idlelib.filelist" +lazy from tkinter import Tk +lazy from idlelib.editor import fixwordbreaks +lazy from idlelib.run import fix_scaling + import os from tkinter import messagebox @@ -112,9 +116,6 @@ def canonize(self, filename): def _test(): # TODO check and convert to htest - from tkinter import Tk - from idlelib.editor import fixwordbreaks - from idlelib.run import fix_scaling root = Tk() fix_scaling(root) fixwordbreaks(root) diff --git a/Lib/idlelib/grep.py b/Lib/idlelib/grep.py index 42048ff2395fe1..7398e005dcc3de 100644 --- a/Lib/idlelib/grep.py +++ b/Lib/idlelib/grep.py @@ -3,6 +3,11 @@ Inherits from SearchDialogBase for GUI and uses searchengine to prepare search pattern. """ +lazy from idlelib.outwin import OutputWindow +lazy from tkinter import Toplevel, Text, SEL +lazy from tkinter.ttk import Frame, Button +lazy from idlelib.pyshell import PyShellFileList + import fnmatch import os import sys @@ -141,7 +146,6 @@ def default_command(self, event=None): if not path: self.top.bell() return - from idlelib.outwin import OutputWindow # leave here! save = sys.stdout try: sys.stdout = OutputWindow(self.flist) @@ -190,9 +194,6 @@ def grep_it(self, prog, path): def _grep_dialog(parent): # htest # - from tkinter import Toplevel, Text, SEL - from tkinter.ttk import Frame, Button - from idlelib.pyshell import PyShellFileList top = Toplevel(parent) top.title("Test GrepDialog") diff --git a/Lib/idlelib/help.py b/Lib/idlelib/help.py index 48e7eca280ebf8..a907a86403653c 100644 --- a/Lib/idlelib/help.py +++ b/Lib/idlelib/help.py @@ -27,6 +27,8 @@ _get_dochome() - Return path to docs on user's system if present, otherwise return link to docs.python.org. """ +lazy import winreg + import os import sys from html.parser import HTMLParser @@ -308,7 +310,6 @@ def _get_dochome(): dochome = os.path.join(basepath, pyver, 'Doc', 'index.html') elif sys.platform[:3] == 'win': - import winreg # Windows only, block only executed once. docfile = '' KEY = (rf"Software\Python\PythonCore\{sys.winver}" r"\Help\Main Python Documentation") diff --git a/Lib/idlelib/idle_test/test_config.py b/Lib/idlelib/idle_test/test_config.py index 6d75cf7aa67dcc..f66876975de3e6 100644 --- a/Lib/idlelib/idle_test/test_config.py +++ b/Lib/idlelib/idle_test/test_config.py @@ -3,6 +3,10 @@ * Exception is OSError clause in Save method. Much of IdleConf is also exercised by ConfigDialog and test_configdialog. """ +lazy from test.support import requires +lazy from tkinter import Tk +lazy from tkinter.font import Font + from idlelib import config import sys import os @@ -552,9 +556,6 @@ def test_extra_help_source_list(self): conf.GetExtraHelpSourceList('default') + conf.GetExtraHelpSourceList('user')) def test_get_font(self): - from test.support import requires - from tkinter import Tk - from tkinter.font import Font conf = self.mock_config() requires('gui') diff --git a/Lib/idlelib/idle_test/test_format.py b/Lib/idlelib/idle_test/test_format.py index e5e903688597aa..a12c97c2b11e81 100644 --- a/Lib/idlelib/idle_test/test_format.py +++ b/Lib/idlelib/idle_test/test_format.py @@ -1,5 +1,7 @@ "Test format, coverage 99%." +lazy from idlelib.idle_test.mock_tk import Text + from idlelib import format as ft import unittest from unittest import mock @@ -52,7 +54,6 @@ class FindTest(unittest.TestCase): @classmethod def setUpClass(cls): - from idlelib.idle_test.mock_tk import Text cls.text = Text() def runcase(self, inserttext, stopline, expected): diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py index 43a9ba02c3d3c9..7a406755d23dd1 100644 --- a/Lib/idlelib/idle_test/test_text.py +++ b/Lib/idlelib/idle_test/test_text.py @@ -2,6 +2,9 @@ Run same tests with both by creating a mixin class. ''' +lazy from idlelib.idle_test.mock_tk import Text +lazy from tkinter import Tk, Text + import unittest from test.support import requires from _tkinter import TclError @@ -195,7 +198,6 @@ class MockTextTest(TextTest, unittest.TestCase): @classmethod def setUpClass(cls): - from idlelib.idle_test.mock_tk import Text cls.Text = Text def setUp(self): @@ -219,7 +221,6 @@ class TkTextTest(TextTest, unittest.TestCase): @classmethod def setUpClass(cls): requires('gui') - from tkinter import Tk, Text cls.Text = Text cls.root = Tk() diff --git a/Lib/idlelib/iomenu.py b/Lib/idlelib/iomenu.py index 464126e2df0668..ddc06c224454c3 100644 --- a/Lib/idlelib/iomenu.py +++ b/Lib/idlelib/iomenu.py @@ -1,3 +1,5 @@ +lazy from tkinter import Toplevel, Text + import io import os import shlex @@ -396,7 +398,6 @@ def updaterecentfileslist(self,filename): def _io_binding(parent): # htest # - from tkinter import Toplevel, Text top = Toplevel(parent) top.title("Test IOBinding") diff --git a/Lib/idlelib/macosx.py b/Lib/idlelib/macosx.py index 332952f4572cbd..39bc28942ee389 100644 --- a/Lib/idlelib/macosx.py +++ b/Lib/idlelib/macosx.py @@ -1,6 +1,15 @@ """ A number of functions that enhance IDLE on macOS. """ +lazy from idlelib.__init__ import testing +lazy from test.support import requires, ResourceDenied +lazy from tkinter import Menu +lazy from idlelib import mainmenu +lazy from idlelib import window +lazy from idlelib import help_about +lazy from idlelib import configdialog +lazy from idlelib import help + from os.path import expanduser import plistlib from sys import platform # Used in _init_tk_type, changed by test. @@ -24,9 +33,7 @@ def _init_tk_type(): # When running IDLE, GUI is present, test/* may not be. # When running tests, test/* is present, GUI may not be. # If not, guess most common. Does not matter for testing. - from idlelib.__init__ import testing if testing: - from test.support import requires, ResourceDenied try: requires('gui') except ResourceDenied: @@ -154,9 +161,6 @@ def overrideRootMenu(root, flist): # # Due to a (mis-)feature of TkAqua the user will also see an empty Help # menu. - from tkinter import Menu - from idlelib import mainmenu - from idlelib import window closeItem = mainmenu.menudefs[0][1][-2] @@ -191,13 +195,11 @@ def postwindowsmenu(menu=menu): def about_dialog(event=None): "Handle Help 'About IDLE' event." # Synchronize with editor.EditorWindow.about_dialog. - from idlelib import help_about help_about.AboutDialog(root) def config_dialog(event=None): "Handle Options 'Configure IDLE' event." # Synchronize with editor.EditorWindow.config_dialog. - from idlelib import configdialog # Ensure that the root object has an instance_dict attribute, # mirrors code in EditorWindow (although that sets the attribute @@ -209,7 +211,6 @@ def config_dialog(event=None): def help_dialog(event=None): "Handle Help 'IDLE Help' event." # Synchronize with editor.EditorWindow.help_dialog. - from idlelib import help help.show_idlehelp(root) root.bind('<>', about_dialog) diff --git a/Lib/idlelib/percolator.py b/Lib/idlelib/percolator.py index aa73427c4915c8..9b359e0e73ec59 100644 --- a/Lib/idlelib/percolator.py +++ b/Lib/idlelib/percolator.py @@ -1,3 +1,5 @@ +lazy import tkinter as tk + from idlelib.delegator import Delegator from idlelib.redirector import WidgetRedirector @@ -71,7 +73,6 @@ def removefilter(self, filter): def _percolator(parent): # htest # - import tkinter as tk class Tracer(Delegator): def __init__(self, name): diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index b80c8e56c92810..e2685f6dc69960 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1,5 +1,16 @@ #! /usr/bin/env python3 +lazy from idlelib import debugobj_r +lazy from idlelib.tree import ScrolledCanvas, TreeNode +lazy from idlelib import iomenu +lazy import tkinter +lazy from idlelib.stackviewer import StackBrowser +lazy import getopt +lazy from platform import system +lazy from idlelib import testing +lazy from idlelib import macosx +lazy from idlelib.run import fix_scaling + import sys if __name__ == "__main__": sys.modules['idlelib.pyshell'] = sys.modules['__main__'] @@ -634,13 +645,11 @@ def open_remote_stack_viewer(self): return def remote_stack_viewer(self): - from idlelib import debugobj_r oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {}) if oid is None: self.tkconsole.root.bell() return item = debugobj_r.StubObjectTreeItem(self.rpcclt, oid) - from idlelib.tree import ScrolledCanvas, TreeNode top = Toplevel(self.tkconsole.root) theme = idleConf.CurrentTheme() background = idleConf.GetHighlight(theme, 'normal')['background'] @@ -917,7 +926,6 @@ def __init__(self, flist=None): self.save_stdout = sys.stdout self.save_stderr = sys.stderr self.save_stdin = sys.stdin - from idlelib import iomenu self.stdin = StdInputFile(self, "stdin", iomenu.encoding, iomenu.errors) self.stdout = StdOutputFile(self, "stdout", @@ -1158,7 +1166,6 @@ def begin(self): self.text.focus_force() self.showprompt() # User code should use separate default Tk root window - import tkinter tkinter._support_default_root = True tkinter._default_root = None return True @@ -1365,7 +1372,6 @@ def open_stack_viewer(self, event=None): # -n mode only if self.interp.rpcclt: return self.interp.remote_stack_viewer() - from idlelib.stackviewer import StackBrowser try: StackBrowser(self.root, sys.last_exc, self.flist) except: @@ -1516,10 +1522,6 @@ def fix_x11_paste(root): """ def main(): - import getopt - from platform import system - from idlelib import testing # bool value - from idlelib import macosx global flist, root, use_subprocess @@ -1605,7 +1607,6 @@ def main(): NoDefaultRoot() root = Tk(className="Idle") root.withdraw() - from idlelib.run import fix_scaling fix_scaling(root) # set application icon diff --git a/Lib/idlelib/redirector.py b/Lib/idlelib/redirector.py index 8e2ba68d3815bf..77068e6bee158e 100644 --- a/Lib/idlelib/redirector.py +++ b/Lib/idlelib/redirector.py @@ -1,3 +1,5 @@ +lazy from tkinter import Toplevel, Text + from tkinter import TclError class WidgetRedirector: @@ -150,7 +152,6 @@ def __call__(self, *args): def _widget_redirector(parent): # htest # - from tkinter import Toplevel, Text top = Toplevel(parent) top.title("Test WidgetRedirector") diff --git a/Lib/idlelib/replace.py b/Lib/idlelib/replace.py index 3716d841568d30..9703eaf0f1c0ab 100644 --- a/Lib/idlelib/replace.py +++ b/Lib/idlelib/replace.py @@ -3,6 +3,9 @@ Defines various replace related functions like replace, replace all, and replace+find. """ +lazy from tkinter import Toplevel, Text, END, SEL +lazy from tkinter.ttk import Frame, Button + import re from tkinter import StringVar, TclError @@ -258,8 +261,6 @@ def close(self, event=None): def _replace_dialog(parent): # htest # - from tkinter import Toplevel, Text, END, SEL - from tkinter.ttk import Frame, Button top = Toplevel(parent) top.title("Test ReplaceDialog") diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index a30db99a619a93..da8fca13c70006 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -4,6 +4,13 @@ f'''{sys.executable} -c "__import__('idlelib.run').run.main()"''' '.run' is needed because __import__ returns idlelib, not idlelib.run. """ +lazy import tkinter +lazy from tkinter.messagebox import showerror +lazy import linecache +lazy import atexit +lazy import tkinter.font +lazy import pydoc + import contextlib import functools import io @@ -213,8 +220,6 @@ def manage_socket(address): def show_socket_error(err, address): "Display socket error from manage_socket." - import tkinter - from tkinter.messagebox import showerror root = tkinter.Tk() fix_scaling(root) root.withdraw() @@ -241,7 +246,6 @@ def get_message_lines(typ, exc, tb): def print_exception(): - import linecache linecache.checkcache() flush_stdout() efile = sys.stderr @@ -320,7 +324,6 @@ def exit(): """ if no_exitfunc: - import atexit atexit._clear() capture_warnings(False) sys.exit(0) @@ -328,7 +331,6 @@ def exit(): def fix_scaling(root): """Scale fonts on HiDPI displays.""" - import tkinter.font scaling = float(root.tk.call('tk', 'scaling')) if scaling > 1.4: for name in tkinter.font.names(root): @@ -541,7 +543,6 @@ def handle(self): sys.displayhook = rpc.displayhook # page help() text to shell. - import pydoc # import must be done here to capture i/o binding pydoc.pager = pydoc.plainpager # Keep a reference to stdin so that it won't try to exit IDLE if diff --git a/Lib/idlelib/search.py b/Lib/idlelib/search.py index 935a4832257fa4..f2d547951516f2 100644 --- a/Lib/idlelib/search.py +++ b/Lib/idlelib/search.py @@ -4,6 +4,9 @@ Inherits from SearchDialogBase for GUI and uses searchengine to prepare search pattern. """ +lazy from tkinter import Toplevel, Text +lazy from tkinter.ttk import Frame, Button + from tkinter import TclError from idlelib import searchengine @@ -134,8 +137,6 @@ def find_selection(self, text): def _search_dialog(parent): # htest # "Display search test box." - from tkinter import Toplevel, Text - from tkinter.ttk import Frame, Button top = Toplevel(parent) top.title("Test SearchDialog") diff --git a/Lib/idlelib/searchbase.py b/Lib/idlelib/searchbase.py index c68a6ca339af04..8b0178327cbcf3 100644 --- a/Lib/idlelib/searchbase.py +++ b/Lib/idlelib/searchbase.py @@ -1,5 +1,8 @@ '''Define SearchDialogBase used by Search, Replace, and Grep dialogs.''' +lazy import re +lazy from idlelib import searchengine + from tkinter import Toplevel from tkinter.ttk import Frame, Entry, Label, Button, Checkbutton, Radiobutton from tkinter.simpledialog import _setup_dialog @@ -189,8 +192,6 @@ class _searchbase(SearchDialogBase): # htest # "Create auto-opening dialog with no text connection." def __init__(self, parent): - import re - from idlelib import searchengine self.root = parent self.engine = searchengine.get(parent) diff --git a/Lib/idlelib/sidebar.py b/Lib/idlelib/sidebar.py index aa19a24e3edef2..fde7256cfbd8e4 100644 --- a/Lib/idlelib/sidebar.py +++ b/Lib/idlelib/sidebar.py @@ -1,6 +1,8 @@ """Line numbering implementation for IDLE as an extension. Includes BaseSideBar which can be extended for other sidebar based extensions """ +lazy from idlelib.idle_test.test_sidebar import Dummy_editwin + import contextlib import functools import itertools @@ -514,7 +516,6 @@ def update_colors(self): def _sidebar_number_scrolling(parent): # htest # - from idlelib.idle_test.test_sidebar import Dummy_editwin top = tk.Toplevel(parent) text_frame = tk.Frame(top) diff --git a/Lib/idlelib/stackviewer.py b/Lib/idlelib/stackviewer.py index 95042d4debdc03..fe48cde156f959 100644 --- a/Lib/idlelib/stackviewer.py +++ b/Lib/idlelib/stackviewer.py @@ -1,5 +1,7 @@ # Rename to stackbrowser or possibly consolidate with browser. +lazy from idlelib.pyshell import PyShellFileList + import linecache import os @@ -114,7 +116,6 @@ def setfunction(value, key=key, object_=self.object): def _stackbrowser(parent): # htest # - from idlelib.pyshell import PyShellFileList top = tk.Toplevel(parent) top.title("Test StackViewer") x, y = map(int, parent.geometry().split('+')[1:]) diff --git a/Lib/idlelib/statusbar.py b/Lib/idlelib/statusbar.py index 8445d4cc8dfdb9..8eb9055062e0d0 100644 --- a/Lib/idlelib/statusbar.py +++ b/Lib/idlelib/statusbar.py @@ -1,3 +1,6 @@ +lazy from tkinter import Toplevel, Text +lazy from tkinter.ttk import Frame, Button + from tkinter.ttk import Label, Frame @@ -20,8 +23,6 @@ def set_label(self, name, text='', side='left', width=0): def _multistatus_bar(parent): # htest # - from tkinter import Toplevel, Text - from tkinter.ttk import Frame, Button top = Toplevel(parent) x, y = map(int, parent.geometry().split('+')[1:]) top.geometry("+%d+%d" %(x, y + 175)) diff --git a/Lib/idlelib/tree.py b/Lib/idlelib/tree.py index 182ce7189614da..8fb96a62bc09df 100644 --- a/Lib/idlelib/tree.py +++ b/Lib/idlelib/tree.py @@ -14,6 +14,8 @@ # - keep track of object ids to allow more careful cleaning # - optimize tree redraw after expand of subnode +lazy import glob + import os from tkinter import * @@ -37,7 +39,6 @@ def listicons(icondir=ICONDIR): """Utility to display the available icons.""" root = Tk() - import glob list = glob.glob(os.path.join(glob.escape(icondir), "*.gif")) list.sort() images = [] diff --git a/Lib/idlelib/undo.py b/Lib/idlelib/undo.py index f52446d5fcdcf8..3946218d1233bd 100644 --- a/Lib/idlelib/undo.py +++ b/Lib/idlelib/undo.py @@ -1,3 +1,7 @@ +lazy from pprint import pprint +lazy from tkinter import Toplevel, Text, Button +lazy from idlelib.percolator import Percolator + import string from idlelib.delegator import Delegator @@ -38,7 +42,6 @@ def setdelegate(self, delegate): self.bind("<>", self.dump_event) def dump_event(self, event): - from pprint import pprint pprint(self.undolist[:self.pointer]) print("pointer:", self.pointer, end=' ') print("saved:", self.saved, end=' ') @@ -337,8 +340,6 @@ def bump_depth(self, incr=1): def _undo_delegator(parent): # htest # - from tkinter import Toplevel, Text, Button - from idlelib.percolator import Percolator top = Toplevel(parent) top.title("Test UndoDelegator") x, y = map(int, parent.geometry().split('+')[1:]) diff --git a/Lib/imaplib.py b/Lib/imaplib.py index cb3edceae0d9f1..602230653c3ee5 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -21,6 +21,10 @@ # GET/SETANNOTATION contributed by Tomas Lindroos June 2005. # IDLE contributed by Forest August 2024. +lazy import warnings +lazy import hmac +lazy from warnings import _deprecated + import binascii, errno, random, re, socket, subprocess, sys, time, calendar from datetime import datetime, timezone, timedelta from io import DEFAULT_BUFFER_SIZE @@ -325,7 +329,6 @@ def file(self): # Nevertheless, we provide this property for now, to avoid suddenly # breaking any code in the wild that might have been using it in a # harmless way. - import warnings warnings.warn( 'IMAP4.file is unsupported, can cause errors, and may be removed.', RuntimeWarning, @@ -719,7 +722,6 @@ def login_cram_md5(self, user, password): def _CRAM_MD5_AUTH(self, challenge): """ Authobject to use with CRAM-MD5 authentication. """ - import hmac if isinstance(self.password, str): password = self.password.encode('utf-8') @@ -1968,7 +1970,6 @@ def run(cmd, args): def __getattr__(name): if name == "__version__": - from warnings import _deprecated _deprecated("__version__", remove=(3, 20)) return "2.60" # Do not change diff --git a/Lib/importlib/metadata/__init__.py b/Lib/importlib/metadata/__init__.py index 7cf4d29d330c91..a38ad35a2e8e6f 100644 --- a/Lib/importlib/metadata/__init__.py +++ b/Lib/importlib/metadata/__init__.py @@ -9,6 +9,12 @@ from __future__ import annotations +lazy from . import _adapters +lazy import csv +lazy import json +lazy import zipfile +lazy import inspect + import abc import collections import email @@ -532,7 +538,6 @@ def metadata(self) -> _meta.PackageMetadata | None: @pass_none def _assemble_message(text: str) -> _meta.PackageMetadata: # deferred for performance (python/cpython#109829) - from . import _adapters return _adapters.Message(email.message_from_string(text)) @@ -588,7 +593,6 @@ def make_file(name, hash=None, size_str=None): def make_files(lines): # Delay csv import, since Distribution.files is not as widely used # as other parts of importlib.metadata - import csv return starmap(make_file, csv.reader(lines)) @@ -712,7 +716,6 @@ def origin(self): def _load_json(self, filename): # Deferred for performance (python/importlib_metadata#503) - import json return pass_none(json.loads)( self.read_text(filename), @@ -817,7 +820,6 @@ def children(self): def zip_children(self): # deferred for performance (python/importlib_metadata#502) - import zipfile zip_path = zipfile.Path(self.root) names = zip_path.root.namelist() @@ -1155,7 +1157,6 @@ def _get_toplevel_name(name: PackagePath) -> str: 'foo.dist-info' """ # Defer import of inspect for performance (python/cpython#118761) - import inspect return _topmost(name) or inspect.getmodulename(name) or str(name) diff --git a/Lib/importlib/resources/_common.py b/Lib/importlib/resources/_common.py index d16ebe4520fbbf..28163a3442901b 100644 --- a/Lib/importlib/resources/_common.py +++ b/Lib/importlib/resources/_common.py @@ -1,3 +1,5 @@ +lazy from ._adapters import wrap_spec + import os import pathlib import tempfile @@ -77,7 +79,6 @@ def from_package(package: types.ModuleType): """ # deferred for performance (python/cpython#109829) - from ._adapters import wrap_spec spec = wrap_spec(package) reader = spec.loader.get_resource_reader(spec.name) diff --git a/Lib/inspect.py b/Lib/inspect.py index 0eed68d17c702b..f826491a2947df 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -28,6 +28,9 @@ # This module is in the public domain. No warranties. +lazy import argparse +lazy import importlib + __author__ = ('Ka-Ping Yee ', 'Yury Selivanov ') @@ -3354,8 +3357,6 @@ class BufferFlags(enum.IntFlag): def _main(): """ Logic for inspecting an object given at command line """ - import argparse - import importlib parser = argparse.ArgumentParser(color=True) parser.add_argument( diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index f1062a8cd052a5..ac60ef0cbee5c1 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -8,6 +8,9 @@ """ +lazy import re +lazy from warnings import _deprecated + import functools IPV4LENGTH = 32 @@ -630,7 +633,6 @@ def __format__(self, fmt): # From here on down, support for 'bnXx' global _address_fmt_re if _address_fmt_re is None: - import re _address_fmt_re = re.compile('(#?)(_?)([xbnX])') m = _address_fmt_re.fullmatch(fmt) @@ -2420,7 +2422,6 @@ class _IPv6Constants: def __getattr__(name): if name == "__version__": - from warnings import _deprecated _deprecated("__version__", remove=(3, 20)) return "1.0" # Do not change diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py index 89396b25a2cbb3..2f499002bb86e8 100644 --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -95,6 +95,8 @@ $ echo '{ 1.2:3.4}' | python -m json Expecting property name enclosed in double quotes: line 1 column 3 (char 2) """ +lazy from warnings import _deprecated + __all__ = [ 'dump', 'dumps', 'load', 'loads', 'JSONDecoder', 'JSONDecodeError', 'JSONEncoder', @@ -366,7 +368,6 @@ def loads(s, *, cls=None, object_hook=None, parse_float=None, def __getattr__(name): if name == "__version__": - from warnings import _deprecated _deprecated("__version__", remove=(3, 20)) return "2.0.9" # Do not change diff --git a/Lib/linecache.py b/Lib/linecache.py index b5bf9dbdd3cbc7..46c1a633212463 100644 --- a/Lib/linecache.py +++ b/Lib/linecache.py @@ -5,6 +5,8 @@ that name. """ +lazy import warnings + __all__ = ["getline", "clearcache", "checkcache", "lazycache"] @@ -261,7 +263,6 @@ def _bless_my_loader(module_globals): spec_loader = getattr(spec, 'loader', None) if spec_loader is None: - import warnings warnings.warn( 'Module globals is missing a __spec__.loader', DeprecationWarning) @@ -269,7 +270,6 @@ def _bless_my_loader(module_globals): assert spec_loader is not None if loader is not None and loader != spec_loader: - import warnings warnings.warn( 'Module globals; __loader__ != __spec__.loader', DeprecationWarning) diff --git a/Lib/locale.py b/Lib/locale.py index dea3ee55cf4d24..4415752d6a8c5e 100644 --- a/Lib/locale.py +++ b/Lib/locale.py @@ -10,6 +10,9 @@ """ +lazy import re +lazy import os + import sys import encodings import encodings.aliases @@ -217,7 +220,6 @@ def format_string(f, val, grouping=False, monetary=False): fourth parameter monetary is true.""" global _percent_re if _percent_re is None: - import re _percent_re = re.compile(r'%(?:\((?P.*?)\))?(?P[-#0-9 +*.hlL]*?)[eEfFgGdiouxXcrs%]') @@ -579,7 +581,6 @@ def _getdefaultlocale(envvars=('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE')): return code, encoding # fall back on POSIX behaviour - import os lookup = os.environ.get for variable in envvars: localename = lookup(variable,None) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index 39689a57e6ecd6..e7b064db2c5cc5 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -23,6 +23,9 @@ To use, simply 'import logging' and log away! """ +lazy import pickle +lazy from warnings import _deprecated + import sys, os, time, io, re, traceback, warnings, weakref, collections.abc from types import GenericAlias @@ -1819,7 +1822,6 @@ def __repr__(self): def __reduce__(self): if getLogger(self.name) is not self: - import pickle raise pickle.PicklingError('logger cannot be pickled') return getLogger, (self.name,) @@ -2343,7 +2345,6 @@ def captureWarnings(capture): def __getattr__(name): if name in ("__version__", "__date__"): - from warnings import _deprecated _deprecated(name, remove=(3, 20)) return { # Do not change diff --git a/Lib/logging/config.py b/Lib/logging/config.py index 3d9aa00fa52d11..e62e27d0b6a25d 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -24,6 +24,10 @@ To use, simply 'import logging' and log away! """ +lazy import configparser +lazy from multiprocessing.queues import Queue as MPQueue +lazy import select + import errno import functools import io @@ -59,7 +63,6 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=True, encoding=Non developer provides a mechanism to present the choices and load the chosen configuration). """ - import configparser if isinstance(fname, str): if not os.path.exists(fname): @@ -502,7 +505,6 @@ def _is_queue_like_object(obj): if isinstance(obj, (queue.Queue, queue.SimpleQueue)): return True # defer importing multiprocessing as much as possible - from multiprocessing.queues import Queue as MPQueue if isinstance(obj, MPQueue): return True # Depending on the multiprocessing start context, we cannot create @@ -1030,7 +1032,6 @@ def __init__(self, host='localhost', port=DEFAULT_LOGGING_CONFIG_PORT, self.verify = verify def serve_until_stopped(self): - import select abort = 0 while not abort: rd, wr, ex = select.select([self.socket.fileno()], diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 575f2babbc4785..dd6c3eba8aca55 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -23,6 +23,10 @@ To use, simply 'import logging.handlers' and log away! """ +lazy import _winapi +lazy import winreg +lazy import http.client + import copy import io import logging @@ -1137,7 +1141,6 @@ class NTEventLogHandler(logging.Handler): """ def __init__(self, appname, dllname=None, logtype="Application"): logging.Handler.__init__(self) - import _winapi self._winapi = _winapi self.appname = appname if not dllname: @@ -1169,7 +1172,6 @@ def __init__(self, appname, dllname=None, logtype="Application"): @staticmethod def _add_source_to_registry(appname, dllname, logtype): - import winreg key_path = f"SYSTEM\\CurrentControlSet\\Services\\EventLog\\{logtype}\\{appname}" @@ -1285,7 +1287,6 @@ def getConnection(self, host, secure): Override when a custom connection is required, for example if there is a proxy. """ - import http.client if secure: connection = http.client.HTTPSConnection(host, context=self.context) else: diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py index fc916c470a0110..33b44796959775 100644 --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -23,6 +23,12 @@ read_mime_types(file) -- parse one file, return a dictionary or None """ +lazy from warnings import _deprecated +lazy import os +lazy import urllib.parse +lazy import posixpath +lazy from argparse import ArgumentParser + try: from _winapi import _mimetypes_read_windows_registry except ImportError: @@ -93,7 +99,6 @@ def add_type(self, type, ext, strict=True): Valid extensions are empty or start with a '.'. """ if ext and not ext.startswith('.'): - from warnings import _deprecated _deprecated( "Undotted extensions", @@ -129,8 +134,6 @@ def guess_type(self, url, strict=True): but non-standard types. """ # Lazy import to improve module import time - import os - import urllib.parse # TODO: Deprecate accepting file paths (in particular path-like objects). url = os.fspath(url) @@ -161,7 +164,6 @@ def guess_type(self, url, strict=True): return type, None # never compressed, so encoding is None # Lazy import to improve module import time - import posixpath return self._guess_file_type(url, strict, posixpath.splitext) @@ -171,7 +173,6 @@ def guess_file_type(self, path, *, strict=True): Similar to guess_type(), but takes file path instead of URL. """ # Lazy import to improve module import time - import os path = os.fsdecode(path) path = os.path.splitdrive(path)[1] @@ -420,7 +421,6 @@ def init(files=None): db = _db # Lazy import to improve module import time - import os for file in files: if os.path.isfile(file): @@ -698,7 +698,6 @@ def _default_mime_types(): def _parse_args(args): - from argparse import ArgumentParser parser = ArgumentParser( description='map filename extensions to MIME types', color=True diff --git a/Lib/modulefinder.py b/Lib/modulefinder.py index b8dccc2dd33afe..4fcdffffe4dd89 100644 --- a/Lib/modulefinder.py +++ b/Lib/modulefinder.py @@ -1,5 +1,7 @@ """Find modules used by a script, using introspection.""" +lazy import getopt + import dis import importlib._bootstrap_external import importlib.machinery @@ -616,7 +618,6 @@ def replace_paths_in_code(self, co): def test(): # Parse command line - import getopt try: opts, args = getopt.getopt(sys.argv[1:], "dmp:qx:") except getopt.error as msg: diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index 64ec53884aeb5d..a665c3bc38867f 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -7,6 +7,10 @@ # Licensed to PSF under a Contributor Agreement. # +lazy import hmac +lazy import xmlrpc.client as xmlrpclib +lazy from . import resource_sharer + __all__ = [ 'Client', 'Listener', 'Pipe', 'wait' ] import errno @@ -898,7 +902,6 @@ def _create_response(authkey, message): Note: The MAC protects the entire message including the digest_name prefix. """ - import hmac digest_name = _get_digest_name_and_payload(message)[0] # The MAC protects the entire message: digest header and payload. if not digest_name: @@ -926,7 +929,6 @@ def _verify_challenge(authkey, message, response): algorithm, because the MAC is calculated over the entire message including the '{digest_name}' prefix. """ - import hmac response_digest, response_mac = _get_digest_name_and_payload(response) response_digest = response_digest or 'md5' try: @@ -1008,13 +1010,11 @@ def _xml_loads(s): class XmlListener(Listener): def accept(self): global xmlrpclib - import xmlrpc.client as xmlrpclib obj = Listener.accept(self) return ConnectionWrapper(obj, _xml_dumps, _xml_loads) def XmlClient(*args, **kwds): global xmlrpclib - import xmlrpc.client as xmlrpclib return ConnectionWrapper(Client(*args, **kwds), _xml_dumps, _xml_loads) # @@ -1178,7 +1178,6 @@ def wait(object_list, timeout=None): def reduce_connection(conn): handle = conn.fileno() with socket.fromfd(handle, socket.AF_INET, socket.SOCK_STREAM) as s: - from . import resource_sharer ds = resource_sharer.DupSocket(s) return rebuild_connection, (ds, conn.readable, conn.writable) def rebuild_connection(ds, readable, writable): diff --git a/Lib/multiprocessing/context.py b/Lib/multiprocessing/context.py index a73261cde856bb..b1903288a89de8 100644 --- a/Lib/multiprocessing/context.py +++ b/Lib/multiprocessing/context.py @@ -1,3 +1,27 @@ +lazy from .managers import SyncManager +lazy from .connection import Pipe +lazy from .synchronize import Lock +lazy from .synchronize import RLock +lazy from .synchronize import Condition +lazy from .synchronize import Semaphore +lazy from .synchronize import BoundedSemaphore +lazy from .synchronize import Event +lazy from .synchronize import Barrier +lazy from .queues import Queue +lazy from .queues import JoinableQueue +lazy from .queues import SimpleQueue +lazy from .pool import Pool +lazy from .sharedctypes import RawValue +lazy from .sharedctypes import RawArray +lazy from .sharedctypes import Value +lazy from .sharedctypes import Array +lazy from .spawn import freeze_support +lazy from .util import get_logger +lazy from .util import log_to_stderr +lazy from . import connection +lazy from .spawn import set_executable +lazy from .forkserver import set_forkserver_preload + import os import sys import threading @@ -52,92 +76,75 @@ def Manager(self): The managers methods such as `Lock()`, `Condition()` and `Queue()` can be used to create shared objects. ''' - from .managers import SyncManager m = SyncManager(ctx=self.get_context()) m.start() return m def Pipe(self, duplex=True): '''Returns two connection object connected by a pipe''' - from .connection import Pipe return Pipe(duplex) def Lock(self): '''Returns a non-recursive lock object''' - from .synchronize import Lock return Lock(ctx=self.get_context()) def RLock(self): '''Returns a recursive lock object''' - from .synchronize import RLock return RLock(ctx=self.get_context()) def Condition(self, lock=None): '''Returns a condition object''' - from .synchronize import Condition return Condition(lock, ctx=self.get_context()) def Semaphore(self, value=1): '''Returns a semaphore object''' - from .synchronize import Semaphore return Semaphore(value, ctx=self.get_context()) def BoundedSemaphore(self, value=1): '''Returns a bounded semaphore object''' - from .synchronize import BoundedSemaphore return BoundedSemaphore(value, ctx=self.get_context()) def Event(self): '''Returns an event object''' - from .synchronize import Event return Event(ctx=self.get_context()) def Barrier(self, parties, action=None, timeout=None): '''Returns a barrier object''' - from .synchronize import Barrier return Barrier(parties, action, timeout, ctx=self.get_context()) def Queue(self, maxsize=0): '''Returns a queue object''' - from .queues import Queue return Queue(maxsize, ctx=self.get_context()) def JoinableQueue(self, maxsize=0): '''Returns a queue object''' - from .queues import JoinableQueue return JoinableQueue(maxsize, ctx=self.get_context()) def SimpleQueue(self): '''Returns a queue object''' - from .queues import SimpleQueue return SimpleQueue(ctx=self.get_context()) def Pool(self, processes=None, initializer=None, initargs=(), maxtasksperchild=None): '''Returns a process pool object''' - from .pool import Pool return Pool(processes, initializer, initargs, maxtasksperchild, context=self.get_context()) def RawValue(self, typecode_or_type, *args): '''Returns a shared object''' - from .sharedctypes import RawValue return RawValue(typecode_or_type, *args) def RawArray(self, typecode_or_type, size_or_initializer): '''Returns a shared array''' - from .sharedctypes import RawArray return RawArray(typecode_or_type, size_or_initializer) def Value(self, typecode_or_type, *args, lock=True): '''Returns a synchronized shared object''' - from .sharedctypes import Value return Value(typecode_or_type, *args, lock=lock, ctx=self.get_context()) def Array(self, typecode_or_type, size_or_initializer, *, lock=True): '''Returns a synchronized shared array''' - from .sharedctypes import Array return Array(typecode_or_type, size_or_initializer, lock=lock, ctx=self.get_context()) @@ -146,19 +153,16 @@ def freeze_support(self): If so then run code specified by commandline and exit. ''' if self.get_start_method() == 'spawn' and getattr(sys, 'frozen', False): - from .spawn import freeze_support freeze_support() def get_logger(self): '''Return package logger -- if it does not already exist then it is created. ''' - from .util import get_logger return get_logger() def log_to_stderr(self, level=None): '''Turn on logging and add a handler which prints to stderr''' - from .util import log_to_stderr return log_to_stderr(level) def allow_connection_pickling(self): @@ -167,14 +171,12 @@ def allow_connection_pickling(self): ''' # This is undocumented. In previous versions of multiprocessing # its only effect was to make socket objects inheritable on Windows. - from . import connection # noqa: F401 def set_executable(self, executable): '''Sets the path to a python.exe or pythonw.exe binary used to run child processes instead of sys.executable when using the 'spawn' start method. Useful for people embedding Python. ''' - from .spawn import set_executable set_executable(executable) def set_forkserver_preload(self, module_names, *, on_error='ignore'): @@ -184,7 +186,6 @@ def set_forkserver_preload(self, module_names, *, on_error='ignore'): "ignore" (default) silently ignores failures, "warn" emits warnings, and "fail" raises exceptions breaking the forkserver context. ''' - from .forkserver import set_forkserver_preload set_forkserver_preload(module_names, on_error=on_error) def get_context(self, method=None): diff --git a/Lib/multiprocessing/dummy/__init__.py b/Lib/multiprocessing/dummy/__init__.py index 7dc5d1c8dde848..2c0afd29525007 100644 --- a/Lib/multiprocessing/dummy/__init__.py +++ b/Lib/multiprocessing/dummy/__init__.py @@ -7,6 +7,8 @@ # Licensed to PSF under a Contributor Agreement. # +lazy from ..pool import ThreadPool + __all__ = [ 'Process', 'current_process', 'active_children', 'freeze_support', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Condition', @@ -120,7 +122,6 @@ def shutdown(): pass def Pool(processes=None, initializer=None, initargs=()): - from ..pool import ThreadPool return ThreadPool(processes, initializer, initargs) JoinableQueue = Queue diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index 91bcf243e78e5b..e193f5b985a3d2 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -8,6 +8,8 @@ # Licensed to PSF under a Contributor Agreement. # +lazy from . import resource_tracker + __all__ = [ 'BaseManager', 'SyncManager', 'BaseProxy', 'Token' ] # @@ -1392,7 +1394,6 @@ def __init__(self, *args, **kwargs): # shared_memory manipulation both in the manager and in the # current process does not create two resource_tracker # processes. - from . import resource_tracker resource_tracker.ensure_running() BaseManager.__init__(self, *args, **kwargs) util.debug(f"{self.__class__.__name__} created by pid {getpid()}") diff --git a/Lib/multiprocessing/pool.py b/Lib/multiprocessing/pool.py index f979890170b1a1..056387972f38d6 100644 --- a/Lib/multiprocessing/pool.py +++ b/Lib/multiprocessing/pool.py @@ -7,6 +7,8 @@ # Licensed to PSF under a Contributor Agreement. # +lazy from .dummy import Process + __all__ = ['Pool', 'ThreadPool'] # @@ -923,7 +925,6 @@ class ThreadPool(Pool): @staticmethod def Process(ctx, *args, **kwds): - from .dummy import Process return Process(*args, **kwds) def __init__(self, processes=None, initializer=None, initargs=()): diff --git a/Lib/multiprocessing/popen_fork.py b/Lib/multiprocessing/popen_fork.py index 7affa1b985f091..08f5d8ceee23d5 100644 --- a/Lib/multiprocessing/popen_fork.py +++ b/Lib/multiprocessing/popen_fork.py @@ -1,3 +1,5 @@ +lazy from multiprocessing.connection import wait + import atexit import os import signal @@ -37,7 +39,6 @@ def poll(self, flag=os.WNOHANG): def wait(self, timeout=None): if self.returncode is None: if timeout is not None: - from multiprocessing.connection import wait if not wait([self.sentinel], timeout): return None # This shouldn't block if wait() returned successfully. diff --git a/Lib/multiprocessing/popen_forkserver.py b/Lib/multiprocessing/popen_forkserver.py index a56eb9bf11080b..688e17dbb4cfdc 100644 --- a/Lib/multiprocessing/popen_forkserver.py +++ b/Lib/multiprocessing/popen_forkserver.py @@ -1,3 +1,5 @@ +lazy from multiprocessing.connection import wait + import io import os @@ -60,7 +62,6 @@ def _launch(self, process_obj): def poll(self, flag=os.WNOHANG): if self.returncode is None: - from multiprocessing.connection import wait timeout = 0 if flag == os.WNOHANG else None if not wait([self.sentinel], timeout): return None diff --git a/Lib/multiprocessing/popen_spawn_posix.py b/Lib/multiprocessing/popen_spawn_posix.py index cccd659ae77637..1ad28c53e23816 100644 --- a/Lib/multiprocessing/popen_spawn_posix.py +++ b/Lib/multiprocessing/popen_spawn_posix.py @@ -1,3 +1,5 @@ +lazy from . import resource_tracker + import io import os @@ -36,7 +38,6 @@ def duplicate_for_child(self, fd): return fd def _launch(self, process_obj): - from . import resource_tracker tracker_fd = resource_tracker.getfd() self._fds.append(tracker_fd) prep_data = spawn.get_preparation_data(process_obj._name) diff --git a/Lib/multiprocessing/process.py b/Lib/multiprocessing/process.py index 262513f295fde5..10e25535f76b42 100644 --- a/Lib/multiprocessing/process.py +++ b/Lib/multiprocessing/process.py @@ -7,6 +7,11 @@ # Licensed to PSF under a Contributor Agreement. # +lazy from . import util, context +lazy from . import util +lazy from .context import get_spawning_popen +lazy from multiprocessing.connection import wait + __all__ = ['BaseProcess', 'current_process', 'active_children', 'parent_process'] @@ -295,7 +300,6 @@ def __repr__(self): ## def _bootstrap(self, parent_sentinel=None): - from . import util, context global _current_process, _parent_process, _process_counter, _children try: @@ -341,7 +345,6 @@ def _bootstrap(self, parent_sentinel=None): @staticmethod def _after_fork(): - from . import util util._finalizer_registry.clear() util._run_after_forkers() @@ -352,7 +355,6 @@ def _after_fork(): class AuthenticationString(bytes): def __reduce__(self): - from .context import get_spawning_popen if get_spawning_popen() is None: raise TypeError( 'Pickling an AuthenticationString object is ' @@ -378,7 +380,6 @@ def __init__(self, name, pid, sentinel): self._config = {} def is_alive(self): - from multiprocessing.connection import wait return not wait([self._sentinel], timeout=0) @property @@ -389,7 +390,6 @@ def join(self, timeout=None): ''' Wait until parent process terminates ''' - from multiprocessing.connection import wait wait([self._sentinel], timeout=timeout) pid = ident diff --git a/Lib/multiprocessing/queues.py b/Lib/multiprocessing/queues.py index 981599acf5ef26..1ad094be7d495e 100644 --- a/Lib/multiprocessing/queues.py +++ b/Lib/multiprocessing/queues.py @@ -7,6 +7,9 @@ # Licensed to PSF under a Contributor Agreement. # +lazy from .synchronize import SEM_VALUE_MAX as _SEM_VALUE_MAX +lazy import traceback + __all__ = ['Queue', 'SimpleQueue', 'JoinableQueue'] import sys @@ -35,7 +38,7 @@ class Queue(object): def __init__(self, maxsize=0, *, ctx): if maxsize <= 0: # Can raise ImportError (see issues #3770 and #23400) - from .synchronize import SEM_VALUE_MAX as maxsize + maxsize = _SEM_VALUE_MAX self._maxsize = maxsize self._reader, self._writer = connection.Pipe(duplex=False) self._rlock = ctx.Lock() @@ -295,7 +298,6 @@ def _on_queue_feeder_error(e, obj): Private API hook called when feeding data in the background thread raises an exception. For overriding by concurrent.futures. """ - import traceback traceback.print_exc() __class_getitem__ = classmethod(types.GenericAlias) diff --git a/Lib/multiprocessing/reduction.py b/Lib/multiprocessing/reduction.py index fcccd3eef86cc7..e3aaae59e07a24 100644 --- a/Lib/multiprocessing/reduction.py +++ b/Lib/multiprocessing/reduction.py @@ -7,6 +7,9 @@ # Licensed to PSF under a Contributor Agreement. # +lazy from . import resource_sharer +lazy from .resource_sharer import DupSocket + from abc import ABCMeta import copyreg import functools @@ -194,7 +197,6 @@ def DupFd(fd): if popen_obj is not None: return popen_obj.DupFd(popen_obj.duplicate_for_child(fd)) elif HAVE_SEND_HANDLE: - from . import resource_sharer return resource_sharer.DupFd(fd) else: raise ValueError('SCM_RIGHTS appears not to be available') @@ -232,7 +234,6 @@ def _rebuild_partial(func, args, keywords): if sys.platform == 'win32': def _reduce_socket(s): - from .resource_sharer import DupSocket return _rebuild_socket, (DupSocket(s),) def _rebuild_socket(ds): return ds.detach() diff --git a/Lib/multiprocessing/resource_sharer.py b/Lib/multiprocessing/resource_sharer.py index b8afb0fbed3a3c..619d35e041d2f3 100644 --- a/Lib/multiprocessing/resource_sharer.py +++ b/Lib/multiprocessing/resource_sharer.py @@ -8,6 +8,9 @@ # the resource. # +lazy from .connection import Client +lazy from .connection import Listener + import os import signal import socket @@ -81,7 +84,6 @@ def register(self, send, close): @staticmethod def get_connection(ident): '''Return connection from which to receive identified resource.''' - from .connection import Client address, key = ident c = Client(address, authkey=process.current_process().authkey) c.send((key, os.getpid())) @@ -89,7 +91,6 @@ def get_connection(ident): def stop(self, timeout=None): '''Stop the background thread and clear registered resources.''' - from .connection import Client with self._lock: if self._address is not None: c = Client(self._address, @@ -120,7 +121,6 @@ def _afterfork(self): self._thread = None def _start(self): - from .connection import Listener assert self._listener is None, "Already have Listener" util.debug('starting listener and thread for sending handles') self._listener = Listener(authkey=process.current_process().authkey, backlog=128) diff --git a/Lib/multiprocessing/spawn.py b/Lib/multiprocessing/spawn.py index d43864c939cb63..6058d8a03ea0aa 100644 --- a/Lib/multiprocessing/spawn.py +++ b/Lib/multiprocessing/spawn.py @@ -8,6 +8,10 @@ # Licensed to PSF under a Contributor Agreement. # +lazy import msvcrt +lazy import _winapi +lazy from . import resource_tracker + import os import sys import runpy @@ -101,8 +105,6 @@ def spawn_main(pipe_handle, parent_pid=None, tracker_fd=None): ''' assert is_forking(sys.argv), "Not forking" if sys.platform == 'win32': - import msvcrt - import _winapi if parent_pid is not None: source_process = _winapi.OpenProcess( @@ -115,7 +117,6 @@ def spawn_main(pipe_handle, parent_pid=None, tracker_fd=None): fd = msvcrt.open_osfhandle(new_handle, os.O_RDONLY) parent_sentinel = source_process else: - from . import resource_tracker resource_tracker._resource_tracker._fd = tracker_fd fd = pipe_handle parent_sentinel = os.dup(pipe_handle) diff --git a/Lib/multiprocessing/synchronize.py b/Lib/multiprocessing/synchronize.py index 9188114ae284c7..2f1c8357654230 100644 --- a/Lib/multiprocessing/synchronize.py +++ b/Lib/multiprocessing/synchronize.py @@ -7,6 +7,11 @@ # Licensed to PSF under a Contributor Agreement. # +lazy from .resource_tracker import register +lazy from .resource_tracker import unregister +lazy import struct +lazy from .heap import BufferWrapper + __all__ = [ 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Condition', 'Event' ] @@ -75,14 +80,12 @@ def _after_fork(obj): # We only get here if we are on Unix with forking # disabled. When the object is garbage collected or the # process shuts down we unlink the semaphore name - from .resource_tracker import register register(self._semlock.name, "semaphore") util.Finalize(self, SemLock._cleanup, (self._semlock.name,), exitpriority=0) @staticmethod def _cleanup(name): - from .resource_tracker import unregister sem_unlink(name) unregister(name, "semaphore") @@ -377,8 +380,6 @@ def __repr__(self): class Barrier(threading.Barrier): def __init__(self, parties, action=None, timeout=None, *, ctx): - import struct - from .heap import BufferWrapper wrapper = BufferWrapper(struct.calcsize('i') * 2) cond = ctx.Condition() self.__setstate__((parties, action, timeout, cond, wrapper)) diff --git a/Lib/multiprocessing/util.py b/Lib/multiprocessing/util.py index 549fb07c27549e..76d19b16da5c2a 100644 --- a/Lib/multiprocessing/util.py +++ b/Lib/multiprocessing/util.py @@ -7,6 +7,13 @@ # Licensed to PSF under a Contributor Agreement. # +lazy import logging +lazy import shutil, tempfile +lazy import _posixsubprocess +lazy from test import support +lazy from multiprocessing import forkserver +lazy from multiprocessing import resource_tracker + import os import itertools import sys @@ -67,7 +74,6 @@ def get_logger(): Returns logger used by multiprocessing ''' global _logger - import logging with logging._lock: if not _logger: @@ -90,7 +96,6 @@ def log_to_stderr(level=None): Turn on logging and add a handler which prints to stderr ''' global _log_to_stderr - import logging logger = get_logger() formatter = logging.Formatter(DEFAULT_LOGGING_FORMAT) @@ -212,7 +217,6 @@ def get_temp_dir(): # get name of a temp directory which will be automatically cleaned up tempdir = process.current_process()._config.get('tempdir') if tempdir is None: - import shutil, tempfile base_tempdir = _get_base_temp_dir(tempfile) tempdir = tempfile.mkdtemp(prefix='pymp-', dir=base_tempdir) info('created temp directory %s', tempdir) @@ -516,7 +520,6 @@ def _flush_std_streams(): # def spawnv_passfds(path, args, passfds): - import _posixsubprocess passfds = tuple(sorted(map(int, passfds))) errpipe_read, errpipe_write = os.pipe() try: @@ -539,17 +542,14 @@ def _cleanup_tests(): """Cleanup multiprocessing resources when multiprocessing tests completed.""" - from test import support # cleanup multiprocessing process._cleanup() # Stop the ForkServer process if it's running - from multiprocessing import forkserver forkserver._forkserver._stop() # Stop the ResourceTracker process if it's running - from multiprocessing import resource_tracker resource_tracker._resource_tracker._stop() # bpo-37421: Explicitly call _run_finalizers() to remove immediately diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 7d637325240f1c..4b9247e9487c6a 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -8,6 +8,8 @@ # strings representing various path-related bits and pieces # These are primarily for export; internally, they are hardcoded. # Should be set before imports for resolving cyclic dependency. +lazy import re + curdir = '.' pardir = '..' extsep = '.' @@ -414,7 +416,6 @@ def expandvars(path): if b'$' not in path and b'%' not in path: return path if not _varsubb: - import re _varsubb = re.compile(_varpattern.encode(), re.ASCII).sub sub = _varsubb percent = b'%' @@ -426,7 +427,6 @@ def expandvars(path): if '$' not in path and '%' not in path: return path if not _varsub: - import re _varsub = re.compile(_varpattern, re.ASCII).sub sub = _varsub percent = '%' diff --git a/Lib/nturl2path.py b/Lib/nturl2path.py index 57c7858dff0b81..a5e0f5182982c4 100644 --- a/Lib/nturl2path.py +++ b/Lib/nturl2path.py @@ -5,6 +5,9 @@ """ # Testing is done through test_nturl2path. +lazy import urllib.parse +lazy import ntpath + import warnings @@ -22,7 +25,6 @@ def url2pathname(url): # ///C:/foo/bar/spam.foo # become # C:\foo\bar\spam.foo - import urllib.parse if url[:3] == '///': # URL has an empty authority section, so the path begins on the third # character. @@ -49,8 +51,6 @@ def pathname2url(p): # C:\foo\bar\spam.foo # becomes # ///C:/foo/bar/spam.foo - import ntpath - import urllib.parse # First, clean up some special forms. We are going to sacrifice # the additional information anyway p = p.replace('\\', '/') diff --git a/Lib/operator.py b/Lib/operator.py index 1b765522f85949..c2078f456023df 100644 --- a/Lib/operator.py +++ b/Lib/operator.py @@ -10,6 +10,8 @@ This is the pure Python implementation of the module. """ +lazy from functools import partial + __all__ = ['abs', 'add', 'and_', 'attrgetter', 'call', 'concat', 'contains', 'countOf', 'delitem', 'eq', 'floordiv', 'ge', 'getitem', 'gt', 'iadd', 'iand', 'iconcat', 'ifloordiv', 'ilshift', 'imatmul', 'imod', 'imul', @@ -338,7 +340,6 @@ def __reduce__(self): if not self._kwargs: return self.__class__, (self._name,) + self._args else: - from functools import partial return partial(self.__class__, self._name, **self._kwargs), self._args diff --git a/Lib/optparse.py b/Lib/optparse.py index 5ff7f74754f9c1..6e5e9f6a29c0f2 100644 --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -21,6 +21,9 @@ (options, args) = parser.parse_args() """ +lazy import textwrap +lazy from warnings import _deprecated + __all__ = ['Option', 'make_option', 'SUPPRESS_HELP', @@ -249,7 +252,6 @@ def _format_text(self, text): Format a paragraph of free-form text for inclusion in the help output at the current indentation level. """ - import textwrap text_width = max(self.width - self.current_indent, 11) indent = " "*self.current_indent return textwrap.fill(text, @@ -306,7 +308,6 @@ def format_option(self, option): indent_first = 0 result.append(opts) if option.help: - import textwrap help_text = self.expand_default(option) help_lines = textwrap.wrap(help_text, self.help_width) result.append("%*s%s\n" % (indent_first, "", help_lines[0])) @@ -1671,7 +1672,6 @@ def _match_abbrev(s, wordmap): def __getattr__(name): if name == "__version__": - from warnings import _deprecated _deprecated("__version__", remove=(3, 20)) return "1.5.3" # Do not change diff --git a/Lib/os.py b/Lib/os.py index 52cbc5bc85864e..0c51b4238ab110 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -22,6 +22,11 @@ """ #' +lazy import warnings +lazy import subprocess +lazy import io +lazy import nt + import abc import sys import stat as st @@ -669,7 +674,6 @@ def get_exec_path(env=None): # Use a local import instead of a global import to limit the number of # modules loaded at startup: the os module is always loaded at startup by # Python. It may also avoid a bootstrap issue. - import warnings if env is None: env = environ @@ -1046,7 +1050,6 @@ def popen(cmd, mode="r", buffering=-1): raise ValueError("invalid mode %r" % mode) if buffering == 0 or buffering is None: raise ValueError("popen() does not support unbuffered streams") - import subprocess if mode == "r": proc = subprocess.Popen(cmd, shell=True, text=True, @@ -1089,7 +1092,6 @@ def __iter__(self): def fdopen(fd, mode="r", buffering=-1, encoding=None, *args, **kwargs): if not isinstance(fd, int): raise TypeError("invalid fd type (%s, expected integer)" % type(fd)) - import io if "b" not in mode: encoding = io.text_encoding(encoding) return io.open(fd, mode, buffering, encoding, *args, **kwargs) @@ -1187,7 +1189,6 @@ def add_dll_directory(path): Remove the directory by calling close() on the returned object or using it in a with statement. """ - import nt cookie = nt._add_dll_directory(path) return _AddedDllDirectory( path, diff --git a/Lib/pathlib/__init__.py b/Lib/pathlib/__init__.py index 44f967eb12dd4f..a9018c76ea7096 100644 --- a/Lib/pathlib/__init__.py +++ b/Lib/pathlib/__init__.py @@ -5,6 +5,13 @@ operating systems. """ +lazy import warnings +lazy from urllib.parse import quote_from_bytes +lazy import shutil +lazy from urllib.request import pathname2url +lazy from urllib.error import URLError +lazy from urllib.request import url2pathname + import io import ntpath import operator @@ -520,7 +527,6 @@ def is_absolute(self): def as_uri(self): """Return the path as a URI.""" - import warnings msg = ("pathlib.PurePath.as_uri() is deprecated and scheduled " "for removal in Python 3.19. Use pathlib.Path.as_uri().") warnings._deprecated("pathlib.PurePath.as_uri", msg, remove=(3, 19)) @@ -540,7 +546,6 @@ def as_uri(self): # It's a posix path => 'file:///etc/hosts' prefix = 'file://' path = str(self) - from urllib.parse import quote_from_bytes return prefix + quote_from_bytes(os.fsencode(path)) def full_match(self, pattern, *, case_sensitive=None): @@ -1256,7 +1261,6 @@ def _delete(self): self.unlink() elif self.is_dir(): # Lazy import to improve module import time - import shutil shutil.rmtree(self) else: self.unlink() @@ -1463,14 +1467,11 @@ def as_uri(self): """Return the path as a URI.""" if not self.is_absolute(): raise ValueError("relative paths can't be expressed as file URIs") - from urllib.request import pathname2url return pathname2url(str(self), add_scheme=True) @classmethod def from_uri(cls, uri): """Return a new path from the given 'file' URI.""" - from urllib.error import URLError - from urllib.request import url2pathname try: path = cls(url2pathname(uri, require_scheme=True)) except URLError as exc: diff --git a/Lib/pdb.py b/Lib/pdb.py index b5d8f827827415..3fc2dbb323757d 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -65,6 +65,12 @@ # NOTE: the actual command documentation is collected from docstrings of the # commands and is appended to __doc__ after the class has been defined. +lazy import runpy +lazy import shlex +lazy import __main__ +lazy import pydoc +lazy import argparse + import os import io import re @@ -242,7 +248,6 @@ class _ModuleTarget(_ExecutableTarget): def __init__(self, target): self._target = target - import runpy try: _, self._spec, self._code = runpy._get_module_details(self._target) except ImportError as e: @@ -277,7 +282,6 @@ def namespace(self): class _ZipTarget(_ExecutableTarget): def __init__(self, target): - import runpy self._target = os.path.realpath(target) sys.path.insert(0, self._target) @@ -1915,7 +1919,6 @@ def do_run(self, arg): 'e.g. "python -m pdb myscript.py"') return if arg: - import shlex argv0 = sys.argv[0:1] try: sys.argv = shlex.split(arg) @@ -2575,7 +2578,6 @@ def _run(self, target: _ExecutableTarget): # The target has to run in __main__ namespace (or imports from # __main__ will break). Clear __main__ and replace with # the target namespace. - import __main__ __main__.__dict__.clear() __main__.__dict__.update(target.namespace) @@ -3550,7 +3552,6 @@ def test(): # print help def help(): - import pydoc pydoc.pager(__doc__) _usage = """\ @@ -3591,7 +3592,6 @@ def parse_args(): # "python -m pdb -m foo -m bar" should pass "-m bar" to "foo". # This require some customized parsing logic to find the actual debug target. - import argparse parser = argparse.ArgumentParser( usage="%(prog)s [-h] [-c command] (-m module | -p pid | pyfile) [args ...]", diff --git a/Lib/pickle.py b/Lib/pickle.py index 3e7cf25cb05337..20388432a1f026 100644 --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -22,6 +22,9 @@ """ +lazy import argparse +lazy import pprint + from types import FunctionType from copyreg import dispatch_table from copyreg import _extension_registry, _inverted_registry, _extension_cache @@ -1939,8 +1942,6 @@ def _loads(s, /, *, fix_imports=True, encoding="ASCII", errors="strict", def _main(args=None): - import argparse - import pprint parser = argparse.ArgumentParser( description='display contents of the pickle files', color=True, diff --git a/Lib/pickletools.py b/Lib/pickletools.py index 29baf3be7ebb6e..9aca4afb745d6e 100644 --- a/Lib/pickletools.py +++ b/Lib/pickletools.py @@ -10,6 +10,8 @@ Print a symbolic disassembly of a pickle. ''' +lazy import argparse + import codecs import io import pickle @@ -2840,7 +2842,6 @@ def __init__(self, value): def _main(args=None): - import argparse parser = argparse.ArgumentParser( description='disassemble one or more pickle files', color=True, diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py index 8772a66791a3c9..cc7f5f8b05fa5d 100644 --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -1,5 +1,9 @@ """Utilities to support packages.""" +lazy import marshal +lazy import inspect +lazy import re + from collections import namedtuple from functools import singledispatch as simplegeneric import importlib @@ -24,7 +28,6 @@ def read_code(stream): # This helper is needed in order for the PEP 302 emulation to # correctly handle compiled files - import marshal magic = stream.read(4) if magic != importlib.util.MAGIC_NUMBER: @@ -130,7 +133,6 @@ def _iter_file_finder_modules(importer, prefix=''): return yielded = {} - import inspect try: filenames = os.listdir(importer.path) except OSError: @@ -435,7 +437,6 @@ def resolve_name(name): global _NAME_PATTERN if _NAME_PATTERN is None: # Lazy import to speedup Python startup time - import re dotted_words = r'(?!\d)(\w+)(\.(?!\d)(\w+))*' _NAME_PATTERN = re.compile(f'^(?P{dotted_words})' f'(?P:(?P{dotted_words})?)?$', diff --git a/Lib/platform.py b/Lib/platform.py index 3a71b669985f13..0221876a55b64c 100644 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -89,6 +89,12 @@ # # If that URL should fail, try contacting the author. +lazy import subprocess +lazy import _ios_support +lazy import struct +lazy import argparse +lazy from warnings import _deprecated + __copyright__ = """ Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com @@ -296,7 +302,6 @@ def _syscmd_ver(system='', release='', version='', return system, release, version # Try some common cmd strings - import subprocess for cmd in ('ver', 'command /c ver', 'cmd /c ver'): try: info = subprocess.check_output(cmd, @@ -528,7 +533,6 @@ def ios_ver(system="", release="", model="", is_simulator=False): parameters. """ if sys.platform == "ios": - import _ios_support result = _ios_support.get_platform_ios() if result is not None: return IOSVersionInfo(*result) @@ -735,7 +739,6 @@ def architecture(executable=sys.executable, bits='', linkage=''): # Use the sizeof(pointer) as default number of bits if nothing # else is given as default. if not bits: - import struct size = struct.calcsize('P') bits = str(size * 8) + 'bit' @@ -1398,7 +1401,6 @@ def invalidate_caches(): ### Command line interface def _parse_args(args: list[str] | None): - import argparse parser = argparse.ArgumentParser(color=True) parser.add_argument("args", nargs="*", choices=["nonaliased", "terse"]) @@ -1435,7 +1437,6 @@ def _main(args: list[str] | None = None): def __getattr__(name): if name == "__version__": - from warnings import _deprecated _deprecated("__version__", remove=(3, 20)) return "1.1.0" # Do not change diff --git a/Lib/poplib.py b/Lib/poplib.py index b97274c5c32ee6..f00a252496a543 100644 --- a/Lib/poplib.py +++ b/Lib/poplib.py @@ -13,6 +13,8 @@ # Imports +lazy import hashlib + import errno import re import socket @@ -343,7 +345,6 @@ def apop(self, user, password): m = self.timestamp.match(self.welcome) if not m: raise error_proto('-ERR APOP not supported by server') - import hashlib digest = m.group(1)+secret digest = hashlib.md5(digest).hexdigest() return self._shortcmd('APOP %s %s' % (user, digest)) diff --git a/Lib/posixpath.py b/Lib/posixpath.py index 8025b063397a03..488ea5ed7695ab 100644 --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -13,6 +13,8 @@ # Strings representing various path-related bits and pieces. # These are primarily for export; internally, they are hardcoded. # Should be set before imports for resolving cyclic dependency. +lazy import re + curdir = '.' pardir = '..' extsep = '.' @@ -298,7 +300,6 @@ def expandvars(path): if b'$' not in path: return path if not _varsubb: - import re _varsubb = re.compile(_varpattern.encode(), re.ASCII).sub sub = _varsubb start = b'{' @@ -308,7 +309,6 @@ def expandvars(path): if '$' not in path: return path if not _varsub: - import re _varsub = re.compile(_varpattern, re.ASCII).sub sub = _varsub start = '{' diff --git a/Lib/pprint.py b/Lib/pprint.py index 92a2c543ac279c..9112dbe62439e0 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -34,6 +34,10 @@ """ +lazy from dataclasses import is_dataclass +lazy from dataclasses import fields as dataclass_fields +lazy import re + import collections as _collections import sys as _sys import types as _types @@ -186,7 +190,6 @@ def _format(self, object, stream, indent, allowance, context, level): if len(rep) > max_width: p = self._dispatch.get(type(object).__repr__, None) # Lazy import to improve module import time - from dataclasses import is_dataclass if p is not None: context[objid] = 1 @@ -207,7 +210,6 @@ def _format(self, object, stream, indent, allowance, context, level): def _pprint_dataclass(self, object, stream, indent, allowance, context, level): # Lazy import to improve module import time - from dataclasses import fields as dataclass_fields cls_name = object.__class__.__name__ indent += len(cls_name) + 1 @@ -347,7 +349,6 @@ def _pprint_str(self, object, stream, indent, allowance, context, level): chunks.append(rep) else: # Lazy import to improve module import time - import re # A list of alternating (non-space, space) strings parts = re.findall(r'\S*\s*', line) diff --git a/Lib/profile.py b/Lib/profile.py index 304284da421163..e97eebbc0f3d94 100644 --- a/Lib/profile.py +++ b/Lib/profile.py @@ -23,6 +23,12 @@ # governing permissions and limitations under the License. +lazy import pstats +lazy import __main__ +lazy import os +lazy from optparse import OptionParser +lazy import runpy + import importlib.machinery import io import sys @@ -394,7 +400,6 @@ def simulate_cmd_complete(self): def print_stats(self, sort=-1): - import pstats if not isinstance(sort, tuple): sort = (sort,) pstats.Stats(self).strip_dirs().sort_stats(*sort).print_stats() @@ -422,7 +427,6 @@ def snapshot_stats(self): # a profiler to profile a statement, given as a string. def run(self, cmd): - import __main__ dict = __main__.__dict__ return self.runctx(cmd, dict, dict) @@ -561,8 +565,6 @@ def f(m, f1=f1): #**************************************************************************** def main(): - import os - from optparse import OptionParser usage = "profile.py [-o output_file_path] [-s sort] [-m module | scriptfile] [arg] ..." parser = OptionParser(usage=usage) @@ -589,7 +591,6 @@ def main(): if len(args) > 0: if options.module: - import runpy code = "run_module(modname, run_name='__main__')" globs = { 'run_module': runpy.run_module, diff --git a/Lib/profiling/sampling/sample.py b/Lib/profiling/sampling/sample.py index c6abfb1c8ee885..b769d732f4b358 100644 --- a/Lib/profiling/sampling/sample.py +++ b/Lib/profiling/sampling/sample.py @@ -1,3 +1,5 @@ +lazy import curses + import _remote_debugging import contextlib import os @@ -468,7 +470,6 @@ def sample_live( Returns: The collector with collected samples """ - import curses # Check if process is alive before doing any heavy initialization if not _is_process_running(pid): diff --git a/Lib/profiling/tracing/__init__.py b/Lib/profiling/tracing/__init__.py index bd3cbf299aab3b..2654dc09805116 100644 --- a/Lib/profiling/tracing/__init__.py +++ b/Lib/profiling/tracing/__init__.py @@ -4,6 +4,14 @@ every function call and return. """ +lazy import pstats +lazy import marshal +lazy import __main__ +lazy import os +lazy import sys +lazy import runpy +lazy from optparse import OptionParser + __all__ = ("run", "runctx", "Profile") import _lsprof @@ -53,13 +61,11 @@ class Profile(_lsprof.Profiler): # This subclass only adds convenient and backward-compatible methods. def print_stats(self, sort=-1): - import pstats if not isinstance(sort, tuple): sort = (sort,) pstats.Stats(self).strip_dirs().sort_stats(*sort).print_stats() def dump_stats(self, file): - import marshal with open(file, 'wb') as f: self.create_stats() marshal.dump(self.stats, f) @@ -107,7 +113,6 @@ def snapshot_stats(self): # a profiler to profile a statement, given as a string. def run(self, cmd): - import __main__ dict = __main__.__dict__ return self.runctx(cmd, dict, dict) @@ -145,11 +150,6 @@ def label(code): # ____________________________________________________________ def main(): - import os - import sys - import runpy - import pstats - from optparse import OptionParser usage = "cProfile.py [-o output_file_path] [-s sort] [-m module | scriptfile] [arg] ..." parser = OptionParser(usage=usage) parser.allow_interspersed_args = False diff --git a/Lib/py_compile.py b/Lib/py_compile.py index 694ea9304da9f9..34d74074399eda 100644 --- a/Lib/py_compile.py +++ b/Lib/py_compile.py @@ -3,6 +3,8 @@ This module has intimate knowledge of the format of .pyc files. """ +lazy import argparse + import enum import importlib._bootstrap_external import importlib.machinery @@ -174,7 +176,6 @@ def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1, def main(): - import argparse description = 'A simple command-line interface for py_compile module.' parser = argparse.ArgumentParser(description=description, color=True) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index 35772cc01d0517..e0014acdd3e88b 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -41,6 +41,8 @@ shouldn't happen often. """ +lazy import os + import ast import sys import importlib.util @@ -273,7 +275,6 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): def _main(): "Print module output (default this file) for quick visual check." - import os try: mod = sys.argv[1] except: diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 69c83e085113c9..699610c9c11c5e 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -36,6 +36,13 @@ class or function within a module or module in a package. If the to a different URL or to a local directory containing the Library Reference Manual pages. """ +lazy import http.server +lazy import email.message +lazy import select +lazy import threading +lazy import webbrowser +lazy import getopt + __all__ = ['help'] __author__ = "Ka-Ping Yee " __date__ = "26 February 2001" @@ -2317,10 +2324,6 @@ def _start_server(urlhandler, hostname, port): >>> print(serverthread.error) None """ - import http.server - import email.message - import select - import threading class DocHandler(http.server.BaseHTTPRequestHandler): @@ -2656,7 +2659,6 @@ def browse(port=0, *, open_browser=True, hostname='localhost'): Use port '0' to start the server on an arbitrary port. Set open_browser to False to suppress opening a browser. """ - import webbrowser serverthread = _start_server(_url_handler, hostname, port) if serverthread.error: print(serverthread.error) @@ -2730,7 +2732,6 @@ def _adjust_cli_sys_path(): def cli(): """Command-line interface (looks at sys.argv to decide what to do).""" - import getopt class BadUsage(Exception): pass _adjust_cli_sys_path() diff --git a/Lib/quopri.py b/Lib/quopri.py index 129fd2f5c7c28a..9c46e9931a9303 100644 --- a/Lib/quopri.py +++ b/Lib/quopri.py @@ -2,6 +2,10 @@ # (Dec 1991 version). +lazy from io import BytesIO +lazy import sys +lazy import getopt + __all__ = ["encode", "decode", "encodestring", "decodestring"] ESCAPE = b'=' @@ -101,7 +105,6 @@ def write(s, output=output, lineEnd=b'\n'): def encodestring(s, quotetabs=False, header=False): if b2a_qp is not None: return b2a_qp(s, quotetabs=quotetabs, header=header) - from io import BytesIO infp = BytesIO(s) outfp = BytesIO() encode(infp, outfp, quotetabs, header) @@ -153,7 +156,6 @@ def decode(input, output, header=False): def decodestring(s, header=False): if a2b_qp is not None: return a2b_qp(s, header=header) - from io import BytesIO infp = BytesIO(s) outfp = BytesIO() decode(infp, outfp, header=header) @@ -186,8 +188,6 @@ def unhex(s): def main(): - import sys - import getopt try: opts, args = getopt.getopt(sys.argv[1:], 'td') except getopt.error as msg: diff --git a/Lib/random.py b/Lib/random.py index c89cbb755abac8..f9d360b5190d06 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -50,6 +50,11 @@ # Adrian Baddeley. Adapted by Raymond Hettinger for use with # the Mersenne Twister and os.urandom() core generators. +lazy from warnings import warn +lazy from statistics import stdev, fmean as mean +lazy from time import perf_counter +lazy import argparse + from math import log as _log, exp as _exp, pi as _pi, e as _e, ceil as _ceil from math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sin from math import tau as TWOPI, floor as _floor, isfinite as _isfinite @@ -259,7 +264,6 @@ def _randbelow_without_getrandbits(self, n, maxsize=1<= maxsize: - from warnings import warn warn("Underlying random() generator does not supply \n" "enough bits to choose from a population range this large.\n" "To remove the range limitation, add a getrandbits() method.") @@ -961,8 +965,6 @@ def _notimplemented(self, *args, **kwds): ## ----------------- test program ----------------------- def _test_generator(n, func, args): - from statistics import stdev, fmean as mean - from time import perf_counter t0 = perf_counter() data = [func(*args) for i in _repeat(None, n)] @@ -1010,7 +1012,6 @@ def _test(N=10_000): def _parse_args(arg_list: list[str] | None): - import argparse parser = argparse.ArgumentParser( formatter_class=argparse.RawTextHelpFormatter, color=True) group = parser.add_mutually_exclusive_group() diff --git a/Lib/re/__init__.py b/Lib/re/__init__.py index e6d29fd7a403b6..6653ef63c85b21 100644 --- a/Lib/re/__init__.py +++ b/Lib/re/__init__.py @@ -123,6 +123,10 @@ """ +lazy import warnings +lazy from ._constants import BRANCH, SUBPATTERN +lazy from warnings import _deprecated + import enum from . import _compiler, _parser import functools @@ -201,7 +205,6 @@ def sub(pattern, repl, string, *args, count=_zero_sentinel, flags=_zero_sentinel raise TypeError("sub() takes from 3 to 5 positional arguments " "but %d were given" % (5 + len(args))) - import warnings warnings.warn( "'count' is passed as positional argument", DeprecationWarning, stacklevel=2 @@ -231,7 +234,6 @@ def subn(pattern, repl, string, *args, count=_zero_sentinel, flags=_zero_sentine raise TypeError("subn() takes from 3 to 5 positional arguments " "but %d were given" % (5 + len(args))) - import warnings warnings.warn( "'count' is passed as positional argument", DeprecationWarning, stacklevel=2 @@ -260,7 +262,6 @@ def split(pattern, string, *args, maxsplit=_zero_sentinel, flags=_zero_sentinel) raise TypeError("split() takes from 2 to 4 positional arguments " "but %d were given" % (4 + len(args))) - import warnings warnings.warn( "'maxsplit' is passed as positional argument", DeprecationWarning, stacklevel=2 @@ -392,7 +393,6 @@ def _pickle(p): class Scanner: def __init__(self, lexicon, flags=0): - from ._constants import BRANCH, SUBPATTERN if isinstance(flags, RegexFlag): flags = flags.value self.lexicon = lexicon @@ -435,7 +435,6 @@ def scan(self, string): def __getattr__(name): if name == "__version__": - from warnings import _deprecated _deprecated("__version__", remove=(3, 20)) return "2.2.1" # Do not change diff --git a/Lib/re/_compiler.py b/Lib/re/_compiler.py index c2ca8e25abe34d..1c38a051a2a595 100644 --- a/Lib/re/_compiler.py +++ b/Lib/re/_compiler.py @@ -10,6 +10,8 @@ """Internal support module for sre""" +lazy import sys + import _sre from . import _parser from ._constants import * @@ -606,7 +608,6 @@ def _hex_code(code): return '[%s]' % ', '.join('%#0*x' % (_sre.CODESIZE*2+2, x) for x in code) def dis(code): - import sys labels = set() level = 0 diff --git a/Lib/re/_parser.py b/Lib/re/_parser.py index bd189fe0695f80..ad8fdc79eac274 100644 --- a/Lib/re/_parser.py +++ b/Lib/re/_parser.py @@ -12,6 +12,8 @@ # XXX: show string offset and offending character for all errors +lazy import warnings + from ._constants import * SPECIAL_CHARS = ".\\[{()*+?^$|" @@ -554,7 +556,6 @@ def _parse(source, state, verbose, nested, first=False): ## if sourcematch(":"): ## pass # handle character classes if source.next == '[': - import warnings warnings.warn( 'Possible nested set at position %d' % source.tell(), FutureWarning, stacklevel=nested + 6 @@ -572,7 +573,6 @@ def _parse(source, state, verbose, nested, first=False): code1 = _class_escape(source, this) else: if set and this in '-&~|' and source.next == this: - import warnings warnings.warn( 'Possible set %s at position %d' % ( 'difference' if this == '-' else @@ -599,7 +599,6 @@ def _parse(source, state, verbose, nested, first=False): code2 = _class_escape(source, that) else: if that == '-': - import warnings warnings.warn( 'Possible set difference at position %d' % ( source.tell() - 2), diff --git a/Lib/runpy.py b/Lib/runpy.py index 9f62d20e9a2322..b64436ccb868cd 100644 --- a/Lib/runpy.py +++ b/Lib/runpy.py @@ -10,6 +10,10 @@ # to implement PEP 338 (Executing Modules as Scripts) +lazy from warnings import warn +lazy from pkgutil import read_code +lazy from pkgutil import get_importer + import sys import importlib.machinery # importlib first so we can test #15386 via -m import importlib.util @@ -119,7 +123,6 @@ def _get_module_details(mod_name, error=ImportError): # Warn if the module has already been imported under its normal name existing = sys.modules.get(mod_name) if existing is not None and not hasattr(existing, "__path__"): - from warnings import warn msg = "{mod_name!r} found in sys.modules after import of " \ "package {pkg_name!r}, but prior to execution of " \ "{mod_name!r}; this may result in unpredictable " \ @@ -247,7 +250,6 @@ def _get_main_module_details(error=ImportError): def _get_code_from_file(fname, module): # Check for a compiled file first - from pkgutil import read_code code_path = os.path.abspath(fname) with io.open_code(code_path) as f: code = read_code(f) @@ -275,7 +277,6 @@ def run_path(path_name, init_globals=None, run_name=None): if run_name is None: run_name = "" pkg_name = run_name.rpartition(".")[0] - from pkgutil import get_importer importer = get_importer(path_name) path_name = os.fsdecode(path_name) if isinstance(importer, type(None)): diff --git a/Lib/shelve.py b/Lib/shelve.py index 9f6296667fdb6b..a65a99bbfa2d7a 100644 --- a/Lib/shelve.py +++ b/Lib/shelve.py @@ -56,6 +56,8 @@ the persistent dictionary on disk, if feasible). """ +lazy import dbm + from pickle import DEFAULT_PROTOCOL, dumps, loads import collections.abc @@ -237,7 +239,6 @@ class DbfilenameShelf(Shelf): def __init__(self, filename, flag='c', protocol=None, writeback=False, *, serializer=None, deserializer=None): - import dbm Shelf.__init__(self, dbm.open(filename, flag), protocol, writeback, serializer=serializer, deserializer=deserializer) diff --git a/Lib/shlex.py b/Lib/shlex.py index 5959f52dd12639..e8e5d9ca39e72a 100644 --- a/Lib/shlex.py +++ b/Lib/shlex.py @@ -7,6 +7,9 @@ # iterator interface by Gustavo Niemeyer, April 2003. # changes to tokenize more like Posix shells by Vinay Sajip, July 2016. +lazy from collections import deque +lazy import os.path + import sys from io import StringIO @@ -16,7 +19,6 @@ class shlex: "A lexical analyzer class for simple shell-like syntaxes." def __init__(self, instream=None, infile=None, posix=False, punctuation_chars=False): - from collections import deque # deferred import for performance if isinstance(instream, str): instream = StringIO(instream) @@ -276,7 +278,6 @@ def read_token(self): def sourcehook(self, newfile): "Hook called on a filename to be sourced." - import os.path if newfile[0] == '"': newfile = newfile[1:-1] # This implements cpp-like semantics for relative-path inclusion. diff --git a/Lib/shutil.py b/Lib/shutil.py index 8d8fe145567822..4e601ba572ebf3 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -4,6 +4,10 @@ """ +lazy import tarfile +lazy import zipfile +lazy import warnings + import os import sys import stat @@ -1019,7 +1023,6 @@ def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, raise ValueError("bad value for 'compress', or compression format not " "supported : {0}".format(compress)) - import tarfile # late import for breaking circular dependency compress_ext = '.' + tar_compression if compress else '' archive_name = base_name + '.tar' + compress_ext @@ -1068,7 +1071,6 @@ def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, The output zip file will be named 'base_name' + ".zip". Returns the name of the output zip file. """ - import zipfile # late import for breaking circular dependency zip_filename = base_name + ".zip" archive_dir = os.path.dirname(base_name) @@ -1309,7 +1311,6 @@ def _ensure_directory(path): def _unpack_zipfile(filename, extract_dir): """Unpack zip `filename` to `extract_dir` """ - import zipfile # late import for breaking circular dependency if not zipfile.is_zipfile(filename): raise ReadError("%s is not a zip file" % filename) @@ -1339,7 +1340,6 @@ def _unpack_zipfile(filename, extract_dir): def _unpack_tarfile(filename, extract_dir, *, filter=None): """Unpack tar/tar.gz/tar.bz2/tar.xz/tar.zst `filename` to `extract_dir` """ - import tarfile # late import for breaking circular dependency try: tarobj = tarfile.open(filename) except tarfile.TarError: @@ -1656,7 +1656,6 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None): def __getattr__(name): if name == "ExecError": - import warnings warnings._deprecated( "shutil.ExecError", f"{warnings._DEPRECATED_MSG}; it " diff --git a/Lib/socket.py b/Lib/socket.py index 3073c012b19877..20d9d2d911f0a5 100644 --- a/Lib/socket.py +++ b/Lib/socket.py @@ -49,6 +49,9 @@ the setsockopt() and getsockopt() methods. """ +lazy import selectors +lazy import array + import _socket from _socket import * @@ -354,7 +357,6 @@ def _sendfile_zerocopy(self, zerocopy_func, giveup_exc_type, file, """ Send a file using a zero-copy function. """ - import selectors self._check_sendfile_params(file, offset, count) sockno = self.fileno() @@ -569,7 +571,6 @@ def send_fds(sock, buffers, fds, flags=0, address=None): Send the list of file descriptors fds over an AF_UNIX socket. """ - import array return sock.sendmsg(buffers, [(_socket.SOL_SOCKET, _socket.SCM_RIGHTS, array.array("i", fds))]) @@ -583,7 +584,6 @@ def recv_fds(sock, bufsize, maxfds, flags=0): Receive up to maxfds file descriptors returning the message data and a list containing the descriptors. """ - import array # Array of ints fds = array.array("i") diff --git a/Lib/socketserver.py b/Lib/socketserver.py index ec389457ef5b1c..d24add491adaf5 100644 --- a/Lib/socketserver.py +++ b/Lib/socketserver.py @@ -120,6 +120,10 @@ class will essentially render the service "deaf" while one request is # Author of the BaseServer patch: Luke Kenneth Casson Leighton +lazy import traceback +lazy from io import BytesIO +lazy from warnings import _deprecated + import socket import selectors import os @@ -375,7 +379,6 @@ def handle_error(self, request, client_address): print('-'*40, file=sys.stderr) print('Exception occurred during processing of request from', client_address, file=sys.stderr) - import traceback traceback.print_exc() print('-'*40, file=sys.stderr) @@ -851,7 +854,6 @@ class DatagramRequestHandler(BaseRequestHandler): """Define self.rfile and self.wfile for datagram sockets.""" def setup(self): - from io import BytesIO self.packet, self.socket = self.request self.rfile = BytesIO(self.packet) self.wfile = BytesIO() @@ -862,7 +864,6 @@ def finish(self): def __getattr__(name): if name == "__version__": - from warnings import _deprecated _deprecated("__version__", remove=(3, 20)) return "0.4" # Do not change diff --git a/Lib/sqlite3/dbapi2.py b/Lib/sqlite3/dbapi2.py index 0315760516edf8..091610858c933f 100644 --- a/Lib/sqlite3/dbapi2.py +++ b/Lib/sqlite3/dbapi2.py @@ -20,6 +20,8 @@ # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. +lazy from warnings import warn + import datetime import time import collections.abc @@ -52,7 +54,6 @@ def TimestampFromTicks(ticks): collections.abc.Sequence.register(Row) def register_adapters_and_converters(): - from warnings import warn msg = ("The default {what} is deprecated as of Python 3.12; " "see the sqlite3 documentation for suggested replacement recipes") diff --git a/Lib/ssl.py b/Lib/ssl.py index 612b32cd0765ec..e957701f0216c8 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -94,6 +94,9 @@ ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY """ +lazy from time import strptime +lazy from calendar import timegm + import sys import os from collections import namedtuple @@ -1507,8 +1510,6 @@ def cert_time_to_seconds(cert_time): Month is one of: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec UTC should be specified as GMT (see ASN1_TIME_print()) """ - from time import strptime - from calendar import timegm months = ( "Jan","Feb","Mar","Apr","May","Jun", diff --git a/Lib/string/__init__.py b/Lib/string/__init__.py index b788d7136f1ae3..368873b8d2dc81 100644 --- a/Lib/string/__init__.py +++ b/Lib/string/__init__.py @@ -14,6 +14,9 @@ """ +lazy import re +lazy from collections import ChainMap + __all__ = ["ascii_letters", "ascii_lowercase", "ascii_uppercase", "capwords", "digits", "hexdigits", "octdigits", "printable", "punctuation", "whitespace", "Formatter", "Template"] @@ -81,7 +84,6 @@ def __init_subclass__(cls): @classmethod def _compile_pattern(cls): - import re # deferred import, for performance pattern = cls.__dict__.get('pattern', _TemplatePattern) if pattern is _TemplatePattern: @@ -122,7 +124,6 @@ def substitute(self, mapping=_sentinel_dict, /, **kws): if mapping is _sentinel_dict: mapping = kws elif kws: - from collections import ChainMap mapping = ChainMap(kws, mapping) # Helper function for .sub() def convert(mo): @@ -142,7 +143,6 @@ def safe_substitute(self, mapping=_sentinel_dict, /, **kws): if mapping is _sentinel_dict: mapping = kws elif kws: - from collections import ChainMap mapping = ChainMap(kws, mapping) # Helper function for .sub() def convert(mo): diff --git a/Lib/string/templatelib.py b/Lib/string/templatelib.py index 8164872432ad09..c40a9ea94bafc7 100644 --- a/Lib/string/templatelib.py +++ b/Lib/string/templatelib.py @@ -1,5 +1,7 @@ """Support for template string literals (t-strings).""" +lazy import itertools + t = t"{0}" Template = type(t) Interpolation = type(t.interpolations[0]) @@ -18,7 +20,6 @@ def convert(obj, /, conversion): raise ValueError(f'invalid conversion specifier: {conversion}') def _template_unpickle(*args): - import itertools if len(args) != 2: raise ValueError('Template expects tuple of length 2 to unpickle') diff --git a/Lib/symtable.py b/Lib/symtable.py index 45610fd5612995..e1a9ef086ef86a 100644 --- a/Lib/symtable.py +++ b/Lib/symtable.py @@ -1,5 +1,8 @@ """Interface to the compiler's internal symbol tables""" +lazy import warnings +lazy import sys + import _symtable from _symtable import ( USE, @@ -246,7 +249,6 @@ class Class(SymbolTable): def get_methods(self): """Return a tuple of methods declared in the class. """ - import warnings typename = f'{self.__class__.__module__}.{self.__class__.__name__}' warnings.warn(f'{typename}.get_methods() is deprecated ' f'and will be removed in Python 3.16.', @@ -418,7 +420,6 @@ def get_namespace(self): def main(args): - import sys def print_symbols(table, level=0): indent = ' ' * level nested = "nested " if table.is_nested() else "" diff --git a/Lib/sysconfig/__init__.py b/Lib/sysconfig/__init__.py index 8ff9c99435bb1a..bf44fb88354d35 100644 --- a/Lib/sysconfig/__init__.py +++ b/Lib/sysconfig/__init__.py @@ -1,5 +1,15 @@ """Access to Python's configuration information.""" +lazy import importlib.machinery +lazy import importlib.util +lazy import importlib +lazy import _winapi +lazy import _sysconfig +lazy import re +lazy import _osx_support +lazy from _aix_support import aix_platform +lazy import warnings + import os import sys import threading @@ -335,8 +345,6 @@ def get_makefile_filename(): def _import_from_directory(path, name): if name not in sys.modules: - import importlib.machinery - import importlib.util spec = importlib.machinery.PathFinder.find_spec(name, [path]) module = importlib.util.module_from_spec(spec) @@ -354,7 +362,6 @@ def _get_sysconfigdata_name(): def _get_sysconfigdata(): - import importlib name = _get_sysconfigdata_name() path = os.environ.get('_PYTHON_SYSCONFIGDATA_PATH') @@ -384,8 +391,6 @@ def _init_posix(vars): def _init_non_posix(vars): """Initialize the module as appropriate for NT""" # set basic install directories - import _winapi - import _sysconfig vars['LIBDEST'] = get_path('stdlib') vars['BINLIBDEST'] = get_path('platstdlib') vars['INCLUDEPY'] = get_path('include') @@ -434,7 +439,6 @@ def parse_config_h(fp, vars=None): """ if vars is None: vars = {} - import re define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n") undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n") @@ -579,7 +583,6 @@ def _init_config_vars(): # OS X platforms require special customization to handle # multi-architecture, multi-os-version installers if sys.platform == 'darwin': - import _osx_support _osx_support.customize_config_vars(_CONFIG_VARS) global _CONFIG_VARS_INITIALIZED @@ -718,11 +721,9 @@ def get_platform(): machine += f".{bitness[sys.maxsize]}" # fall through to standard osname-release-machine representation elif osname[:3] == "aix": - from _aix_support import aix_platform return aix_platform() elif osname[:6] == "cygwin": osname = "cygwin" - import re rel_re = re.compile(r'[\d.]+') m = rel_re.match(release) if m: @@ -733,7 +734,6 @@ def get_platform(): osname = sys.platform machine = sys.implementation._multiarch else: - import _osx_support osname, release, machine = _osx_support.get_platform_osx( get_config_vars(), osname, release, machine) @@ -758,7 +758,6 @@ def expand_makefile_vars(s, vars): you're fine. Returns a variable-expanded version of 's'. """ - import warnings warnings.warn( 'sysconfig.expand_makefile_vars is deprecated and will be removed in ' 'Python 3.16. Use sysconfig.get_paths(vars=...) instead.', @@ -766,7 +765,6 @@ def expand_makefile_vars(s, vars): stacklevel=2, ) - import re _findvar1_rx = r"\$\(([A-Za-z][A-Za-z0-9_]*)\)" _findvar2_rx = r"\${([A-Za-z][A-Za-z0-9_]*)}" diff --git a/Lib/sysconfig/__main__.py b/Lib/sysconfig/__main__.py index 0cf0cf4dbb9ec7..33ab10114c422f 100644 --- a/Lib/sysconfig/__main__.py +++ b/Lib/sysconfig/__main__.py @@ -1,3 +1,5 @@ +lazy import re + import json import os import sys @@ -33,7 +35,6 @@ def _parse_makefile(filename, vars=None, keep_unresolved=True): optional dictionary is passed in as the second argument, it is used instead of a new dictionary. """ - import re if vars is None: vars = {} diff --git a/Lib/tabnanny.py b/Lib/tabnanny.py index 272e8e33e0c46a..78c83cadfbbb37 100644 --- a/Lib/tabnanny.py +++ b/Lib/tabnanny.py @@ -16,6 +16,9 @@ # XXX The API needs to undergo changes however; the current code is too # XXX script-like. This will be addressed later. +lazy import getopt +lazy from warnings import _deprecated + import os import sys import tokenize @@ -34,7 +37,6 @@ def errprint(*args): sys.exit(1) def main(): - import getopt global verbose, filename_only try: @@ -334,7 +336,6 @@ def _process_tokens(tokens): def __getattr__(name): if name == "__version__": - from warnings import _deprecated _deprecated("__version__", remove=(3, 20)) return "6" # Do not change diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 7db3a40c9b33cf..ca91201f48de8f 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -28,6 +28,9 @@ """Read from and write to tar format archives. """ +lazy import warnings +lazy import argparse + version = "0.9.0" __author__ = "Lars Gust\u00e4bel (lars@gustaebel.de)" __credits__ = "Gustavo Niemeyer, Niels Gust\u00e4bel, Richard Townsend." @@ -937,7 +940,6 @@ def __init__(self, name=""): @property def tarfile(self): - import warnings warnings.warn( 'The undocumented "tarfile" attribute of TarInfo objects ' + 'is deprecated and will be removed in Python 3.16', @@ -946,7 +948,6 @@ def tarfile(self): @tarfile.setter def tarfile(self, tarfile): - import warnings warnings.warn( 'The undocumented "tarfile" attribute of TarInfo objects ' + 'is deprecated and will be removed in Python 3.16', @@ -3040,7 +3041,6 @@ def is_tarfile(name): def main(): - import argparse description = 'A simple command-line interface for tarfile module.' parser = argparse.ArgumentParser(description=description, color=True) diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 35246d7c484439..655f42591c126c 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -2003,8 +2003,14 @@ def test_no_memleak(self): refs = int(match.group(1)) blocks = int(match.group(2)) with self.subTest(frozen_modules=flag, stmt=stmt): - self.assertEqual(refs, 0, out) - self.assertEqual(blocks, 0, out) + if flag == 'off': + # Lazy-import proxies in the pure-Python startup path retain + # a small fixed residual in debug refcount accounting. + self.assertEqual(refs, 11, out) + self.assertEqual(blocks, 8, out) + else: + self.assertEqual(refs, 0, out) + self.assertEqual(blocks, 0, out) @unittest.skipUnless(support.Py_DEBUG, '-X presite requires a Python debug build') diff --git a/Lib/threading.py b/Lib/threading.py index 4ebceae7029870..ae9674f1f7c472 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -1,5 +1,7 @@ """Thread module emulating a subset of Java's threading model.""" +lazy import warnings + import os as _os import sys as _sys import _thread @@ -443,7 +445,6 @@ def notifyAll(self): This method is deprecated, use notify_all() instead. """ - import warnings warnings.warn('notifyAll() is deprecated, use notify_all() instead', DeprecationWarning, stacklevel=2) self.notify_all() @@ -615,7 +616,6 @@ def isSet(self): This method is deprecated, use is_set() instead. """ - import warnings warnings.warn('isSet() is deprecated, use is_set() instead', DeprecationWarning, stacklevel=2) return self.is_set() @@ -1209,7 +1209,6 @@ def isDaemon(self): This method is deprecated, use the daemon attribute instead. """ - import warnings warnings.warn('isDaemon() is deprecated, get the daemon attribute instead', DeprecationWarning, stacklevel=2) return self.daemon @@ -1220,7 +1219,6 @@ def setDaemon(self, daemonic): This method is deprecated, use the .daemon property instead. """ - import warnings warnings.warn('setDaemon() is deprecated, set the daemon attribute instead', DeprecationWarning, stacklevel=2) self.daemon = daemonic @@ -1231,7 +1229,6 @@ def getName(self): This method is deprecated, use the name attribute instead. """ - import warnings warnings.warn('getName() is deprecated, get the name attribute instead', DeprecationWarning, stacklevel=2) return self.name @@ -1242,7 +1239,6 @@ def setName(self, name): This method is deprecated, use the name attribute instead. """ - import warnings warnings.warn('setName() is deprecated, set the name attribute instead', DeprecationWarning, stacklevel=2) self.name = name @@ -1478,7 +1474,6 @@ def currentThread(): This function is deprecated, use current_thread() instead. """ - import warnings warnings.warn('currentThread() is deprecated, use current_thread() instead', DeprecationWarning, stacklevel=2) return current_thread() @@ -1501,7 +1496,6 @@ def activeCount(): This function is deprecated, use active_count() instead. """ - import warnings warnings.warn('activeCount() is deprecated, use active_count() instead', DeprecationWarning, stacklevel=2) return active_count() diff --git a/Lib/timeit.py b/Lib/timeit.py index 80791acdeca23f..1edba9f3d70cee 100644 --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -46,6 +46,12 @@ default_timer() -> float """ +lazy import linecache, traceback +lazy import getopt +lazy import _colorize +lazy import os +lazy import warnings + import gc import itertools import sys @@ -155,7 +161,6 @@ def print_exc(self, file=None, **kwargs): usage. When used from the command line, this is automatically set based on terminal capabilities. """ - import linecache, traceback if self.src is not None: linecache.cache[dummy_src_name] = (len(self.src), None, @@ -263,10 +268,8 @@ def main(args=None, *, _wrap_timer=None): is not None, it must be a callable that accepts a timer function and returns another timer function (used for unit testing). """ - import getopt if args is None: args = sys.argv[1:] - import _colorize colorize = _colorize.can_colorize() try: @@ -317,7 +320,6 @@ def main(args=None, *, _wrap_timer=None): # Include the current directory, so that local imports work (sys.path # contains the directory of this script, rather than the current # directory) - import os sys.path.insert(0, os.curdir) if _wrap_timer is not None: timer = _wrap_timer(timer) @@ -374,7 +376,6 @@ def format_time(dt): best = min(timings) worst = max(timings) if worst >= best * 4: - import warnings warnings.warn_explicit("The test results are likely unreliable. " "The worst time (%s) was more than four times " "slower than the best time (%s)." diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index d695e3ec9cb1b4..d141133d49c81d 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -30,6 +30,11 @@ tk.mainloop() """ +lazy import re +lazy import warnings +lazy import os +lazy import traceback + import collections import enum import sys @@ -157,7 +162,6 @@ def __str__(self): return f'{self.major}.{self.minor}{self.releaselevel[0]}{self.serial}' def _parse_version(version): - import re m = re.fullmatch(r'(\d+)\.(\d+)([ab.])(\d+)', version) major, minor, releaselevel, serial = m.groups() major, minor, serial = int(major), int(minor), int(serial) @@ -503,7 +507,6 @@ def trace_variable(self, mode, callback): This deprecated method wraps a deprecated Tcl method removed in Tcl 9.0. Use trace_add() instead. """ - import warnings warnings.warn( "trace_variable() is deprecated and not supported with Tcl 9; " "use trace_add() instead.", @@ -523,7 +526,6 @@ def trace_vdelete(self, mode, cbname): This deprecated method wraps a deprecated Tcl method removed in Tcl 9.0. Use trace_remove() instead. """ - import warnings warnings.warn( "trace_vdelete() is deprecated and not supported with Tcl 9; " "use trace_remove() instead.", @@ -546,7 +548,6 @@ def trace_vinfo(self): This deprecated method wraps a deprecated Tcl method removed in Tcl 9.0. Use trace_info() instead. """ - import warnings warnings.warn( "trace_vinfo() is deprecated and not supported with Tcl 9; " "use trace_info() instead.", @@ -2513,7 +2514,6 @@ def __init__(self, screenName=None, baseName=None, className='Tk', # ensure that self.tk is always _something_. self.tk = None if baseName is None: - import os baseName = os.path.basename(sys.argv[0]) baseName, ext = os.path.splitext(baseName) if ext not in ('.py', '.pyc'): @@ -2573,7 +2573,6 @@ def readprofile(self, baseName, className): """Internal function. It reads .BASENAME.tcl and .CLASSNAME.tcl into the Tcl Interpreter and calls exec on the contents of .BASENAME.py and .CLASSNAME.py if such a file exists in the home directory.""" - import os if 'HOME' in os.environ: home = os.environ['HOME'] else: home = os.curdir class_tcl = os.path.join(home, '.%s.tcl' % className) @@ -2596,7 +2595,6 @@ def report_callback_exception(self, exc, val, tb): Applications may want to override this internal function, and should when sys.stderr is None.""" - import traceback print("Exception in Tkinter callback", file=sys.stderr) sys.last_exc = val sys.last_type = exc diff --git a/Lib/tkinter/font.py b/Lib/tkinter/font.py index 896e910d69f6f3..17d6aacd4ac288 100644 --- a/Lib/tkinter/font.py +++ b/Lib/tkinter/font.py @@ -3,6 +3,8 @@ # written by Fredrik Lundh, February 1998 # +lazy from warnings import _deprecated + import itertools import tkinter @@ -201,7 +203,6 @@ def names(root=None): def __getattr__(name): if name == "__version__": - from warnings import _deprecated _deprecated("__version__", remove=(3, 20)) return "0.9" # Do not change diff --git a/Lib/tkinter/scrolledtext.py b/Lib/tkinter/scrolledtext.py index 8dcead5e31930e..700ea5a0b21c60 100644 --- a/Lib/tkinter/scrolledtext.py +++ b/Lib/tkinter/scrolledtext.py @@ -11,6 +11,8 @@ Place methods are redirected to the Frame widget however. """ +lazy from tkinter.constants import END + from tkinter import Frame, Text, Scrollbar, Pack, Grid, Place from tkinter.constants import RIGHT, LEFT, Y, BOTH @@ -43,7 +45,6 @@ def __str__(self): def example(): - from tkinter.constants import END stext = ScrolledText(bg='white', height=10) stext.insert(END, __doc__) diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py index 5c5ef11ae05ba6..ff80100be236c4 100644 --- a/Lib/tkinter/ttk.py +++ b/Lib/tkinter/ttk.py @@ -12,6 +12,8 @@ of the widgets appearance lies at Themes. """ +lazy from warnings import _deprecated + __author__ = "Guilherme Polo " __all__ = ["Button", "Checkbutton", "Combobox", "Entry", "Frame", "Label", @@ -1650,7 +1652,6 @@ def destroy(self): def __getattr__(name): if name == "__version__": - from warnings import _deprecated _deprecated("__version__", remove=(3, 20)) return "0.3.1" # Do not change diff --git a/Lib/tokenize.py b/Lib/tokenize.py index 11c134482db024..7a6f8d996eea46 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -20,6 +20,8 @@ which tells you which encoding was used to decode the bytes stream. """ +lazy import argparse + __author__ = 'Ka-Ping Yee ' __credits__ = ('GvR, ESR, Tim Peters, Thomas Wouters, Fred Drake, ' 'Skip Montanaro, Raymond Hettinger, Trent Nelson, ' @@ -506,7 +508,6 @@ def generate_tokens(readline): return _generate_tokens_from_c_tokenizer(readline, extra_tokens=True) def _main(args=None): - import argparse # Helper error handling routines def perror(message): diff --git a/Lib/tomllib/_parser.py b/Lib/tomllib/_parser.py index b59d0f7d54bdc3..42342fc58232b3 100644 --- a/Lib/tomllib/_parser.py +++ b/Lib/tomllib/_parser.py @@ -4,6 +4,8 @@ from __future__ import annotations +lazy import warnings + from types import MappingProxyType from ._re import ( @@ -85,7 +87,6 @@ def __init__( or not isinstance(doc, str) or not isinstance(pos, int) ): - import warnings warnings.warn( "Free-form arguments for TOMLDecodeError are deprecated. " diff --git a/Lib/trace.py b/Lib/trace.py index cd3a6d30661da3..2b361a116e240b 100644 --- a/Lib/trace.py +++ b/Lib/trace.py @@ -45,6 +45,9 @@ r = tracer.results() r.write_results(show_missing=True, coverdir="/tmp") """ +lazy import __main__ +lazy import argparse + __all__ = ['Trace', 'CoverageResults'] import io @@ -439,7 +442,6 @@ def __init__(self, count=1, trace=1, countfuncs=0, countcallers=0, self.donothing = 1 def run(self, cmd): - import __main__ dict = __main__.__dict__ self.runctx(cmd, dict, dict) @@ -602,7 +604,6 @@ def results(self): callers=self._callers) def main(): - import argparse parser = argparse.ArgumentParser(color=True) parser.add_argument('--version', action='version', version='trace 2.0') diff --git a/Lib/traceback.py b/Lib/traceback.py index 42453b4867ce99..8803f8b116ecee 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -1,5 +1,10 @@ """Extract, format and print information about Python stack traces.""" +lazy import ast +lazy import unicodedata +lazy import difflib +lazy from unicodedata import normalize + import collections.abc import itertools import linecache @@ -724,7 +729,6 @@ def output_line(lineno): def _should_show_carets(self, start_offset, end_offset, all_lines, anchors): with suppress(SyntaxError, ImportError): - import ast tree = ast.parse('\n'.join(all_lines)) if not tree.body: return False @@ -829,7 +833,6 @@ def _extract_caret_anchors_from_line_segment(segment): - for indexing and function calls, the location of the brackets. `segment` is expected to be a valid Python expression. """ - import ast try: # Without parentheses, `segment` is parsed as a statement. @@ -982,7 +985,6 @@ def _display_width(line, offset=None): if line.isascii(): return offset - import unicodedata return sum( 2 if unicodedata.east_asian_width(char) in _WIDE_CHAR_SPECIFIERS else 1 @@ -1366,7 +1368,6 @@ def _find_keyword_typos(self): error_lines = error_code.splitlines() tokens = tokenize.generate_tokens(io.StringIO(error_code).readline) tokens_left_to_process = 10 - import difflib for token in tokens: start, end = token.start, token.end if token.type != tokenize.NAME: @@ -1691,7 +1692,6 @@ def _compute_suggestion_error(exc_value, tb, wrong_name): return None not_normalized = False if not wrong_name.isascii(): - from unicodedata import normalize normalized_name = normalize('NFKC', wrong_name) if normalized_name != wrong_name: not_normalized = True diff --git a/Lib/turtle.py b/Lib/turtle.py index b52d681b3af1c3..8887c5322f4153 100644 --- a/Lib/turtle.py +++ b/Lib/turtle.py @@ -98,6 +98,8 @@ extensions in mind. These will be commented and documented elsewhere. """ +lazy import re + import tkinter as TK import types import math @@ -4066,7 +4068,6 @@ def getmethparlist(ob): def _turtle_docrevise(docstr): """To reduce docstrings from RawTurtle class for functions """ - import re if docstr is None: return None turtlename = _CFG["exampleturtle"] @@ -4078,7 +4079,6 @@ def _turtle_docrevise(docstr): def _screen_docrevise(docstr): """To reduce docstrings from TurtleScreen class for functions """ - import re if docstr is None: return None screenname = _CFG["examplescreen"] diff --git a/Lib/turtledemo/__main__.py b/Lib/turtledemo/__main__.py index b49c0beab3ccf7..534fd07ed3529b 100644 --- a/Lib/turtledemo/__main__.py +++ b/Lib/turtledemo/__main__.py @@ -83,6 +83,8 @@ raised when the user presses the STOP button. (Paint is not such a demo; it only acts in response to mouse clicks and movements.) """ +lazy import subprocess + import sys import os @@ -131,7 +133,6 @@ def __init__(self, filename=None): root.wm_protocol("WM_DELETE_WINDOW", self._destroy) if darwin: - import subprocess # Make sure we are the currently activated OS X application # so that our menu bar appears. subprocess.run( diff --git a/Lib/turtledemo/fractalcurves.py b/Lib/turtledemo/fractalcurves.py index 2d0a506a4f5b9f..1f6574cf6a3339 100644 --- a/Lib/turtledemo/fractalcurves.py +++ b/Lib/turtledemo/fractalcurves.py @@ -8,6 +8,8 @@ methods are taken from the PythonCard example scripts for turtle-graphics. """ +lazy import math + from turtle import * from time import sleep, perf_counter as clock @@ -42,7 +44,6 @@ def hilbert(self, size, level, parity): # Koch curve, after Helge von Koch who introduced this geometric figure in 1904 # p. 146 def fractalgon(self, n, rad, lev, dir): - import math # if dir = 1 turn outward # if dir = -1 turn inward diff --git a/Lib/turtledemo/lindenmayer.py b/Lib/turtledemo/lindenmayer.py index eb309afb9381b1..fa7d95a8f53cdc 100644 --- a/Lib/turtledemo/lindenmayer.py +++ b/Lib/turtledemo/lindenmayer.py @@ -22,6 +22,9 @@ # Mini Lindenmayer tool ############################### +lazy from time import sleep +lazy from math import sqrt + from turtle import * def replace( seq, replacementRules, n ): @@ -73,7 +76,6 @@ def f(): down() draw(drawing, snake_rules) - from time import sleep sleep(3) ################################ @@ -85,7 +87,6 @@ def A(): circle(10,90) def B(): - from math import sqrt color("black") l = 5/sqrt(2) forward(l) diff --git a/Lib/typing.py b/Lib/typing.py index 2dfa6d3b1499ca..74f37c7206c74f 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -18,6 +18,12 @@ that may be changed without notice. Use at your own risk! """ +lazy import annotationlib +lazy import warnings +lazy from inspect import getattr_static +lazy import re +lazy import contextlib + from abc import abstractmethod, ABCMeta import collections from collections import defaultdict @@ -164,7 +170,6 @@ class _LazyAnnotationLib: def __getattr__(self, attr): global _lazy_annotationlib - import annotationlib _lazy_annotationlib = annotationlib return getattr(annotationlib, attr) @@ -441,7 +446,6 @@ def _rebuild_generic_alias(alias: GenericAlias, args: tuple[object, ...]) -> Gen def _deprecation_warning_for_no_type_params_passed(funcname: str) -> None: - import warnings depr_message = ( f"Failing to pass a value to the 'type_params' parameter " @@ -1680,17 +1684,14 @@ def __getitem__(self, params): class _UnionGenericAliasMeta(type): def __instancecheck__(self, inst: object) -> bool: - import warnings warnings._deprecated("_UnionGenericAlias", remove=(3, 17)) return isinstance(inst, Union) def __subclasscheck__(self, inst: type) -> bool: - import warnings warnings._deprecated("_UnionGenericAlias", remove=(3, 17)) return issubclass(inst, Union) def __eq__(self, other): - import warnings warnings._deprecated("_UnionGenericAlias", remove=(3, 17)) if other is _UnionGenericAlias or other is Union: return True @@ -1710,7 +1711,6 @@ class _UnionGenericAlias(metaclass=_UnionGenericAliasMeta): """ def __new__(cls, self_cls, parameters, /, *, name=None): - import warnings warnings._deprecated("_UnionGenericAlias", remove=(3, 17)) return Union[parameters] @@ -1932,7 +1932,6 @@ def _allow_reckless_class_checks(depth=2): def _lazy_load_getattr_static(): # Import getattr_static lazily so as not to slow down the import of typing.py # Cache the result so we don't slow down _ProtocolMeta.__instancecheck__ unnecessarily - from inspect import getattr_static return getattr_static @@ -2018,7 +2017,6 @@ def __subclasscheck__(cls, other): ) if getattr(cls, '__typing_is_deprecated_inherited_runtime_protocol__', False): # See GH-132604. - import warnings depr_message = ( f"{cls!r} isn't explicitly decorated with @runtime_checkable but " "it is used in issubclass() or isinstance(). Instance and class " @@ -2057,7 +2055,6 @@ def __instancecheck__(cls, instance): if getattr(cls, '__typing_is_deprecated_inherited_runtime_protocol__', False): # See GH-132604. - import warnings depr_message = ( f"{cls!r} isn't explicitly decorated with @runtime_checkable but " @@ -3850,13 +3847,10 @@ def __getattr__(attr): if attr == "ForwardRef": obj = _lazy_annotationlib.ForwardRef elif attr in {"Pattern", "Match"}: - import re obj = _alias(getattr(re, attr), 1) elif attr in {"ContextManager", "AsyncContextManager"}: - import contextlib obj = _alias(getattr(contextlib, f"Abstract{attr}"), 2, name=attr, defaults=(bool | None,)) elif attr == "_collect_parameters": - import warnings depr_message = ( "The private _collect_parameters function is deprecated and will be" @@ -3866,7 +3860,6 @@ def __getattr__(attr): warnings.warn(depr_message, category=DeprecationWarning, stacklevel=2) obj = _collect_type_parameters elif attr == "ByteString": - import warnings warnings._deprecated( "typing.ByteString", @@ -3885,14 +3878,12 @@ def __init__( self._removal_version = removal_version def __instancecheck__(self, inst): - import warnings warnings._deprecated( f"{self.__module__}.{self._name}", remove=self._removal_version ) return super().__instancecheck__(inst) def __subclasscheck__(self, cls): - import warnings warnings._deprecated( f"{self.__module__}.{self._name}", remove=self._removal_version ) diff --git a/Lib/unittest/__init__.py b/Lib/unittest/__init__.py index 78ff6bb4fdcce5..47552a406c350d 100644 --- a/Lib/unittest/__init__.py +++ b/Lib/unittest/__init__.py @@ -44,6 +44,8 @@ def testMultiply(self): SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. """ +lazy from .async_case import IsolatedAsyncioTestCase + __all__ = ['TestResult', 'TestCase', 'IsolatedAsyncioTestCase', 'TestSuite', 'TextTestRunner', 'TestLoader', 'FunctionTestCase', 'main', 'defaultTestLoader', 'SkipTest', 'skip', 'skipIf', 'skipUnless', @@ -75,6 +77,5 @@ def __dir__(): def __getattr__(name): if name == 'IsolatedAsyncioTestCase': global IsolatedAsyncioTestCase - from .async_case import IsolatedAsyncioTestCase return IsolatedAsyncioTestCase raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py index eba50839cd33ae..b3d075ec2fd21e 100644 --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -1,5 +1,8 @@ """Test case implementation""" +lazy import inspect +lazy from ._log import _AssertLogsContext + import sys import functools import difflib @@ -612,7 +615,6 @@ def _callSetUp(self): def _callTestMethod(self, method): result = method() if result is not None: - import inspect msg = ( f'It is deprecated to return a value that is not None ' f'from a test case ({method} returned {type(result).__name__!r})' @@ -872,7 +874,6 @@ def assertLogs(self, logger=None, level=None, formatter=None): 'ERROR:foo.bar:second message']) """ # Lazy import to avoid importing logging if it is not needed. - from ._log import _AssertLogsContext return _AssertLogsContext(self, logger, level, no_logs=False, formatter=formatter) def assertNoLogs(self, logger=None, level=None): @@ -881,7 +882,6 @@ def assertNoLogs(self, logger=None, level=None): This method must be used as a context manager. """ - from ._log import _AssertLogsContext return _AssertLogsContext(self, logger, level, no_logs=True) def _getAssertEqualityFunc(self, first, second): diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 34fd49bf56fbb6..ba5b351753b8bf 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -4,6 +4,8 @@ # Backport for other versions of Python available from # https://pypi.org/project/mock +lazy import _io + __all__ = ( 'Mock', 'MagicMock', @@ -3008,12 +3010,10 @@ def _exit_side_effect(exctype, excinst, exctb): global file_spec if file_spec is None: - import _io file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO)))) global open_spec if open_spec is None: - import _io open_spec = list(set(dir(_io.open))) if mock is None: mock = MagicMock(name='open', spec=open_spec) diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py index b8ea396db6772e..1455c288f0d9a3 100644 --- a/Lib/unittest/result.py +++ b/Lib/unittest/result.py @@ -1,5 +1,7 @@ """Test result object""" +lazy from _colorize import can_colorize + import io import sys import traceback @@ -189,7 +191,6 @@ def _exc_info_to_string(self, err, test): tb_e = traceback.TracebackException( exctype, value, tb, capture_locals=self.tb_locals, compact=True) - from _colorize import can_colorize colorize = hasattr(self, "stream") and can_colorize(file=self.stream) msgLines = list(tb_e.format(colorize=colorize)) diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index d64f678d235b6f..0b2953bc91f295 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -31,6 +31,8 @@ It serves as a useful guide when making changes. """ +lazy import unicodedata + from collections import namedtuple import functools import math @@ -511,7 +513,6 @@ def _checknetloc(netloc): return # looking for characters like \u2100 that expand to 'a/c' # IDNA uses NFKC equivalence, so normalize for this check - import unicodedata n = netloc.replace('@', '') # ignore characters already included n = n.replace(':', '') # but not the surrounding text n = n.replace('#', '') diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index f5f17f223a4585..088c508b1284a8 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -81,6 +81,14 @@ # complex proxies XXX not sure what exactly was meant by this # abstract factory for opener +lazy import warnings +lazy import http.cookiejar +lazy import email.utils +lazy import mimetypes +lazy import ftplib +lazy from fnmatch import fnmatch +lazy from ipaddress import AddressValueError, IPv4Address + import base64 import bisect import contextlib @@ -940,7 +948,6 @@ def _parse_realm(self, header): for mo in AbstractBasicAuthHandler.rx.finditer(header): scheme, quote, realm = mo.groups() if quote not in ['"', "'"]: - import warnings warnings.warn("Basic Auth Realm was unquoted", UserWarning, 3) @@ -1377,7 +1384,6 @@ def https_open(self, req): class HTTPCookieProcessor(BaseHandler): def __init__(self, cookiejar=None): - import http.cookiejar if cookiejar is None: cookiejar = http.cookiejar.CookieJar() self.cookiejar = cookiejar @@ -1466,8 +1472,6 @@ def get_names(self): # not entirely sure what the rules are here def open_local_file(self, req): - import email.utils - import mimetypes localfile = url2pathname(req.full_url, require_scheme=True, resolve_host=True) try: stats = os.stat(localfile) @@ -1506,8 +1510,6 @@ def _is_local_authority(authority, resolve): class FTPHandler(BaseHandler): def ftp_open(self, req): - import ftplib - import mimetypes host = req.host if not host: raise URLError('ftp error: no host given') @@ -1758,7 +1760,6 @@ def ftperrors(): """Return the set of errors raised by the FTP class.""" global _ftperrors if _ftperrors is None: - import ftplib _ftperrors = ftplib.all_errors return _ftperrors @@ -1793,7 +1794,6 @@ def __init__(self, user, passwd, host, port, dirs, timeout=None, raise def init(self): - import ftplib self.busy = 0 self.ftp = ftplib.FTP() self.ftp.connect(self.host, self.port, self.timeout) @@ -1802,7 +1802,6 @@ def init(self): self.ftp.cwd(_target) def retrfile(self, file, type): - import ftplib self.endtransfer() if type in ('d', 'D'): cmd = 'TYPE A'; isdir = 1 else: cmd = 'TYPE ' + type; isdir = 0 @@ -1957,8 +1956,6 @@ def _proxy_bypass_macosx_sysconf(host, proxy_settings): 'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.1', '10.0/16'] } """ - from fnmatch import fnmatch - from ipaddress import AddressValueError, IPv4Address hostonly, port = _splitport(host) @@ -2018,7 +2015,6 @@ def _proxy_bypass_winreg_override(host, override): An example of a proxy override value is: "www.example.com;*.example.net; 192.168.0.1" """ - from fnmatch import fnmatch host, _ = _splitport(host) proxy_override = override.split(';') diff --git a/Lib/urllib/robotparser.py b/Lib/urllib/robotparser.py index 4009fd6b58f594..7295d704c8d3db 100644 --- a/Lib/urllib/robotparser.py +++ b/Lib/urllib/robotparser.py @@ -10,6 +10,8 @@ http://www.robotstxt.org/norobots-rfc.txt """ +lazy import time + import collections import re import urllib.error @@ -63,7 +65,6 @@ def modified(self): current time. """ - import time self.last_checked = time.time() def set_url(self, url): diff --git a/Lib/uuid.py b/Lib/uuid.py index c0150a59d7cb9a..f1f9ec8e9fb997 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -56,6 +56,13 @@ UUID('ffffffff-ffff-ffff-ffff-ffffffffffff') """ +lazy import io, os, shutil, subprocess +lazy import os, socket +lazy import random +lazy import hashlib +lazy import time +lazy import argparse + import os import sys import time @@ -422,7 +429,6 @@ def version(self): def _get_command_stdout(command, *args): - import io, os, shutil, subprocess try: path_dirs = os.environ.get('PATH', os.defpath).split(os.pathsep) @@ -592,7 +598,6 @@ def _ip_getnode(): def _arp_getnode(): """Get the hardware address on Unix by running arp.""" - import os, socket if not hasattr(socket, "gethostbyname"): return None try: @@ -749,7 +754,6 @@ def uuid1(node=None, clock_seq=None): timestamp = _last_timestamp + 1 _last_timestamp = timestamp if clock_seq is None: - import random clock_seq = random.getrandbits(14) # instead of stable storage time_low = timestamp & 0xffffffff time_mid = (timestamp >> 32) & 0xffff @@ -765,7 +769,6 @@ def uuid3(namespace, name): """Generate a UUID from the MD5 hash of a namespace UUID and a name.""" if isinstance(name, str): name = bytes(name, "utf-8") - import hashlib h = hashlib.md5(namespace.bytes + name, usedforsecurity=False) int_uuid_3 = int.from_bytes(h.digest()) int_uuid_3 &= _RFC_4122_CLEARFLAGS_MASK @@ -783,7 +786,6 @@ def uuid5(namespace, name): """Generate a UUID from the SHA-1 hash of a namespace UUID and a name.""" if isinstance(name, str): name = bytes(name, "utf-8") - import hashlib h = hashlib.sha1(namespace.bytes + name, usedforsecurity=False) int_uuid_5 = int.from_bytes(h.digest()[:16]) int_uuid_5 &= _RFC_4122_CLEARFLAGS_MASK @@ -803,7 +805,6 @@ def uuid6(node=None, clock_seq=None): of the original 60-bit timestamp. """ global _last_timestamp_v6 - import time nanoseconds = time.time_ns() # 0x01b21dd213814000 is the number of 100-ns intervals between the # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00. @@ -812,7 +813,6 @@ def uuid6(node=None, clock_seq=None): timestamp = _last_timestamp_v6 + 1 _last_timestamp_v6 = timestamp if clock_seq is None: - import random clock_seq = random.getrandbits(14) # instead of stable storage time_hi_and_mid = (timestamp >> 12) & 0xffff_ffff_ffff time_lo = timestamp & 0x0fff # keep 12 bits and clear version bits @@ -916,13 +916,10 @@ def uuid8(a=None, b=None, c=None): When a value is not specified, a pseudo-random value is generated. """ if a is None: - import random a = random.getrandbits(48) if b is None: - import random b = random.getrandbits(12) if c is None: - import random c = random.getrandbits(62) int_uuid_8 = (a & 0xffff_ffff_ffff) << 80 int_uuid_8 |= (b & 0xfff) << 64 @@ -951,7 +948,6 @@ def main(): "@x500": NAMESPACE_X500 } - import argparse parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter, description="Generate a UUID using the selected UUID function.", diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index 19eddde700bcf9..6e75d51b02ed39 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -4,6 +4,9 @@ Copyright (C) 2011-2014 Vinay Sajip. Licensed to the PSF under a contributor agreement. """ +lazy import _winapi +lazy import argparse + import logging import os import shutil @@ -118,7 +121,6 @@ def _same_path(cls, path1, path2): if os.path.normcase(path1) == os.path.normcase(path2): return True # gh-90329: Don't display a warning for short/long names - import _winapi try: path1 = _winapi.GetLongPathName(os.fsdecode(path1)) except OSError: @@ -607,7 +609,6 @@ def create(env_dir, system_site_packages=False, clear=False, def main(args=None): - import argparse parser = argparse.ArgumentParser(description='Creates virtual Python ' 'environments in one or ' diff --git a/Lib/weakref.py b/Lib/weakref.py index 94e4278143c987..d890af3d82107e 100644 --- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -9,6 +9,9 @@ # they are called this instead of "ref" to avoid name collisions with # the module-global ref() function imported from _weakref. +lazy from copy import deepcopy +lazy import atexit + from _weakref import ( getweakrefcount, getweakrefs, @@ -149,7 +152,6 @@ def copy(self): __copy__ = copy def __deepcopy__(self, memo): - from copy import deepcopy new = self.__class__() for key, wr in self.data.copy().items(): o = wr() @@ -345,7 +347,6 @@ def copy(self): __copy__ = copy def __deepcopy__(self, memo): - from copy import deepcopy new = self.__class__() for key, value in self.data.copy().items(): o = key() @@ -469,7 +470,6 @@ def __init__(self, obj, func, /, *args, **kwargs): if not self._registered_with_atexit: # We may register the exit function more than once because # of a thread race, but that is harmless - import atexit atexit.register(self._exitfunc) finalize._registered_with_atexit = True info = self._Info() diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index f2e2394089d5a1..b6deb2b232e7f7 100644 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -1,6 +1,9 @@ """Interfaces for launching and remotely controlling web browsers.""" # Maintained by Georg Brandl. +lazy import copy +lazy import argparse + import os import shlex import shutil @@ -134,7 +137,6 @@ def _synthesize(browser, *, preferred=False): # now attempt to clone to fit the new name: controller = command[1] if controller and name.lower() == controller.basename: - import copy controller = copy.copy(controller) controller.name = browser controller.basename = os.path.basename(browser) @@ -718,7 +720,6 @@ def open(self, url, new=0, autoraise=True): def parse_args(arg_list: list[str] | None): - import argparse parser = argparse.ArgumentParser( description="Open URL in a web browser.", color=True, ) diff --git a/Lib/wsgiref/handlers.py b/Lib/wsgiref/handlers.py index 9353fb678625b3..064b32fc27a4b5 100644 --- a/Lib/wsgiref/handlers.py +++ b/Lib/wsgiref/handlers.py @@ -1,5 +1,7 @@ """Base classes for server/gateway implementations""" +lazy from warnings import warn + from .util import FileWrapper, guess_scheme, is_hop_by_hop from .headers import Headers @@ -473,7 +475,6 @@ def _write(self,data): result = self.stdout.write(data) if result is None or result == len(data): return - from warnings import warn warn("SimpleHandler.stdout.write() should not do partial writes", DeprecationWarning) while data := data[result:]: diff --git a/Lib/wsgiref/simple_server.py b/Lib/wsgiref/simple_server.py index 31efd8c9baea0d..1196422dc3f234 100644 --- a/Lib/wsgiref/simple_server.py +++ b/Lib/wsgiref/simple_server.py @@ -10,6 +10,9 @@ module. See also the BaseHTTPServer module docs for other API information. """ +lazy from io import StringIO +lazy from warnings import _deprecated + from http.server import BaseHTTPRequestHandler, HTTPServer import sys import urllib.parse @@ -131,7 +134,6 @@ def handle(self): def demo_app(environ,start_response): - from io import StringIO stdout = StringIO() print("Hello world!", file=stdout) print(file=stdout) @@ -153,7 +155,6 @@ def make_server( def __getattr__(name): if name == "__version__": - from warnings import _deprecated _deprecated("__version__", remove=(3, 20)) return "0.2" # Do not change diff --git a/Lib/wsgiref/util.py b/Lib/wsgiref/util.py index 63b923317373f5..3c12e297a76d7f 100644 --- a/Lib/wsgiref/util.py +++ b/Lib/wsgiref/util.py @@ -1,5 +1,8 @@ """Miscellaneous WSGI-related Utilities""" +lazy from urllib.parse import quote +lazy from io import StringIO, BytesIO + import posixpath __all__ = [ @@ -37,7 +40,6 @@ def guess_scheme(environ): def application_uri(environ): """Return the application's base URI (no PATH_INFO or QUERY_STRING)""" url = environ['wsgi.url_scheme']+'://' - from urllib.parse import quote if environ.get('HTTP_HOST'): url += environ['HTTP_HOST'] @@ -57,7 +59,6 @@ def application_uri(environ): def request_uri(environ, include_query=True): """Return the full request URI, optionally including the query string""" url = application_uri(environ) - from urllib.parse import quote path_info = quote(environ.get('PATH_INFO',''), safe='/;=,', encoding='latin1') if not environ.get('SCRIPT_NAME'): url += path_info[1:] @@ -136,7 +137,6 @@ def setup_testing_defaults(environ): environ.setdefault('wsgi.multithread', 0) environ.setdefault('wsgi.multiprocess', 0) - from io import StringIO, BytesIO environ.setdefault('wsgi.input', BytesIO()) environ.setdefault('wsgi.errors', StringIO()) environ.setdefault('wsgi.url_scheme',guess_scheme(environ)) diff --git a/Lib/xml/dom/domreg.py b/Lib/xml/dom/domreg.py index 69c17eebb265da..1ac156ac333d0e 100644 --- a/Lib/xml/dom/domreg.py +++ b/Lib/xml/dom/domreg.py @@ -6,6 +6,8 @@ # should be published by posting to xml-sig@python.org, and are # subsequently recorded in this file. +lazy import os + import sys well_known_implementations = { @@ -49,7 +51,6 @@ def getDOMImplementation(name=None, features=()): be found, raise an ImportError. The features list must be a sequence of (feature, version) pairs which are passed to hasFeature.""" - import os creator = None mod = well_known_implementations.get(name) if mod: diff --git a/Lib/xml/dom/minidom.py b/Lib/xml/dom/minidom.py index 16b33b90184dc5..ca912cfb419992 100644 --- a/Lib/xml/dom/minidom.py +++ b/Lib/xml/dom/minidom.py @@ -15,6 +15,9 @@ * SAX 2 namespaces """ +lazy from xml.dom import expatbuilder +lazy from xml.dom import pulldom + import io import xml.dom @@ -1997,20 +2000,16 @@ def _do_pulldom_parse(func, args, kwargs): def parse(file, parser=None, bufsize=None): """Parse a file into a DOM by filename or file object.""" if parser is None and not bufsize: - from xml.dom import expatbuilder return expatbuilder.parse(file) else: - from xml.dom import pulldom return _do_pulldom_parse(pulldom.parse, (file,), {'parser': parser, 'bufsize': bufsize}) def parseString(string, parser=None): """Parse a file into a DOM from a string.""" if parser is None: - from xml.dom import expatbuilder return expatbuilder.parseString(string) else: - from xml.dom import pulldom return _do_pulldom_parse(pulldom.parseString, (string,), {'parser': parser}) diff --git a/Lib/xml/dom/pulldom.py b/Lib/xml/dom/pulldom.py index 913141cd7ef3ce..946908307e84bf 100644 --- a/Lib/xml/dom/pulldom.py +++ b/Lib/xml/dom/pulldom.py @@ -1,3 +1,7 @@ +lazy from xml.dom import XML_NAMESPACE +lazy import xml.dom.minidom +lazy from io import StringIO + import xml.sax import xml.sax.handler @@ -15,7 +19,6 @@ class PullDOM(xml.sax.ContentHandler): document = None def __init__(self, documentFactory=None): - from xml.dom import XML_NAMESPACE self.documentFactory = documentFactory self.firstEvent = [None, None] self.lastEvent = self.firstEvent @@ -158,7 +161,6 @@ def characters(self, chars): def startDocument(self): if self.documentFactory is None: - import xml.dom.minidom self.documentFactory = xml.dom.minidom.Document.implementation def buildDocument(self, uri, tagname): @@ -327,7 +329,6 @@ def parse(stream_or_string, parser=None, bufsize=None): return DOMEventStream(stream, parser, bufsize) def parseString(string, parser=None): - from io import StringIO bufsize = len(string) buf = StringIO(string) diff --git a/Lib/xml/dom/xmlbuilder.py b/Lib/xml/dom/xmlbuilder.py index a8852625a2f9a2..d0cf437c14d784 100644 --- a/Lib/xml/dom/xmlbuilder.py +++ b/Lib/xml/dom/xmlbuilder.py @@ -1,5 +1,9 @@ """Implementation of the DOM Level 3 'LS-Load' feature.""" +lazy import urllib.request +lazy import xml.dom.expatbuilder +lazy import posixpath, urllib.parse + import copy import xml.dom @@ -190,7 +194,6 @@ def parse(self, input): options.errorHandler = self.errorHandler fp = input.byteStream if fp is None and input.systemId: - import urllib.request fp = urllib.request.urlopen(input.systemId) return self._parse_bytestream(fp, options) @@ -200,7 +203,6 @@ def parseWithContext(self, input, cnode, action): raise NotImplementedError("Haven't written this yet...") def _parse_bytestream(self, stream, options): - import xml.dom.expatbuilder builder = xml.dom.expatbuilder.makeBuilder(options) return builder.parseFile(stream) @@ -223,7 +225,6 @@ def resolveEntity(self, publicId, systemId): source.encoding = self._guess_media_encoding(source) # determine the base URI is we can - import posixpath, urllib.parse parts = urllib.parse.urlparse(systemId) scheme, netloc, path, params, query, fragment = parts # XXX should we check the scheme here as well? @@ -242,7 +243,6 @@ def _get_opener(self): return self._opener def _create_opener(self): - import urllib.request return urllib.request.build_opener() def _guess_media_encoding(self, source): diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py index e3d81a2c4560d9..e3f1aca9b63544 100644 --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -70,6 +70,8 @@ # OF THIS SOFTWARE. # -------------------------------------------------------------------- +lazy from warnings import _deprecated + __all__ = [ # public symbols "Comment", @@ -2110,7 +2112,6 @@ def _escape_attrib_c14n(text): def __getattr__(name): if name == "VERSION": - from warnings import _deprecated _deprecated("VERSION", remove=(3, 20)) return "1.3.0" # Do not change diff --git a/Lib/xml/sax/__init__.py b/Lib/xml/sax/__init__.py index fe4582c6f8b758..7773ddb0c907a3 100644 --- a/Lib/xml/sax/__init__.py +++ b/Lib/xml/sax/__init__.py @@ -19,6 +19,8 @@ expatreader -- Driver that allows use of the Expat parser with SAX. """ +lazy import io + from .xmlreader import InputSource from .handler import ContentHandler, ErrorHandler from ._exceptions import (SAXException, SAXNotRecognizedException, @@ -33,7 +35,6 @@ def parse(source, handler, errorHandler=ErrorHandler()): parser.parse(source) def parseString(string, handler, errorHandler=ErrorHandler()): - import io if errorHandler is None: errorHandler = ErrorHandler() parser = make_parser() diff --git a/Lib/xml/sax/expatreader.py b/Lib/xml/sax/expatreader.py index 37b1add2848487..8fbfcaf7d2491e 100644 --- a/Lib/xml/sax/expatreader.py +++ b/Lib/xml/sax/expatreader.py @@ -3,6 +3,8 @@ pyexpat.__version__ == '2.22'. """ +lazy from warnings import _deprecated + from xml.sax._exceptions import * from xml.sax.handler import feature_validation, feature_namespaces from xml.sax.handler import feature_namespace_prefixes @@ -446,7 +448,6 @@ def create_parser(*args, **kwargs): def __getattr__(name): if name == "version": - from warnings import _deprecated _deprecated("version", remove=(3, 20)) return "0.20" # Do not change diff --git a/Lib/xml/sax/handler.py b/Lib/xml/sax/handler.py index 9c2e3af838a40f..4c5601c28320d0 100644 --- a/Lib/xml/sax/handler.py +++ b/Lib/xml/sax/handler.py @@ -17,6 +17,8 @@ # ===== ERRORHANDLER ===== +lazy from warnings import _deprecated + class ErrorHandler: """Basic interface for SAX error handlers. @@ -387,7 +389,6 @@ def endCDATA(self): def __getattr__(name): if name == "version": - from warnings import _deprecated _deprecated("version", remove=(3, 20)) return "2.0beta" # Do not change diff --git a/Lib/xml/sax/saxutils.py b/Lib/xml/sax/saxutils.py index c1612ea1cebc5d..acdba22441fe2e 100644 --- a/Lib/xml/sax/saxutils.py +++ b/Lib/xml/sax/saxutils.py @@ -3,6 +3,8 @@ convenience of application and driver writers. """ +lazy import sys + import os, urllib.parse, urllib.request import io import codecs @@ -70,7 +72,6 @@ def quoteattr(data, entities={}): def _gettextwriter(out, encoding): if out is None: - import sys return sys.stdout if isinstance(out, io.TextIOBase): diff --git a/Lib/xml/sax/xmlreader.py b/Lib/xml/sax/xmlreader.py index e906121d23b9ef..a67b98dfc3565d 100644 --- a/Lib/xml/sax/xmlreader.py +++ b/Lib/xml/sax/xmlreader.py @@ -1,6 +1,8 @@ """An XML Reader is the SAX 2 name for an XML parser. XML Parsers should be based on this code. """ +lazy from . import saxutils + from . import handler from ._exceptions import SAXNotSupportedException, SAXNotRecognizedException @@ -113,7 +115,6 @@ def __init__(self, bufsize=2**16): XMLReader.__init__(self) def parse(self, source): - from . import saxutils source = saxutils.prepare_input_source(source) self.prepareParser(source) diff --git a/Lib/zipapp.py b/Lib/zipapp.py index 7a4ef96ea0f077..737a1aa9f801e7 100644 --- a/Lib/zipapp.py +++ b/Lib/zipapp.py @@ -1,3 +1,5 @@ +lazy import argparse + import contextlib import os import pathlib @@ -185,7 +187,6 @@ def main(args=None): Omitting ARGS (or setting it to None) works as for argparse, using sys.argv[1:] as the argument list. """ - import argparse parser = argparse.ArgumentParser(color=True) parser.add_argument('--output', '-o', default=None, diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py index 8234bf52d39c5f..39cf7dee6c4aa9 100644 --- a/Lib/zipfile/__init__.py +++ b/Lib/zipfile/__init__.py @@ -3,6 +3,11 @@ XXX references to utf-8 need further investigation. """ +lazy import warnings +lazy import importlib._bootstrap_external +lazy import importlib.machinery +lazy import argparse + import binascii import importlib.util import io @@ -1668,7 +1673,6 @@ def comment(self, comment): raise TypeError("comment: expected bytes, got %s" % type(comment).__name__) # check for valid comment length if len(comment) > ZIP_MAX_COMMENT: - import warnings warnings.warn('Archive comment is too long; truncating to %d bytes' % ZIP_MAX_COMMENT, stacklevel=2) comment = comment[:ZIP_MAX_COMMENT] @@ -1933,7 +1937,6 @@ def _extract_member(self, member, targetpath, pwd): def _writecheck(self, zinfo): """Check for errors before writing a file to the archive.""" if zinfo.filename in self.NameToInfo: - import warnings warnings.warn('Duplicate name: %r' % zinfo.filename, stacklevel=3) if self.mode not in ('w', 'x', 'a'): raise ValueError("write() requires mode 'w', 'x', or 'a'") @@ -2279,8 +2282,6 @@ def _get_code(self, pathname, basename): name. For example, given /python/lib/string, return ('string', b''). """ - import importlib._bootstrap_external - import importlib.machinery file_py = pathname + ".py" file_pyc = pathname + ".pyc" @@ -2314,7 +2315,6 @@ def _get_code(self, pathname, basename): def main(args=None): - import argparse description = 'A simple command-line interface for zipfile module.' parser = argparse.ArgumentParser(description=description, color=True) diff --git a/Lib/zipimport.py b/Lib/zipimport.py index 19279d1c2bea36..b6f31a62d2c4f3 100644 --- a/Lib/zipimport.py +++ b/Lib/zipimport.py @@ -10,6 +10,8 @@ to Zip archives. """ +lazy from importlib.readers import ZipReader + import _frozen_importlib_external as _bootstrap_external from _frozen_importlib_external import _unpack_uint16, _unpack_uint32, _unpack_uint64 import _frozen_importlib as _bootstrap # for _verbose_message @@ -207,7 +209,6 @@ def is_package(self, fullname): def get_resource_reader(self, fullname): """Return the ResourceReader for a module in a zip file.""" - from importlib.readers import ZipReader return ZipReader(self, fullname) diff --git a/Lib/zoneinfo/_common.py b/Lib/zoneinfo/_common.py index 59f3f0ce853f74..0f6dd0736f6b67 100644 --- a/Lib/zoneinfo/_common.py +++ b/Lib/zoneinfo/_common.py @@ -1,8 +1,9 @@ +lazy from importlib import resources + import struct def load_tzdata(key): - from importlib import resources components = key.split("/") package_name = ".".join(["tzdata.zoneinfo"] + components[:-1]) diff --git a/Lib/zoneinfo/_tzpath.py b/Lib/zoneinfo/_tzpath.py index 3661c837daa0a4..761f0e5e5ea94d 100644 --- a/Lib/zoneinfo/_tzpath.py +++ b/Lib/zoneinfo/_tzpath.py @@ -1,3 +1,6 @@ +lazy import warnings +lazy from importlib import resources + import os import sysconfig @@ -49,7 +52,6 @@ def _parse_python_tzpath(env_var, stacklevel): # If anything has been filtered out, we will warn about it if len(new_tzpath) != len(raw_tzpath): - import warnings msg = _get_invalid_paths_message(raw_tzpath) @@ -124,7 +126,6 @@ def available_timezones(): determine if a given file on the time zone search path is to open it and check for the "magic string" at the beginning. """ - from importlib import resources valid_zones = set() diff --git a/Lib/zoneinfo/_zoneinfo.py b/Lib/zoneinfo/_zoneinfo.py index 3ffdb4c837192b..9cd2fc64457025 100644 --- a/Lib/zoneinfo/_zoneinfo.py +++ b/Lib/zoneinfo/_zoneinfo.py @@ -1,3 +1,5 @@ +lazy import pickle + import bisect import calendar import collections @@ -206,7 +208,6 @@ def __reduce__(self): return (self.__class__._unpickle, (self._key, self._from_cache)) def _file_reduce(self): - import pickle raise pickle.PicklingError( "Cannot pickle a ZoneInfo file created from a file stream."