Skip to content

Commit

Permalink
license_files - Add support for glob patterns + add default patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
cdce8p authored and hroncok committed Jan 12, 2022
1 parent c121d28 commit 490a2b2
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 27 deletions.
4 changes: 4 additions & 0 deletions changelog.d/2620.breaking.rst
Original file line number Diff line number Diff line change
@@ -0,0 +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``. -- by :user:`cdce8p`
1 change: 1 addition & 0 deletions changelog.d/2620.change.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The ``license_file`` and ``license_files`` options now support glob patterns. -- by :user:`cdce8p`
2 changes: 2 additions & 0 deletions changelog.d/2620.deprecation.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The ``license_file`` option is now marked as deprecated.
Use ``license_files`` instead. -- by :user:`cdce8p`
1 change: 1 addition & 0 deletions changelog.d/2620.doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added documentation for the ``license_files`` option. -- by :user:`cdce8p`
11 changes: 11 additions & 0 deletions docs/references/keywords.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`_.
Expand Down
2 changes: 1 addition & 1 deletion docs/userguide/declarative_config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
55 changes: 34 additions & 21 deletions setuptools/command/sdist.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import sys
import io
import contextlib
from glob import iglob

from setuptools.extern import ordered_set

Expand Down Expand Up @@ -194,29 +195,41 @@ 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:
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))
68 changes: 63 additions & 5 deletions setuptools/tests/test_egg_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,15 +533,23 @@ 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]
license_file = LICENSE
"""),
'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):
Expand Down Expand Up @@ -621,7 +629,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]
Expand All @@ -640,7 +648,36 @@ 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': "",
'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):
Expand Down Expand Up @@ -745,7 +782,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):
Expand Down
1 change: 1 addition & 0 deletions setuptools/tests/test_manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down

0 comments on commit 490a2b2

Please sign in to comment.