From: JinWang An Date: Mon, 27 Mar 2023 08:02:48 +0000 (+0900) Subject: Imported Upstream version 62.1.0 X-Git-Tag: upstream/62.1.0^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=18d12d175f87b71c279675dc2514ec519baf0b9a;p=platform%2Fupstream%2Fpython-setuptools.git Imported Upstream version 62.1.0 --- diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 5c2f2e4..1125d38 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 62.0.0 +current_version = 62.1.0 commit = True tag = True diff --git a/CHANGES.rst b/CHANGES.rst index 126457b..5061ecb 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,16 @@ +v62.1.0 +------- + + +Changes +^^^^^^^ +* #3258: Merge pypa/distutils@5229dad46b. + +Misc +^^^^ +* #3249: Simplified ``package_dir`` obtained via auto-discovery. + + v62.0.0 ------- diff --git a/docs/userguide/dependency_management.rst b/docs/userguide/dependency_management.rst index 279f794..d15b45c 100644 --- a/docs/userguide/dependency_management.rst +++ b/docs/userguide/dependency_management.rst @@ -43,7 +43,7 @@ other two types of dependency keyword, this one is specified in your Declaring required dependency ============================= This is where a package declares its core dependencies, without which it won't -be able to run. ``setuptools`` support automatically download and install +be able to run. ``setuptools`` supports automatically downloading and installing these dependencies when the package is installed. Although there is more finesse to it, let's start with a simple example. @@ -90,7 +90,7 @@ that verify the availability of the specified dependencies at runtime. Platform specific dependencies ------------------------------ -Setuptools offer the capability to evaluate certain conditions before blindly +Setuptools offers the capability to evaluate certain conditions before blindly installing everything listed in ``install_requires``. This is great for platform specific dependencies. For example, the ``enum`` package was added in Python 3.4, therefore, package that depends on it can elect to install it only when @@ -250,9 +250,9 @@ distributions, if the package's dependencies aren't already installed: Optional dependencies ===================== Setuptools allows you to declare dependencies that only get installed under -specific circumstances. These dependencies are specified with ``extras_require`` +specific circumstances. These dependencies are specified with the ``extras_require`` keyword and are only installed if another package depends on it (either -directly or indirectly) This makes it convenient to declare dependencies for +directly or indirectly). This makes it convenient to declare dependencies for ancillary functions such as "tests" and "docs". .. note:: diff --git a/setup.cfg b/setup.cfg index 78c088a..4b38624 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = setuptools -version = 62.0.0 +version = 62.1.0 author = Python Packaging Authority author_email = distutils-sig@python.org description = Easily download, build, install, upgrade, and uninstall Python packages diff --git a/setuptools/_distutils/command/build.py b/setuptools/_distutils/command/build.py index 4355a63..9606b81 100644 --- a/setuptools/_distutils/command/build.py +++ b/setuptools/_distutils/command/build.py @@ -81,7 +81,8 @@ class build(Command): "--plat-name only supported on Windows (try " "using './configure --help' on your platform)") - plat_specifier = ".%s-%d.%d" % (self.plat_name, *sys.version_info[:2]) + plat_specifier = ".%s-%s" % (self.plat_name, + sys.implementation.cache_tag) # Make it so Python 2.x and Python 2.x with --with-pydebug don't # share the same build directories. Doing so confuses the build diff --git a/setuptools/_distutils/py39compat.py b/setuptools/_distutils/py39compat.py new file mode 100644 index 0000000..9de9501 --- /dev/null +++ b/setuptools/_distutils/py39compat.py @@ -0,0 +1,21 @@ +import sys +import platform + + +def add_ext_suffix_39(vars): + """ + Ensure vars contains 'EXT_SUFFIX'. pypa/distutils#130 + """ + import _imp + ext_suffix = _imp.extension_suffixes()[0] + vars.update( + EXT_SUFFIX=ext_suffix, + # sysconfig sets SO to match EXT_SUFFIX, so maintain + # that expectation. + # https://github.com/python/cpython/blob/785cc6770588de087d09e89a69110af2542be208/Lib/sysconfig.py#L671-L673 + SO=ext_suffix, + ) + + +needs_ext_suffix = sys.version_info < (3, 10) and platform.system() == 'Windows' +add_ext_suffix = add_ext_suffix_39 if needs_ext_suffix else lambda vars: None diff --git a/setuptools/_distutils/sysconfig.py b/setuptools/_distutils/sysconfig.py index 9fad383..55a42e1 100644 --- a/setuptools/_distutils/sysconfig.py +++ b/setuptools/_distutils/sysconfig.py @@ -9,13 +9,13 @@ Written by: Fred L. Drake, Jr. Email: """ -import _imp import os import re import sys import sysconfig from .errors import DistutilsPlatformError +from . import py39compat IS_PYPY = '__pypy__' in sys.builtin_module_names @@ -48,6 +48,7 @@ def _is_python_source_dir(d): return True return False + _sys_home = getattr(sys, '_home', None) if os.name == 'nt': @@ -59,11 +60,13 @@ if os.name == 'nt': project_base = _fix_pcbuild(project_base) _sys_home = _fix_pcbuild(_sys_home) + def _python_build(): if _sys_home: return _is_python_source_dir(_sys_home) return _is_python_source_dir(project_base) + python_build = _python_build() @@ -79,6 +82,7 @@ except AttributeError: # this attribute, which is fine. pass + def get_python_version(): """Return a string containing the major and minor Python version, leaving off the patchlevel. Sample return values could be '1.5' @@ -192,7 +196,6 @@ def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): "on platform '%s'" % os.name) - def customize_compiler(compiler): """Do any platform-specific customization of a CCompiler instance. @@ -217,8 +220,9 @@ def customize_compiler(compiler): _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True' (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \ - get_config_vars('CC', 'CXX', 'CFLAGS', - 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') + get_config_vars( + 'CC', 'CXX', 'CFLAGS', + 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') if 'CC' in os.environ: newcc = os.environ['CC'] @@ -280,7 +284,6 @@ def get_config_h_filename(): return sysconfig.get_config_h_filename() - def get_makefile_filename(): """Return full pathname of installed Makefile from the Python build.""" return sysconfig.get_makefile_filename() @@ -302,6 +305,7 @@ _variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") + def parse_makefile(fn, g=None): """Parse a Makefile-style file. @@ -310,7 +314,9 @@ def parse_makefile(fn, g=None): used instead of a new dictionary. """ from distutils.text_file import TextFile - fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1, errors="surrogateescape") + fp = TextFile( + fn, strip_comments=1, skip_blanks=1, join_lines=1, + errors="surrogateescape") if g is None: g = {} @@ -319,7 +325,7 @@ def parse_makefile(fn, g=None): while True: line = fp.readline() - if line is None: # eof + if line is None: # eof break m = _variable_rx.match(line) if m: @@ -363,7 +369,8 @@ def parse_makefile(fn, g=None): item = os.environ[n] elif n in renamed_variables: - if name.startswith('PY_') and name[3:] in renamed_variables: + if name.startswith('PY_') and \ + name[3:] in renamed_variables: item = "" elif 'PY_' + n in notdone: @@ -379,7 +386,8 @@ def parse_makefile(fn, g=None): if "$" in after: notdone[name] = value else: - try: value = int(value) + try: + value = int(value) except ValueError: done[name] = value.strip() else: @@ -387,7 +395,7 @@ def parse_makefile(fn, g=None): del notdone[name] if name.startswith('PY_') \ - and name[3:] in renamed_variables: + and name[3:] in renamed_variables: name = name[3:] if name not in done: @@ -449,6 +457,7 @@ def get_config_vars(*args): global _config_vars if _config_vars is None: _config_vars = sysconfig.get_config_vars().copy() + py39compat.add_ext_suffix(_config_vars) if args: vals = [] @@ -458,6 +467,7 @@ def get_config_vars(*args): else: return _config_vars + def get_config_var(name): """Return the value of a single variable using the dictionary returned by 'get_config_vars()'. Equivalent to @@ -465,5 +475,6 @@ def get_config_var(name): """ if name == 'SO': import warnings - warnings.warn('SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2) + warnings.warn( + 'SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2) return get_config_vars().get(name) diff --git a/setuptools/_distutils/tests/test_build.py b/setuptools/_distutils/tests/test_build.py index 83a9e4f..9372441 100644 --- a/setuptools/_distutils/tests/test_build.py +++ b/setuptools/_distutils/tests/test_build.py @@ -24,10 +24,10 @@ class BuildTestCase(support.TempdirManager, wanted = os.path.join(cmd.build_base, 'lib') self.assertEqual(cmd.build_purelib, wanted) - # build_platlib is 'build/lib.platform-x.x[-pydebug]' + # build_platlib is 'build/lib.platform-cache_tag[-pydebug]' # examples: - # build/lib.macosx-10.3-i386-2.7 - plat_spec = '.%s-%d.%d' % (cmd.plat_name, *sys.version_info[:2]) + # build/lib.macosx-10.3-i386-cpython39 + plat_spec = '.%s-%s' % (cmd.plat_name, sys.implementation.cache_tag) if hasattr(sys, 'gettotalrefcount'): self.assertTrue(cmd.build_platlib.endswith('-pydebug')) plat_spec += '-pydebug' diff --git a/setuptools/_distutils/tests/test_install.py b/setuptools/_distutils/tests/test_install.py index 5dbc06b..3aef9e4 100644 --- a/setuptools/_distutils/tests/test_install.py +++ b/setuptools/_distutils/tests/test_install.py @@ -56,14 +56,15 @@ class InstallTestCase(support.TempdirManager, expected = os.path.normpath(expected) self.assertEqual(got, expected) - libdir = os.path.join(destination, "lib", "python") + impl_name = sys.implementation.name.replace("cpython", "python") + libdir = os.path.join(destination, "lib", impl_name) check_path(cmd.install_lib, libdir) _platlibdir = getattr(sys, "platlibdir", "lib") - platlibdir = os.path.join(destination, _platlibdir, "python") + platlibdir = os.path.join(destination, _platlibdir, impl_name) check_path(cmd.install_platlib, platlibdir) check_path(cmd.install_purelib, libdir) check_path(cmd.install_headers, - os.path.join(destination, "include", "python", "foopkg")) + os.path.join(destination, "include", impl_name, "foopkg")) check_path(cmd.install_scripts, os.path.join(destination, "bin")) check_path(cmd.install_data, destination) diff --git a/setuptools/_distutils/tests/test_sysconfig.py b/setuptools/_distutils/tests/test_sysconfig.py index 9de3cb7..e671f9e 100644 --- a/setuptools/_distutils/tests/test_sysconfig.py +++ b/setuptools/_distutils/tests/test_sysconfig.py @@ -40,6 +40,8 @@ class SysconfigTestCase(support.EnvironGuard, unittest.TestCase): @unittest.skipIf(sys.platform == 'win32', 'Makefile only exists on Unix like systems') + @unittest.skipIf(sys.implementation.name != 'cpython', + 'Makefile only exists in CPython') def test_get_makefile_filename(self): makefile = sysconfig.get_makefile_filename() self.assertTrue(os.path.isfile(makefile), makefile) @@ -299,6 +301,14 @@ class SysconfigTestCase(support.EnvironGuard, unittest.TestCase): result = sysconfig.parse_config_h(f) self.assertTrue(isinstance(result, dict)) + @unittest.skipUnless(sys.platform == 'win32', + 'Testing windows pyd suffix') + @unittest.skipUnless(sys.implementation.name == 'cpython', + 'Need cpython for this test') + def test_win_ext_suffix(self): + self.assertTrue(sysconfig.get_config_var("EXT_SUFFIX").endswith(".pyd")) + self.assertNotEqual(sysconfig.get_config_var("EXT_SUFFIX"), ".pyd") + def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.TestLoader().loadTestsFromTestCase(SysconfigTestCase)) diff --git a/setuptools/_distutils/version.py b/setuptools/_distutils/version.py index 35e181d..31f504e 100644 --- a/setuptools/_distutils/version.py +++ b/setuptools/_distutils/version.py @@ -50,14 +50,14 @@ class Version: """ def __init__ (self, vstring=None): + if vstring: + self.parse(vstring) warnings.warn( "distutils Version classes are deprecated. " "Use packaging.version instead.", DeprecationWarning, stacklevel=2, ) - if vstring: - self.parse(vstring) def __repr__ (self): return "%s ('%s')" % (self.__class__.__name__, str(self)) diff --git a/setuptools/config/expand.py b/setuptools/config/expand.py index ff9b2c9..da55d4e 100644 --- a/setuptools/config/expand.py +++ b/setuptools/config/expand.py @@ -312,8 +312,12 @@ def find_packages( where = kwargs.pop('where', ['.']) packages: List[str] = [] fill_package_dir = {} if fill_package_dir is None else fill_package_dir + search = list(unique_everseen(always_iterable(where))) - for path in unique_everseen(always_iterable(where)): + if len(search) == 1 and all(not _same_path(search[0], x) for x in (".", root_dir)): + fill_package_dir.setdefault("", search[0]) + + for path in search: package_path = _nest_path(root_dir, path) pkgs = PackageFinder.find(package_path, **kwargs) packages.extend(pkgs) @@ -326,8 +330,27 @@ def find_packages( return packages +def _same_path(p1: _Path, p2: _Path) -> bool: + """Differs from os.path.samefile because it does not require paths to exist. + Purely string based (no comparison between i-nodes). + >>> _same_path("a/b", "./a/b") + True + >>> _same_path("a/b", "a/./b") + True + >>> _same_path("a/b", "././a/b") + True + >>> _same_path("a/b", "./a/b/c/..") + True + >>> _same_path("a/b", "../a/b/c") + False + >>> _same_path("a", "a/b") + False + """ + return os.path.normpath(p1) == os.path.normpath(p2) + + def _nest_path(parent: _Path, path: _Path) -> str: - path = parent if path == "." else os.path.join(parent, path) + path = parent if path in {".", ""} else os.path.join(parent, path) return os.path.normpath(path) diff --git a/setuptools/tests/config/test_expand.py b/setuptools/tests/config/test_expand.py index 3a59edb..15053c8 100644 --- a/setuptools/tests/config/test_expand.py +++ b/setuptools/tests/config/test_expand.py @@ -130,7 +130,7 @@ def test_resolve_class(tmp_path, package_dir, file, module, return_value): ({}, {"pkg", "other", "dir1", "dir1.dir2"}), # default value for `namespaces` ] ) -def test_find_packages(tmp_path, monkeypatch, args, pkgs): +def test_find_packages(tmp_path, args, pkgs): files = { "pkg/__init__.py", "other/__init__.py", @@ -153,3 +153,33 @@ def test_find_packages(tmp_path, monkeypatch, args, pkgs): ] assert set(expand.find_packages(where=where, **args)) == pkgs + + +@pytest.mark.parametrize( + "files, where, expected_package_dir", + [ + (["pkg1/__init__.py", "pkg1/other.py"], ["."], {}), + (["pkg1/__init__.py", "pkg2/__init__.py"], ["."], {}), + (["src/pkg1/__init__.py", "src/pkg1/other.py"], ["src"], {"": "src"}), + (["src/pkg1/__init__.py", "src/pkg2/__init__.py"], ["src"], {"": "src"}), + ( + ["src1/pkg1/__init__.py", "src2/pkg2/__init__.py"], + ["src1", "src2"], + {"pkg1": "src1/pkg1", "pkg2": "src2/pkg2"}, + ), + ( + ["src/pkg1/__init__.py", "pkg2/__init__.py"], + ["src", "."], + {"pkg1": "src/pkg1"}, + ), + ], +) +def test_fill_package_dir(tmp_path, files, where, expected_package_dir): + write_files({k: "" for k in files}, tmp_path) + pkg_dir = {} + kwargs = {"root_dir": tmp_path, "fill_package_dir": pkg_dir, "namespaces": False} + pkgs = expand.find_packages(where=where, **kwargs) + assert set(pkg_dir.items()) == set(expected_package_dir.items()) + for pkg in pkgs: + pkg_path = find_package_path(pkg, pkg_dir, tmp_path) + assert os.path.exists(pkg_path)