Skip to content
Open
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
1 change: 1 addition & 0 deletions newsfragments/5120.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Preserved ``Dynamic: requires-dist`` in generated core metadata when ``dependencies`` is listed as dynamic and the resolved dependency list is empty.
5 changes: 4 additions & 1 deletion setuptools/_core_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,11 @@ def write_field(key, value):
self._write_list(file, 'License-File', safe_license_files)
_write_requirements(self, file)

dynamic_fields = set(getattr(self, "_setuptools_dynamic", ()))
for field, attr in _POSSIBLE_DYNAMIC_FIELDS.items():
if (val := getattr(self, attr, None)) and not is_static(val):
if field in dynamic_fields:
write_field('Dynamic', field)
elif (val := getattr(self, attr, None)) and not is_static(val):
write_field('Dynamic', field)

long_description = self.get_long_description()
Expand Down
9 changes: 9 additions & 0 deletions setuptools/config/_apply_pyprojecttoml.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def _apply_project_table(dist: Distribution, config: dict, root_dir: StrPath):

project_table = {k: _static.attempt_conversion(v) for k, v in orig_config.items()}
_handle_missing_dynamic(dist, project_table)
_handle_dynamic_metadata(dist, project_table)
_unify_entry_points(project_table)

for field, value in project_table.items():
Expand Down Expand Up @@ -137,6 +138,14 @@ def _handle_missing_dynamic(dist: Distribution, project_table: dict):
project_table[field] = _RESET_PREVIOUSLY_DEFINED.get(field)


def _handle_dynamic_metadata(dist: Distribution, project_table: dict):
dynamic = set(project_table.get("dynamic", []))
if "dependencies" in dynamic:
metadata_dynamic = set(getattr(dist.metadata, "_setuptools_dynamic", ()))
metadata_dynamic.add("requires-dist")
dist.metadata._setuptools_dynamic = metadata_dynamic


def json_compatible_key(key: str) -> str:
"""As defined in :pep:`566#json-compatible-metadata`"""
return key.lower().replace("-", "_")
Expand Down
16 changes: 16 additions & 0 deletions setuptools/tests/config/test_apply_pyprojecttoml.py
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,22 @@ def test_listed_in_dynamic(self, tmp_path, attr, field, value):
dist_value = _some_attrgetter(f"metadata.{attr}", attr)(dist)
assert dist_value == value

def test_empty_dynamic_dependencies_in_metadata(self, tmp_path):
pyproject = self.pyproject(tmp_path, ["dependencies"])
dist = makedist(tmp_path, install_requires=[])
dist = pyprojecttoml.apply_configuration(dist, pyproject)
metadata = core_metadata(dist)
assert "Dynamic: requires-dist\n" in metadata
assert "Requires-Dist:" not in metadata

def test_empty_static_dependencies_not_dynamic_in_metadata(self, tmp_path):
extra = "dependencies = []\n"
pyproject = self.pyproject(tmp_path, [], extra)
dist = pyprojecttoml.apply_configuration(makedist(tmp_path), pyproject)
metadata = core_metadata(dist)
assert "Dynamic:" not in metadata
assert "Requires-Dist:" not in metadata

def test_license_files_exempt_from_dynamic(self, monkeypatch, tmp_path):
"""
license-file is currently not considered in the context of dynamic.
Expand Down