Skip to content

Commit b18ea48

Browse files
committed
Add minimal validation to license glob patterns
1 parent 6f0aee2 commit b18ea48

File tree

1 file changed

+33
-9
lines changed

1 file changed

+33
-9
lines changed

setuptools/dist.py

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import os
77
import re
88
import sys
9-
from collections.abc import Iterable, MutableMapping, Sequence
9+
from collections.abc import Iterable, Iterator, MutableMapping, Sequence
1010
from glob import iglob
1111
from pathlib import Path
1212
from typing import TYPE_CHECKING, Any, Union
@@ -450,27 +450,51 @@ def _finalize_license_files(self) -> None:
450450
patterns = ['LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*']
451451

452452
self.metadata.license_files = list(
453-
map(
454-
lambda path: path.replace(os.sep, "/"),
455-
unique_everseen(self._expand_patterns(patterns)),
456-
)
453+
unique_everseen(self._expand_patterns(patterns)),
457454
)
458455

459-
@staticmethod
460-
def _expand_patterns(patterns):
456+
if license_files and not self.metadata.license_files:
457+
# Pattern explicitly given but no file found
458+
if not self.metadata.license_files:
459+
SetuptoolsDeprecationWarning.emit(
460+
"Cannot find any license files for the given patterns.",
461+
f"The glob patterns {patterns!r} do not match any file.",
462+
due_date=(2026, 2, 20),
463+
# Warning introduced on 2025/02/18
464+
# PEP 639 requires us to error, but as a transition period
465+
# we will only issue a warning to give people time to prepare.
466+
# After the transition, this should raise an InvalidConfigError.
467+
)
468+
469+
@classmethod
470+
def _expand_patterns(cls, patterns: list[str]) -> Iterator[str]:
461471
"""
462472
>>> list(Distribution._expand_patterns(['LICENSE']))
463473
['LICENSE']
464474
>>> list(Distribution._expand_patterns(['pyproject.toml', 'LIC*']))
465475
['pyproject.toml', 'LICENSE']
466476
"""
467477
return (
468-
path
478+
path.replace(os.sep, "/")
469479
for pattern in patterns
470-
for path in sorted(iglob(pattern, recursive=True))
480+
for path in sorted(cls._find_pattern(pattern))
471481
if not path.endswith('~') and os.path.isfile(path)
472482
)
473483

484+
@staticmethod
485+
def _find_pattern(pattern: str) -> Iterator[str]:
486+
"""
487+
>>> list(Distribution._find_pattern("setuptools/**/pyprojecttoml.py"))
488+
['setuptools/config/pyprojecttoml.py']
489+
>>> list(Distribution._find_pattern("../LICENSE"))
490+
Traceback (most recent call last):
491+
...
492+
setuptools.errors.InvalidConfigError: Pattern '../LICENSE' cannot contain '..'
493+
"""
494+
if ".." in pattern: # XXX: Any other invalid character?
495+
raise InvalidConfigError(f"Pattern {pattern!r} cannot contain '..'")
496+
return iglob(pattern, recursive=True)
497+
474498
# FIXME: 'Distribution._parse_config_files' is too complex (14)
475499
def _parse_config_files(self, filenames=None): # noqa: C901
476500
"""

0 commit comments

Comments
 (0)