From c2f1e13c12a4484ef505005df3495193168503a0 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Mon, 2 Feb 2026 12:35:12 +0000 Subject: [PATCH 1/2] Parse ext-module.define-macros from pyproject.toml as list of tuples --- setuptools/config/_apply_pyprojecttoml.py | 8 +++++- .../tests/config/test_apply_pyprojecttoml.py | 27 ++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/setuptools/config/_apply_pyprojecttoml.py b/setuptools/config/_apply_pyprojecttoml.py index 2a59446042..e808762f11 100644 --- a/setuptools/config/_apply_pyprojecttoml.py +++ b/setuptools/config/_apply_pyprojecttoml.py @@ -268,10 +268,16 @@ 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 + 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..7ef8dabf54 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,27 @@ 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 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): From b44354e912596d5c77a231cedb4bcdda347a8377 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Mon, 2 Feb 2026 15:08:53 +0000 Subject: [PATCH 2/2] Add news fragments --- newsfragments/5169.misc.rst | 1 + setuptools/config/_apply_pyprojecttoml.py | 2 ++ setuptools/tests/config/test_apply_pyprojecttoml.py | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 newsfragments/5169.misc.rst 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 e808762f11..225c693866 100644 --- a/setuptools/config/_apply_pyprojecttoml.py +++ b/setuptools/config/_apply_pyprojecttoml.py @@ -274,6 +274,8 @@ def _ext_modules(dist: Distribution, val: list[dict]) -> list[Extension]: 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 diff --git a/setuptools/tests/config/test_apply_pyprojecttoml.py b/setuptools/tests/config/test_apply_pyprojecttoml.py index 7ef8dabf54..b6b21a3e9b 100644 --- a/setuptools/tests/config/test_apply_pyprojecttoml.py +++ b/setuptools/tests/config/test_apply_pyprojecttoml.py @@ -567,9 +567,10 @@ def test_pyproject_define_macros_as_tuples(self, tmp_path, monkeypatch): [[tool.setuptools.ext-modules]] name = "my.ext" sources = ["hello.c", "world.c"] - define-macros = [ ["FIRST_SINGLE"], ["SECOND_TWO", "1"]] + 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")