From 749b97499ea36d9a7660ed73db622837ae64c57d Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Sun, 28 Mar 2021 13:37:48 +0200 Subject: [PATCH 1/5] license_files - Add support for glob patterns + add default patterns --- setuptools/command/sdist.py | 53 +++++++++++++++++++------------ setuptools/tests/test_egg_info.py | 4 +-- setuptools/tests/test_manifest.py | 1 + 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index 887b7efa05..cd308ab9dd 100644 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -4,6 +4,8 @@ import sys import io import contextlib +import warnings +from glob import iglob from setuptools.extern import ordered_set @@ -194,29 +196,38 @@ def check_license(self): """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: + warnings.warn( + "The 'license_file' option is deprecated. Use 'license_files' instead.", + DeprecationWarning) + patterns.append(opts['license_file'][1]) + + if 'license_file' not in opts and 'license_files' not in opts: + 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/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py index bf95b03ce6..4915c0cb40 100644 --- a/setuptools/tests/test_egg_info.py +++ b/setuptools/tests/test_egg_info.py @@ -537,7 +537,7 @@ def test_doesnt_provides_extra(self, tmpdir_cwd, env): 'setup.cfg': DALS(""" """), 'LICENSE': "Test license" - }, False), # no license_file attribute + }, True), # no license_file attribute, LICENSE auto-included ({ 'setup.cfg': DALS(""" [metadata] @@ -625,7 +625,7 @@ def test_setup_cfg_license_file( 'setup.cfg': DALS(""" """), 'LICENSE': "Test license" - }, [], ['LICENSE']), # no license_files attribute + }, ['LICENSE'], []), # no license_files attribute, LICENSE auto-included ({ 'setup.cfg': DALS(""" [metadata] diff --git a/setuptools/tests/test_manifest.py b/setuptools/tests/test_manifest.py index 82bdb9c643..589cefb2c0 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', From 91e7956d961ef84080c30eb5253c220fa3b001dc Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Sun, 28 Mar 2021 13:39:35 +0200 Subject: [PATCH 2/5] Add documentation + changelog entries --- changelog.d/2620.breaking.rst | 5 +++++ changelog.d/2620.change.rst | 1 + changelog.d/2620.deprecation.rst | 2 ++ changelog.d/2620.doc.rst | 1 + docs/references/keywords.rst | 12 ++++++++++++ docs/userguide/declarative_config.rst | 2 +- 6 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 changelog.d/2620.breaking.rst create mode 100644 changelog.d/2620.change.rst create mode 100644 changelog.d/2620.deprecation.rst create mode 100644 changelog.d/2620.doc.rst diff --git a/changelog.d/2620.breaking.rst b/changelog.d/2620.breaking.rst new file mode 100644 index 0000000000..de91facc57 --- /dev/null +++ b/changelog.d/2620.breaking.rst @@ -0,0 +1,5 @@ +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``. +Any ``exclude`` in ``MANIFEST.in`` will overwrite it. -- by :user:`cdce8p` diff --git a/changelog.d/2620.change.rst b/changelog.d/2620.change.rst new file mode 100644 index 0000000000..5470592d17 --- /dev/null +++ b/changelog.d/2620.change.rst @@ -0,0 +1 @@ +The ``license_file`` and ``license_files`` options now support glob patterns. -- by :user:`cdce8p` diff --git a/changelog.d/2620.deprecation.rst b/changelog.d/2620.deprecation.rst new file mode 100644 index 0000000000..1af5f2461a --- /dev/null +++ b/changelog.d/2620.deprecation.rst @@ -0,0 +1,2 @@ +The ``license_file`` option is now marked as deprecated. +Use ``license_files`` instead. -- by :user:`cdce8p` diff --git a/changelog.d/2620.doc.rst b/changelog.d/2620.doc.rst new file mode 100644 index 0000000000..7564adaca4 --- /dev/null +++ b/changelog.d/2620.doc.rst @@ -0,0 +1 @@ +Added documentation for the ``license_files`` option. -- by :user:`cdce8p` diff --git a/docs/references/keywords.rst b/docs/references/keywords.rst index 03ce9fa23a..6485437b84 100644 --- a/docs/references/keywords.rst +++ b/docs/references/keywords.rst @@ -76,6 +76,18 @@ 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*``. + Any ``exclude`` specified in ``MANIFEST.in`` will overwrite it. + ``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 f2e8b81f75..7c97ca1cfa 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 From 1da769c049093b6492b63422272f56b6e95df39d Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Sun, 28 Mar 2021 14:32:52 +0200 Subject: [PATCH 3/5] Additional test cases --- setuptools/tests/test_egg_info.py | 65 +++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py index 4915c0cb40..4751d1b553 100644 --- a/setuptools/tests/test_egg_info.py +++ b/setuptools/tests/test_egg_info.py @@ -545,7 +545,15 @@ def test_doesnt_provides_extra(self, tmpdir_cwd, env): """), '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): @@ -644,7 +652,37 @@ def test_setup_cfg_license_file( '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': DALS(""" + """), + '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 +787,28 @@ def test_setup_cfg_license_files( '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): From 0f34639e5aa630b8cbe32af9cfe8dfec7be890e7 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Sun, 28 Mar 2021 17:34:01 +0200 Subject: [PATCH 4/5] Change deprecation warning --- setuptools/command/sdist.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index cd308ab9dd..278b8ce0b6 100644 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -4,7 +4,6 @@ import sys import io import contextlib -import warnings from glob import iglob from setuptools.extern import ordered_set @@ -208,9 +207,9 @@ def check_license(self): else ordered_set.OrderedSet(license_files) if 'license_file' in opts: - warnings.warn( - "The 'license_file' option is deprecated. Use 'license_files' instead.", - DeprecationWarning) + 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: From 608c376e86326c879dd52b56660b2247a3ca854e Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Sat, 3 Apr 2021 21:34:00 +0200 Subject: [PATCH 5/5] Small changes --- changelog.d/2620.breaking.rst | 3 +-- docs/references/keywords.rst | 1 - setuptools/command/sdist.py | 3 +++ setuptools/tests/test_egg_info.py | 3 +-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/changelog.d/2620.breaking.rst b/changelog.d/2620.breaking.rst index de91facc57..431e7105d9 100644 --- a/changelog.d/2620.breaking.rst +++ b/changelog.d/2620.breaking.rst @@ -1,5 +1,4 @@ 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``. -Any ``exclude`` in ``MANIFEST.in`` will overwrite it. -- by :user:`cdce8p` +This matches the behavior of ``bdist_wheel``. -- by :user:`cdce8p` diff --git a/docs/references/keywords.rst b/docs/references/keywords.rst index 6485437b84..619b2d1493 100644 --- a/docs/references/keywords.rst +++ b/docs/references/keywords.rst @@ -86,7 +86,6 @@ Keywords 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*``. - Any ``exclude`` specified in ``MANIFEST.in`` will overwrite it. ``keywords`` A list of strings or a comma-separated string providing descriptive diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index 278b8ce0b6..a6ea814a30 100644 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -213,6 +213,9 @@ def check_license(self): 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: diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py index 4751d1b553..80d3577424 100644 --- a/setuptools/tests/test_egg_info.py +++ b/setuptools/tests/test_egg_info.py @@ -654,8 +654,7 @@ def test_setup_cfg_license_file( 'LICENSE-XYZ': "XYZ license" }, ['LICENSE-ABC'], ['LICENSE-XYZ']), # subset is manually excluded pytest.param({ - 'setup.cfg': DALS(""" - """), + 'setup.cfg': "", 'LICENSE-ABC': "ABC license", 'COPYING-ABC': "ABC copying", 'NOTICE-ABC': "ABC notice",