From acaa51cb814894b05a4ac5c770a4d18205a8149b Mon Sep 17 00:00:00 2001 From: donBarbos Date: Fri, 7 Feb 2025 06:07:30 +0400 Subject: [PATCH 1/8] Improve import time of codeop --- Lib/codeop.py | 17 ++++++++++++----- ...25-02-07-05-55-08.gh-issue-118761.aayL_A.rst | 2 ++ 2 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-02-07-05-55-08.gh-issue-118761.aayL_A.rst diff --git a/Lib/codeop.py b/Lib/codeop.py index adf000ba29f88c..e7e4c69e7c0ced 100644 --- a/Lib/codeop.py +++ b/Lib/codeop.py @@ -33,7 +33,6 @@ """ import __future__ -import warnings _features = [getattr(__future__, fname) for fname in __future__.all_feature_names] @@ -47,15 +46,18 @@ PyCF_ONLY_AST = 0x400 PyCF_ALLOW_INCOMPLETE_INPUT = 0x4000 + def _maybe_compile(compiler, source, filename, symbol): # Check for source consisting of only blank lines and comments. for line in source.split("\n"): line = line.strip() - if line and line[0] != '#': - break # Leave it alone. + if line and line[0] != "#": + break # Leave it alone. else: if symbol != "eval": - source = "pass" # Replace it with a 'pass' statement + source = "pass" # Replace it with a 'pass' statement + + import warnings # Disable compiler warnings when checking for incomplete input. with warnings.catch_warnings(): @@ -74,6 +76,7 @@ def _maybe_compile(compiler, source, filename, symbol): return compiler(source, filename, symbol, incomplete_input=False) + def _compile(source, filename, symbol, incomplete_input=True): flags = 0 if incomplete_input: @@ -81,6 +84,7 @@ def _compile(source, filename, symbol, incomplete_input=True): flags |= PyCF_DONT_IMPLY_DEDENT return compile(source, filename, symbol, flags) + def compile_command(source, filename="", symbol="single"): r"""Compile a command and determine whether it is incomplete. @@ -102,17 +106,19 @@ def compile_command(source, filename="", symbol="single"): """ return _maybe_compile(_compile, source, filename, symbol) + class Compile: """Instances of this class behave much like the built-in compile function, but if one is used to compile text containing a future statement, it "remembers" and compiles all subsequent program texts with the statement in force.""" + def __init__(self): self.flags = PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT def __call__(self, source, filename, symbol, flags=0, **kwargs): flags |= self.flags - if kwargs.get('incomplete_input', True) is False: + if kwargs.get("incomplete_input", True) is False: flags &= ~PyCF_DONT_IMPLY_DEDENT flags &= ~PyCF_ALLOW_INCOMPLETE_INPUT codeob = compile(source, filename, symbol, flags, True) @@ -123,6 +129,7 @@ def __call__(self, source, filename, symbol, flags=0, **kwargs): self.flags |= feature.compiler_flag return codeob + class CommandCompiler: """Instances of this class have __call__ methods identical in signature to compile_command; the difference is that if the diff --git a/Misc/NEWS.d/next/Library/2025-02-07-05-55-08.gh-issue-118761.aayL_A.rst b/Misc/NEWS.d/next/Library/2025-02-07-05-55-08.gh-issue-118761.aayL_A.rst new file mode 100644 index 00000000000000..3be037472aede3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-02-07-05-55-08.gh-issue-118761.aayL_A.rst @@ -0,0 +1,2 @@ +Improve import time of :mod:`codeop` by lazy import ``warnings``. Patch by +Semyon Moroz. From ca2f8bc056752a1ae318d60fc7242703314d4838 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Fri, 7 Feb 2025 08:04:51 +0400 Subject: [PATCH 2/8] Always lazy import warnings --- Lib/ctypes/_layout.py | 2 -- Lib/hmac.py | 11 +++++------ Lib/importlib/_bootstrap_external.py | 6 +++++- Lib/importlib/metadata/__init__.py | 2 +- Lib/importlib/resources/_common.py | 2 +- Lib/importlib/resources/_functional.py | 3 +-- Lib/importlib/resources/readers.py | 2 +- Lib/logging/__init__.py | 8 +++++++- Lib/pkgutil.py | 2 -- Lib/pydoc.py | 7 +++++-- Lib/rlcompleter.py | 5 +++-- Lib/ssl.py | 7 ++++++- Lib/tempfile.py | 10 ++++++---- Lib/traceback.py | 2 +- Lib/urllib/parse.py | 13 ++++++++++++- Lib/xml/etree/ElementTree.py | 7 ++++++- Lib/zipimport.py | 2 +- 17 files changed, 61 insertions(+), 30 deletions(-) diff --git a/Lib/ctypes/_layout.py b/Lib/ctypes/_layout.py index e30db598ab22e1..adda3f9a6f2acc 100644 --- a/Lib/ctypes/_layout.py +++ b/Lib/ctypes/_layout.py @@ -5,8 +5,6 @@ """ import sys -import warnings -import struct from _ctypes import CField, buffer_info import ctypes diff --git a/Lib/hmac.py b/Lib/hmac.py index 8b4eb2fe741e60..16e88182d69006 100644 --- a/Lib/hmac.py +++ b/Lib/hmac.py @@ -3,7 +3,6 @@ Implements the HMAC algorithm as described by RFC 2104. """ -import warnings as _warnings try: import _hashlib as _hashopenssl except ImportError: @@ -31,9 +30,7 @@ class HMAC: """ blocksize = 64 # 512-bit HMAC; can be changed in subclasses. - __slots__ = ( - "_hmac", "_inner", "_outer", "block_size", "digest_size" - ) + __slots__ = ("_hmac", "_inner", "_outer", "block_size", "digest_size") def __init__(self, key, msg=None, digestmod=''): """Create a new HMAC object. @@ -81,15 +78,17 @@ def _init_old(self, key, msg, digestmod): self._inner = digest_cons() self.digest_size = self._inner.digest_size + import warnings + if hasattr(self._inner, 'block_size'): blocksize = self._inner.block_size if blocksize < 16: - _warnings.warn('block_size of %d seems too small; using our ' + warnings.warn('block_size of %d seems too small; using our ' 'default of %d.' % (blocksize, self.blocksize), RuntimeWarning, 2) blocksize = self.blocksize else: - _warnings.warn('No block_size attribute on given digest object; ' + warnings.warn('No block_size attribute on given digest object; ' 'Assuming %d.' % (self.blocksize), RuntimeWarning, 2) blocksize = self.blocksize diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 8bcd741c446bd2..4968ba4c0ef536 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -26,7 +26,6 @@ import _imp import _io import sys -import _warnings import marshal @@ -259,6 +258,7 @@ def cache_from_source(path, debug_override=None, *, optimization=None): """ if debug_override is not None: + import _warnings _warnings.warn('the debug_override parameter is deprecated; use ' "'optimization' instead", DeprecationWarning) if optimization is not None: @@ -663,6 +663,7 @@ def _bless_my_loader(module_globals): if loader is None: exc = AttributeError if spec_loader is missing else ValueError raise exc('Module globals is missing a __spec__.loader') + import _warnings _warnings.warn( 'Module globals is missing a __spec__.loader', DeprecationWarning) @@ -670,6 +671,7 @@ 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) @@ -716,6 +718,7 @@ def _search_registry(cls, fullname): @classmethod def find_spec(cls, fullname, path=None, target=None): + import _warnings _warnings.warn('importlib.machinery.WindowsRegistryFinder is ' 'deprecated; use site configuration instead. ' 'Future versions of Python may not enable this ' @@ -1224,6 +1227,7 @@ def invalidate_caches(): def _path_hooks(path): """Search sys.path_hooks for a finder for 'path'.""" if sys.path_hooks is not None and not sys.path_hooks: + import _warnings _warnings.warn('sys.path_hooks is empty', ImportWarning) for hook in sys.path_hooks: try: diff --git a/Lib/importlib/metadata/__init__.py b/Lib/importlib/metadata/__init__.py index 8ce62dd864fc27..8b18df081d2c49 100644 --- a/Lib/importlib/metadata/__init__.py +++ b/Lib/importlib/metadata/__init__.py @@ -12,7 +12,6 @@ import zipfile import operator import textwrap -import warnings import functools import itertools import posixpath @@ -341,6 +340,7 @@ def __new__(cls, *args, **kwargs): if getattr(getattr(cls, name), '__isabstractmethod__', False) } if abstract: + import warnings warnings.warn( f"Unimplemented abstract methods {abstract}", DeprecationWarning, diff --git a/Lib/importlib/resources/_common.py b/Lib/importlib/resources/_common.py index 4e9014c45a056e..d69c21aae2fb85 100644 --- a/Lib/importlib/resources/_common.py +++ b/Lib/importlib/resources/_common.py @@ -6,7 +6,6 @@ import types import importlib import inspect -import warnings import itertools from typing import Union, Optional, cast @@ -35,6 +34,7 @@ def wrapper(anchor=undefined, package=undefined): if package is not undefined: if anchor is not undefined: return func(anchor, package) + import warnings warnings.warn( "First parameter to files is renamed to 'anchor'", DeprecationWarning, diff --git a/Lib/importlib/resources/_functional.py b/Lib/importlib/resources/_functional.py index f59416f2dd627d..3ce523f560bdcd 100644 --- a/Lib/importlib/resources/_functional.py +++ b/Lib/importlib/resources/_functional.py @@ -1,7 +1,5 @@ """Simplified function-based API for importlib.resources""" -import warnings - from ._common import files, as_file @@ -51,6 +49,7 @@ def contents(anchor, *path_names): The iterable returns :class:`str` resources (e.g. files). The iterable does not recurse into subdirectories. """ + import warnings warnings.warn( "importlib.resources.contents is deprecated. " "Use files(anchor).iterdir() instead.", diff --git a/Lib/importlib/resources/readers.py b/Lib/importlib/resources/readers.py index 70fc7e2b9c0145..7ccd45e0f52ebf 100644 --- a/Lib/importlib/resources/readers.py +++ b/Lib/importlib/resources/readers.py @@ -6,7 +6,6 @@ import pathlib import operator import re -import warnings import zipfile from collections.abc import Iterator @@ -194,6 +193,7 @@ def _ensure_traversable(path): if not isinstance(path, str): return path + import warnings warnings.warn( "String arguments are deprecated. Pass a Traversable instead.", DeprecationWarning, diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index aa9b79d8cab4bb..66b1587978ee63 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -23,7 +23,7 @@ To use, simply 'import logging' and log away! """ -import sys, os, time, io, re, traceback, warnings, weakref, collections.abc +import sys, os, time, io, re, traceback, weakref, collections.abc from types import GenericAlias from string import Template @@ -1531,6 +1531,7 @@ def warning(self, msg, *args, **kwargs): self._log(WARNING, msg, args, **kwargs) def warn(self, msg, *args, **kwargs): + import warnings warnings.warn("The 'warn' method is deprecated, " "use 'warning' instead", DeprecationWarning, 2) self.warning(msg, *args, **kwargs) @@ -1912,6 +1913,7 @@ def warning(self, msg, *args, **kwargs): self.log(WARNING, msg, *args, **kwargs) def warn(self, msg, *args, **kwargs): + import warnings warnings.warn("The 'warn' method is deprecated, " "use 'warning' instead", DeprecationWarning, 2) self.warning(msg, *args, **kwargs) @@ -2180,6 +2182,7 @@ def warning(msg, *args, **kwargs): root.warning(msg, *args, **kwargs) def warn(msg, *args, **kwargs): + import warnings warnings.warn("The 'warn' function is deprecated, " "use 'warning' instead", DeprecationWarning, 2) warning(msg, *args, **kwargs) @@ -2299,6 +2302,7 @@ def _showwarning(message, category, filename, lineno, file=None, line=None): if _warnings_showwarning is not None: _warnings_showwarning(message, category, filename, lineno, file, line) else: + import warnings s = warnings.formatwarning(message, category, filename, lineno, line) logger = getLogger("py.warnings") if not logger.handlers: @@ -2316,9 +2320,11 @@ def captureWarnings(capture): global _warnings_showwarning if capture: if _warnings_showwarning is None: + import warnings _warnings_showwarning = warnings.showwarning warnings.showwarning = _showwarning else: if _warnings_showwarning is not None: + import warnings warnings.showwarning = _warnings_showwarning _warnings_showwarning = None diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py index b84d72f2395d45..8772a66791a3c9 100644 --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -8,8 +8,6 @@ import os import os.path import sys -from types import ModuleType -import warnings __all__ = [ 'get_importer', 'iter_importers', diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 1839b88fec28b1..fabf1a5552e73e 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -64,14 +64,12 @@ class or function within a module or module in a package. If the import io import os import pkgutil -import platform import re import sys import sysconfig import time import tokenize import urllib.parse -import warnings from annotationlib import Format from collections import deque from reprlib import Repr @@ -376,6 +374,7 @@ def sort_attributes(attrs, object): def ispackage(path): """Guess whether a path refers to a package directory.""" + import warnings warnings.warn('The pydoc.ispackage() function is deprecated', DeprecationWarning, stacklevel=2) if os.path.isdir(path): @@ -394,6 +393,7 @@ def source_synopsis(file): if tok_type == tokenize.STRING: string += tok_string elif tok_type == tokenize.NEWLINE: + import warnings with warnings.catch_warnings(): # Ignore the "invalid escape sequence" warning. warnings.simplefilter("ignore", SyntaxWarning) @@ -457,6 +457,7 @@ def __init__(self, filename, exc_info): self.value = exc_info self.tb = exc_info.__traceback__ else: + import warnings warnings.warn("A tuple value for exc_info is deprecated, use an exception instance", DeprecationWarning) @@ -2294,6 +2295,7 @@ def callback(path, modname, desc): print(modname, desc and '- ' + desc) def onerror(modname): pass + import warnings with warnings.catch_warnings(): warnings.filterwarnings('ignore') # ignore problems during import ModuleScanner().run(callback, key, onerror=onerror) @@ -2543,6 +2545,7 @@ def callback(path, modname, desc): modname = modname[:-9] + ' (package)' search_result.append((modname, desc and '- ' + desc)) + import warnings with warnings.catch_warnings(): warnings.filterwarnings('ignore') # ignore problems during import def onerror(modname): diff --git a/Lib/rlcompleter.py b/Lib/rlcompleter.py index 23eb0020f42e8a..c805fa33764211 100644 --- a/Lib/rlcompleter.py +++ b/Lib/rlcompleter.py @@ -35,12 +35,12 @@ import keyword import re import __main__ -import warnings __all__ = ["Completer"] + class Completer: - def __init__(self, namespace = None): + def __init__(self, namespace=None): """Create a new completer for the command line. Completer([namespace]) -> completer instance. @@ -89,6 +89,7 @@ def complete(self, text, state): return None if state == 0: + import warnings with warnings.catch_warnings(action="ignore"): if "." in text: self.matches = self.attr_matches(text) diff --git a/Lib/ssl.py b/Lib/ssl.py index 05df4ad7f0f05c..53e1afbf8bad55 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -262,7 +262,6 @@ class _TLSMessageType: import socket as _socket import base64 # for DER-to-PEM translation import errno -import warnings socket_error = OSError # keep that public name in module namespace @@ -429,6 +428,7 @@ class SSLContext(_SSLContext): def __new__(cls, protocol=None, *args, **kwargs): if protocol is None: + import warnings warnings.warn( "ssl.SSLContext() without protocol argument is deprecated.", category=DeprecationWarning, @@ -473,6 +473,7 @@ def wrap_bio(self, incoming, outgoing, server_side=False, ) def set_npn_protocols(self, npn_protocols): + import warnings warnings.warn( "ssl NPN is deprecated, use ALPN instead", DeprecationWarning, @@ -521,8 +522,10 @@ def _load_windows_store_certs(self, storename, purpose): try: self.load_verify_locations(cadata=cert) except SSLError as exc: + import warnings warnings.warn(f"Bad certificate in Windows certificate store: {exc!s}") except PermissionError: + import warnings warnings.warn("unable to enumerate Windows certificate store") def load_default_certs(self, purpose=Purpose.SERVER_AUTH): @@ -914,6 +917,7 @@ def selected_npn_protocol(self): """Return the currently selected NPN protocol as a string, or ``None`` if a next protocol was not negotiated or if NPN is not supported by one of the peers.""" + import warnings warnings.warn( "ssl NPN is deprecated, use ALPN instead", DeprecationWarning, @@ -1183,6 +1187,7 @@ def get_unverified_chain(self): @_sslcopydoc def selected_npn_protocol(self): self._checkClosed() + import warnings warnings.warn( "ssl NPN is deprecated, use ALPN instead", DeprecationWarning, diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 0eb9ddeb6ac377..dc13bf5acdf276 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -37,7 +37,6 @@ # Imports. import functools as _functools -import warnings as _warnings import io as _io import os as _os import shutil as _shutil @@ -480,7 +479,8 @@ def __del__(self): close_called = self.close_called self.cleanup() if not close_called: - _warnings.warn(self.warn_message, ResourceWarning) + import warnings + warnings.warn(self.warn_message, ResourceWarning) class _TemporaryFileWrapper: @@ -769,7 +769,8 @@ def __iter__(self): def __del__(self): if not self.closed: - _warnings.warn( + import warnings + warnings.warn( "Unclosed file {!r}".format(self), ResourceWarning, stacklevel=2, @@ -953,7 +954,8 @@ def onexc(func, path, exc): def _cleanup(cls, name, warn_message, ignore_errors=False, delete=True): if delete: cls._rmtree(name, ignore_errors=ignore_errors) - _warnings.warn(warn_message, ResourceWarning) + import warnings + warnings.warn(warn_message, ResourceWarning) def __repr__(self): return "<{} {!r}>".format(self.__class__.__name__, self.name) diff --git a/Lib/traceback.py b/Lib/traceback.py index 31c73efcef5a52..fe155c5f6677dd 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -5,7 +5,6 @@ import linecache import sys import textwrap -import warnings from contextlib import suppress import _colorize from _colorize import ANSIColors @@ -1178,6 +1177,7 @@ def from_exception(cls, exc, *args, **kwargs): @property def exc_type(self): + import warnings warnings.warn('Deprecated in 3.13. Use exc_type_str instead.', DeprecationWarning, stacklevel=2) return self._exc_type diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index 9d51f4c6812b57..01079591e10a59 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -36,7 +36,6 @@ import math import re import types -import warnings import ipaddress __all__ = ["urlparse", "urlunparse", "urljoin", "urldefrag", @@ -825,6 +824,7 @@ def _unquote(s): qs = bytes(memoryview(qs)) except TypeError: if not qs: + import warnings warnings.warn(f"Accepting {type(qs).__name__} objects with " f"false value in urllib.parse.parse_qsl() is " f"deprecated as of 3.14", @@ -1081,6 +1081,7 @@ def urlencode(query, doseq=False, safe='', encoding=None, errors=None, def to_bytes(url): + import warnings warnings.warn("urllib.parse.to_bytes() is deprecated as of 3.8", DeprecationWarning, stacklevel=2) return _to_bytes(url) @@ -1114,6 +1115,7 @@ def unwrap(url): def splittype(url): + import warnings warnings.warn("urllib.parse.splittype() is deprecated as of 3.8, " "use urllib.parse.urlparse() instead", DeprecationWarning, stacklevel=2) @@ -1135,6 +1137,7 @@ def _splittype(url): def splithost(url): + import warnings warnings.warn("urllib.parse.splithost() is deprecated as of 3.8, " "use urllib.parse.urlparse() instead", DeprecationWarning, stacklevel=2) @@ -1158,6 +1161,7 @@ def _splithost(url): def splituser(host): + import warnings warnings.warn("urllib.parse.splituser() is deprecated as of 3.8, " "use urllib.parse.urlparse() instead", DeprecationWarning, stacklevel=2) @@ -1171,6 +1175,7 @@ def _splituser(host): def splitpasswd(user): + import warnings warnings.warn("urllib.parse.splitpasswd() is deprecated as of 3.8, " "use urllib.parse.urlparse() instead", DeprecationWarning, stacklevel=2) @@ -1184,6 +1189,7 @@ def _splitpasswd(user): def splitport(host): + import warnings warnings.warn("urllib.parse.splitport() is deprecated as of 3.8, " "use urllib.parse.urlparse() instead", DeprecationWarning, stacklevel=2) @@ -1207,6 +1213,7 @@ def _splitport(host): def splitnport(host, defport=-1): + import warnings warnings.warn("urllib.parse.splitnport() is deprecated as of 3.8, " "use urllib.parse.urlparse() instead", DeprecationWarning, stacklevel=2) @@ -1231,6 +1238,7 @@ def _splitnport(host, defport=-1): def splitquery(url): + import warnings warnings.warn("urllib.parse.splitquery() is deprecated as of 3.8, " "use urllib.parse.urlparse() instead", DeprecationWarning, stacklevel=2) @@ -1246,6 +1254,7 @@ def _splitquery(url): def splittag(url): + import warnings warnings.warn("urllib.parse.splittag() is deprecated as of 3.8, " "use urllib.parse.urlparse() instead", DeprecationWarning, stacklevel=2) @@ -1261,6 +1270,7 @@ def _splittag(url): def splitattr(url): + import warnings warnings.warn("urllib.parse.splitattr() is deprecated as of 3.8, " "use urllib.parse.urlparse() instead", DeprecationWarning, stacklevel=2) @@ -1275,6 +1285,7 @@ def _splitattr(url): def splitvalue(attr): + import warnings warnings.warn("urllib.parse.splitvalue() is deprecated as of 3.8, " "use urllib.parse.parse_qsl() instead", DeprecationWarning, stacklevel=2) diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py index ce67d7d7d54748..8ce589fe875b79 100644 --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -94,7 +94,6 @@ import sys import re -import warnings import io import collections import collections.abc @@ -200,6 +199,7 @@ def __len__(self): return len(self._children) def __bool__(self): + import warnings warnings.warn( "Testing an element's truth value will always return True in " "future versions. " @@ -602,6 +602,7 @@ def find(self, path, namespaces=None): # assert self._root is not None if path[:1] == "/": path = "." + path + import warnings warnings.warn( "This search is broken in 1.3 and earlier, and will be " "fixed in a future version. If you rely on the current " @@ -624,6 +625,7 @@ def findtext(self, path, default=None, namespaces=None): # assert self._root is not None if path[:1] == "/": path = "." + path + import warnings warnings.warn( "This search is broken in 1.3 and earlier, and will be " "fixed in a future version. If you rely on the current " @@ -646,6 +648,7 @@ def findall(self, path, namespaces=None): # assert self._root is not None if path[:1] == "/": path = "." + path + import warnings warnings.warn( "This search is broken in 1.3 and earlier, and will be " "fixed in a future version. If you rely on the current " @@ -668,6 +671,7 @@ def iterfind(self, path, namespaces=None): # assert self._root is not None if path[:1] == "/": path = "." + path + import warnings warnings.warn( "This search is broken in 1.3 and earlier, and will be " "fixed in a future version. If you rely on the current " @@ -1700,6 +1704,7 @@ def _default(self, text): if hasattr(self.target, "doctype"): self.target.doctype(name, pubid, system[1:-1]) elif hasattr(self, "doctype"): + import warnings warnings.warn( "The doctype() method of XMLParser is ignored. " "Define doctype() method on the TreeBuilder target.", diff --git a/Lib/zipimport.py b/Lib/zipimport.py index e5192c4d074c4b..2054f0a46c64ef 100644 --- a/Lib/zipimport.py +++ b/Lib/zipimport.py @@ -20,7 +20,6 @@ import marshal # for loads import sys # for modules import time # for mktime -import _warnings # For warn() __all__ = ['ZipImportError', 'zipimporter'] @@ -223,6 +222,7 @@ def load_module(self, fullname): """ msg = ("zipimport.zipimporter.load_module() is deprecated and slated for " "removal in Python 3.12; use exec_module() instead") + import _warnings _warnings.warn(msg, DeprecationWarning) code, ispackage, modpath = _get_module_code(self, fullname) mod = sys.modules.get(fullname) From f88c5b15a967e1a93d0af49d1fc1b8ba518c33cc Mon Sep 17 00:00:00 2001 From: donBarbos Date: Fri, 7 Feb 2025 04:45:08 +0000 Subject: [PATCH 3/8] Update Misc/NEWS.d/next/Library/2025-02-07-05-55-08.gh-issue-118761.aayL_A.rst Co-authored-by: Wulian233 <1055917385@qq.com> --- .../next/Library/2025-02-07-05-55-08.gh-issue-118761.aayL_A.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-02-07-05-55-08.gh-issue-118761.aayL_A.rst b/Misc/NEWS.d/next/Library/2025-02-07-05-55-08.gh-issue-118761.aayL_A.rst index 3be037472aede3..04da69d2147177 100644 --- a/Misc/NEWS.d/next/Library/2025-02-07-05-55-08.gh-issue-118761.aayL_A.rst +++ b/Misc/NEWS.d/next/Library/2025-02-07-05-55-08.gh-issue-118761.aayL_A.rst @@ -1,2 +1,2 @@ -Improve import time of :mod:`codeop` by lazy import ``warnings``. Patch by +Improve import time of various stdlib by lazy import ``warnings``. Patch by Semyon Moroz. From f1f77a57b67ab0c16de2e46c9cfeb0af1f2f22b9 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Fri, 7 Feb 2025 08:50:45 +0400 Subject: [PATCH 4/8] Correct my mistake --- Lib/pydoc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/pydoc.py b/Lib/pydoc.py index fabf1a5552e73e..52712ef9034ade 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -64,6 +64,7 @@ class or function within a module or module in a package. If the import io import os import pkgutil +import platform import re import sys import sysconfig From 6210539e3c3b12c636b82b938cf84fe010ea860c Mon Sep 17 00:00:00 2001 From: donBarbos Date: Fri, 7 Feb 2025 14:17:53 +0400 Subject: [PATCH 5/8] Update 2025-02-07-05-55-08.gh-issue-118761.aayL_A.rst Co-authored-by: Vinay Sajip --- .../next/Library/2025-02-07-05-55-08.gh-issue-118761.aayL_A.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-02-07-05-55-08.gh-issue-118761.aayL_A.rst b/Misc/NEWS.d/next/Library/2025-02-07-05-55-08.gh-issue-118761.aayL_A.rst index 04da69d2147177..1c57361385c42a 100644 --- a/Misc/NEWS.d/next/Library/2025-02-07-05-55-08.gh-issue-118761.aayL_A.rst +++ b/Misc/NEWS.d/next/Library/2025-02-07-05-55-08.gh-issue-118761.aayL_A.rst @@ -1,2 +1,2 @@ -Improve import time of various stdlib by lazy import ``warnings``. Patch by +Improve import time of various stdlib modules by lazy import ``warnings``. Patch by Semyon Moroz. From 212a25fe865ea3c6c4fa622dc8d1d6b28450aaf4 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Fri, 7 Feb 2025 19:59:22 +0400 Subject: [PATCH 6/8] Revert changing styles --- Lib/codeop.py | 7 +++---- Lib/hmac.py | 4 +++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Lib/codeop.py b/Lib/codeop.py index e7e4c69e7c0ced..d608790c10a569 100644 --- a/Lib/codeop.py +++ b/Lib/codeop.py @@ -46,16 +46,15 @@ PyCF_ONLY_AST = 0x400 PyCF_ALLOW_INCOMPLETE_INPUT = 0x4000 - def _maybe_compile(compiler, source, filename, symbol): # Check for source consisting of only blank lines and comments. for line in source.split("\n"): line = line.strip() - if line and line[0] != "#": - break # Leave it alone. + if line and line[0] != '#': + break # Leave it alone. else: if symbol != "eval": - source = "pass" # Replace it with a 'pass' statement + source = "pass" # Replace it with a 'pass' statement import warnings diff --git a/Lib/hmac.py b/Lib/hmac.py index 16e88182d69006..98c7301597ea49 100644 --- a/Lib/hmac.py +++ b/Lib/hmac.py @@ -30,7 +30,9 @@ class HMAC: """ blocksize = 64 # 512-bit HMAC; can be changed in subclasses. - __slots__ = ("_hmac", "_inner", "_outer", "block_size", "digest_size") + __slots__ = ( + "_hmac", "_inner", "_outer", "block_size", "digest_size" + ) def __init__(self, key, msg=None, digestmod=''): """Create a new HMAC object. From e976ca07c6c86b29145627e979fb600953ca88ce Mon Sep 17 00:00:00 2001 From: donBarbos Date: Fri, 7 Feb 2025 20:04:45 +0400 Subject: [PATCH 7/8] Revert more --- Lib/codeop.py | 7 +------ Lib/rlcompleter.py | 3 +-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Lib/codeop.py b/Lib/codeop.py index d608790c10a569..41136e998530c9 100644 --- a/Lib/codeop.py +++ b/Lib/codeop.py @@ -75,7 +75,6 @@ def _maybe_compile(compiler, source, filename, symbol): return compiler(source, filename, symbol, incomplete_input=False) - def _compile(source, filename, symbol, incomplete_input=True): flags = 0 if incomplete_input: @@ -83,7 +82,6 @@ def _compile(source, filename, symbol, incomplete_input=True): flags |= PyCF_DONT_IMPLY_DEDENT return compile(source, filename, symbol, flags) - def compile_command(source, filename="", symbol="single"): r"""Compile a command and determine whether it is incomplete. @@ -105,19 +103,17 @@ def compile_command(source, filename="", symbol="single"): """ return _maybe_compile(_compile, source, filename, symbol) - class Compile: """Instances of this class behave much like the built-in compile function, but if one is used to compile text containing a future statement, it "remembers" and compiles all subsequent program texts with the statement in force.""" - def __init__(self): self.flags = PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT def __call__(self, source, filename, symbol, flags=0, **kwargs): flags |= self.flags - if kwargs.get("incomplete_input", True) is False: + if kwargs.get('incomplete_input', True) is False: flags &= ~PyCF_DONT_IMPLY_DEDENT flags &= ~PyCF_ALLOW_INCOMPLETE_INPUT codeob = compile(source, filename, symbol, flags, True) @@ -128,7 +124,6 @@ def __call__(self, source, filename, symbol, flags=0, **kwargs): self.flags |= feature.compiler_flag return codeob - class CommandCompiler: """Instances of this class have __call__ methods identical in signature to compile_command; the difference is that if the diff --git a/Lib/rlcompleter.py b/Lib/rlcompleter.py index c805fa33764211..88e3c19910ab1d 100644 --- a/Lib/rlcompleter.py +++ b/Lib/rlcompleter.py @@ -38,9 +38,8 @@ __all__ = ["Completer"] - class Completer: - def __init__(self, namespace=None): + def __init__(self, namespace = None): """Create a new completer for the command line. Completer([namespace]) -> completer instance. From 3e7f0ad43314ad38ac527b333d7c78cae5a3e2bc Mon Sep 17 00:00:00 2001 From: donBarbos Date: Wed, 12 Feb 2025 23:23:03 +0400 Subject: [PATCH 8/8] Add suggestions --- Lib/hmac.py | 4 ++-- Lib/importlib/_bootstrap_external.py | 6 +----- Lib/zipimport.py | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Lib/hmac.py b/Lib/hmac.py index 98c7301597ea49..0577c151b6583c 100644 --- a/Lib/hmac.py +++ b/Lib/hmac.py @@ -86,8 +86,8 @@ def _init_old(self, key, msg, digestmod): blocksize = self._inner.block_size if blocksize < 16: warnings.warn('block_size of %d seems too small; using our ' - 'default of %d.' % (blocksize, self.blocksize), - RuntimeWarning, 2) + 'default of %d.' % (blocksize, self.blocksize), + RuntimeWarning, 2) blocksize = self.blocksize else: warnings.warn('No block_size attribute on given digest object; ' diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 4968ba4c0ef536..8bcd741c446bd2 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -26,6 +26,7 @@ import _imp import _io import sys +import _warnings import marshal @@ -258,7 +259,6 @@ def cache_from_source(path, debug_override=None, *, optimization=None): """ if debug_override is not None: - import _warnings _warnings.warn('the debug_override parameter is deprecated; use ' "'optimization' instead", DeprecationWarning) if optimization is not None: @@ -663,7 +663,6 @@ def _bless_my_loader(module_globals): if loader is None: exc = AttributeError if spec_loader is missing else ValueError raise exc('Module globals is missing a __spec__.loader') - import _warnings _warnings.warn( 'Module globals is missing a __spec__.loader', DeprecationWarning) @@ -671,7 +670,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) @@ -718,7 +716,6 @@ def _search_registry(cls, fullname): @classmethod def find_spec(cls, fullname, path=None, target=None): - import _warnings _warnings.warn('importlib.machinery.WindowsRegistryFinder is ' 'deprecated; use site configuration instead. ' 'Future versions of Python may not enable this ' @@ -1227,7 +1224,6 @@ def invalidate_caches(): def _path_hooks(path): """Search sys.path_hooks for a finder for 'path'.""" if sys.path_hooks is not None and not sys.path_hooks: - import _warnings _warnings.warn('sys.path_hooks is empty', ImportWarning) for hook in sys.path_hooks: try: diff --git a/Lib/zipimport.py b/Lib/zipimport.py index 2054f0a46c64ef..e5192c4d074c4b 100644 --- a/Lib/zipimport.py +++ b/Lib/zipimport.py @@ -20,6 +20,7 @@ import marshal # for loads import sys # for modules import time # for mktime +import _warnings # For warn() __all__ = ['ZipImportError', 'zipimporter'] @@ -222,7 +223,6 @@ def load_module(self, fullname): """ msg = ("zipimport.zipimporter.load_module() is deprecated and slated for " "removal in Python 3.12; use exec_module() instead") - import _warnings _warnings.warn(msg, DeprecationWarning) code, ispackage, modpath = _get_module_code(self, fullname) mod = sys.modules.get(fullname)