From d99049eab419667828d03bc03d0919547e3907b5 Mon Sep 17 00:00:00 2001 From: JinWang An Date: Mon, 27 Mar 2023 17:02:33 +0900 Subject: [PATCH] Imported Upstream version 56.0.0 --- .bumpversion.cfg | 2 +- CHANGES.rst | 28 ++++++++++ docs/pkg_resources.rst | 7 +++ docs/references/keywords.rst | 11 ++++ docs/userguide/declarative_config.rst | 2 +- docs/userguide/dependency_management.rst | 8 +-- docs/userguide/quickstart.rst | 2 +- pkg_resources/extern/__init__.py | 21 ++++---- setup.cfg | 2 +- setuptools/command/sdist.py | 55 +++++++++++-------- setuptools/extern/__init__.py | 21 ++++---- setuptools/tests/test_egg_info.py | 68 ++++++++++++++++++++++-- setuptools/tests/test_manifest.py | 1 + setuptools/tests/test_virtualenv.py | 2 +- 14 files changed, 175 insertions(+), 55 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 7fe611a..dd76f43 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 55.0.0 +current_version = 56.0.0 commit = True tag = True diff --git a/CHANGES.rst b/CHANGES.rst index d073fa8..ef1d926 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,31 @@ +v56.0.0 +------- + + +Deprecations +^^^^^^^^^^^^ +* #2620: The ``license_file`` option is now marked as deprecated. + Use ``license_files`` instead. -- by :user:`cdce8p` + +Breaking Changes +^^^^^^^^^^^^^^^^ +* #2620: If neither ``license_file`` nor ``license_files`` is specified, the ``sdist`` + option will now auto-include files that match the following patterns: + ``LICEN[CS]E*``, ``COPYING*``, ``NOTICE*``, ``AUTHORS*``. + This matches the behavior of ``bdist_wheel``. -- by :user:`cdce8p` + +Changes +^^^^^^^ +* #2620: The ``license_file`` and ``license_files`` options now support glob patterns. -- by :user:`cdce8p` +* #2632: Implemented ``VendorImporter.find_spec()`` method to get rid + of ``ImportWarning`` that Python 3.10 emits when only the old-style + importer hooks are present -- by :user:`webknjaz` + +Documentation changes +^^^^^^^^^^^^^^^^^^^^^ +* #2620: Added documentation for the ``license_files`` option. -- by :user:`cdce8p` + + v55.0.0 ------- diff --git a/docs/pkg_resources.rst b/docs/pkg_resources.rst index 19d4324..994bea6 100644 --- a/docs/pkg_resources.rst +++ b/docs/pkg_resources.rst @@ -10,6 +10,13 @@ eggs, support for merging packages that have separately-distributed modules or subpackages, and APIs for managing Python's current "working set" of active packages. +Use of ``pkg_resources`` is discouraged in favor of +`importlib.resources `_, +`importlib.metadata `_, +and their backports (`resources `_, +`metadata `_). +Please consider using those libraries instead of pkg_resources. + .. contents:: **Table of Contents** diff --git a/docs/references/keywords.rst b/docs/references/keywords.rst index 03ce9fa..619b2d1 100644 --- a/docs/references/keywords.rst +++ b/docs/references/keywords.rst @@ -76,6 +76,17 @@ Keywords ``license`` A string specifying the license of the package. +``license_file`` + + .. warning:: + ``license_file`` is deprecated. Use ``license_files`` instead. + +``license_files`` + + A list of glob patterns for license related files that should be included. + If neither ``license_file`` nor ``license_files`` is specified, this option + defaults to ``LICEN[CS]E*``, ``COPYING*``, ``NOTICE*``, and ``AUTHORS*``. + ``keywords`` A list of strings or a comma-separated string providing descriptive meta-data. See: `PEP 0314`_. diff --git a/docs/userguide/declarative_config.rst b/docs/userguide/declarative_config.rst index f2e8b81..7c97ca1 100644 --- a/docs/userguide/declarative_config.rst +++ b/docs/userguide/declarative_config.rst @@ -184,7 +184,7 @@ maintainer_email maintainer-email str classifiers classifier file:, list-comma license str license_file str -license_files list-comma +license_files list-comma 42.0.0 description summary file:, str long_description long-description file:, str long_description_content_type str 38.6.0 diff --git a/docs/userguide/dependency_management.rst b/docs/userguide/dependency_management.rst index 6108d9b..188083e 100644 --- a/docs/userguide/dependency_management.rst +++ b/docs/userguide/dependency_management.rst @@ -3,7 +3,7 @@ Dependencies Management in Setuptools ===================================== There are three types of dependency styles offered by setuptools: -1) build system requirement, required dependency and 3) optional +1) build system requirement, 2) required dependency and 3) optional dependency. .. Note:: @@ -19,8 +19,8 @@ Build system requirement Package requirement ------------------- After organizing all the scripts and files and getting ready for packaging, -there needs to be a way to tell Python what programs it need to actually -do the packgaging (in our case, ``setuptools`` of course). Usually, +there needs to be a way to tell Python what programs it needs to actually +do the packaging (in our case, ``setuptools`` of course). Usually, you also need the ``wheel`` package as well since it is recommended that you upload a ``.whl`` file to PyPI alongside your ``.tar.gz`` file. Unlike the other two types of dependency keyword, this one is specified in your @@ -47,7 +47,7 @@ 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 these dependencies when the package is installed. Although there is more -finess to it, let's start with a simple example. +finesse to it, let's start with a simple example. .. tab:: setup.cfg diff --git a/docs/userguide/quickstart.rst b/docs/userguide/quickstart.rst index 7f111dd..2807f59 100644 --- a/docs/userguide/quickstart.rst +++ b/docs/userguide/quickstart.rst @@ -62,7 +62,7 @@ the minimum from setuptools import setup setup( - name='mypackage"' + name='mypackage', version='0.0.1', packages=['mypackage'], install_requires=[ diff --git a/pkg_resources/extern/__init__.py b/pkg_resources/extern/__init__.py index 1fbb4fc..fed5929 100644 --- a/pkg_resources/extern/__init__.py +++ b/pkg_resources/extern/__init__.py @@ -1,3 +1,4 @@ +import importlib.util import sys @@ -20,17 +21,10 @@ class VendorImporter: yield self.vendor_pkg + '.' yield '' - def find_module(self, fullname, path=None): - """ - Return self when fullname starts with root_name and the - target module is one vendored through this importer. - """ + def _module_matches_namespace(self, fullname): + """Figure out if the target module is vendored.""" root, base, target = fullname.partition(self.root_name + '.') - if root: - return - if not any(map(target.startswith, self.vendored_names)): - return - return self + return not root and any(map(target.startswith, self.vendored_names)) def load_module(self, fullname): """ @@ -60,6 +54,13 @@ class VendorImporter: def exec_module(self, module): pass + def find_spec(self, fullname, path=None, target=None): + """Return a module spec for vendored names.""" + return ( + importlib.util.spec_from_loader(fullname, self) + if self._module_matches_namespace(fullname) else None + ) + def install(self): """ Install this importer into sys.meta_path if not already present. diff --git a/setup.cfg b/setup.cfg index 6bb6508..ebdc2c6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,7 +2,7 @@ license_files = LICENSE name = setuptools -version = 55.0.0 +version = 56.0.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/command/sdist.py b/setuptools/command/sdist.py index 887b7ef..a6ea814 100644 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -4,6 +4,7 @@ import os import sys import io import contextlib +from glob import iglob from setuptools.extern import ordered_set @@ -194,29 +195,41 @@ class sdist(sdist_add_defaults, orig.sdist): """Checks if license_file' or 'license_files' is configured and adds any valid paths to 'self.filelist'. """ - - files = ordered_set.OrderedSet() - opts = self.distribution.get_option_dict('metadata') - # ignore the source of the value - _, license_file = opts.get('license_file', (None, None)) - - if license_file is None: - log.debug("'license_file' option was not specified") - else: - files.add(license_file) - + files = ordered_set.OrderedSet() try: - files.update(self.distribution.metadata.license_files) + license_files = self.distribution.metadata.license_files except TypeError: log.warn("warning: 'license_files' option is malformed") - - for f in files: - if not os.path.exists(f): - log.warn( - "warning: Failed to find the configured license file '%s'", - f) - files.remove(f) - - self.filelist.extend(files) + license_files = ordered_set.OrderedSet() + patterns = license_files if isinstance(license_files, ordered_set.OrderedSet) \ + else ordered_set.OrderedSet(license_files) + + if 'license_file' in opts: + log.warn( + "warning: the 'license_file' option is deprecated, " + "use 'license_files' instead") + patterns.append(opts['license_file'][1]) + + if 'license_file' not in opts and 'license_files' not in opts: + # Default patterns match the ones wheel uses + # See https://wheel.readthedocs.io/en/stable/user_guide.html + # -> 'Including license files in the generated wheel file' + patterns = ('LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*') + + for pattern in patterns: + for path in iglob(pattern): + if path.endswith('~'): + log.debug( + "ignoring license file '%s' as it looks like a backup", + path) + continue + + if path not in files and os.path.isfile(path): + log.info( + "adding license file '%s' (matched pattern '%s')", + path, pattern) + files.add(path) + + self.filelist.extend(sorted(files)) diff --git a/setuptools/extern/__init__.py b/setuptools/extern/__init__.py index 399701a..7df32fd 100644 --- a/setuptools/extern/__init__.py +++ b/setuptools/extern/__init__.py @@ -1,3 +1,4 @@ +import importlib.util import sys @@ -20,17 +21,10 @@ class VendorImporter: yield self.vendor_pkg + '.' yield '' - def find_module(self, fullname, path=None): - """ - Return self when fullname starts with root_name and the - target module is one vendored through this importer. - """ + def _module_matches_namespace(self, fullname): + """Figure out if the target module is vendored.""" root, base, target = fullname.partition(self.root_name + '.') - if root: - return - if not any(map(target.startswith, self.vendored_names)): - return - return self + return not root and any(map(target.startswith, self.vendored_names)) def load_module(self, fullname): """ @@ -60,6 +54,13 @@ class VendorImporter: def exec_module(self, module): pass + def find_spec(self, fullname, path=None, target=None): + """Return a module spec for vendored names.""" + return ( + importlib.util.spec_from_loader(fullname, self) + if self._module_matches_namespace(fullname) else None + ) + def install(self): """ Install this importer into sys.meta_path if not already present. diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py index bf95b03..80d3577 100644 --- a/setuptools/tests/test_egg_info.py +++ b/setuptools/tests/test_egg_info.py @@ -537,7 +537,7 @@ class TestEggInfo: 'setup.cfg': DALS(""" """), 'LICENSE': "Test license" - }, False), # no license_file attribute + }, True), # no license_file attribute, LICENSE auto-included ({ 'setup.cfg': DALS(""" [metadata] @@ -545,7 +545,15 @@ class TestEggInfo: """), 'MANIFEST.in': "exclude LICENSE", 'LICENSE': "Test license" - }, False) # license file is manually excluded + }, False), # license file is manually excluded + pytest.param({ + 'setup.cfg': DALS(""" + [metadata] + license_file = LICEN[CS]E* + """), + 'LICENSE': "Test license", + }, True, + id="glob_pattern"), ]) def test_setup_cfg_license_file( self, tmpdir_cwd, env, files, license_in_sources): @@ -625,7 +633,7 @@ class TestEggInfo: 'setup.cfg': DALS(""" """), 'LICENSE': "Test license" - }, [], ['LICENSE']), # no license_files attribute + }, ['LICENSE'], []), # no license_files attribute, LICENSE auto-included ({ 'setup.cfg': DALS(""" [metadata] @@ -644,7 +652,36 @@ class TestEggInfo: 'MANIFEST.in': "exclude LICENSE-XYZ", 'LICENSE-ABC': "ABC license", 'LICENSE-XYZ': "XYZ license" - }, ['LICENSE-ABC'], ['LICENSE-XYZ']) # subset is manually excluded + }, ['LICENSE-ABC'], ['LICENSE-XYZ']), # subset is manually excluded + pytest.param({ + 'setup.cfg': "", + 'LICENSE-ABC': "ABC license", + 'COPYING-ABC': "ABC copying", + 'NOTICE-ABC': "ABC notice", + 'AUTHORS-ABC': "ABC authors", + 'LICENCE-XYZ': "XYZ license", + 'LICENSE': "License", + 'INVALID-LICENSE': "Invalid license", + }, [ + 'LICENSE-ABC', + 'COPYING-ABC', + 'NOTICE-ABC', + 'AUTHORS-ABC', + 'LICENCE-XYZ', + 'LICENSE', + ], ['INVALID-LICENSE'], + # ('LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*') + id="default_glob_patterns"), + pytest.param({ + 'setup.cfg': DALS(""" + [metadata] + license_files = + LICENSE* + """), + 'LICENSE-ABC': "ABC license", + 'NOTICE-XYZ': "XYZ notice", + }, ['LICENSE-ABC'], ['NOTICE-XYZ'], + id="no_default_glob_patterns"), ]) def test_setup_cfg_license_files( self, tmpdir_cwd, env, files, incl_licenses, excl_licenses): @@ -749,7 +786,28 @@ class TestEggInfo: 'LICENSE-PQR': "PQR license", 'LICENSE-XYZ': "XYZ license" # manually excluded - }, ['LICENSE-XYZ'], ['LICENSE-ABC', 'LICENSE-PQR']) + }, ['LICENSE-XYZ'], ['LICENSE-ABC', 'LICENSE-PQR']), + pytest.param({ + 'setup.cfg': DALS(""" + [metadata] + license_file = LICENSE* + """), + 'LICENSE-ABC': "ABC license", + 'NOTICE-XYZ': "XYZ notice", + }, ['LICENSE-ABC'], ['NOTICE-XYZ'], + id="no_default_glob_patterns"), + pytest.param({ + 'setup.cfg': DALS(""" + [metadata] + license_file = LICENSE* + license_files = + NOTICE* + """), + 'LICENSE-ABC': "ABC license", + 'NOTICE-ABC': "ABC notice", + 'AUTHORS-ABC': "ABC authors", + }, ['LICENSE-ABC', 'NOTICE-ABC'], ['AUTHORS-ABC'], + id="combined_glob_patterrns"), ]) def test_setup_cfg_license_file_license_files( self, tmpdir_cwd, env, files, incl_licenses, excl_licenses): diff --git a/setuptools/tests/test_manifest.py b/setuptools/tests/test_manifest.py index 82bdb9c..589cefb 100644 --- a/setuptools/tests/test_manifest.py +++ b/setuptools/tests/test_manifest.py @@ -55,6 +55,7 @@ def touch(filename): default_files = frozenset(map(make_local_path, [ 'README.rst', 'MANIFEST.in', + 'LICENSE', 'setup.py', 'app.egg-info/PKG-INFO', 'app.egg-info/SOURCES.txt', diff --git a/setuptools/tests/test_virtualenv.py b/setuptools/tests/test_virtualenv.py index 9cf6d30..399dbaf 100644 --- a/setuptools/tests/test_virtualenv.py +++ b/setuptools/tests/test_virtualenv.py @@ -85,7 +85,7 @@ def _get_pip_versions(): mark('pip==18.1', issue2599), mark('pip==19.3.1', pytest.mark.xfail(reason='pypa/pip#6599')), 'pip==20.0.2', - 'https://github.com/pypa/pip/archive/master.zip', + 'https://github.com/pypa/pip/archive/main.zip', ] versions = itertools.chain( -- 2.34.1