From 212336eadd14c32043af975c4380e0134a887156 Mon Sep 17 00:00:00 2001 From: "Joshua C. Randall" Date: Fri, 22 Oct 2021 21:32:29 +0000 Subject: [PATCH 1/6] fix binary wheel tag determination --- src/poetry/core/masonry/builders/wheel.py | 42 ++++++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/poetry/core/masonry/builders/wheel.py b/src/poetry/core/masonry/builders/wheel.py index 14fc71dd0..9fbeb0657 100644 --- a/src/poetry/core/masonry/builders/wheel.py +++ b/src/poetry/core/masonry/builders/wheel.py @@ -17,8 +17,7 @@ from typing import TYPE_CHECKING from typing import TextIO -from packaging.tags import sys_tags - +from poetry.core import __vendor_site__ from poetry.core import __version__ from poetry.core.constraints.version import parse_constraint from poetry.core.masonry.builders.builder import Builder @@ -327,16 +326,49 @@ def dist_info_name(self, name: NormalizedName, version: str) -> str: escaped_name = distribution_name(name) return f"{escaped_name}-{version}.dist-info" + def get_tags(self) -> list[str]: + env = os.environ + pythonpath = env.get("PYTHONPATH", "").strip() + if pythonpath == "": + env["PYTHONPATH"] = __vendor_site__ + else: + env["PYTHONPATH"] = os.pathsep.join([__vendor_site__, pythonpath]) + try: + tags = ( + subprocess.check_output( + [ + self.executable.as_posix(), + "-c", + """ +from packaging.tags import sys_tags +for tag in sys_tags(): + print(tag) + """, + ], + env=env, + stderr=subprocess.STDOUT, + ) + .decode("utf-8") + .strip() + .splitlines() + ) + except subprocess.CalledProcessError as cpe: + raise RuntimeError( + "get_tags failed to get sys_tags for python interpreter" + f" '{self.executable.as_posix()}' using PYTHONPATH='{pythonpath}'" + " to supply packaging.tags package: script exited" + f" {cpe.returncode} with output '{cpe.output}'" + ) + return tags + @property def tag(self) -> str: if self._package.build_script: - sys_tag = next(sys_tags()) - tag = (sys_tag.interpreter, sys_tag.abi, sys_tag.platform) + return self.get_tags()[0] else: platform = "any" impl = "py2.py3" if self.supports_python2() else "py3" tag = (impl, "none", platform) - return "-".join(tag) def _add_file( From 271244499671ef48aff3317c3bcce6450f17050c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Marquis?= Date: Tue, 16 May 2023 13:53:17 +0200 Subject: [PATCH 2/6] get tags using importlib --- src/poetry/core/masonry/builders/wheel.py | 34 +++++++++++++++-------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/poetry/core/masonry/builders/wheel.py b/src/poetry/core/masonry/builders/wheel.py index 9fbeb0657..0a7874736 100644 --- a/src/poetry/core/masonry/builders/wheel.py +++ b/src/poetry/core/masonry/builders/wheel.py @@ -10,6 +10,7 @@ import subprocess import tempfile import zipfile +import packaging.tags from base64 import urlsafe_b64encode from io import StringIO @@ -17,7 +18,6 @@ from typing import TYPE_CHECKING from typing import TextIO -from poetry.core import __vendor_site__ from poetry.core import __version__ from poetry.core.constraints.version import parse_constraint from poetry.core.masonry.builders.builder import Builder @@ -328,22 +328,33 @@ def dist_info_name(self, name: NormalizedName, version: str) -> str: def get_tags(self) -> list[str]: env = os.environ - pythonpath = env.get("PYTHONPATH", "").strip() - if pythonpath == "": - env["PYTHONPATH"] = __vendor_site__ - else: - env["PYTHONPATH"] = os.pathsep.join([__vendor_site__, pythonpath]) try: tags = ( subprocess.check_output( [ self.executable.as_posix(), "-c", - """ -from packaging.tags import sys_tags -for tag in sys_tags(): - print(tag) - """, + f""" +import importlib.util +import sys + +from pathlib import Path + +spec = importlib.util.spec_from_file_location( + "packaging", Path(r"{packaging.__file__}") +) + +packaging = importlib.util.module_from_spec(spec) +sys.modules[spec.name] = packaging + +spec = importlib.util.spec_from_file_location( + "packaging.tags", Path(r"{packaging.tags.__file__}") +) +packaging_tags = importlib.util.module_from_spec(spec) +spec.loader.exec_module(packaging_tags) +for t in packaging_tags.sys_tags(): + print(t.interpreter, t.abi, t.platform, sep="-") +""", ], env=env, stderr=subprocess.STDOUT, @@ -353,6 +364,7 @@ def get_tags(self) -> list[str]: .splitlines() ) except subprocess.CalledProcessError as cpe: + pythonpath = env.get("PYTHONPATH", "").strip() raise RuntimeError( "get_tags failed to get sys_tags for python interpreter" f" '{self.executable.as_posix()}' using PYTHONPATH='{pythonpath}'" From 86882627b413c794c78f75a2d38f6d33bad278b7 Mon Sep 17 00:00:00 2001 From: "Joshua C. Randall" Date: Tue, 16 May 2023 11:00:33 +0200 Subject: [PATCH 3/6] add support for filtering compatible tags using wheel-tag-regex config option --- src/poetry/core/json/schemas/poetry-schema.json | 5 +++++ src/poetry/core/masonry/builders/wheel.py | 11 ++++++++++- src/poetry/core/packages/project_package.py | 3 +++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/poetry/core/json/schemas/poetry-schema.json b/src/poetry/core/json/schemas/poetry-schema.json index 564559070..8b7a9c257 100644 --- a/src/poetry/core/json/schemas/poetry-schema.json +++ b/src/poetry/core/json/schemas/poetry-schema.json @@ -647,6 +647,11 @@ }, "script": { "$ref": "#/definitions/build-script" + }, + "wheel-tag-regex": { + "type": "string", + "description": "Regex pattern to use to select a wheel tag from the list of tags supplied by the python interpreter.", + "default": ".*" } } }, diff --git a/src/poetry/core/masonry/builders/wheel.py b/src/poetry/core/masonry/builders/wheel.py index 0a7874736..b14ba541e 100644 --- a/src/poetry/core/masonry/builders/wheel.py +++ b/src/poetry/core/masonry/builders/wheel.py @@ -5,6 +5,7 @@ import hashlib import logging import os +import re import shutil import stat import subprocess @@ -376,7 +377,15 @@ def get_tags(self) -> list[str]: @property def tag(self) -> str: if self._package.build_script: - return self.get_tags()[0] + tags = self.get_tags() + wheel_tag_pattern = re.compile(self._poetry.package.build_wheel_tag_regex()) + for tag in tags: + if wheel_tag_pattern.search(tag) is not None: + return tag + raise RuntimeError( + "no sys tags matched regex" + f" '{self._poetry.package.build_wheel_tag_regex()}': {','.join(tags)}" + ) else: platform = "any" impl = "py2.py3" if self.supports_python2() else "py3" diff --git a/src/poetry/core/packages/project_package.py b/src/poetry/core/packages/project_package.py index 7cf82fd24..42f8055b4 100644 --- a/src/poetry/core/packages/project_package.py +++ b/src/poetry/core/packages/project_package.py @@ -100,3 +100,6 @@ def __hash__(self) -> int: def build_should_generate_setup(self) -> bool: return self.build_config.get("generate-setup-file", False) + + def build_wheel_tag_regex(self) -> str: + return self.build_config.get("wheel-tag-regex", ".*") From 088207955dfbba4b005fc37ec4874b0b21cce1b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Marquis?= Date: Tue, 16 May 2023 13:45:14 +0200 Subject: [PATCH 4/6] fix typo in test_wheel_c_extension variable --- tests/masonry/builders/test_complete.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/masonry/builders/test_complete.py b/tests/masonry/builders/test_complete.py index 4e4dff019..682cbd9d3 100644 --- a/tests/masonry/builders/test_complete.py +++ b/tests/masonry/builders/test_complete.py @@ -46,14 +46,14 @@ def clear_samples_dist() -> None: platform.python_implementation().lower() == "pypy", reason="Disable test for PyPy" ) @pytest.mark.parametrize( - ["project", "exptected_c_dir"], + ["project", "expected_c_dir"], [ ("extended", "extended"), ("extended_with_no_setup", "extended"), ("src_extended", "src/extended"), ], ) -def test_wheel_c_extension(project: str, exptected_c_dir: str) -> None: +def test_wheel_c_extension(project: str, expected_c_dir: str) -> None: module_path = fixtures_dir / project builder = Builder(Factory().create_poetry(module_path)) builder.build(fmt="all") @@ -63,7 +63,7 @@ def test_wheel_c_extension(project: str, exptected_c_dir: str) -> None: with tarfile.open(sdist, "r") as tar: assert "extended-0.1/build.py" in tar.getnames() - assert f"extended-0.1/{exptected_c_dir}/extended.c" in tar.getnames() + assert f"extended-0.1/{expected_c_dir}/extended.c" in tar.getnames() whl = list((module_path / "dist").glob("extended-0.1-cp*-cp*-*.whl"))[0] assert whl.exists() From 42934b30c7ca010e488aafde1059a16a8dfe81eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Marquis?= Date: Fri, 19 May 2023 09:50:29 +0200 Subject: [PATCH 5/6] Initial mock test for get_tags with regex - WIP --- tests/masonry/builders/test_wheel.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/masonry/builders/test_wheel.py b/tests/masonry/builders/test_wheel.py index 2a9ee05a0..dba027bfe 100644 --- a/tests/masonry/builders/test_wheel.py +++ b/tests/masonry/builders/test_wheel.py @@ -147,6 +147,30 @@ def test_wheel_localversionlabel() -> None: assert local_version_string + ".dist-info/METADATA" in z.namelist() +def test_wheel_get_tags(mocker: MockerFixture) -> None: + class MockGetTags: + def get_tags(self) -> list[str]: + return [ + ( + 'cp311-cp311-manylinux_2_37_x86_64' + 'cp311-abi3-manylinux_2_36_x86_64' + 'cp311-none-manylinux_2_35_x86_64' + 'cp311-abi3-linux_x86_64' + ) + ] + + p = mocker.patch("packaging.tags") + p.return_value = MockGetTags() + + module_path = fixtures_dir / "get_tags" + WheelBuilder.make(Factory().create_poetry(module_path)) + + tag = "cp311-cp311-manylinux_2_37_x86_64" + whl = module_path / "dist" / (tag + ".whl") + + assert whl.exists() + + def test_wheel_package_src() -> None: module_path = fixtures_dir / "source_package" WheelBuilder.make(Factory().create_poetry(module_path)) From 87af8b91db8882ccfbf5dbd767e13287e9449e2a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 19 May 2023 08:19:49 +0000 Subject: [PATCH 6/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/poetry/core/masonry/builders/wheel.py | 3 ++- tests/masonry/builders/test_wheel.py | 10 ++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/poetry/core/masonry/builders/wheel.py b/src/poetry/core/masonry/builders/wheel.py index b14ba541e..79896f6d0 100644 --- a/src/poetry/core/masonry/builders/wheel.py +++ b/src/poetry/core/masonry/builders/wheel.py @@ -11,7 +11,6 @@ import subprocess import tempfile import zipfile -import packaging.tags from base64 import urlsafe_b64encode from io import StringIO @@ -19,6 +18,8 @@ from typing import TYPE_CHECKING from typing import TextIO +import packaging.tags + from poetry.core import __version__ from poetry.core.constraints.version import parse_constraint from poetry.core.masonry.builders.builder import Builder diff --git a/tests/masonry/builders/test_wheel.py b/tests/masonry/builders/test_wheel.py index dba027bfe..5c08bd4c0 100644 --- a/tests/masonry/builders/test_wheel.py +++ b/tests/masonry/builders/test_wheel.py @@ -151,12 +151,10 @@ def test_wheel_get_tags(mocker: MockerFixture) -> None: class MockGetTags: def get_tags(self) -> list[str]: return [ - ( - 'cp311-cp311-manylinux_2_37_x86_64' - 'cp311-abi3-manylinux_2_36_x86_64' - 'cp311-none-manylinux_2_35_x86_64' - 'cp311-abi3-linux_x86_64' - ) + "cp311-cp311-manylinux_2_37_x86_64" + "cp311-abi3-manylinux_2_36_x86_64" + "cp311-none-manylinux_2_35_x86_64" + "cp311-abi3-linux_x86_64" ] p = mocker.patch("packaging.tags")