Skip to content

Commit ecf3c22

Browse files
authored
fix: add License-file metadata entry (#329)
Fix #328. --------- Signed-off-by: Henry Schreiner <[email protected]>
1 parent 27a9d62 commit ecf3c22

File tree

7 files changed

+50
-26
lines changed

7 files changed

+50
-26
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ wheel.expand-macos-universal-tags = false
169169
wheel.install-dir = "."
170170

171171
# The licence file(s) to include in the wheel metadata directory.
172-
wheel.license-files = ["LICENSE*", "COPYING*", "COPYRIGHT*"]
172+
wheel.license-files = ["LICEN[CS]E*", "COPYING*", "NOTICE*", "AUTHORS*"]
173173

174174
# This will backport an internal copy of FindPython if CMake is less than this
175175
# value. Set to 0 or the empty string to disable. The default will be kept in

docs/configuration.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,10 @@ for now.
177177

178178
:::
179179

180-
By default, any `LICENSE*`, `COPYING*`, or `COPYRIGHT*` file in the root of the
181-
build directory will be picked up. You can specify an exact list of files if you
182-
prefer, or if you your license file is in a different directory. The files must
183-
have unique names. Globbing patterns are supported.
180+
By default, any `LICEN[CS]E*`, `COPYING*`, `NOTICE*`, or `AUTHORS*` file in the
181+
root of the build directory will be picked up. You can specify an exact list of
182+
files if you prefer, or if your license file is in a different directory.
183+
Globbing patterns are supported.
184184

185185
```toml
186186
[tool.scikit-build]

src/scikit_build_core/build/_wheelfile.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import stat
1111
import time
1212
import zipfile
13-
from collections.abc import Set
13+
from collections.abc import Mapping, Set
1414
from email.message import Message
1515
from email.policy import EmailPolicy
1616
from pathlib import Path, PurePosixPath
@@ -73,6 +73,7 @@ class WheelWriter:
7373
wheel_metadata = WheelMetadata(root_is_purelib=False)
7474
buildver: str = ""
7575
zipfile: zipfile.ZipFile | None = None
76+
license_files: Mapping[Path, bytes] = dataclasses.field(default_factory=dict)
7677

7778
@property
7879
def name_ver(self) -> str:
@@ -117,12 +118,22 @@ def dist_info_contents(self) -> dict[str, bytes]:
117118
entry_points.write("\n")
118119

119120
self.wheel_metadata.tags = self.tags
121+
120122
# Using deepcopy here because of a bug in pyproject-metadata
121123
# https://github.com/FFY00/python-pyproject-metadata/pull/49
124+
rfc822 = copy.deepcopy(self.metadata).as_rfc822()
125+
for fp in self.license_files:
126+
rfc822["License-File"] = f"{fp}"
127+
128+
license_entries = {
129+
f"licenses/{fp}": data for fp, data in self.license_files.items()
130+
}
131+
122132
return {
123-
"METADATA": bytes(copy.deepcopy(self.metadata).as_rfc822()),
133+
"METADATA": bytes(rfc822),
124134
"WHEEL": self.wheel_metadata.as_bytes(),
125135
"entry_points.txt": entry_points.getvalue().encode("utf-8"),
136+
**license_entries,
126137
}
127138

128139
def build(self, wheel_dirs: dict[str, Path]) -> None:

src/scikit_build_core/build/wheel.py

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

33
import dataclasses
4-
import glob
54
import os
65
import shutil
76
import sys
@@ -146,6 +145,16 @@ def _build_wheel_impl(
146145
else:
147146
install_dir = wheel_dirs["platlib"] / settings.wheel.install_dir
148147

148+
license_files = {
149+
x: x.read_bytes()
150+
for y in settings.wheel.license_files
151+
for x in Path().glob(y)
152+
}
153+
if settings.wheel.license_files and not license_files:
154+
logger.warning(
155+
"No license files found, set wheel.license-files to [] to suppress this warning"
156+
)
157+
149158
config = CMaker(
150159
cmake,
151160
source_dir=Path(settings.cmake.source_dir or "."),
@@ -162,12 +171,19 @@ def _build_wheel_impl(
162171
if metadata_directory is None:
163172
msg = "metadata_directory must be specified if wheel_directory is None"
164173
raise AssertionError(msg)
165-
wheel = WheelWriter(metadata, Path(metadata_directory), tags.as_tags_set())
174+
wheel = WheelWriter(
175+
metadata,
176+
Path(metadata_directory),
177+
tags.as_tags_set(),
178+
license_files=license_files,
179+
)
166180
dist_info_contents = wheel.dist_info_contents()
167181
dist_info = Path(metadata_directory) / f"{wheel.name_ver}.dist-info"
168182
dist_info.mkdir(parents=True)
169183
for key, data in dist_info_contents.items():
170184
path = dist_info / key
185+
if not path.parent.is_dir():
186+
path.parent.mkdir(exist_ok=True, parents=True)
171187
path.write_bytes(data)
172188
return WheelImplReturn(wheel_filename=dist_info.name)
173189

@@ -215,22 +231,13 @@ def _build_wheel_impl(
215231

216232
process_script_dir(wheel_dirs["scripts"])
217233

218-
license_files = [
219-
Path(x)
220-
for y in settings.wheel.license_files
221-
for x in glob.glob(y, recursive=True)
222-
]
223-
if settings.wheel.license_files and not license_files:
224-
logger.warning(
225-
"No license files found, set wheel.license-files to [] to suppress this warning"
226-
)
227-
228-
with WheelWriter(metadata, Path(wheel_directory), tags.as_tags_set()) as wheel:
234+
with WheelWriter(
235+
metadata,
236+
Path(wheel_directory),
237+
tags.as_tags_set(),
238+
license_files=license_files,
239+
) as wheel:
229240
wheel.build(wheel_dirs)
230-
for license_file in license_files:
231-
wheel.write(
232-
str(license_file), f"{wheel.dist_info}/licenses/{license_file.name}"
233-
)
234241

235242
if editable:
236243
modules = {

src/scikit_build_core/settings/skbuild_model.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class WheelSettings:
100100

101101
#: A list of license files to include in the wheel. Supports glob patterns.
102102
license_files: List[str] = dataclasses.field(
103-
default_factory=lambda: ["LICENSE*", "COPYING*", "COPYRIGHT*"]
103+
default_factory=lambda: ["LICEN[CS]E*", "COPYING*", "NOTICE*", "AUTHORS*"]
104104
)
105105

106106

tests/test_pyproject_pep517.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ def test_prepare_metdata_for_build_wheel():
273273
"Requires-Python": ">=3.7",
274274
"Provides-Extra": "test",
275275
"Requires-Dist": 'pytest>=6.0; extra == "test"',
276+
"License-File": "LICENSE",
276277
}
277278

278279
for k, b in answer.items():

tests/test_skbuild_settings.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,12 @@ def test_skbuild_settings_default(tmp_path):
3737
assert settings.wheel.packages is None
3838
assert settings.wheel.py_api == ""
3939
assert not settings.wheel.expand_macos_universal_tags
40-
assert settings.wheel.license_files == ["LICENSE*", "COPYING*", "COPYRIGHT*"]
40+
assert settings.wheel.license_files == [
41+
"LICEN[CS]E*",
42+
"COPYING*",
43+
"NOTICE*",
44+
"AUTHORS*",
45+
]
4146
assert settings.backport.find_python == "3.26.1"
4247
assert settings.strict_config
4348
assert not settings.experimental

0 commit comments

Comments
 (0)