Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion distutils/dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
overload,
)

from jaraco.text import SeparatedValues
from packaging.utils import canonicalize_name, canonicalize_version

from ._log import log
Expand Down Expand Up @@ -75,6 +76,34 @@ def _ensure_list(value: str | Iterable[str], fieldname) -> str | list[str]:
return value


def _repair_newlines(value: str) -> str:
"""
Repair a ``keywords`` or ``platforms`` value that improperly uses
newlines to separate items.

These fields separate items with commas (and, in the old specification,
PEP 345, with spaces). Newlines were never a valid separator and corrupt
the generated ``PKG-INFO``/``METADATA`` (pypa/setuptools#4887). As a
forgiving measure, values that supply these fields as newline-separated
strings (e.g. a triple-quoted string with one item per line) have each
line treated as a separate item by replacing newlines with commas, but
the behavior is deprecated. Empty items produced by consecutive or
trailing separators are dropped by the caller.
"""
if "\n" not in value:
return value
# A plain warning (UserWarning) rather than DeprecationWarning so that
# it's shown by default; DeprecationWarning is suppressed outside of test
# runners and this needs to reach setuptools users (cf. distutils.log.Log).
warnings.warn(
Comment thread
jaraco marked this conversation as resolved.
"Newlines are not a valid separator for the 'keywords' and "
"'platforms' fields and their use is deprecated. Separate items "
"with commas instead. This will raise an error in the future.",
stacklevel=2,
)
return value.replace("\n", ",")


class Distribution:
"""The core of the Distutils. Most of the work hiding behind 'setup'
is really done within a Distribution instance, which farms the work out
Expand Down Expand Up @@ -643,7 +672,8 @@ def finalize_options(self) -> None:
if value is None:
continue
if isinstance(value, str):
value = [elm.strip() for elm in value.split(',')]
# SeparatedValues strips whitespace and discards empty items.
value = list(SeparatedValues(_repair_newlines(value)))
setattr(self.metadata, attr, value)

def _show_help(
Expand Down
22 changes: 22 additions & 0 deletions distutils/tests/test_dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,28 @@ def test_finalize_options(self):
assert dist.metadata.platforms == ['foo bar']
assert dist.metadata.keywords == ['foo bar']

# Newlines are an invalid (deprecated) separator; each line is
# treated as a separate item (pypa/setuptools#4887).
attrs = {
'keywords': 'one\ntwo\nthree\nfour',
'platforms': 'one\ntwo\nthree\nfour',
}
with pytest.warns(UserWarning, match="Newlines"):
dist = Distribution(attrs=attrs)
assert dist.metadata.platforms == ['one', 'two', 'three', 'four']
assert dist.metadata.keywords == ['one', 'two', 'three', 'four']

# Consecutive, leading, or trailing newlines must not produce
# empty items (e.g. from a triple-quoted string with blank lines).
attrs = {
'keywords': '\none two\n\nthree four\n',
'platforms': '\none two\n\nthree four\n',
}
with pytest.warns(UserWarning, match="Newlines"):
dist = Distribution(attrs=attrs)
assert dist.metadata.platforms == ['one two', 'three four']
assert dist.metadata.keywords == ['one two', 'three four']

def test_get_command_packages(self):
dist = Distribution()
assert dist.command_packages is None
Expand Down
1 change: 1 addition & 0 deletions newsfragments/4887.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Newline-separated ``keywords`` and ``platforms``, which are invalid and corrupt the generated metadata (pypa/setuptools#4887), are now handled forgivingly: each line is treated as a separate item and a deprecation warning is emitted. Newlines were never a valid separator for these fields -- the `old specification <https://peps.python.org/pep-0345/>`_ separated items with spaces and the current one uses commas.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies = [
"packaging",
"jaraco.functools >= 4",
"more_itertools",
"jaraco.text",
]
dynamic = ["version"]

Expand Down
Loading