Skip to content

Commit 2704faf

Browse files
committed
Add initial support for license-files
1 parent 7cc7d33 commit 2704faf

File tree

13 files changed

+176
-5
lines changed

13 files changed

+176
-5
lines changed

doc/pyproject_toml.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ requires-python
9898
license
9999
A table with either a ``file`` key (a relative path to a license file) or a
100100
``text`` key (the license text).
101+
license-files
102+
A list of glob patterns for license files to include. Defaults to ``['COPYING*', 'LICENSE*']``.
101103
authors
102104
A list of tables with ``name`` and ``email`` keys (both optional) describing
103105
the authors of the project.

flit_core/flit_core/common.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ class Metadata(object):
354354
obsoletes_dist = ()
355355
requires_external = ()
356356
provides_extra = ()
357+
license_files = ()
357358
dynamic = ()
358359

359360
metadata_version = "2.3"
@@ -425,6 +426,10 @@ def write_metadata_file(self, fp):
425426
for clsfr in self.classifiers:
426427
fp.write(u'Classifier: {}\n'.format(clsfr))
427428

429+
# TODO: License-File requires Metadata-Version '2.4'
430+
# for file in self.license_files:
431+
# fp.write(u'License-File: {}\n'.format(file))
432+
428433
for req in self.requires_dist:
429434
normalised_req = self._normalise_requires_dist(req)
430435
fp.write(u'Requires-Dist: {}\n'.format(normalised_req))

flit_core/flit_core/config.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class ConfigError(ValueError):
6060
'readme',
6161
'requires-python',
6262
'license',
63+
'license-files',
6364
'authors',
6465
'maintainers',
6566
'keywords',
@@ -73,6 +74,8 @@ class ConfigError(ValueError):
7374
'dynamic',
7475
}
7576

77+
default_license_files_globs = ['COPYING*', 'LICENSE*']
78+
7679

7780
def read_flit_config(path):
7881
"""Read and check the `pyproject.toml` file with data about the package.
@@ -427,6 +430,13 @@ def _prep_metadata(md_sect, path):
427430
# For internal use, record the main requirements as a '.none' extra.
428431
res.reqs_by_extra['.none'] = reqs_noextra
429432

433+
if path:
434+
license_files = _license_files_from_globs(
435+
path.parent, default_license_files_globs, use_defaults=True
436+
)
437+
res.referenced_files.extend(license_files)
438+
md_dict['license_files'] = license_files
439+
430440
return res
431441

432442
def _expand_requires_extra(re):
@@ -439,6 +449,37 @@ def _expand_requires_extra(re):
439449
yield '{} ; extra == "{}"'.format(req, extra)
440450

441451

452+
def _license_files_from_globs(project_dir: Path, globs, use_defaults = False):
453+
license_files = []
454+
for pattern in globs:
455+
if pattern.startswith("/"):
456+
raise ConfigError(
457+
"Invalid glob pattern for [project.license-files]: '{}'. "
458+
"Pattern must not start with '/'.".format(pattern)
459+
)
460+
if ".." in pattern:
461+
raise ConfigError(
462+
"Invalid glob pattern for [project.license-files]: '{}'. "
463+
"Pattern must not contain '..'".format(pattern)
464+
)
465+
try:
466+
files = [
467+
str(file.relative_to(project_dir)).replace(osp.sep, "/")
468+
for file in project_dir.glob(pattern)
469+
if file.is_file()
470+
]
471+
except ValueError as ex:
472+
raise ConfigError(
473+
"Invalid glob pattern for [project.license-files]: '{}'. {}".format(pattern, ex.args[0])
474+
)
475+
476+
if not files and not use_defaults:
477+
raise ConfigError(
478+
"No files found for [project.license-files]: '{}' pattern".format(pattern)
479+
)
480+
license_files.extend(files)
481+
return sorted(license_files)
482+
442483
def _check_type(d, field_name, cls):
443484
if not isinstance(d[field_name], cls):
444485
raise ConfigError(
@@ -551,6 +592,18 @@ def read_pep621_metadata(proj, path) -> LoadedConfig:
551592
"file or text field required in [project.license] table"
552593
)
553594

595+
license_files = []
596+
if 'license-files' in proj:
597+
_check_type(proj, 'license-files', list)
598+
globs = proj['license-files']
599+
license_files = _license_files_from_globs(path.parent, globs)
600+
else:
601+
license_files = _license_files_from_globs(
602+
path.parent, default_license_files_globs, use_defaults=True
603+
)
604+
lc.referenced_files.extend(license_files)
605+
md_dict['license_files'] = license_files
606+
554607
if 'authors' in proj:
555608
_check_type(proj, 'authors', list)
556609
md_dict.update(pep621_people(proj['authors']))

flit_core/flit_core/wheel.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,8 @@ def write_metadata(self):
183183
with self._write_to_zip(self.dist_info + '/entry_points.txt') as f:
184184
common.write_entry_points(self.entrypoints, f)
185185

186-
for base in ('COPYING', 'LICENSE'):
187-
for path in sorted(self.directory.glob(base + '*')):
188-
if path.is_file():
189-
self._add_file(path, '%s/%s' % (self.dist_info, path.name))
186+
for file in self.metadata.license_files:
187+
self._add_file(self.directory / file, '%s/licenses/%s' % (self.dist_info, file))
190188

191189
with self._write_to_zip(self.dist_info + '/WHEEL') as f:
192190
_write_wheel_file(f, supports_py2=self.metadata.supports_py2)

flit_core/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ dependencies = []
1313
requires-python = '>=3.6'
1414
readme = "README.rst"
1515
license = {file = "LICENSE"}
16+
license-files = ["LICENSE*", "flit_core/vendor/**/LICENSE*"]
1617
classifiers = [
1718
"License :: OSI Approved :: BSD License",
1819
"Topic :: Software Development :: Libraries :: Python Modules",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This file should be added to wheels
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Readme
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This file should be added to wheels
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Example module"""
2+
3+
__version__ = '0.1'
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
[build-system]
2+
requires = ["flit_core >=3.2,<4"]
3+
build-backend = "flit_core.buildapi"
4+
5+
[project]
6+
name = "module1"
7+
authors = [
8+
{name = "Sir Röbin", email = "robin@camelot.uk"}
9+
]
10+
maintainers = [
11+
{name = "Sir Galahad"}
12+
]
13+
readme = "README.rst"
14+
license-files = ["**/LICENSE*"]
15+
requires-python = ">=3.7"
16+
dependencies = [
17+
"requests >= 2.18",
18+
"docutils",
19+
]
20+
keywords = ["example", "test"]
21+
dynamic = [
22+
"version",
23+
"description",
24+
]
25+
26+
[project.optional-dependencies]
27+
test = [
28+
"pytest",
29+
"mock; python_version<'3.6'"
30+
]
31+
32+
[project.urls]
33+
homepage = "http://github.com/sirrobin/module1"
34+
35+
[project.entry-points.flit_test_example]
36+
foo = "module1:main"
37+
38+
[tool.flit.module]
39+
name = "module1a"

0 commit comments

Comments
 (0)