diff --git a/changelog.d/3674.change.rst b/changelog.d/3674.change.rst new file mode 100644 index 0000000000..e90e16eb5d --- /dev/null +++ b/changelog.d/3674.change.rst @@ -0,0 +1 @@ +Sync with pypa/distutils@e0787fa, including pypa/distutils#183 updating distutils to use the Python logging framework. diff --git a/setuptools/_distutils/README b/setuptools/_distutils/README deleted file mode 100644 index 23f488506f..0000000000 --- a/setuptools/_distutils/README +++ /dev/null @@ -1,11 +0,0 @@ -This directory contains the Distutils package. - -There's a full documentation available at: - - http://docs.python.org/distutils/ - -The Distutils-SIG web page is also a good starting point: - - http://www.python.org/sigs/distutils-sig/ - -$Id$ diff --git a/setuptools/_distutils/__init__.py b/setuptools/_distutils/__init__.py index b3ac0146cb..1a188c35cb 100644 --- a/setuptools/_distutils/__init__.py +++ b/setuptools/_distutils/__init__.py @@ -1,17 +1,7 @@ -"""distutils - -The main package for the Python Module Distribution Utilities. Normally -used from a setup script as - - from distutils.core import setup - - setup (...) -""" - import sys import importlib -__version__ = sys.version[: sys.version.index(' ')] +__version__, _, _ = sys.version.partition(' ') try: diff --git a/setuptools/_distutils/_collections.py b/setuptools/_distutils/_collections.py index 98fce8008d..02556614a5 100644 --- a/setuptools/_distutils/_collections.py +++ b/setuptools/_distutils/_collections.py @@ -1,5 +1,7 @@ import collections +import functools import itertools +import operator # from jaraco.collections 3.5.1 @@ -54,3 +56,139 @@ def __contains__(self, other): def __len__(self): return len(list(iter(self))) + + +# from jaraco.collections 3.7 +class RangeMap(dict): + """ + A dictionary-like object that uses the keys as bounds for a range. + Inclusion of the value for that range is determined by the + key_match_comparator, which defaults to less-than-or-equal. + A value is returned for a key if it is the first key that matches in + the sorted list of keys. + + One may supply keyword parameters to be passed to the sort function used + to sort keys (i.e. key, reverse) as sort_params. + + Let's create a map that maps 1-3 -> 'a', 4-6 -> 'b' + + >>> r = RangeMap({3: 'a', 6: 'b'}) # boy, that was easy + >>> r[1], r[2], r[3], r[4], r[5], r[6] + ('a', 'a', 'a', 'b', 'b', 'b') + + Even float values should work so long as the comparison operator + supports it. + + >>> r[4.5] + 'b' + + But you'll notice that the way rangemap is defined, it must be open-ended + on one side. + + >>> r[0] + 'a' + >>> r[-1] + 'a' + + One can close the open-end of the RangeMap by using undefined_value + + >>> r = RangeMap({0: RangeMap.undefined_value, 3: 'a', 6: 'b'}) + >>> r[0] + Traceback (most recent call last): + ... + KeyError: 0 + + One can get the first or last elements in the range by using RangeMap.Item + + >>> last_item = RangeMap.Item(-1) + >>> r[last_item] + 'b' + + .last_item is a shortcut for Item(-1) + + >>> r[RangeMap.last_item] + 'b' + + Sometimes it's useful to find the bounds for a RangeMap + + >>> r.bounds() + (0, 6) + + RangeMap supports .get(key, default) + + >>> r.get(0, 'not found') + 'not found' + + >>> r.get(7, 'not found') + 'not found' + + One often wishes to define the ranges by their left-most values, + which requires use of sort params and a key_match_comparator. + + >>> r = RangeMap({1: 'a', 4: 'b'}, + ... sort_params=dict(reverse=True), + ... key_match_comparator=operator.ge) + >>> r[1], r[2], r[3], r[4], r[5], r[6] + ('a', 'a', 'a', 'b', 'b', 'b') + + That wasn't nearly as easy as before, so an alternate constructor + is provided: + + >>> r = RangeMap.left({1: 'a', 4: 'b', 7: RangeMap.undefined_value}) + >>> r[1], r[2], r[3], r[4], r[5], r[6] + ('a', 'a', 'a', 'b', 'b', 'b') + + """ + + def __init__(self, source, sort_params={}, key_match_comparator=operator.le): + dict.__init__(self, source) + self.sort_params = sort_params + self.match = key_match_comparator + + @classmethod + def left(cls, source): + return cls( + source, sort_params=dict(reverse=True), key_match_comparator=operator.ge + ) + + def __getitem__(self, item): + sorted_keys = sorted(self.keys(), **self.sort_params) + if isinstance(item, RangeMap.Item): + result = self.__getitem__(sorted_keys[item]) + else: + key = self._find_first_match_(sorted_keys, item) + result = dict.__getitem__(self, key) + if result is RangeMap.undefined_value: + raise KeyError(key) + return result + + def get(self, key, default=None): + """ + Return the value for key if key is in the dictionary, else default. + If default is not given, it defaults to None, so that this method + never raises a KeyError. + """ + try: + return self[key] + except KeyError: + return default + + def _find_first_match_(self, keys, item): + is_match = functools.partial(self.match, item) + matches = list(filter(is_match, keys)) + if matches: + return matches[0] + raise KeyError(item) + + def bounds(self): + sorted_keys = sorted(self.keys(), **self.sort_params) + return (sorted_keys[RangeMap.first_item], sorted_keys[RangeMap.last_item]) + + # some special values for the RangeMap + undefined_value = type(str('RangeValueUndefined'), (), {})() + + class Item(int): + "RangeMap Item" + + first_item = Item(0) + last_item = Item(-1) diff --git a/setuptools/_distutils/_log.py b/setuptools/_distutils/_log.py new file mode 100644 index 0000000000..4a2ae0acb8 --- /dev/null +++ b/setuptools/_distutils/_log.py @@ -0,0 +1,4 @@ +import logging + + +log = logging.getLogger() diff --git a/setuptools/_distutils/_msvccompiler.py b/setuptools/_distutils/_msvccompiler.py index 729c2dd521..8b4023c420 100644 --- a/setuptools/_distutils/_msvccompiler.py +++ b/setuptools/_distutils/_msvccompiler.py @@ -22,16 +22,16 @@ with contextlib.suppress(ImportError): import winreg -from distutils.errors import ( +from .errors import ( DistutilsExecError, DistutilsPlatformError, CompileError, LibError, LinkError, ) -from distutils.ccompiler import CCompiler, gen_lib_options -from distutils import log -from distutils.util import get_platform +from .ccompiler import CCompiler, gen_lib_options +from ._log import log +from .util import get_platform from itertools import count diff --git a/setuptools/_distutils/archive_util.py b/setuptools/_distutils/archive_util.py index 5dfe2a16ff..7f9e1e00cc 100644 --- a/setuptools/_distutils/archive_util.py +++ b/setuptools/_distutils/archive_util.py @@ -13,10 +13,10 @@ zipfile = None -from distutils.errors import DistutilsExecError -from distutils.spawn import spawn -from distutils.dir_util import mkpath -from distutils import log +from .errors import DistutilsExecError +from .spawn import spawn +from .dir_util import mkpath +from ._log import log try: from pwd import getpwnam diff --git a/setuptools/_distutils/bcppcompiler.py b/setuptools/_distutils/bcppcompiler.py index 80b6bd8522..5d6b86536e 100644 --- a/setuptools/_distutils/bcppcompiler.py +++ b/setuptools/_distutils/bcppcompiler.py @@ -15,17 +15,17 @@ import os import warnings -from distutils.errors import ( +from .errors import ( DistutilsExecError, CompileError, LibError, LinkError, UnknownFileError, ) -from distutils.ccompiler import CCompiler, gen_preprocess_options -from distutils.file_util import write_file -from distutils.dep_util import newer -from distutils import log +from .ccompiler import CCompiler, gen_preprocess_options +from .file_util import write_file +from .dep_util import newer +from ._log import log warnings.warn( @@ -210,7 +210,7 @@ def link( # noqa: C901 ) if runtime_library_dirs: - log.warn( + log.warning( "I don't know what to do with 'runtime_library_dirs': %s", str(runtime_library_dirs), ) diff --git a/setuptools/_distutils/ccompiler.py b/setuptools/_distutils/ccompiler.py index 97551c99fe..646353111f 100644 --- a/setuptools/_distutils/ccompiler.py +++ b/setuptools/_distutils/ccompiler.py @@ -7,19 +7,19 @@ import os import re -from distutils.errors import ( +from .errors import ( CompileError, LinkError, UnknownFileError, DistutilsPlatformError, DistutilsModuleError, ) -from distutils.spawn import spawn -from distutils.file_util import move_file -from distutils.dir_util import mkpath -from distutils.dep_util import newer_group -from distutils.util import split_quoted, execute -from distutils import log +from .spawn import spawn +from .file_util import move_file +from .dir_util import mkpath +from .dep_util import newer_group +from .util import split_quoted, execute +from ._log import log class CCompiler: diff --git a/setuptools/_distutils/cmd.py b/setuptools/_distutils/cmd.py index 68a9267c65..918db85325 100644 --- a/setuptools/_distutils/cmd.py +++ b/setuptools/_distutils/cmd.py @@ -7,9 +7,11 @@ import sys import os import re -from distutils.errors import DistutilsOptionError -from distutils import util, dir_util, file_util, archive_util, dep_util -from distutils import log +import logging + +from .errors import DistutilsOptionError +from . import util, dir_util, file_util, archive_util, dep_util +from ._log import log class Command: @@ -156,14 +158,14 @@ def dump_options(self, header=None, indent=""): if header is None: header = "command options for '%s':" % self.get_command_name() - self.announce(indent + header, level=log.INFO) + self.announce(indent + header, level=logging.INFO) indent = indent + " " for (option, _, _) in self.user_options: option = option.translate(longopt_xlate) if option[-1] == "=": option = option[:-1] value = getattr(self, option) - self.announce(indent + "{} = {}".format(option, value), level=log.INFO) + self.announce(indent + "{} = {}".format(option, value), level=logging.INFO) def run(self): """A command's raison d'etre: carry out the action it exists to @@ -179,10 +181,7 @@ def run(self): "abstract method -- subclass %s must override" % self.__class__ ) - def announce(self, msg, level=1): - """If the current verbosity level is of greater than or equal to - 'level' print 'msg' to stdout. - """ + def announce(self, msg, level=logging.DEBUG): log.log(level, msg) def debug_print(self, msg): @@ -334,7 +333,7 @@ def get_sub_commands(self): # -- External world manipulation ----------------------------------- def warn(self, msg): - log.warn("warning: %s: %s\n", self.get_command_name(), msg) + log.warning("warning: %s: %s\n", self.get_command_name(), msg) def execute(self, func, args, msg=None, level=1): util.execute(func, args, msg, dry_run=self.dry_run) diff --git a/setuptools/_distutils/command/bdist.py b/setuptools/_distutils/command/bdist.py index de37dae0ff..bf0baab0d2 100644 --- a/setuptools/_distutils/command/bdist.py +++ b/setuptools/_distutils/command/bdist.py @@ -6,14 +6,14 @@ import os import warnings -from distutils.core import Command -from distutils.errors import DistutilsPlatformError, DistutilsOptionError -from distutils.util import get_platform +from ..core import Command +from ..errors import DistutilsPlatformError, DistutilsOptionError +from ..util import get_platform def show_formats(): """Print list of available formats (arguments to "--format" option).""" - from distutils.fancy_getopt import FancyGetopt + from ..fancy_getopt import FancyGetopt formats = [] for format in bdist.format_commands: diff --git a/setuptools/_distutils/command/bdist_dumb.py b/setuptools/_distutils/command/bdist_dumb.py index 0f52330f67..071da77e18 100644 --- a/setuptools/_distutils/command/bdist_dumb.py +++ b/setuptools/_distutils/command/bdist_dumb.py @@ -5,12 +5,12 @@ $exec_prefix).""" import os -from distutils.core import Command -from distutils.util import get_platform -from distutils.dir_util import remove_tree, ensure_relative -from distutils.errors import DistutilsPlatformError -from distutils.sysconfig import get_python_version -from distutils import log +from ..core import Command +from ..util import get_platform +from ..dir_util import remove_tree, ensure_relative +from ..errors import DistutilsPlatformError +from ..sysconfig import get_python_version +from distutils._log import log class bdist_dumb(Command): diff --git a/setuptools/_distutils/command/bdist_rpm.py b/setuptools/_distutils/command/bdist_rpm.py index 6a50ef34ea..340527b08a 100644 --- a/setuptools/_distutils/command/bdist_rpm.py +++ b/setuptools/_distutils/command/bdist_rpm.py @@ -7,17 +7,17 @@ import sys import os -from distutils.core import Command -from distutils.debug import DEBUG -from distutils.file_util import write_file -from distutils.errors import ( +from ..core import Command +from ..debug import DEBUG +from ..file_util import write_file +from ..errors import ( DistutilsOptionError, DistutilsPlatformError, DistutilsFileError, DistutilsExecError, ) -from distutils.sysconfig import get_python_version -from distutils import log +from ..sysconfig import get_python_version +from distutils._log import log class bdist_rpm(Command): diff --git a/setuptools/_distutils/command/build.py b/setuptools/_distutils/command/build.py index 6d453419d0..c3ab410f29 100644 --- a/setuptools/_distutils/command/build.py +++ b/setuptools/_distutils/command/build.py @@ -4,13 +4,13 @@ import sys import os -from distutils.core import Command -from distutils.errors import DistutilsOptionError -from distutils.util import get_platform +from ..core import Command +from ..errors import DistutilsOptionError +from ..util import get_platform def show_compilers(): - from distutils.ccompiler import show_compilers + from ..ccompiler import show_compilers show_compilers() diff --git a/setuptools/_distutils/command/build_clib.py b/setuptools/_distutils/command/build_clib.py index 50bb9bbabb..f90c566432 100644 --- a/setuptools/_distutils/command/build_clib.py +++ b/setuptools/_distutils/command/build_clib.py @@ -15,14 +15,14 @@ # cut 'n paste. Sigh. import os -from distutils.core import Command -from distutils.errors import DistutilsSetupError -from distutils.sysconfig import customize_compiler -from distutils import log +from ..core import Command +from ..errors import DistutilsSetupError +from ..sysconfig import customize_compiler +from distutils._log import log def show_compilers(): - from distutils.ccompiler import show_compilers + from ..ccompiler import show_compilers show_compilers() @@ -92,7 +92,7 @@ def run(self): return # Yech -- this is cut 'n pasted from build_ext.py! - from distutils.ccompiler import new_compiler + from ..ccompiler import new_compiler self.compiler = new_compiler( compiler=self.compiler, dry_run=self.dry_run, force=self.force diff --git a/setuptools/_distutils/command/build_ext.py b/setuptools/_distutils/command/build_ext.py index 3c6cee7e36..f4c0eccd4f 100644 --- a/setuptools/_distutils/command/build_ext.py +++ b/setuptools/_distutils/command/build_ext.py @@ -8,8 +8,8 @@ import os import re import sys -from distutils.core import Command -from distutils.errors import ( +from ..core import Command +from ..errors import ( DistutilsOptionError, DistutilsSetupError, CCompilerError, @@ -17,12 +17,12 @@ CompileError, DistutilsPlatformError, ) -from distutils.sysconfig import customize_compiler, get_python_version -from distutils.sysconfig import get_config_h_filename -from distutils.dep_util import newer_group -from distutils.extension import Extension -from distutils.util import get_platform -from distutils import log +from ..sysconfig import customize_compiler, get_python_version +from ..sysconfig import get_config_h_filename +from ..dep_util import newer_group +from ..extension import Extension +from ..util import get_platform +from distutils._log import log from . import py37compat from site import USER_BASE @@ -33,7 +33,7 @@ def show_compilers(): - from distutils.ccompiler import show_compilers + from ..ccompiler import show_compilers show_compilers() @@ -280,7 +280,7 @@ def finalize_options(self): # noqa: C901 raise DistutilsOptionError("parallel should be an integer") def run(self): # noqa: C901 - from distutils.ccompiler import new_compiler + from ..ccompiler import new_compiler # 'self.extensions', as supplied by setup.py, is a list of # Extension instances. See the documentation for Extension (in @@ -373,7 +373,7 @@ def check_extensions_list(self, extensions): # noqa: C901 ext_name, build_info = ext - log.warn( + log.warning( "old-style (ext_name, build_info) tuple found in " "ext_modules for extension '%s' " "-- please convert to Extension instance", @@ -413,7 +413,9 @@ def check_extensions_list(self, extensions): # noqa: C901 # Medium-easy stuff: same syntax/semantics, different names. ext.runtime_library_dirs = build_info.get('rpath') if 'def_file' in build_info: - log.warn("'def_file' element of build info dict " "no longer supported") + log.warning( + "'def_file' element of build info dict " "no longer supported" + ) # Non-trivial stuff: 'macros' split into 'define_macros' # and 'undef_macros'. @@ -597,7 +599,7 @@ def swig_sources(self, sources, extension): # the temp dir. if self.swig_cpp: - log.warn("--swig-cpp is deprecated - use --swig-opts=-c++") + log.warning("--swig-cpp is deprecated - use --swig-opts=-c++") if ( self.swig_cpp @@ -704,7 +706,7 @@ def get_ext_filename(self, ext_name): of the file from which it will be loaded (eg. "foo/bar.so", or "foo\bar.pyd"). """ - from distutils.sysconfig import get_config_var + from ..sysconfig import get_config_var ext_path = ext_name.split('.') ext_suffix = get_config_var('EXT_SUFFIX') @@ -742,7 +744,7 @@ def get_libraries(self, ext): # noqa: C901 # to need it mentioned explicitly, though, so that's what we do. # Append '_d' to the python import library on debug builds. if sys.platform == "win32": - from distutils._msvccompiler import MSVCCompiler + from .._msvccompiler import MSVCCompiler if not isinstance(self.compiler, MSVCCompiler): template = "python%d%d" @@ -764,7 +766,7 @@ def get_libraries(self, ext): # noqa: C901 # On Cygwin (and if required, other POSIX-like platforms based on # Windows like MinGW) it is simply necessary that all symbols in # shared libraries are resolved at link time. - from distutils.sysconfig import get_config_var + from ..sysconfig import get_config_var link_libpython = False if get_config_var('Py_ENABLE_SHARED'): diff --git a/setuptools/_distutils/command/build_py.py b/setuptools/_distutils/command/build_py.py index 47c6158e0f..9f78324452 100644 --- a/setuptools/_distutils/command/build_py.py +++ b/setuptools/_distutils/command/build_py.py @@ -7,10 +7,10 @@ import sys import glob -from distutils.core import Command -from distutils.errors import DistutilsOptionError, DistutilsFileError -from distutils.util import convert_path -from distutils import log +from ..core import Command +from ..errors import DistutilsOptionError, DistutilsFileError +from ..util import convert_path +from distutils._log import log class build_py(Command): @@ -212,7 +212,7 @@ def check_package(self, package, package_dir): def check_module(self, module, module_file): if not os.path.isfile(module_file): - log.warn("file %s (for module %s) not found", module_file, module) + log.warning("file %s (for module %s) not found", module_file, module) return False else: return True @@ -384,7 +384,7 @@ def byte_compile(self, files): self.warn('byte-compiling is disabled, skipping.') return - from distutils.util import byte_compile + from ..util import byte_compile prefix = self.build_lib if prefix[-1] != os.sep: diff --git a/setuptools/_distutils/command/build_scripts.py b/setuptools/_distutils/command/build_scripts.py index 2cc5d1e09c..87174f6bb1 100644 --- a/setuptools/_distutils/command/build_scripts.py +++ b/setuptools/_distutils/command/build_scripts.py @@ -6,10 +6,10 @@ import re from stat import ST_MODE from distutils import sysconfig -from distutils.core import Command -from distutils.dep_util import newer -from distutils.util import convert_path -from distutils import log +from ..core import Command +from ..dep_util import newer +from ..util import convert_path +from distutils._log import log import tokenize shebang_pattern = re.compile('^#!.*python[0-9.]*([ \t].*)?$') diff --git a/setuptools/_distutils/command/check.py b/setuptools/_distutils/command/check.py index 539481c946..575e49fb4b 100644 --- a/setuptools/_distutils/command/check.py +++ b/setuptools/_distutils/command/check.py @@ -4,8 +4,8 @@ """ import contextlib -from distutils.core import Command -from distutils.errors import DistutilsSetupError +from ..core import Command +from ..errors import DistutilsSetupError with contextlib.suppress(ImportError): import docutils.utils diff --git a/setuptools/_distutils/command/clean.py b/setuptools/_distutils/command/clean.py index b731b60609..d6eb3ebad6 100644 --- a/setuptools/_distutils/command/clean.py +++ b/setuptools/_distutils/command/clean.py @@ -5,9 +5,9 @@ # contributed by Bastian Kleineidam , added 2000-03-18 import os -from distutils.core import Command -from distutils.dir_util import remove_tree -from distutils import log +from ..core import Command +from ..dir_util import remove_tree +from distutils._log import log class clean(Command): @@ -64,7 +64,7 @@ def run(self): if os.path.exists(directory): remove_tree(directory, dry_run=self.dry_run) else: - log.warn("'%s' does not exist -- can't clean it", directory) + log.warning("'%s' does not exist -- can't clean it", directory) # just for the heck of it, try to remove the base build directory: # we might have emptied it right now, but if not we don't care diff --git a/setuptools/_distutils/command/config.py b/setuptools/_distutils/command/config.py index 4492c89660..8bf0e4893b 100644 --- a/setuptools/_distutils/command/config.py +++ b/setuptools/_distutils/command/config.py @@ -12,10 +12,10 @@ import os import re -from distutils.core import Command -from distutils.errors import DistutilsExecError -from distutils.sysconfig import customize_compiler -from distutils import log +from ..core import Command +from ..errors import DistutilsExecError +from ..sysconfig import customize_compiler +from distutils._log import log LANG_EXT = {"c": ".c", "c++": ".cxx"} @@ -87,7 +87,7 @@ def _check_compiler(self): """ # We do this late, and only on-demand, because this is an expensive # import. - from distutils.ccompiler import CCompiler, new_compiler + from ..ccompiler import CCompiler, new_compiler if not isinstance(self.compiler, CCompiler): self.compiler = new_compiler( @@ -174,7 +174,7 @@ def try_cpp(self, body=None, headers=None, include_dirs=None, lang="c"): preprocessor succeeded, false if there were any errors. ('body' probably isn't of much use, but what the heck.) """ - from distutils.ccompiler import CompileError + from ..ccompiler import CompileError self._check_compiler() ok = True @@ -217,7 +217,7 @@ def try_compile(self, body, headers=None, include_dirs=None, lang="c"): """Try to compile a source file built from 'body' and 'headers'. Return true on success, false otherwise. """ - from distutils.ccompiler import CompileError + from ..ccompiler import CompileError self._check_compiler() try: @@ -243,7 +243,7 @@ def try_link( 'headers', to executable form. Return true on success, false otherwise. """ - from distutils.ccompiler import CompileError, LinkError + from ..ccompiler import CompileError, LinkError self._check_compiler() try: @@ -269,7 +269,7 @@ def try_run( built from 'body' and 'headers'. Return true on success, false otherwise. """ - from distutils.ccompiler import CompileError, LinkError + from ..ccompiler import CompileError, LinkError self._check_compiler() try: diff --git a/setuptools/_distutils/command/install.py b/setuptools/_distutils/command/install.py index a38cddcda5..08d2f8812f 100644 --- a/setuptools/_distutils/command/install.py +++ b/setuptools/_distutils/command/install.py @@ -8,14 +8,14 @@ import sysconfig import itertools -from distutils import log -from distutils.core import Command -from distutils.debug import DEBUG -from distutils.sysconfig import get_config_vars -from distutils.file_util import write_file -from distutils.util import convert_path, subst_vars, change_root -from distutils.util import get_platform -from distutils.errors import DistutilsOptionError, DistutilsPlatformError +from distutils._log import log +from ..core import Command +from ..debug import DEBUG +from ..sysconfig import get_config_vars +from ..file_util import write_file +from ..util import convert_path, subst_vars, change_root +from ..util import get_platform +from ..errors import DistutilsOptionError, DistutilsPlatformError from . import _framework_compat as fw from .. import _collections @@ -515,7 +515,7 @@ def dump_dirs(self, msg): """Dumps the list of user options.""" if not DEBUG: return - from distutils.fancy_getopt import longopt_xlate + from ..fancy_getopt import longopt_xlate log.debug(msg + ":") for opt in self.user_options: @@ -644,7 +644,7 @@ def handle_extra_path(self): self.extra_path = self.distribution.extra_path if self.extra_path is not None: - log.warn( + log.warning( "Distribution option extra_path is deprecated. " "See issue27919 for details." ) diff --git a/setuptools/_distutils/command/install_data.py b/setuptools/_distutils/command/install_data.py index 23d91aded2..d92ed87a64 100644 --- a/setuptools/_distutils/command/install_data.py +++ b/setuptools/_distutils/command/install_data.py @@ -6,8 +6,8 @@ # contributed by Bastian Kleineidam import os -from distutils.core import Command -from distutils.util import change_root, convert_path +from ..core import Command +from ..util import change_root, convert_path class install_data(Command): diff --git a/setuptools/_distutils/command/install_egg_info.py b/setuptools/_distutils/command/install_egg_info.py index d5e68a6e47..f3e8f3447d 100644 --- a/setuptools/_distutils/command/install_egg_info.py +++ b/setuptools/_distutils/command/install_egg_info.py @@ -9,8 +9,9 @@ import sys import re -from distutils.cmd import Command -from distutils import log, dir_util +from ..cmd import Command +from .. import dir_util +from .._log import log class install_egg_info(Command): diff --git a/setuptools/_distutils/command/install_headers.py b/setuptools/_distutils/command/install_headers.py index 87046ab391..1cdee823dc 100644 --- a/setuptools/_distutils/command/install_headers.py +++ b/setuptools/_distutils/command/install_headers.py @@ -3,7 +3,7 @@ Implements the Distutils 'install_headers' command, to install C/C++ header files to the Python include directory.""" -from distutils.core import Command +from ..core import Command # XXX force is never used diff --git a/setuptools/_distutils/command/install_lib.py b/setuptools/_distutils/command/install_lib.py index ad3089c8b1..840d3403c4 100644 --- a/setuptools/_distutils/command/install_lib.py +++ b/setuptools/_distutils/command/install_lib.py @@ -7,8 +7,8 @@ import importlib.util import sys -from distutils.core import Command -from distutils.errors import DistutilsOptionError +from ..core import Command +from ..errors import DistutilsOptionError # Extension for Python source files. @@ -126,7 +126,7 @@ def byte_compile(self, files): self.warn('byte-compiling is disabled, skipping.') return - from distutils.util import byte_compile + from ..util import byte_compile # Get the "--root" directory supplied to the "install" command, # and use it as a prefix to strip off the purported filename diff --git a/setuptools/_distutils/command/install_scripts.py b/setuptools/_distutils/command/install_scripts.py index f09bd64420..ec6ec5acaa 100644 --- a/setuptools/_distutils/command/install_scripts.py +++ b/setuptools/_distutils/command/install_scripts.py @@ -6,8 +6,8 @@ # contributed by Bastian Kleineidam import os -from distutils.core import Command -from distutils import log +from ..core import Command +from distutils._log import log from stat import ST_MODE diff --git a/setuptools/_distutils/command/register.py b/setuptools/_distutils/command/register.py index c1402650d7..55c1045ec6 100644 --- a/setuptools/_distutils/command/register.py +++ b/setuptools/_distutils/command/register.py @@ -7,12 +7,13 @@ import getpass import io +import logging import urllib.parse import urllib.request from warnings import warn -from distutils.core import PyPIRCCommand -from distutils import log +from ..core import PyPIRCCommand +from distutils._log import log class register(PyPIRCCommand): @@ -153,7 +154,7 @@ def send_metadata(self): # noqa: C901 3. have the server generate a new password for you (and email it to you), or 4. quit Your selection [default 1]: ''', - log.INFO, + logging.INFO, ) choice = input() if not choice: @@ -174,7 +175,7 @@ def send_metadata(self): # noqa: C901 auth.add_password(self.realm, host, username, password) # send the info to the server and report the result code, result = self.post_to_server(self.build_post_data('submit'), auth) - self.announce('Server response ({}): {}'.format(code, result), log.INFO) + self.announce('Server response ({}): {}'.format(code, result), logging.INFO) # possibly save the login if code == 200: @@ -188,11 +189,11 @@ def send_metadata(self): # noqa: C901 'I can store your PyPI login so future ' 'submissions will be faster.' ), - log.INFO, + logging.INFO, ) self.announce( '(the login will be stored in %s)' % self._get_rc_file(), - log.INFO, + logging.INFO, ) choice = 'X' while choice.lower() not in 'yn': @@ -265,7 +266,8 @@ def post_to_server(self, data, auth=None): # noqa: C901 '''Post a query to the server, and return a string response.''' if 'name' in data: self.announce( - 'Registering {} to {}'.format(data['name'], self.repository), log.INFO + 'Registering {} to {}'.format(data['name'], self.repository), + logging.INFO, ) # Build up the MIME payload for the urllib2 POST data boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' @@ -315,5 +317,5 @@ def post_to_server(self, data, auth=None): # noqa: C901 result = 200, 'OK' if self.show_response: msg = '\n'.join(('-' * 75, data, '-' * 75)) - self.announce(msg, log.INFO) + self.announce(msg, logging.INFO) return result diff --git a/setuptools/_distutils/command/sdist.py b/setuptools/_distutils/command/sdist.py index d6e9489d1b..5cfd4c1456 100644 --- a/setuptools/_distutils/command/sdist.py +++ b/setuptools/_distutils/command/sdist.py @@ -7,23 +7,23 @@ from glob import glob from warnings import warn -from distutils.core import Command +from ..core import Command from distutils import dir_util from distutils import file_util from distutils import archive_util -from distutils.text_file import TextFile -from distutils.filelist import FileList -from distutils import log -from distutils.util import convert_path -from distutils.errors import DistutilsOptionError, DistutilsTemplateError +from ..text_file import TextFile +from ..filelist import FileList +from distutils._log import log +from ..util import convert_path +from ..errors import DistutilsOptionError, DistutilsTemplateError def show_formats(): """Print all possible values for the 'formats' option (used by the "--help-formats" command-line option). """ - from distutils.fancy_getopt import FancyGetopt - from distutils.archive_util import ARCHIVE_FORMATS + from ..fancy_getopt import FancyGetopt + from ..archive_util import ARCHIVE_FORMATS formats = [] for format in ARCHIVE_FORMATS.keys(): @@ -481,12 +481,12 @@ def make_release_tree(self, base_dir, files): msg = "copying files to %s..." % base_dir if not files: - log.warn("no files to distribute -- empty manifest?") + log.warning("no files to distribute -- empty manifest?") else: log.info(msg) for file in files: if not os.path.isfile(file): - log.warn("'%s' not a regular file -- skipping", file) + log.warning("'%s' not a regular file -- skipping", file) else: dest = os.path.join(base_dir, file) self.copy_file(file, dest, link=link) diff --git a/setuptools/_distutils/command/upload.py b/setuptools/_distutils/command/upload.py index 6af5394339..16e15d8b60 100644 --- a/setuptools/_distutils/command/upload.py +++ b/setuptools/_distutils/command/upload.py @@ -8,13 +8,13 @@ import os import io import hashlib +import logging from base64 import standard_b64encode from urllib.request import urlopen, Request, HTTPError from urllib.parse import urlparse -from distutils.errors import DistutilsError, DistutilsOptionError -from distutils.core import PyPIRCCommand -from distutils.spawn import spawn -from distutils import log +from ..errors import DistutilsError, DistutilsOptionError +from ..core import PyPIRCCommand +from ..spawn import spawn # PyPI Warehouse supports MD5, SHA256, and Blake2 (blake2-256) @@ -171,7 +171,7 @@ def upload_file(self, command, pyversion, filename): # noqa: C901 body = body.getvalue() msg = "Submitting {} to {}".format(filename, self.repository) - self.announce(msg, log.INFO) + self.announce(msg, logging.INFO) # build the Request headers = { @@ -190,16 +190,18 @@ def upload_file(self, command, pyversion, filename): # noqa: C901 status = e.code reason = e.msg except OSError as e: - self.announce(str(e), log.ERROR) + self.announce(str(e), logging.ERROR) raise if status == 200: - self.announce('Server response ({}): {}'.format(status, reason), log.INFO) + self.announce( + 'Server response ({}): {}'.format(status, reason), logging.INFO + ) if self.show_response: text = self._read_pypi_response(result) msg = '\n'.join(('-' * 75, text, '-' * 75)) - self.announce(msg, log.INFO) + self.announce(msg, logging.INFO) else: msg = 'Upload failed ({}): {}'.format(status, reason) - self.announce(msg, log.ERROR) + self.announce(msg, logging.ERROR) raise DistutilsError(msg) diff --git a/setuptools/_distutils/config.py b/setuptools/_distutils/config.py index 6e0c3a71f1..9a4044adaf 100644 --- a/setuptools/_distutils/config.py +++ b/setuptools/_distutils/config.py @@ -6,7 +6,7 @@ import os from configparser import RawConfigParser -from distutils.cmd import Command +from .cmd import Command DEFAULT_PYPIRC = """\ [distutils] diff --git a/setuptools/_distutils/core.py b/setuptools/_distutils/core.py index de13978f02..34cafbceec 100644 --- a/setuptools/_distutils/core.py +++ b/setuptools/_distutils/core.py @@ -10,8 +10,8 @@ import sys import tokenize -from distutils.debug import DEBUG -from distutils.errors import ( +from .debug import DEBUG +from .errors import ( DistutilsSetupError, DistutilsError, CCompilerError, @@ -19,10 +19,10 @@ ) # Mainly import these so setup scripts can "from distutils.core import" them. -from distutils.dist import Distribution -from distutils.cmd import Command -from distutils.config import PyPIRCCommand -from distutils.extension import Extension +from .dist import Distribution +from .cmd import Command +from .config import PyPIRCCommand +from .extension import Extension __all__ = ['Distribution', 'Command', 'PyPIRCCommand', 'Extension', 'setup'] diff --git a/setuptools/_distutils/cygwinccompiler.py b/setuptools/_distutils/cygwinccompiler.py index 2c4da5b57e..f15b8eee26 100644 --- a/setuptools/_distutils/cygwinccompiler.py +++ b/setuptools/_distutils/cygwinccompiler.py @@ -7,56 +7,61 @@ """ import os +import re import sys import copy import shlex import warnings from subprocess import check_output -from distutils.unixccompiler import UnixCCompiler -from distutils.file_util import write_file -from distutils.errors import ( +from .unixccompiler import UnixCCompiler +from .file_util import write_file +from .errors import ( DistutilsExecError, DistutilsPlatformError, CCompilerError, CompileError, ) -from distutils.version import LooseVersion, suppress_known_deprecation +from .version import LooseVersion, suppress_known_deprecation +from ._collections import RangeMap + + +_msvcr_lookup = RangeMap.left( + { + # MSVC 7.0 + 1300: ['msvcr70'], + # MSVC 7.1 + 1310: ['msvcr71'], + # VS2005 / MSVC 8.0 + 1400: ['msvcr80'], + # VS2008 / MSVC 9.0 + 1500: ['msvcr90'], + # VS2010 / MSVC 10.0 + 1600: ['msvcr100'], + # VS2012 / MSVC 11.0 + 1700: ['msvcr110'], + # VS2013 / MSVC 12.0 + 1800: ['msvcr120'], + # VS2015 / MSVC 14.0 + 1900: ['ucrt', 'vcruntime140'], + 2000: RangeMap.undefined_value, + }, +) def get_msvcr(): """Include the appropriate MSVC runtime library if Python was built with MSVC 7.0 or later. """ - msc_pos = sys.version.find('MSC v.') - if msc_pos != -1: - msc_ver = sys.version[msc_pos + 6 : msc_pos + 10] - if msc_ver == '1300': - # MSVC 7.0 - return ['msvcr70'] - elif msc_ver == '1310': - # MSVC 7.1 - return ['msvcr71'] - elif msc_ver == '1400': - # VS2005 / MSVC 8.0 - return ['msvcr80'] - elif msc_ver == '1500': - # VS2008 / MSVC 9.0 - return ['msvcr90'] - elif msc_ver == '1600': - # VS2010 / MSVC 10.0 - return ['msvcr100'] - elif msc_ver == '1700': - # VS2012 / MSVC 11.0 - return ['msvcr110'] - elif msc_ver == '1800': - # VS2013 / MSVC 12.0 - return ['msvcr120'] - elif 1900 <= int(msc_ver) < 2000: - # VS2015 / MSVC 14.0 - return ['ucrt', 'vcruntime140'] - else: - raise ValueError("Unknown MS Compiler version %s " % msc_ver) + match = re.search(r'MSC v\.(\d{4})', sys.version) + try: + msc_ver = int(match.group(1)) + except AttributeError: + return + try: + return _msvcr_lookup[msc_ver] + except KeyError: + raise ValueError("Unknown MS Compiler version %s " % msc_ver) _runtime_library_dirs_msg = ( @@ -280,17 +285,6 @@ def __init__(self, verbose=0, dry_run=0, force=0): linker_so='{} {}'.format(self.linker_dll, shared_option), ) - # Maybe we should also append -mthreads, but then the finished - # dlls need another dll (mingwm10.dll see Mingw32 docs) - # (-mthreads: Support thread-safe exception handling on `Mingw32') - - # no additional libraries needed - self.dll_libraries = [] - - # Include the appropriate MSVC runtime library if Python was built - # with MSVC 7.0 or later. - self.dll_libraries = get_msvcr() - def runtime_library_dir_option(self, dir): raise DistutilsPlatformError(_runtime_library_dirs_msg) diff --git a/setuptools/_distutils/dep_util.py b/setuptools/_distutils/dep_util.py index db1fa01996..48da8641c6 100644 --- a/setuptools/_distutils/dep_util.py +++ b/setuptools/_distutils/dep_util.py @@ -5,7 +5,7 @@ timestamp dependency analysis.""" import os -from distutils.errors import DistutilsFileError +from .errors import DistutilsFileError def newer(source, target): diff --git a/setuptools/_distutils/dir_util.py b/setuptools/_distutils/dir_util.py index 6f0bb8ad76..80f7764902 100644 --- a/setuptools/_distutils/dir_util.py +++ b/setuptools/_distutils/dir_util.py @@ -4,8 +4,8 @@ import os import errno -from distutils.errors import DistutilsInternalError, DistutilsFileError -from distutils import log +from .errors import DistutilsInternalError, DistutilsFileError +from ._log import log # cache for by mkpath() -- in addition to cheapening redundant calls, # eliminates redundant "creating /foo/bar/baz" messages in dry-run mode @@ -229,7 +229,7 @@ def remove_tree(directory, verbose=1, dry_run=0): if abspath in _path_created: del _path_created[abspath] except OSError as exc: - log.warn("error removing %s: %s", directory, exc) + log.warning("error removing %s: %s", directory, exc) def ensure_relative(path): diff --git a/setuptools/_distutils/dist.py b/setuptools/_distutils/dist.py index 917cd94a0c..d7458a052f 100644 --- a/setuptools/_distutils/dist.py +++ b/setuptools/_distutils/dist.py @@ -9,6 +9,7 @@ import re import pathlib import contextlib +import logging from email import message_from_file try: @@ -16,16 +17,16 @@ except ImportError: warnings = None -from distutils.errors import ( +from .errors import ( DistutilsOptionError, DistutilsModuleError, DistutilsArgError, DistutilsClassError, ) -from distutils.fancy_getopt import FancyGetopt, translate_longopt -from distutils.util import check_environ, strtobool, rfc822_escape -from distutils import log -from distutils.debug import DEBUG +from .fancy_getopt import FancyGetopt, translate_longopt +from .util import check_environ, strtobool, rfc822_escape +from ._log import log +from .debug import DEBUG # Regex to define acceptable Distutils command names. This is not *quite* # the same as a Python NAME -- I don't allow leading underscores. The fact @@ -44,7 +45,7 @@ def _ensure_list(value, fieldname): typename = type(value).__name__ msg = "Warning: '{fieldname}' should be a list, got type '{typename}'" msg = msg.format(**locals()) - log.log(log.WARN, msg) + log.warning(msg) value = list(value) return value @@ -465,7 +466,7 @@ def parse_command_line(self): parser.set_aliases({'licence': 'license'}) args = parser.getopt(args=self.script_args, object=self) option_order = parser.get_option_order() - log.set_verbosity(self.verbose) + logging.getLogger().setLevel(logging.WARN - 10 * self.verbose) # for display options we return immediately if self.handle_display_options(option_order): @@ -956,7 +957,7 @@ def reinitialize_command(self, command, reinit_subcommands=0): # -- Methods that operate on the Distribution ---------------------- - def announce(self, msg, level=log.INFO): + def announce(self, msg, level=logging.INFO): log.log(level, msg) def run_commands(self): diff --git a/setuptools/_distutils/fancy_getopt.py b/setuptools/_distutils/fancy_getopt.py index 830f047e28..6abb884d36 100644 --- a/setuptools/_distutils/fancy_getopt.py +++ b/setuptools/_distutils/fancy_getopt.py @@ -12,7 +12,7 @@ import string import re import getopt -from distutils.errors import DistutilsGetoptError, DistutilsArgError +from .errors import DistutilsGetoptError, DistutilsArgError # Much like command_re in distutils.core, this is close to but not quite # the same as a Python NAME -- except, in the spirit of most GNU diff --git a/setuptools/_distutils/file_util.py b/setuptools/_distutils/file_util.py index 1f1e444b1c..1b7cd53bd9 100644 --- a/setuptools/_distutils/file_util.py +++ b/setuptools/_distutils/file_util.py @@ -4,8 +4,8 @@ """ import os -from distutils.errors import DistutilsFileError -from distutils import log +from .errors import DistutilsFileError +from ._log import log # for generating verbose output in 'copy_file()' _copy_action = {None: 'copying', 'hard': 'hard linking', 'sym': 'symbolically linking'} diff --git a/setuptools/_distutils/filelist.py b/setuptools/_distutils/filelist.py index 987931a988..6dadf923d7 100644 --- a/setuptools/_distutils/filelist.py +++ b/setuptools/_distutils/filelist.py @@ -9,9 +9,9 @@ import fnmatch import functools -from distutils.util import convert_path -from distutils.errors import DistutilsTemplateError, DistutilsInternalError -from distutils import log +from .util import convert_path +from .errors import DistutilsTemplateError, DistutilsInternalError +from ._log import log class FileList: @@ -120,13 +120,13 @@ def process_template_line(self, line): # noqa: C901 self.debug_print("include " + ' '.join(patterns)) for pattern in patterns: if not self.include_pattern(pattern, anchor=1): - log.warn("warning: no files found matching '%s'", pattern) + log.warning("warning: no files found matching '%s'", pattern) elif action == 'exclude': self.debug_print("exclude " + ' '.join(patterns)) for pattern in patterns: if not self.exclude_pattern(pattern, anchor=1): - log.warn( + log.warning( ( "warning: no previously-included files " "found matching '%s'" @@ -138,7 +138,7 @@ def process_template_line(self, line): # noqa: C901 self.debug_print("global-include " + ' '.join(patterns)) for pattern in patterns: if not self.include_pattern(pattern, anchor=0): - log.warn( + log.warning( ( "warning: no files found matching '%s' " "anywhere in distribution" @@ -150,7 +150,7 @@ def process_template_line(self, line): # noqa: C901 self.debug_print("global-exclude " + ' '.join(patterns)) for pattern in patterns: if not self.exclude_pattern(pattern, anchor=0): - log.warn( + log.warning( ( "warning: no previously-included files matching " "'%s' found anywhere in distribution" @@ -165,13 +165,13 @@ def process_template_line(self, line): # noqa: C901 msg = ( "warning: no files found matching '%s' " "under directory '%s'" ) - log.warn(msg, pattern, dir) + log.warning(msg, pattern, dir) elif action == 'recursive-exclude': self.debug_print("recursive-exclude {} {}".format(dir, ' '.join(patterns))) for pattern in patterns: if not self.exclude_pattern(pattern, prefix=dir): - log.warn( + log.warning( ( "warning: no previously-included files matching " "'%s' found under directory '%s'" @@ -183,12 +183,12 @@ def process_template_line(self, line): # noqa: C901 elif action == 'graft': self.debug_print("graft " + dir_pattern) if not self.include_pattern(None, prefix=dir_pattern): - log.warn("warning: no directories found matching '%s'", dir_pattern) + log.warning("warning: no directories found matching '%s'", dir_pattern) elif action == 'prune': self.debug_print("prune " + dir_pattern) if not self.exclude_pattern(None, prefix=dir_pattern): - log.warn( + log.warning( ("no previously-included directories found " "matching '%s'"), dir_pattern, ) diff --git a/setuptools/_distutils/log.py b/setuptools/_distutils/log.py index be25f6cabd..bb789c300d 100644 --- a/setuptools/_distutils/log.py +++ b/setuptools/_distutils/log.py @@ -1,80 +1,38 @@ -"""A simple log mechanism styled after PEP 282.""" +""" +A simple log mechanism styled after PEP 282. -# The class here is styled after PEP 282 so that it could later be -# replaced with a standard Python logging implementation. +Retained for compatibility and should not be used. +""" -import sys +import logging -DEBUG = 1 -INFO = 2 -WARN = 3 -ERROR = 4 -FATAL = 5 +from ._log import log as _global_log -class Log: - def __init__(self, threshold=WARN): - self.threshold = threshold +DEBUG = logging.DEBUG +INFO = logging.INFO +WARN = logging.WARN +ERROR = logging.ERROR +FATAL = logging.FATAL - def _log(self, level, msg, args): - if level not in (DEBUG, INFO, WARN, ERROR, FATAL): - raise ValueError('%s wrong log level' % str(level)) - - if level >= self.threshold: - if args: - msg = msg % args - if level in (WARN, ERROR, FATAL): - stream = sys.stderr - else: - stream = sys.stdout - try: - stream.write('%s\n' % msg) - except UnicodeEncodeError: - # emulate backslashreplace error handler - encoding = stream.encoding - msg = msg.encode(encoding, "backslashreplace").decode(encoding) - stream.write('%s\n' % msg) - stream.flush() - - def log(self, level, msg, *args): - self._log(level, msg, args) - - def debug(self, msg, *args): - self._log(DEBUG, msg, args) - - def info(self, msg, *args): - self._log(INFO, msg, args) - - def warn(self, msg, *args): - self._log(WARN, msg, args) - - def error(self, msg, *args): - self._log(ERROR, msg, args) - - def fatal(self, msg, *args): - self._log(FATAL, msg, args) - - -_global_log = Log() log = _global_log.log debug = _global_log.debug info = _global_log.info -warn = _global_log.warn +warn = _global_log.warning error = _global_log.error fatal = _global_log.fatal def set_threshold(level): - # return the old threshold for use from tests - old = _global_log.threshold - _global_log.threshold = level - return old + orig = _global_log.level + _global_log.setLevel(level) + return orig def set_verbosity(v): if v <= 0: - set_threshold(WARN) + set_threshold(logging.WARN) elif v == 1: - set_threshold(INFO) + set_threshold(logging.INFO) elif v >= 2: - set_threshold(DEBUG) + set_threshold(logging.DEBUG) diff --git a/setuptools/_distutils/msvc9compiler.py b/setuptools/_distutils/msvc9compiler.py index 2202183108..a4714a559d 100644 --- a/setuptools/_distutils/msvc9compiler.py +++ b/setuptools/_distutils/msvc9compiler.py @@ -18,16 +18,16 @@ import re import warnings -from distutils.errors import ( +from .errors import ( DistutilsExecError, DistutilsPlatformError, CompileError, LibError, LinkError, ) -from distutils.ccompiler import CCompiler, gen_lib_options -from distutils import log -from distutils.util import get_platform +from .ccompiler import CCompiler, gen_lib_options +from ._log import log +from .util import get_platform import winreg diff --git a/setuptools/_distutils/msvccompiler.py b/setuptools/_distutils/msvccompiler.py index 1069e9951a..59ebe99caa 100644 --- a/setuptools/_distutils/msvccompiler.py +++ b/setuptools/_distutils/msvccompiler.py @@ -11,15 +11,15 @@ import sys import os import warnings -from distutils.errors import ( +from .errors import ( DistutilsExecError, DistutilsPlatformError, CompileError, LibError, LinkError, ) -from distutils.ccompiler import CCompiler, gen_lib_options -from distutils import log +from .ccompiler import CCompiler, gen_lib_options +from ._log import log _can_read_reg = False try: diff --git a/setuptools/_distutils/spawn.py b/setuptools/_distutils/spawn.py index b18ba9db7d..afefe525ef 100644 --- a/setuptools/_distutils/spawn.py +++ b/setuptools/_distutils/spawn.py @@ -10,9 +10,9 @@ import os import subprocess -from distutils.errors import DistutilsExecError -from distutils.debug import DEBUG -from distutils import log +from .errors import DistutilsExecError +from .debug import DEBUG +from ._log import log def spawn(cmd, search_path=1, verbose=0, dry_run=0, env=None): # noqa: C901 diff --git a/setuptools/_distutils/sysconfig.py b/setuptools/_distutils/sysconfig.py index 6a979f8c91..0ec69366fd 100644 --- a/setuptools/_distutils/sysconfig.py +++ b/setuptools/_distutils/sysconfig.py @@ -537,13 +537,7 @@ def get_config_vars(*args): _config_vars = sysconfig.get_config_vars().copy() py39compat.add_ext_suffix(_config_vars) - if args: - vals = [] - for name in args: - vals.append(_config_vars.get(name)) - return vals - else: - return _config_vars + return [_config_vars.get(name) for name in args] if args else _config_vars def get_config_var(name): diff --git a/setuptools/_distutils/tests/support.py b/setuptools/_distutils/tests/support.py index 5203ed19d4..fd4b11bf75 100644 --- a/setuptools/_distutils/tests/support.py +++ b/setuptools/_distutils/tests/support.py @@ -5,29 +5,14 @@ import tempfile import sysconfig import itertools +import pathlib import pytest +from more_itertools import always_iterable -from distutils.log import DEBUG, INFO, WARN, ERROR, FATAL from distutils.core import Distribution -@pytest.mark.usefixtures('distutils_logging_silencer') -class LoggingSilencer: - def _log(self, level, msg, args): - if level not in (DEBUG, INFO, WARN, ERROR, FATAL): - raise ValueError('%s wrong log level' % str(level)) - if not isinstance(msg, str): - raise TypeError("msg should be str, not '%.200s'" % (type(msg).__name__)) - self.logs.append((level, msg, args)) - - def get_logs(self, *levels): - return [msg % args for level, msg, args in self.logs if level in levels] - - def clear_logs(self): - self.logs = [] - - @pytest.mark.usefixtures('distutils_managed_tempdir') class TempdirManager: """ @@ -46,16 +31,9 @@ def mkdtemp(self): def write_file(self, path, content='xxx'): """Writes a file in the given path. - path can be a string or a sequence. """ - if isinstance(path, (list, tuple)): - path = os.path.join(*path) - f = open(path, 'w') - try: - f.write(content) - finally: - f.close() + pathlib.Path(*always_iterable(path)).write_text(content) def create_dist(self, pkg_name='foo', **kw): """Will generate a test environment. diff --git a/setuptools/_distutils/tests/test_archive_util.py b/setuptools/_distutils/tests/test_archive_util.py index d0f5b73481..7778c3ad36 100644 --- a/setuptools/_distutils/tests/test_archive_util.py +++ b/setuptools/_distutils/tests/test_archive_util.py @@ -48,7 +48,7 @@ def same_drive(*paths): return all_equal(pathlib.Path(path).drive for path in paths) -class ArchiveUtilTestCase(support.TempdirManager, support.LoggingSilencer): +class ArchiveUtilTestCase(support.TempdirManager): @pytest.mark.usefixtures('needs_zlib') def test_make_tarball(self, name='archive'): # creating something to tar diff --git a/setuptools/_distutils/tests/test_bdist_dumb.py b/setuptools/_distutils/tests/test_bdist_dumb.py index 8624a4290d..b9bec05137 100644 --- a/setuptools/_distutils/tests/test_bdist_dumb.py +++ b/setuptools/_distutils/tests/test_bdist_dumb.py @@ -26,7 +26,6 @@ @pytest.mark.usefixtures('save_cwd') class TestBuildDumb( support.TempdirManager, - support.LoggingSilencer, ): @pytest.mark.usefixtures('needs_zlib') def test_simple_built(self): diff --git a/setuptools/_distutils/tests/test_bdist_rpm.py b/setuptools/_distutils/tests/test_bdist_rpm.py index 2d14bafc98..4a702fb913 100644 --- a/setuptools/_distutils/tests/test_bdist_rpm.py +++ b/setuptools/_distutils/tests/test_bdist_rpm.py @@ -42,7 +42,6 @@ def sys_executable_encodable(): @pytest.mark.usefixtures('save_cwd') class TestBuildRpm( support.TempdirManager, - support.LoggingSilencer, ): @mac_woes @requires_zlib() diff --git a/setuptools/_distutils/tests/test_build.py b/setuptools/_distutils/tests/test_build.py index 80367607f5..66d8af50ac 100644 --- a/setuptools/_distutils/tests/test_build.py +++ b/setuptools/_distutils/tests/test_build.py @@ -7,7 +7,7 @@ from sysconfig import get_platform -class TestBuild(support.TempdirManager, support.LoggingSilencer): +class TestBuild(support.TempdirManager): def test_finalize_options(self): pkg_dir, dist = self.create_dist() cmd = build(dist) diff --git a/setuptools/_distutils/tests/test_build_clib.py b/setuptools/_distutils/tests/test_build_clib.py index c931c06ec5..709d0b7d66 100644 --- a/setuptools/_distutils/tests/test_build_clib.py +++ b/setuptools/_distutils/tests/test_build_clib.py @@ -10,7 +10,7 @@ from distutils.tests import support -class TestBuildCLib(support.TempdirManager, support.LoggingSilencer): +class TestBuildCLib(support.TempdirManager): def test_check_library_dist(self): pkg_dir, dist = self.create_dist() cmd = build_clib(dist) diff --git a/setuptools/_distutils/tests/test_build_ext.py b/setuptools/_distutils/tests/test_build_ext.py index cf6e98985c..f5058487a5 100644 --- a/setuptools/_distutils/tests/test_build_ext.py +++ b/setuptools/_distutils/tests/test_build_ext.py @@ -18,7 +18,6 @@ from distutils import sysconfig from distutils.tests.support import ( TempdirManager, - LoggingSilencer, copy_xxmodule_c, fixup_build_ext, ) @@ -85,7 +84,7 @@ def extension_redirect(mod, path): @pytest.mark.usefixtures('user_site_dir') -class TestBuildExt(TempdirManager, LoggingSilencer): +class TestBuildExt(TempdirManager): def build_ext(self, *args, **kwargs): return build_ext(*args, **kwargs) diff --git a/setuptools/_distutils/tests/test_build_py.py b/setuptools/_distutils/tests/test_build_py.py index 63543dcaa1..3bef9d79ec 100644 --- a/setuptools/_distutils/tests/test_build_py.py +++ b/setuptools/_distutils/tests/test_build_py.py @@ -2,7 +2,6 @@ import os import sys -import unittest.mock as mock import pytest @@ -14,7 +13,7 @@ @support.combine_markers -class TestBuildPy(support.TempdirManager, support.LoggingSilencer): +class TestBuildPy(support.TempdirManager): def test_package_data(self): sources = self.mkdtemp() f = open(os.path.join(sources, "__init__.py"), "w") @@ -151,7 +150,7 @@ def test_dir_in_package_data(self): except DistutilsFileError: self.fail("failed package_data when data dir includes a dir") - def test_dont_write_bytecode(self): + def test_dont_write_bytecode(self, caplog): # makes sure byte_compile is not used dist = self.create_dist()[1] cmd = build_py(dist) @@ -165,10 +164,9 @@ def test_dont_write_bytecode(self): finally: sys.dont_write_bytecode = old_dont_write_bytecode - assert 'byte-compiling is disabled' in self.logs[0][1] % self.logs[0][2] + assert 'byte-compiling is disabled' in caplog.records[0].message - @mock.patch("distutils.command.build_py.log.warn") - def test_namespace_package_does_not_warn(self, log_warn): + def test_namespace_package_does_not_warn(self, caplog): """ Originally distutils implementation did not account for PEP 420 and included warns for package directories that did not contain @@ -182,13 +180,6 @@ def test_namespace_package_does_not_warn(self, log_warn): os.makedirs("ns/pkg") open("ns/pkg/module.py", "w").close() - # Set up a trap if the undesirable effect is observed: - def _trap(msg, *args): - if "package init file" in msg and "not found" in msg: - raise AssertionError(f"Undesired warning: {msg!r} {args!r}") - - log_warn.side_effect = _trap - # Configure the package: attrs = { "name": "ns.pkg", @@ -206,4 +197,7 @@ def _trap(msg, *args): assert module_path.replace(os.sep, "/") == "ns/pkg/module.py" cmd.run() - # Test should complete successfully with no exception + + assert not any( + "package init file" in msg and "not found" in msg for msg in caplog.messages + ) diff --git a/setuptools/_distutils/tests/test_build_scripts.py b/setuptools/_distutils/tests/test_build_scripts.py index 00d7fc5929..1a5753c772 100644 --- a/setuptools/_distutils/tests/test_build_scripts.py +++ b/setuptools/_distutils/tests/test_build_scripts.py @@ -9,7 +9,7 @@ from distutils.tests import support -class TestBuildScripts(support.TempdirManager, support.LoggingSilencer): +class TestBuildScripts(support.TempdirManager): def test_default_settings(self): cmd = self.get_build_scripts_cmd("/foo/bar", []) assert not cmd.force diff --git a/setuptools/_distutils/tests/test_check.py b/setuptools/_distutils/tests/test_check.py index 3e5f6034bf..546540679a 100644 --- a/setuptools/_distutils/tests/test_check.py +++ b/setuptools/_distutils/tests/test_check.py @@ -18,7 +18,7 @@ @support.combine_markers -class TestCheck(support.LoggingSilencer, support.TempdirManager): +class TestCheck(support.TempdirManager): def _run(self, metadata=None, cwd=None, **options): if metadata is None: metadata = {} diff --git a/setuptools/_distutils/tests/test_clean.py b/setuptools/_distutils/tests/test_clean.py index 4166bb7e9b..157b60a1e9 100644 --- a/setuptools/_distutils/tests/test_clean.py +++ b/setuptools/_distutils/tests/test_clean.py @@ -5,7 +5,7 @@ from distutils.tests import support -class TestClean(support.TempdirManager, support.LoggingSilencer): +class TestClean(support.TempdirManager): def test_simple_run(self): pkg_dir, dist = self.create_dist() cmd = clean(dist) diff --git a/setuptools/_distutils/tests/test_cmd.py b/setuptools/_distutils/tests/test_cmd.py index e4d5bf3c01..3aac448d5e 100644 --- a/setuptools/_distutils/tests/test_cmd.py +++ b/setuptools/_distutils/tests/test_cmd.py @@ -1,6 +1,5 @@ """Tests for distutils.cmd.""" import os -from test.support import captured_stdout from distutils.cmd import Command from distutils.dist import Distribution @@ -100,17 +99,9 @@ def test_ensure_dirname(self, cmd): with pytest.raises(DistutilsOptionError): cmd.ensure_dirname('option2') - def test_debug_print(self, cmd): - with captured_stdout() as stdout: - cmd.debug_print('xxx') - stdout.seek(0) - assert stdout.read() == '' - - debug.DEBUG = True - try: - with captured_stdout() as stdout: - cmd.debug_print('xxx') - stdout.seek(0) - assert stdout.read() == 'xxx\n' - finally: - debug.DEBUG = False + def test_debug_print(self, cmd, capsys, monkeypatch): + cmd.debug_print('xxx') + assert capsys.readouterr().out == '' + monkeypatch.setattr(debug, 'DEBUG', True) + cmd.debug_print('xxx') + assert capsys.readouterr().out == 'xxx\n' diff --git a/setuptools/_distutils/tests/test_config.py b/setuptools/_distutils/tests/test_config.py index 43ba6766ae..1ae615db95 100644 --- a/setuptools/_distutils/tests/test_config.py +++ b/setuptools/_distutils/tests/test_config.py @@ -46,12 +46,8 @@ @support.combine_markers -@pytest.mark.usefixtures('threshold_warn') @pytest.mark.usefixtures('pypirc') -class BasePyPIRCCommandTestCase( - support.TempdirManager, - support.LoggingSilencer, -): +class BasePyPIRCCommandTestCase(support.TempdirManager): pass diff --git a/setuptools/_distutils/tests/test_config_cmd.py b/setuptools/_distutils/tests/test_config_cmd.py index 65c60f64dd..e72a7c5ff8 100644 --- a/setuptools/_distutils/tests/test_config_cmd.py +++ b/setuptools/_distutils/tests/test_config_cmd.py @@ -7,7 +7,7 @@ from distutils.command.config import dump_file, config from distutils.tests import support -from distutils import log +from distutils._log import log @pytest.fixture(autouse=True) @@ -18,7 +18,7 @@ def info_log(request, monkeypatch): @support.combine_markers -class TestConfig(support.LoggingSilencer, support.TempdirManager): +class TestConfig(support.TempdirManager): def _info(self, msg, *args): for line in msg.splitlines(): self._logs.append(line) diff --git a/setuptools/_distutils/tests/test_core.py b/setuptools/_distutils/tests/test_core.py index 5fe7e958f5..2c11ff769e 100644 --- a/setuptools/_distutils/tests/test_core.py +++ b/setuptools/_distutils/tests/test_core.py @@ -4,7 +4,6 @@ import distutils.core import os import sys -from test.support import captured_stdout import pytest @@ -121,20 +120,12 @@ def test_run_commands(self, temp_file): distutils.core.run_commands(dist) assert 'build' in dist.have_run - def test_debug_mode(self): + def test_debug_mode(self, capsys, monkeypatch): # this covers the code called when DEBUG is set sys.argv = ['setup.py', '--name'] - with captured_stdout() as stdout: - distutils.core.setup(name='bar') - stdout.seek(0) - assert stdout.read() == 'bar\n' - - distutils.core.DEBUG = True - try: - with captured_stdout() as stdout: - distutils.core.setup(name='bar') - finally: - distutils.core.DEBUG = False - stdout.seek(0) + distutils.core.setup(name='bar') + capsys.readouterr().out == 'bar\n' + monkeypatch.setattr(distutils.core, 'DEBUG', True) + distutils.core.setup(name='bar') wanted = "options (after parsing config files):\n" - assert stdout.readlines()[0] == wanted + assert capsys.readouterr().out.startswith(wanted) diff --git a/setuptools/_distutils/tests/test_dir_util.py b/setuptools/_distutils/tests/test_dir_util.py index cd7e018f5e..0c6db4afae 100644 --- a/setuptools/_distutils/tests/test_dir_util.py +++ b/setuptools/_distutils/tests/test_dir_util.py @@ -12,7 +12,6 @@ ensure_relative, ) -from distutils import log from distutils.tests import support import pytest @@ -20,36 +19,26 @@ @pytest.fixture(autouse=True) def stuff(request, monkeypatch, distutils_managed_tempdir): self = request.instance - self._logs = [] tmp_dir = self.mkdtemp() self.root_target = os.path.join(tmp_dir, 'deep') self.target = os.path.join(self.root_target, 'here') self.target2 = os.path.join(tmp_dir, 'deep2') - monkeypatch.setattr(log, 'info', self._log) class TestDirUtil(support.TempdirManager): - def _log(self, msg, *args): - if len(args) > 0: - self._logs.append(msg % args) - else: - self._logs.append(msg) - - def test_mkpath_remove_tree_verbosity(self): - + def test_mkpath_remove_tree_verbosity(self, caplog): mkpath(self.target, verbose=0) - wanted = [] - assert self._logs == wanted + assert not caplog.records remove_tree(self.root_target, verbose=0) mkpath(self.target, verbose=1) wanted = ['creating %s' % self.root_target, 'creating %s' % self.target] - assert self._logs == wanted - self._logs = [] + assert caplog.messages == wanted + caplog.clear() remove_tree(self.root_target, verbose=1) wanted = ["removing '%s' (and everything under it)" % self.root_target] - assert self._logs == wanted + assert caplog.messages == wanted @pytest.mark.skipif("platform.system() == 'Windows'") def test_mkpath_with_custom_mode(self): @@ -61,24 +50,24 @@ def test_mkpath_with_custom_mode(self): mkpath(self.target2, 0o555) assert stat.S_IMODE(os.stat(self.target2).st_mode) == 0o555 & ~umask - def test_create_tree_verbosity(self): + def test_create_tree_verbosity(self, caplog): create_tree(self.root_target, ['one', 'two', 'three'], verbose=0) - assert self._logs == [] + assert caplog.messages == [] remove_tree(self.root_target, verbose=0) wanted = ['creating %s' % self.root_target] create_tree(self.root_target, ['one', 'two', 'three'], verbose=1) - assert self._logs == wanted + assert caplog.messages == wanted remove_tree(self.root_target, verbose=0) - def test_copy_tree_verbosity(self): + def test_copy_tree_verbosity(self, caplog): mkpath(self.target, verbose=0) copy_tree(self.target, self.target2, verbose=0) - assert self._logs == [] + assert caplog.messages == [] remove_tree(self.root_target, verbose=0) @@ -89,7 +78,7 @@ def test_copy_tree_verbosity(self): wanted = ['copying {} -> {}'.format(a_file, self.target2)] copy_tree(self.target, self.target2, verbose=1) - assert self._logs == wanted + assert caplog.messages == wanted remove_tree(self.root_target, verbose=0) remove_tree(self.target2, verbose=0) diff --git a/setuptools/_distutils/tests/test_dist.py b/setuptools/_distutils/tests/test_dist.py index 52e0b3ce26..b5e81d0356 100644 --- a/setuptools/_distutils/tests/test_dist.py +++ b/setuptools/_distutils/tests/test_dist.py @@ -13,9 +13,7 @@ from distutils.dist import Distribution, fix_help_options from distutils.cmd import Command -from test.support import captured_stdout, captured_stderr from distutils.tests import support -from distutils import log pydistutils_cfg = '.' * (os.name == 'posix') + 'pydistutils.cfg' @@ -52,10 +50,7 @@ def clear_argv(): @support.combine_markers @pytest.mark.usefixtures('save_env') @pytest.mark.usefixtures('save_argv') -class TestDistributionBehavior( - support.LoggingSilencer, - support.TempdirManager, -): +class TestDistributionBehavior(support.TempdirManager): def create_distribution(self, configfiles=()): d = TestDistribution() d._config_files = configfiles @@ -240,10 +235,8 @@ def test_get_command_packages(self): def test_announce(self): # make sure the level is known dist = Distribution() - args = ('ok',) - kwargs = {'level': 'ok2'} - with pytest.raises(ValueError): - dist.announce(args, kwargs) + with pytest.raises(TypeError): + dist.announce('ok', level='ok2') def test_find_config_files_disable(self, temp_home): # Ticket #1180: Allow user to disable their home config file. @@ -373,16 +366,15 @@ def test_classifier(self): meta = self.format_metadata(dist) assert 'Metadata-Version: 1.1' in meta - def test_classifier_invalid_type(self): + def test_classifier_invalid_type(self, caplog): attrs = { 'name': 'Boa', 'version': '3.0', 'classifiers': ('Programming Language :: Python :: 3',), } - with captured_stderr() as error: - d = Distribution(attrs) + d = Distribution(attrs) # should have warning about passing a non-list - assert 'should be a list' in error.getvalue() + assert 'should be a list' in caplog.messages[0] # should be converted to a list assert isinstance(d.metadata.classifiers, list) assert d.metadata.classifiers == list(attrs['classifiers']) @@ -396,16 +388,15 @@ def test_keywords(self): dist = Distribution(attrs) assert dist.get_keywords() == ['spam', 'eggs', 'life of brian'] - def test_keywords_invalid_type(self): + def test_keywords_invalid_type(self, caplog): attrs = { 'name': 'Monty', 'version': '1.0', 'keywords': ('spam', 'eggs', 'life of brian'), } - with captured_stderr() as error: - d = Distribution(attrs) + d = Distribution(attrs) # should have warning about passing a non-list - assert 'should be a list' in error.getvalue() + assert 'should be a list' in caplog.messages[0] # should be converted to a list assert isinstance(d.metadata.keywords, list) assert d.metadata.keywords == list(attrs['keywords']) @@ -419,16 +410,15 @@ def test_platforms(self): dist = Distribution(attrs) assert dist.get_platforms() == ['GNU/Linux', 'Some Evil Platform'] - def test_platforms_invalid_types(self): + def test_platforms_invalid_types(self, caplog): attrs = { 'name': 'Monty', 'version': '1.0', 'platforms': ('GNU/Linux', 'Some Evil Platform'), } - with captured_stderr() as error: - d = Distribution(attrs) + d = Distribution(attrs) # should have warning about passing a non-list - assert 'should be a list' in error.getvalue() + assert 'should be a list' in caplog.messages[0] # should be converted to a list assert isinstance(d.metadata.platforms, list) assert d.metadata.platforms == list(attrs['platforms']) @@ -479,18 +469,17 @@ def test_fix_help_options(self): assert fancy_options[0] == ('a', 'b', 'c') assert fancy_options[1] == (1, 2, 3) - def test_show_help(self, request): + def test_show_help(self, request, capsys): # smoke test, just makes sure some help is displayed - reset_log = functools.partial(log.set_threshold, log._global_log.threshold) - request.addfinalizer(reset_log) dist = Distribution() sys.argv = [] dist.help = 1 dist.script_name = 'setup.py' - with captured_stdout() as s: - dist.parse_command_line() + dist.parse_command_line() - output = [line for line in s.getvalue().split('\n') if line.strip() != ''] + output = [ + line for line in capsys.readouterr().out.split('\n') if line.strip() != '' + ] assert output def test_read_metadata(self): diff --git a/setuptools/_distutils/tests/test_file_util.py b/setuptools/_distutils/tests/test_file_util.py index b2e83c52f2..9f44f91dfa 100644 --- a/setuptools/_distutils/tests/test_file_util.py +++ b/setuptools/_distutils/tests/test_file_util.py @@ -4,7 +4,6 @@ import unittest.mock as mock from distutils.file_util import move_file, copy_file -from distutils import log from distutils.tests import support from distutils.errors import DistutilsFileError from .py38compat import unlink @@ -14,22 +13,14 @@ @pytest.fixture(autouse=True) def stuff(request, monkeypatch, distutils_managed_tempdir): self = request.instance - self._logs = [] tmp_dir = self.mkdtemp() self.source = os.path.join(tmp_dir, 'f1') self.target = os.path.join(tmp_dir, 'f2') self.target_dir = os.path.join(tmp_dir, 'd1') - monkeypatch.setattr(log, 'info', self._log) class TestFileUtil(support.TempdirManager): - def _log(self, msg, *args): - if len(args) > 0: - self._logs.append(msg % args) - else: - self._logs.append(msg) - - def test_move_file_verbosity(self): + def test_move_file_verbosity(self, caplog): f = open(self.source, 'w') try: f.write('some content') @@ -37,25 +28,24 @@ def test_move_file_verbosity(self): f.close() move_file(self.source, self.target, verbose=0) - wanted = [] - assert self._logs == wanted + assert not caplog.messages # back to original state move_file(self.target, self.source, verbose=0) move_file(self.source, self.target, verbose=1) wanted = ['moving {} -> {}'.format(self.source, self.target)] - assert self._logs == wanted + assert caplog.messages == wanted # back to original state move_file(self.target, self.source, verbose=0) - self._logs = [] + caplog.clear() # now the target is a dir os.mkdir(self.target_dir) move_file(self.source, self.target_dir, verbose=1) wanted = ['moving {} -> {}'.format(self.source, self.target_dir)] - assert self._logs == wanted + assert caplog.messages == wanted def test_move_file_exception_unpacking_rename(self): # see issue 22182 diff --git a/setuptools/_distutils/tests/test_filelist.py b/setuptools/_distutils/tests/test_filelist.py index 7ff9d3e866..2cee42cddd 100644 --- a/setuptools/_distutils/tests/test_filelist.py +++ b/setuptools/_distutils/tests/test_filelist.py @@ -1,18 +1,16 @@ """Tests for distutils.filelist.""" import os import re +import logging + from distutils import debug -from distutils.log import WARN from distutils.errors import DistutilsTemplateError from distutils.filelist import glob_to_re, translate_pattern, FileList from distutils import filelist -from test.support import captured_stdout - import pytest import jaraco.path -from distutils.tests import support from . import py38compat as os_helper @@ -37,14 +35,16 @@ def make_local_path(s): return s.replace('/', os.sep) -class TestFileList(support.LoggingSilencer): - def assertNoWarnings(self): - assert self.get_logs(WARN) == [] - self.clear_logs() +class TestFileList: + def assertNoWarnings(self, caplog): + warnings = [rec for rec in caplog.records if rec.levelno == logging.WARNING] + assert not warnings + caplog.clear() - def assertWarnings(self): - assert len(self.get_logs(WARN)) > 0 - self.clear_logs() + def assertWarnings(self, caplog): + warnings = [rec for rec in caplog.records if rec.levelno == logging.WARNING] + assert warnings + caplog.clear() def test_glob_to_re(self): sep = os.sep @@ -110,19 +110,14 @@ def test_process_template_line(self): assert file_list.files == wanted - def test_debug_print(self): + def test_debug_print(self, capsys, monkeypatch): file_list = FileList() - with captured_stdout() as stdout: - file_list.debug_print('xxx') - assert stdout.getvalue() == '' - - debug.DEBUG = True - try: - with captured_stdout() as stdout: - file_list.debug_print('xxx') - assert stdout.getvalue() == 'xxx\n' - finally: - debug.DEBUG = False + file_list.debug_print('xxx') + assert capsys.readouterr().out == '' + + monkeypatch.setattr(debug, 'DEBUG', True) + file_list.debug_print('xxx') + assert capsys.readouterr().out == 'xxx\n' def test_set_allfiles(self): file_list = FileList() @@ -188,7 +183,7 @@ def test_include_pattern(self): file_list.include_pattern('*') assert file_list.allfiles == ['a.py', 'b.txt'] - def test_process_template(self): + def test_process_template(self, caplog): mlp = make_local_path # invalid lines file_list = FileList() @@ -212,11 +207,11 @@ def test_process_template(self): file_list.process_template_line('include *.py') assert file_list.files == ['a.py'] - self.assertNoWarnings() + self.assertNoWarnings(caplog) file_list.process_template_line('include *.rb') assert file_list.files == ['a.py'] - self.assertWarnings() + self.assertWarnings(caplog) # exclude file_list = FileList() @@ -224,11 +219,11 @@ def test_process_template(self): file_list.process_template_line('exclude *.py') assert file_list.files == ['b.txt', mlp('d/c.py')] - self.assertNoWarnings() + self.assertNoWarnings(caplog) file_list.process_template_line('exclude *.rb') assert file_list.files == ['b.txt', mlp('d/c.py')] - self.assertWarnings() + self.assertWarnings(caplog) # global-include file_list = FileList() @@ -236,11 +231,11 @@ def test_process_template(self): file_list.process_template_line('global-include *.py') assert file_list.files == ['a.py', mlp('d/c.py')] - self.assertNoWarnings() + self.assertNoWarnings(caplog) file_list.process_template_line('global-include *.rb') assert file_list.files == ['a.py', mlp('d/c.py')] - self.assertWarnings() + self.assertWarnings(caplog) # global-exclude file_list = FileList() @@ -248,11 +243,11 @@ def test_process_template(self): file_list.process_template_line('global-exclude *.py') assert file_list.files == ['b.txt'] - self.assertNoWarnings() + self.assertNoWarnings(caplog) file_list.process_template_line('global-exclude *.rb') assert file_list.files == ['b.txt'] - self.assertWarnings() + self.assertWarnings(caplog) # recursive-include file_list = FileList() @@ -260,11 +255,11 @@ def test_process_template(self): file_list.process_template_line('recursive-include d *.py') assert file_list.files == [mlp('d/b.py'), mlp('d/d/e.py')] - self.assertNoWarnings() + self.assertNoWarnings(caplog) file_list.process_template_line('recursive-include e *.py') assert file_list.files == [mlp('d/b.py'), mlp('d/d/e.py')] - self.assertWarnings() + self.assertWarnings(caplog) # recursive-exclude file_list = FileList() @@ -272,11 +267,11 @@ def test_process_template(self): file_list.process_template_line('recursive-exclude d *.py') assert file_list.files == ['a.py', mlp('d/c.txt')] - self.assertNoWarnings() + self.assertNoWarnings(caplog) file_list.process_template_line('recursive-exclude e *.py') assert file_list.files == ['a.py', mlp('d/c.txt')] - self.assertWarnings() + self.assertWarnings(caplog) # graft file_list = FileList() @@ -284,11 +279,11 @@ def test_process_template(self): file_list.process_template_line('graft d') assert file_list.files == [mlp('d/b.py'), mlp('d/d/e.py')] - self.assertNoWarnings() + self.assertNoWarnings(caplog) file_list.process_template_line('graft e') assert file_list.files == [mlp('d/b.py'), mlp('d/d/e.py')] - self.assertWarnings() + self.assertWarnings(caplog) # prune file_list = FileList() @@ -296,11 +291,11 @@ def test_process_template(self): file_list.process_template_line('prune d') assert file_list.files == ['a.py', mlp('f/f.py')] - self.assertNoWarnings() + self.assertNoWarnings(caplog) file_list.process_template_line('prune e') assert file_list.files == ['a.py', mlp('f/f.py')] - self.assertWarnings() + self.assertWarnings(caplog) class TestFindAll: diff --git a/setuptools/_distutils/tests/test_install.py b/setuptools/_distutils/tests/test_install.py index 32a18b2f2f..102218bc00 100644 --- a/setuptools/_distutils/tests/test_install.py +++ b/setuptools/_distutils/tests/test_install.py @@ -4,8 +4,7 @@ import sys import site import pathlib - -from test.support import captured_stdout +import logging import pytest @@ -30,7 +29,6 @@ def _make_ext_name(modname): @pytest.mark.usefixtures('save_env') class TestInstall( support.TempdirManager, - support.LoggingSilencer, ): @pytest.mark.xfail( 'platform.system() == "Windows" and sys.version_info > (3, 11)', @@ -246,13 +244,9 @@ def test_record_extensions(self): ] assert found == expected - def test_debug_mode(self): + def test_debug_mode(self, caplog, monkeypatch): # this covers the code called when DEBUG is set - old_logs_len = len(self.logs) - install_module.DEBUG = True - try: - with captured_stdout(): - self.test_record() - finally: - install_module.DEBUG = False - assert len(self.logs) > old_logs_len + monkeypatch.setattr(install_module, 'DEBUG', True) + caplog.set_level(logging.DEBUG) + self.test_record() + assert any(rec for rec in caplog.records if rec.levelno == logging.DEBUG) diff --git a/setuptools/_distutils/tests/test_install_data.py b/setuptools/_distutils/tests/test_install_data.py index f77c790fca..9badbc264f 100644 --- a/setuptools/_distutils/tests/test_install_data.py +++ b/setuptools/_distutils/tests/test_install_data.py @@ -10,7 +10,6 @@ @pytest.mark.usefixtures('save_env') class TestInstallData( support.TempdirManager, - support.LoggingSilencer, ): def test_simple_run(self): pkg_dir, dist = self.create_dist() diff --git a/setuptools/_distutils/tests/test_install_headers.py b/setuptools/_distutils/tests/test_install_headers.py index 7594f5af3c..1e8ccf7991 100644 --- a/setuptools/_distutils/tests/test_install_headers.py +++ b/setuptools/_distutils/tests/test_install_headers.py @@ -10,7 +10,6 @@ @pytest.mark.usefixtures('save_env') class TestInstallHeaders( support.TempdirManager, - support.LoggingSilencer, ): def test_simple_run(self): # we have two headers diff --git a/setuptools/_distutils/tests/test_install_lib.py b/setuptools/_distutils/tests/test_install_lib.py index a654a66a79..0bd67cd04d 100644 --- a/setuptools/_distutils/tests/test_install_lib.py +++ b/setuptools/_distutils/tests/test_install_lib.py @@ -15,7 +15,6 @@ @pytest.mark.usefixtures('save_env') class TestInstallLib( support.TempdirManager, - support.LoggingSilencer, ): def test_finalize_options(self): dist = self.create_dist()[1] @@ -94,7 +93,7 @@ def test_get_inputs(self): inputs = cmd.get_inputs() assert len(inputs) == 2, inputs - def test_dont_write_bytecode(self): + def test_dont_write_bytecode(self, caplog): # makes sure byte_compile is not used dist = self.create_dist()[1] cmd = install_lib(dist) @@ -108,4 +107,4 @@ def test_dont_write_bytecode(self): finally: sys.dont_write_bytecode = old_dont_write_bytecode - assert 'byte-compiling is disabled' in self.logs[0][1] % self.logs[0][2] + assert 'byte-compiling is disabled' in caplog.messages[0] diff --git a/setuptools/_distutils/tests/test_install_scripts.py b/setuptools/_distutils/tests/test_install_scripts.py index 0d17f11b5b..58313f2864 100644 --- a/setuptools/_distutils/tests/test_install_scripts.py +++ b/setuptools/_distutils/tests/test_install_scripts.py @@ -8,7 +8,7 @@ from distutils.tests import support -class TestInstallScripts(support.TempdirManager, support.LoggingSilencer): +class TestInstallScripts(support.TempdirManager): def test_default_settings(self): dist = Distribution() dist.command_obj["build"] = support.DummyCommand(build_scripts="/foo/bar") diff --git a/setuptools/_distutils/tests/test_log.py b/setuptools/_distutils/tests/test_log.py index 7aeee4057f..ec6a0c8051 100644 --- a/setuptools/_distutils/tests/test_log.py +++ b/setuptools/_distutils/tests/test_log.py @@ -1,52 +1,13 @@ """Tests for distutils.log""" -import io -import sys -from test.support import swap_attr +import logging -import pytest - -from distutils import log +from distutils._log import log class TestLog: - @pytest.mark.parametrize( - 'errors', - ( - 'strict', - 'backslashreplace', - 'surrogateescape', - 'replace', - 'ignore', - ), - ) - def test_non_ascii(self, errors): - # Issues #8663, #34421: test that non-encodable text is escaped with - # backslashreplace error handler and encodable non-ASCII text is - # output as is. - stdout = io.TextIOWrapper(io.BytesIO(), encoding='cp437', errors=errors) - stderr = io.TextIOWrapper(io.BytesIO(), encoding='cp437', errors=errors) - old_threshold = log.set_threshold(log.DEBUG) - try: - with swap_attr(sys, 'stdout', stdout), swap_attr(sys, 'stderr', stderr): - log.debug('Dεbug\tMėssãge') - log.fatal('Fαtal\tÈrrōr') - finally: - log.set_threshold(old_threshold) - - stdout.seek(0) - assert stdout.read().rstrip() == ( - 'Dεbug\tM?ss?ge' - if errors == 'replace' - else 'Dεbug\tMssge' - if errors == 'ignore' - else 'Dεbug\tM\\u0117ss\\xe3ge' - ) - stderr.seek(0) - assert stderr.read().rstrip() == ( - 'Fαtal\t?rr?r' - if errors == 'replace' - else 'Fαtal\trrr' - if errors == 'ignore' - else 'Fαtal\t\\xc8rr\\u014dr' - ) + def test_non_ascii(self, caplog): + caplog.set_level(logging.DEBUG) + log.debug('Dεbug\tMėssãge') + log.fatal('Fαtal\tÈrrōr') + assert caplog.messages == ['Dεbug\tMėssãge', 'Fαtal\tÈrrōr'] diff --git a/setuptools/_distutils/tests/test_register.py b/setuptools/_distutils/tests/test_register.py index 0a5765f1fd..a10393b5e6 100644 --- a/setuptools/_distutils/tests/test_register.py +++ b/setuptools/_distutils/tests/test_register.py @@ -6,7 +6,6 @@ from distutils.command import register as register_module from distutils.command.register import register from distutils.errors import DistutilsSetupError -from distutils.log import INFO from distutils.tests.test_config import BasePyPIRCCommandTestCase import pytest @@ -303,14 +302,13 @@ def test_register_invalid_long_description(self, monkeypatch): with pytest.raises(DistutilsSetupError): cmd.run() - def test_list_classifiers(self): + def test_list_classifiers(self, caplog): cmd = self._get_cmd() cmd.list_classifiers = 1 cmd.run() - results = self.get_logs(INFO) - assert results == ['running check', 'xxx'] + assert caplog.messages == ['running check', 'xxx'] - def test_show_response(self): + def test_show_response(self, caplog): # test that the --show-response option return a well formatted response cmd = self._get_cmd() inputs = Inputs('1', 'tarek', 'y') @@ -321,5 +319,4 @@ def test_show_response(self): finally: del register_module.input - results = self.get_logs(INFO) - assert results[3] == 75 * '-' + '\nxxx\n' + 75 * '-' + assert caplog.messages[3] == 75 * '-' + '\nxxx\n' + 75 * '-' diff --git a/setuptools/_distutils/tests/test_sdist.py b/setuptools/_distutils/tests/test_sdist.py index b11fe7c41e..97504722ac 100644 --- a/setuptools/_distutils/tests/test_sdist.py +++ b/setuptools/_distutils/tests/test_sdist.py @@ -5,7 +5,6 @@ import zipfile from os.path import join from textwrap import dedent -from test.support import captured_stdout from .unix_compat import require_unix_id, require_uid_0, pwd, grp import pytest @@ -19,7 +18,6 @@ from distutils.tests.test_config import BasePyPIRCCommandTestCase from distutils.errors import DistutilsOptionError from distutils.spawn import find_executable # noqa: F401 -from distutils.log import WARN from distutils.filelist import FileList from distutils.archive_util import ARCHIVE_FORMATS @@ -252,8 +250,12 @@ def test_add_defaults(self): f.close() assert manifest == MANIFEST % {'sep': os.sep} + @staticmethod + def warnings(messages, prefix='warning: '): + return [msg for msg in messages if msg.startswith(prefix)] + @pytest.mark.usefixtures('needs_zlib') - def test_metadata_check_option(self): + def test_metadata_check_option(self, caplog): # testing the `medata-check` option dist, cmd = self.get_cmd(metadata={}) @@ -261,21 +263,15 @@ def test_metadata_check_option(self): # with the `check` subcommand cmd.ensure_finalized() cmd.run() - warnings = [ - msg for msg in self.get_logs(WARN) if msg.startswith('warning: check:') - ] - assert len(warnings) == 1 + assert len(self.warnings(caplog.messages, 'warning: check: ')) == 1 # trying with a complete set of metadata - self.clear_logs() + caplog.clear() dist, cmd = self.get_cmd() cmd.ensure_finalized() cmd.metadata_check = 0 cmd.run() - warnings = [ - msg for msg in self.get_logs(WARN) if msg.startswith('warning: check:') - ] - assert len(warnings) == 0 + assert len(self.warnings(caplog.messages, 'warning: check: ')) == 0 def test_check_metadata_deprecated(self): # makes sure make_metadata is deprecated @@ -285,15 +281,14 @@ def test_check_metadata_deprecated(self): cmd.check_metadata() assert len(w.warnings) == 1 - def test_show_formats(self): - with captured_stdout() as stdout: - show_formats() + def test_show_formats(self, capsys): + show_formats() # the output should be a header line + one line per format num_formats = len(ARCHIVE_FORMATS.keys()) output = [ line - for line in stdout.getvalue().split('\n') + for line in capsys.readouterr().out.split('\n') if line.strip().startswith('--formats=') ] assert len(output) == num_formats @@ -323,28 +318,27 @@ def test_finalize_options(self): # the following tests make sure there is a nice error message instead # of a traceback when parsing an invalid manifest template - def _check_template(self, content): + def _check_template(self, content, caplog): dist, cmd = self.get_cmd() os.chdir(self.tmp_dir) self.write_file('MANIFEST.in', content) cmd.ensure_finalized() cmd.filelist = FileList() cmd.read_template() - warnings = self.get_logs(WARN) - assert len(warnings) == 1 + assert len(self.warnings(caplog.messages)) == 1 - def test_invalid_template_unknown_command(self): - self._check_template('taunt knights *') + def test_invalid_template_unknown_command(self, caplog): + self._check_template('taunt knights *', caplog) - def test_invalid_template_wrong_arguments(self): + def test_invalid_template_wrong_arguments(self, caplog): # this manifest command takes one argument - self._check_template('prune') + self._check_template('prune', caplog) @pytest.mark.skipif("platform.system() != 'Windows'") - def test_invalid_template_wrong_path(self): + def test_invalid_template_wrong_path(self, caplog): # on Windows, trailing slashes are not allowed # this used to crash instead of raising a warning: #8286 - self._check_template('include examples/') + self._check_template('include examples/', caplog) @pytest.mark.usefixtures('needs_zlib') def test_get_file_list(self): diff --git a/setuptools/_distutils/tests/test_spawn.py b/setuptools/_distutils/tests/test_spawn.py index 5da499777a..08a34ee2b8 100644 --- a/setuptools/_distutils/tests/test_spawn.py +++ b/setuptools/_distutils/tests/test_spawn.py @@ -17,7 +17,7 @@ import pytest -class TestSpawn(support.TempdirManager, support.LoggingSilencer): +class TestSpawn(support.TempdirManager): @pytest.mark.skipif("os.name not in ('nt', 'posix')") def test_spawn(self): tmpdir = self.mkdtemp() diff --git a/setuptools/_distutils/tests/test_upload.py b/setuptools/_distutils/tests/test_upload.py index fb905b641a..9685c065f5 100644 --- a/setuptools/_distutils/tests/test_upload.py +++ b/setuptools/_distutils/tests/test_upload.py @@ -8,7 +8,6 @@ from distutils.command.upload import upload from distutils.core import Distribution from distutils.errors import DistutilsError -from distutils.log import ERROR, INFO from distutils.tests.test_config import PYPIRC, BasePyPIRCCommandTestCase import pytest @@ -109,7 +108,7 @@ def test_saved_password(self): cmd.finalize_options() assert cmd.password == 'xxx' - def test_upload(self): + def test_upload(self, caplog): tmp = self.mkdtemp() path = os.path.join(tmp, 'xxx') self.write_file(path) @@ -150,7 +149,7 @@ def test_upload(self): ) # The PyPI response body was echoed - results = self.get_logs(INFO) + results = caplog.messages assert results[-1] == 75 * '-' + '\nxyzzy\n' + 75 * '-' # bpo-32304: archives whose last byte was b'\r' were corrupted due to @@ -178,11 +177,11 @@ def test_upload_correct_cr(self): assert int(headers['Content-length']) >= 2172 assert b'long description\r' in self.last_open.req.data - def test_upload_fails(self): + def test_upload_fails(self, caplog): self.next_msg = "Not Found" self.next_code = 404 with pytest.raises(DistutilsError): - self.test_upload() + self.test_upload(caplog) @pytest.mark.parametrize( 'exception,expected,raised_exception', @@ -196,7 +195,7 @@ def test_upload_fails(self): ), ], ) - def test_wrong_exception_order(self, exception, expected, raised_exception): + def test_wrong_exception_order(self, exception, expected, raised_exception, caplog): tmp = self.mkdtemp() path = os.path.join(tmp, 'xxx') self.write_file(path) @@ -213,6 +212,6 @@ def test_wrong_exception_order(self, exception, expected, raised_exception): cmd = upload(dist) cmd.ensure_finalized() cmd.run() - results = self.get_logs(ERROR) + results = caplog.messages assert expected in results[-1] - self.clear_logs() + caplog.clear() diff --git a/setuptools/_distutils/unixccompiler.py b/setuptools/_distutils/unixccompiler.py index 4ab771a475..4bf2e6a681 100644 --- a/setuptools/_distutils/unixccompiler.py +++ b/setuptools/_distutils/unixccompiler.py @@ -19,11 +19,11 @@ import shlex import itertools -from distutils import sysconfig -from distutils.dep_util import newer -from distutils.ccompiler import CCompiler, gen_preprocess_options, gen_lib_options -from distutils.errors import DistutilsExecError, CompileError, LibError, LinkError -from distutils import log +from . import sysconfig +from .dep_util import newer +from .ccompiler import CCompiler, gen_preprocess_options, gen_lib_options +from .errors import DistutilsExecError, CompileError, LibError, LinkError +from ._log import log from ._macos_compat import compiler_fixup # XXX Things not currently handled: diff --git a/setuptools/_distutils/util.py b/setuptools/_distutils/util.py index 4763202b67..8668b43699 100644 --- a/setuptools/_distutils/util.py +++ b/setuptools/_distutils/util.py @@ -13,10 +13,10 @@ import sysconfig import functools -from distutils.errors import DistutilsPlatformError, DistutilsByteCompileError -from distutils.dep_util import newer -from distutils.spawn import spawn -from distutils import log +from .errors import DistutilsPlatformError, DistutilsByteCompileError +from .dep_util import newer +from .spawn import spawn +from ._log import log def get_host_platform(): diff --git a/setuptools/_distutils/versionpredicate.py b/setuptools/_distutils/versionpredicate.py index 6ea1192d4c..d6c0c007aa 100644 --- a/setuptools/_distutils/versionpredicate.py +++ b/setuptools/_distutils/versionpredicate.py @@ -1,7 +1,7 @@ """Module for parsing and testing package version predicate strings. """ import re -import distutils.version +from . import version import operator @@ -22,8 +22,8 @@ def splitUp(pred): if not res: raise ValueError("bad package restriction syntax: %r" % pred) comp, verStr = res.groups() - with distutils.version.suppress_known_deprecation(): - other = distutils.version.StrictVersion(verStr) + with version.suppress_known_deprecation(): + other = version.StrictVersion(verStr) return (comp, other) @@ -170,6 +170,6 @@ def split_provision(value): raise ValueError("illegal provides specification: %r" % value) ver = m.group(2) or None if ver: - with distutils.version.suppress_known_deprecation(): - ver = distutils.version.StrictVersion(ver) + with version.suppress_known_deprecation(): + ver = version.StrictVersion(ver) return m.group(1), ver