diff --git a/newsfragments/5169.misc.rst b/newsfragments/5169.misc.rst new file mode 100644 index 0000000000..37f78c9b79 --- /dev/null +++ b/newsfragments/5169.misc.rst @@ -0,0 +1 @@ +Pre-process ``ext-module.define-macros`` from ``pyproject.toml`` into a list of tuples. diff --git a/setuptools/config/_apply_pyprojecttoml.py b/setuptools/config/_apply_pyprojecttoml.py index 2a59446042..225c693866 100644 --- a/setuptools/config/_apply_pyprojecttoml.py +++ b/setuptools/config/_apply_pyprojecttoml.py @@ -268,10 +268,18 @@ def _optional_dependencies(dist: Distribution, val: dict, _root_dir: StrPath | N def _ext_modules(dist: Distribution, val: list[dict]) -> list[Extension]: existing = dist.ext_modules or [] args = ({k.replace("-", "_"): v for k, v in x.items()} for x in val) - new = [Extension(**kw) for kw in args] + new = (Extension(**_adjust_ext_attrs(kw)) for kw in args) return [*existing, *new] +def _adjust_ext_attrs(attrs: dict) -> dict: + # https://github.com/pypa/setuptools/issues/4810 + # In TOML there is no differentiation between tuples and lists, + # and distutils requires lists... + attrs["define_macros"] = list(map(tuple, attrs.get("define_macros") or [])) + return attrs + + def _noop(_dist: Distribution, val: _T) -> _T: return val diff --git a/setuptools/tests/config/test_apply_pyprojecttoml.py b/setuptools/tests/config/test_apply_pyprojecttoml.py index 8f48c4316d..b6b21a3e9b 100644 --- a/setuptools/tests/config/test_apply_pyprojecttoml.py +++ b/setuptools/tests/config/test_apply_pyprojecttoml.py @@ -535,9 +535,14 @@ def test_invalid_module_name(self, tmp_path, monkeypatch, module): class TestExtModules: + def make_dist(self, toml_config): + pyproject = Path("pyproject.toml") + pyproject.write_text(cleandoc(toml_config), encoding="utf-8") + with pytest.warns(pyprojecttoml._ExperimentalConfiguration): + return pyprojecttoml.apply_configuration(Distribution({}), pyproject) + def test_pyproject_sets_attribute(self, tmp_path, monkeypatch): monkeypatch.chdir(tmp_path) - pyproject = Path("pyproject.toml") toml_config = """ [project] name = "test" @@ -547,13 +552,28 @@ def test_pyproject_sets_attribute(self, tmp_path, monkeypatch): {name = "my.ext", sources = ["hello.c", "world.c"]} ] """ - pyproject.write_text(cleandoc(toml_config), encoding="utf-8") - with pytest.warns(pyprojecttoml._ExperimentalConfiguration): - dist = pyprojecttoml.apply_configuration(Distribution({}), pyproject) + dist = self.make_dist(toml_config) assert len(dist.ext_modules) == 1 assert dist.ext_modules[0].name == "my.ext" assert set(dist.ext_modules[0].sources) == {"hello.c", "world.c"} + def test_pyproject_define_macros_as_tuples(self, tmp_path, monkeypatch): + # https://github.com/pypa/setuptools/issues/4810 + monkeypatch.chdir(tmp_path) + toml_config = """ + [project] + name = "test" + version = "42.0" + [[tool.setuptools.ext-modules]] + name = "my.ext" + sources = ["hello.c", "world.c"] + define-macros = [["FIRST_SINGLE"], ["SECOND_TWO", "1"]] + """ + dist = self.make_dist(toml_config) + assert isinstance(dist.ext_modules[0].define_macros[0], tuple) + assert dist.ext_modules[0].define_macros[0] == ("FIRST_SINGLE",) + assert dist.ext_modules[0].define_macros[1] == ("SECOND_TWO", "1") + class TestDeprecatedFields: def test_namespace_packages(self, tmp_path):