Imported Upstream version 56.0.0 upstream/56.0.0
authorJinWang An <jinwang.an@samsung.com>
Mon, 27 Mar 2023 08:02:33 +0000 (17:02 +0900)
committerJinWang An <jinwang.an@samsung.com>
Mon, 27 Mar 2023 08:02:33 +0000 (17:02 +0900)
14 files changed:
.bumpversion.cfg
CHANGES.rst
docs/pkg_resources.rst
docs/references/keywords.rst
docs/userguide/declarative_config.rst
docs/userguide/dependency_management.rst
docs/userguide/quickstart.rst
pkg_resources/extern/__init__.py
setup.cfg
setuptools/command/sdist.py
setuptools/extern/__init__.py
setuptools/tests/test_egg_info.py
setuptools/tests/test_manifest.py
setuptools/tests/test_virtualenv.py

index 7fe611a698da7b1380b57a091036eef29866c713..dd76f43d91381b440a34302ce5eab6d86e92043d 100644 (file)
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 55.0.0
+current_version = 56.0.0
 commit = True
 tag = True
 
index d073fa8ef3f8b9f5fca717b7b27767f5e612d6dd..ef1d926b1540d985fc827617a0e47801f72a29fe 100644 (file)
@@ -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
 -------
 
index 19d43244d1b4edd63a069796a50a307f0e29a02e..994bea6f2bbf7bf7f818af79c91b457008e5f6b2 100644 (file)
@@ -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 <https://docs.python.org/3/library/importlib.html#module-importlib.resources>`_,
+`importlib.metadata <https://docs.python.org/3/library/importlib.metadata.html>`_,
+and their backports (`resources <https://pypi.org/project/importlib_resources>`_,
+`metadata <https://pypi.org/project/importlib_metadata>`_).
+Please consider using those libraries instead of pkg_resources.
+
 
 .. contents:: **Table of Contents**
 
index 03ce9fa23a4e6f8630515e86fa539fbece95feeb..619b2d149348ca32b59fbaf810f799803ee7b4f2 100644 (file)
@@ -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`_.
index f2e8b81f75572749d33462514ede853670164c42..7c97ca1cfa040d67df45aa191fd494b8e5694e83 100644 (file)
@@ -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
index 6108d9b2e99074b0e778c8ffc1a2ba6a3071e009..188083e0fb892c26994520babf45811f8b93bc06 100644 (file)
@@ -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
 
index 7f111dd57517904b5f60c9dc0d6c514ea44726b8..2807f59bee9c3cdc1aa1c5194723826b036a7a92 100644 (file)
@@ -62,7 +62,7 @@ the minimum
         from setuptools import setup
 
         setup(
-            name='mypackage"'
+            name='mypackage',
             version='0.0.1',
             packages=['mypackage'],
             install_requires=[
index 1fbb4fcc896a4e3c3eff795c6ed77d2c4e6d0a55..fed59295403b80b1711d0d189ff97dde22808690 100644 (file)
@@ -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.
index 6bb6508f8bf16b84e67496c9b7646f3dfbdeb43e..ebdc2c638c8f0336334f1b76e4281a89746d4132 100644 (file)
--- 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
index 887b7efa0522be4c51d50416d7149669dc24550d..a6ea814a30bd5ab61f150d3151df41853850b769 100644 (file)
@@ -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))
index 399701a044e31b9677aae265ac04b08ef9334302..7df32fdea241d3734f159f17ff5ade49810bdce5 100644 (file)
@@ -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.
index bf95b03ce66af944d71358ae31f290b38aae80a5..80d35774249cd8cadf290ac73290c6fa65d360bd 100644 (file)
@@ -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):
index 82bdb9c64321d53e594176c2e6354ffe364b21af..589cefb2c015e2f7679e1384d3fe5e6405b7304f 100644 (file)
@@ -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',
index 9cf6d30f7dd6c219bc356ddf05c8c44c432cf71b..399dbaf0bbec0f838f7246f9caecf09c971857a0 100644 (file)
@@ -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(