|
53 | 53 | from mesonpy._compat import cached_property, read_binary
|
54 | 54 |
|
55 | 55 |
|
| 56 | +try: |
| 57 | + from packaging.licenses import InvalidLicenseExpression, canonicalize_license_expression |
| 58 | +except ImportError: |
| 59 | + # PEP-639 support requires packaging >= 24.2. |
| 60 | + def canonicalize_license_expression(s: str) -> str: # type: ignore[misc] |
| 61 | + warnings.warn( |
| 62 | + 'canonicalization and validation of license expression in "project.license" ' |
| 63 | + 'as defined by PEP-639 requires packaging version 24.2 or later.', stacklevel=2) |
| 64 | + return s |
| 65 | + |
| 66 | + class InvalidLicenseExpression(Exception): # type: ignore[no-redef] |
| 67 | + pass |
| 68 | + |
| 69 | + |
56 | 70 | if typing.TYPE_CHECKING: # pragma: no cover
|
57 | 71 | from typing import Any, Callable, DefaultDict, Dict, List, Literal, Optional, Sequence, TextIO, Tuple, Type, TypeVar, Union
|
58 | 72 |
|
@@ -251,6 +265,10 @@ def from_pyproject( # type: ignore[override]
|
251 | 265 | fields = ', '.join(f'"{x}"' for x in unsupported_dynamic)
|
252 | 266 | raise pyproject_metadata.ConfigurationError(f'Unsupported dynamic fields: {fields}')
|
253 | 267 |
|
| 268 | + # Validate license field to be a valid SDPX license expression. |
| 269 | + if isinstance(metadata.license, str): |
| 270 | + metadata.license = canonicalize_license_expression(metadata.license) |
| 271 | + |
254 | 272 | return metadata
|
255 | 273 |
|
256 | 274 | @property
|
@@ -339,13 +357,6 @@ def _data_dir(self) -> str:
|
339 | 357 | def _libs_dir(self) -> str:
|
340 | 358 | return f'.{self._metadata.distribution_name}.mesonpy.libs'
|
341 | 359 |
|
342 |
| - @property |
343 |
| - def _license_file(self) -> Optional[pathlib.Path]: |
344 |
| - license_ = self._metadata.license |
345 |
| - if license_ and isinstance(license_, pyproject_metadata.License): |
346 |
| - return license_.file |
347 |
| - return None |
348 |
| - |
349 | 360 | @property
|
350 | 361 | def wheel(self) -> bytes:
|
351 | 362 | """Return WHEEL file for dist-info."""
|
@@ -428,9 +439,17 @@ def _wheel_write_metadata(self, whl: mesonpy._wheelfile.WheelFile) -> None:
|
428 | 439 | if self.entrypoints_txt:
|
429 | 440 | whl.writestr(f'{self._distinfo_dir}/entry_points.txt', self.entrypoints_txt)
|
430 | 441 |
|
431 |
| - # add license (see https://github.com/mesonbuild/meson-python/issues/88) |
432 |
| - if self._license_file: |
433 |
| - whl.write(self._license_file, f'{self._distinfo_dir}/{os.path.basename(self._license_file)}') |
| 442 | + # Add pre-PEP-639 license files. |
| 443 | + if isinstance(self._metadata.license, pyproject_metadata.License): |
| 444 | + license_file = self._metadata.license.file |
| 445 | + if license_file: |
| 446 | + whl.write(license_file, f'{self._distinfo_dir}/{os.path.basename(license_file)}') |
| 447 | + |
| 448 | + # Add PEP-639 license-files. Use ``getattr()`` for compatibility with pyproject-metadata < 0.9.0. |
| 449 | + license_files = getattr(self._metadata, 'license_files', None) |
| 450 | + if license_files: |
| 451 | + for f in license_files: |
| 452 | + whl.write(f, f'{self._distinfo_dir}/licenses/{pathlib.Path(f).as_posix()}') |
434 | 453 |
|
435 | 454 | def build(self, directory: Path) -> pathlib.Path:
|
436 | 455 | wheel_file = pathlib.Path(directory, f'{self.name}.whl')
|
@@ -1023,7 +1042,7 @@ def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
|
1023 | 1042 | warnings.showwarning = _showwarning
|
1024 | 1043 | try:
|
1025 | 1044 | return func(*args, **kwargs)
|
1026 |
| - except (Error, pyproject_metadata.ConfigurationError) as exc: |
| 1045 | + except (Error, InvalidLicenseExpression, pyproject_metadata.ConfigurationError) as exc: |
1027 | 1046 | prefix = f'{style.ERROR}meson-python: error:{style.RESET} '
|
1028 | 1047 | _log('\n' + textwrap.indent(str(exc), prefix))
|
1029 | 1048 | raise SystemExit(1) from exc
|
|
0 commit comments