[bumpversion]
-current_version = 60.1.1
+current_version = 60.2.0
commit = True
tag = True
+v60.2.0
+-------
+
+
+Changes
+^^^^^^^
+* #2974: Setuptools now relies on the Python logging infrastructure to log messages. Instead of using ``distutils.log.*``, use ``logging.getLogger(name).*``.
+* #2987: Sync with pypa/distutils@2def21c5d74fdd2fe7996ee4030ac145a9d751bd, including fix for missing get_versions attribute (#2969), more reliance on sysconfig from stdlib.
+
+Misc
+^^^^
+* #2962: Avoid attempting to use local distutils when the presiding version of Setuptools on the path doesn't have one.
+* #2983: Restore 'add_shim' as the way to invoke the hook. Avoids compatibility issues between different versions of Setuptools with the distutils local implementation.
+
+
v60.1.1
-------
import importlib.abc
import importlib.util
- # In cases of path manipulation during sitecustomize,
- # Setuptools might actually not be present even though
- # the hook has been loaded. Allow the caller to fall
- # back to stdlib behavior. See #2980.
- if not importlib.util.find_spec('setuptools'):
+ try:
+ mod = importlib.import_module('setuptools._distutils')
+ except Exception:
+ # There are a couple of cases where setuptools._distutils
+ # may not be present:
+ # - An older Setuptools without a local distutils is
+ # taking precedence. Ref #2957.
+ # - Path manipulation during sitecustomize removes
+ # setuptools from the path but only after the hook
+ # has been loaded. Ref #2980.
+ # In either case, fall back to stdlib behavior.
return
class DistutilsLoader(importlib.abc.Loader):
def create_module(self, spec):
- return importlib.import_module('setuptools._distutils')
+ return mod
def exec_module(self, module):
pass
DISTUTILS_FINDER = DistutilsMetaFinder()
-def ensure_shim():
- DISTUTILS_FINDER in sys.meta_path or add_shim()
+def add_shim():
+ DISTUTILS_FINDER in sys.meta_path or insert_shim()
@contextlib.contextmanager
def shim():
- add_shim()
+ insert_shim()
try:
yield
finally:
remove_shim()
-def add_shim():
+def insert_shim():
sys.meta_path.insert(0, DISTUTILS_FINDER)
[metadata]
name = setuptools
-version = 60.1.1
+version = 60.2.0
author = Python Packaging Authority
author_email = distutils-sig@python.org
description = Easily download, build, install, upgrade, and uninstall Python packages
pip>=19.1 # For proper file:// URLs support.
jaraco.envs>=2.2
pytest-xdist
- sphinx
+ sphinx>=4.3.2
jaraco.path>=3.2.0
docs =
import os
var = 'SETUPTOOLS_USE_DISTUTILS'
enabled = os.environ.get(var, 'local') == 'local'
- enabled and __import__('_distutils_hack').ensure_shim()
+ enabled and __import__('_distutils_hack').add_shim()
""").lstrip().replace('\n', '; ')
def initialize_options(self):
from setuptools.dist import Distribution
from setuptools.depends import Require
from . import monkey
+from . import logging
__all__ = [
def setup(**attrs):
# Make sure we have any requirements needed to interpret 'attrs'.
+ logging.configure()
_install_setup_requires(attrs)
return distutils.core.setup(**attrs)
out_string = check_output(shlex.split(cc) + ['-dumpmachine'])
return out_string.strip().endswith(b'cygwin')
+
+get_versions = None
+"""
+A stand-in for the previous get_versions() function to prevent failures
+when monkeypatched. See pypa/setuptools#2969.
+"""
# The class here is styled after PEP 282 so that it could later be
# replaced with a standard Python logging implementation.
+import sys
+
DEBUG = 1
INFO = 2
WARN = 3
ERROR = 4
FATAL = 5
-import sys
class Log:
def fatal(self, msg, *args):
self._log(FATAL, msg, args)
+
_global_log = Log()
log = _global_log.log
debug = _global_log.debug
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
+
def set_verbosity(v):
if v <= 0:
set_threshold(WARN)
import os
import re
import sys
+import sysconfig
from .errors import DistutilsPlatformError
inc_dir = os.path.join(_sys_home or project_base, "PC")
else:
inc_dir = _sys_home or project_base
+ return os.path.join(inc_dir, 'pyconfig.h')
else:
- inc_dir = get_python_inc(plat_specific=1)
+ return sysconfig.get_config_h_filename()
- return os.path.join(inc_dir, 'pyconfig.h')
-
-
-# Allow this value to be patched by pkgsrc. Ref pypa/distutils#16.
-_makefile_tmpl = 'config-{python_ver}{build_flags}{multiarch}'
def get_makefile_filename():
"""Return full pathname of installed Makefile from the Python build."""
- if python_build:
- return os.path.join(_sys_home or project_base, "Makefile")
- lib_dir = get_python_lib(plat_specific=0, standard_lib=1)
- multiarch = (
- '-%s' % sys.implementation._multiarch
- if hasattr(sys.implementation, '_multiarch') else ''
- )
- config_file = _makefile_tmpl.format(
- python_ver=get_python_version(),
- build_flags=build_flags,
- multiarch=multiarch,
- )
- return os.path.join(lib_dir, config_file, 'Makefile')
+ return sysconfig.get_makefile_filename()
def parse_config_h(fp, g=None):
optional dictionary is passed in as the second argument, it is
used instead of a new dictionary.
"""
- if g is None:
- g = {}
- define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
- undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
- #
- while True:
- line = fp.readline()
- if not line:
- break
- m = define_rx.match(line)
- if m:
- n, v = m.group(1, 2)
- try: v = int(v)
- except ValueError: pass
- g[n] = v
- else:
- m = undef_rx.match(line)
- if m:
- g[m.group(1)] = 0
- return g
+ return sysconfig.parse_config_h(fp, vars=g)
# Regexes needed for parsing Makefile (and similar syntaxes,
archive.close()
def test_suite():
- return unittest.makeSuite(ArchiveUtilTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(ArchiveUtilTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
def test_suite():
- return unittest.makeSuite(BuildTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(BuildTestCase)
if __name__ == '__main__':
run_unittest(test_suite())
self.assertEqual(contents, sorted(wanted))
def test_suite():
- return unittest.makeSuite(BuildDumbTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(BuildDumbTestCase)
if __name__ == '__main__':
run_unittest(test_suite())
def test_suite():
- return unittest.makeSuite(BDistMSITestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(BDistMSITestCase)
if __name__ == '__main__':
run_unittest(test_suite())
os.remove(os.path.join(pkg_dir, 'dist', 'foo-0.1-1.noarch.rpm'))
def test_suite():
- return unittest.makeSuite(BuildRpmTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(BuildRpmTestCase)
if __name__ == '__main__':
run_unittest(test_suite())
self.assertGreater(len(exe_file), 10)
def test_suite():
- return unittest.makeSuite(BuildWinInstTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(BuildWinInstTestCase)
if __name__ == '__main__':
run_unittest(test_suite())
self.assertEqual(cmd.executable, os.path.normpath(sys.executable))
def test_suite():
- return unittest.makeSuite(BuildTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(BuildTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
self.assertIn('libfoo.a', os.listdir(build_temp))
def test_suite():
- return unittest.makeSuite(BuildCLibTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(BuildCLibTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
def test_suite():
suite = unittest.TestSuite()
- suite.addTest(unittest.makeSuite(BuildExtTestCase))
- suite.addTest(unittest.makeSuite(ParallelBuildExtTestCase))
+ suite.addTest(unittest.TestLoader().loadTestsFromTestCase(BuildExtTestCase))
+ suite.addTest(unittest.TestLoader().loadTestsFromTestCase(ParallelBuildExtTestCase))
return suite
if __name__ == '__main__':
def test_suite():
- return unittest.makeSuite(BuildPyTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(BuildPyTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
self.assertIn(name, built)
def test_suite():
- return unittest.makeSuite(BuildScriptsTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(BuildScriptsTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
'restructuredtext': 1})
def test_suite():
- return unittest.makeSuite(CheckTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(CheckTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
cmd.run()
def test_suite():
- return unittest.makeSuite(cleanTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(cleanTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
debug.DEBUG = False
def test_suite():
- return unittest.makeSuite(CommandTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(CommandTestCase)
if __name__ == '__main__':
run_unittest(test_suite())
def test_suite():
- return unittest.makeSuite(PyPIRCCommandTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(PyPIRCCommandTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
self.assertFalse(os.path.exists(f))
def test_suite():
- return unittest.makeSuite(ConfigTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(ConfigTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
self.assertEqual(stdout.readlines()[0], wanted)
def test_suite():
- return unittest.makeSuite(CoreTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(CoreTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
self.assertRaises(ValueError, get_msvcr)
def test_suite():
- return unittest.makeSuite(CygwinCCompilerTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(CygwinCCompilerTestCase)
if __name__ == '__main__':
run_unittest(test_suite())
def test_suite():
- return unittest.makeSuite(DepUtilTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(DepUtilTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
def test_suite():
- return unittest.makeSuite(DirUtilTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(DirUtilTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
def test_suite():
suite = unittest.TestSuite()
- suite.addTest(unittest.makeSuite(DistributionTestCase))
- suite.addTest(unittest.makeSuite(MetadataTestCase))
+ suite.addTest(unittest.TestLoader().loadTestsFromTestCase(DistributionTestCase))
+ suite.addTest(unittest.TestLoader().loadTestsFromTestCase(MetadataTestCase))
return suite
if __name__ == "__main__":
"Unknown Extension options: 'chic'")
def test_suite():
- return unittest.makeSuite(ExtensionTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(ExtensionTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
def test_suite():
- return unittest.makeSuite(FileUtilTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(FileUtilTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
def test_suite():
return unittest.TestSuite([
- unittest.makeSuite(FileListTestCase),
- unittest.makeSuite(FindAllTestCase),
+ unittest.TestLoader().loadTestsFromTestCase(FileListTestCase),
+ unittest.TestLoader().loadTestsFromTestCase(FindAllTestCase),
])
def test_suite():
- return unittest.makeSuite(InstallTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(InstallTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
self.assertTrue(os.path.exists(os.path.join(inst, rone)))
def test_suite():
- return unittest.makeSuite(InstallDataTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(InstallDataTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
self.assertEqual(len(cmd.get_outputs()), 2)
def test_suite():
- return unittest.makeSuite(InstallHeadersTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(InstallHeadersTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
def test_suite():
- return unittest.makeSuite(InstallLibTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(InstallLibTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
def test_suite():
- return unittest.makeSuite(InstallScriptsTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(InstallScriptsTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
'Fαtal\t\\xc8rr\\u014dr')
def test_suite():
- return unittest.makeSuite(TestLog)
+ return unittest.TestLoader().loadTestsFromTestCase(TestLog)
if __name__ == "__main__":
run_unittest(test_suite())
def test_suite():
- return unittest.makeSuite(msvc9compilerTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(msvc9compilerTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
compiler = _msvccompiler.MSVCCompiler()
compiler._paths = "expected"
inner_cmd = 'import os; assert os.environ["PATH"] == "expected"'
- command = ['python', '-c', inner_cmd]
+ command = [sys.executable, '-c', inner_cmd]
threads = [
CheckThread(target=compiler.spawn, args=[command])
def test_suite():
- return unittest.makeSuite(msvccompilerTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(msvccompilerTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
def test_suite():
- return unittest.makeSuite(RegisterTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(RegisterTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
archive.close()
def test_suite():
- return unittest.makeSuite(SDistTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(SDistTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
def test_suite():
- return unittest.makeSuite(SpawnTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(SpawnTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
config_h = sysconfig.get_config_h_filename()
self.assertTrue(os.path.isfile(config_h), config_h)
+ @unittest.skipIf(sys.platform == 'win32',
+ 'Makefile only exists on Unix like systems')
+ def test_get_makefile_filename(self):
+ makefile = sysconfig.get_makefile_filename()
+ self.assertTrue(os.path.isfile(makefile), makefile)
+
def test_get_python_lib(self):
# XXX doesn't work on Linux when Python was never installed before
#self.assertTrue(os.path.isdir(lib_dir), lib_dir)
outs, errs = p.communicate()
self.assertEqual(0, p.returncode, "Subprocess failed: " + outs)
+ def test_parse_config_h(self):
+ config_h = sysconfig.get_config_h_filename()
+ input = {}
+ with open(config_h, encoding="utf-8") as f:
+ result = sysconfig.parse_config_h(f, g=input)
+ self.assertTrue(input is result)
+ with open(config_h, encoding="utf-8") as f:
+ result = sysconfig.parse_config_h(f)
+ self.assertTrue(isinstance(result, dict))
def test_suite():
suite = unittest.TestSuite()
- suite.addTest(unittest.makeSuite(SysconfigTestCase))
+ suite.addTest(unittest.TestLoader().loadTestsFromTestCase(SysconfigTestCase))
return suite
in_file.close()
def test_suite():
- return unittest.makeSuite(TextFileTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(TextFileTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
def test_suite():
- return unittest.makeSuite(UnixCCompilerTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(UnixCCompilerTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
def test_suite():
- return unittest.makeSuite(uploadTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(uploadTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
def test_suite():
- return unittest.makeSuite(UtilTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(UtilTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
(v1, v2, res))
def test_suite():
- return unittest.makeSuite(VersionTestCase)
+ return unittest.TestLoader().loadTestsFromTestCase(VersionTestCase)
if __name__ == "__main__":
run_unittest(test_suite())
--- /dev/null
+import sys
+import logging
+import distutils.log
+from . import monkey
+
+
+def _not_warning(record):
+ return record.levelno < logging.WARNING
+
+
+def configure():
+ """
+ Configure logging to emit warning and above to stderr
+ and everything else to stdout. This behavior is provided
+ for compatibilty with distutils.log but may change in
+ the future.
+ """
+ err_handler = logging.StreamHandler()
+ err_handler.setLevel(logging.WARNING)
+ out_handler = logging.StreamHandler(sys.stdout)
+ out_handler.addFilter(_not_warning)
+ handlers = err_handler, out_handler
+ logging.basicConfig(
+ format="{message}", style='{', handlers=handlers, level=logging.DEBUG)
+ monkey.patch_func(set_threshold, distutils.log, 'set_threshold')
+
+
+def set_threshold(level):
+ logging.root.setLevel(level*10)
+ return set_threshold.unpatched(level)
[testenv]
deps =
- # workaround for sphinx-doc/sphinx#9562
- # TODO: remove after Sphinx>4.1.2 is available.
- sphinx@git+https://github.com/sphinx-doc/sphinx; python_version>="3.10"
# TODO: remove after man-group/pytest-plugins#188 is solved
pytest-virtualenv @ git+https://github.com/jaraco/pytest-plugins@distutils-deprecated#subdirectory=pytest-virtualenv
commands =