Skip to content

Commit 0540625

Browse files
rmarquisradoering
authored andcommitted
Fix wheel tag determination (python-poetry#591)
Co-authored-by: Joshua C. Randall <[email protected]> Co-authored-by: Randy Döring <[email protected]> (cherry picked from commit 5da9a2e)
1 parent bf6c63f commit 0540625

File tree

3 files changed

+82
-3
lines changed

3 files changed

+82
-3
lines changed

src/poetry/core/masonry/builders/wheel.py

+48-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import shutil
99
import stat
1010
import subprocess
11+
import sys
1112
import tempfile
1213
import zipfile
1314

@@ -17,7 +18,7 @@
1718
from typing import TYPE_CHECKING
1819
from typing import TextIO
1920

20-
from packaging.tags import sys_tags
21+
import packaging.tags
2122

2223
from poetry.core import __version__
2324
from poetry.core.constraints.version import parse_constraint
@@ -26,6 +27,7 @@
2627
from poetry.core.masonry.utils.helpers import distribution_name
2728
from poetry.core.masonry.utils.helpers import normalize_file_permissions
2829
from poetry.core.masonry.utils.package_include import PackageInclude
30+
from poetry.core.utils.helpers import decode
2931
from poetry.core.utils.helpers import temporary_directory
3032

3133

@@ -327,16 +329,59 @@ def dist_info_name(self, name: NormalizedName, version: str) -> str:
327329
escaped_name = distribution_name(name)
328330
return f"{escaped_name}-{version}.dist-info"
329331

332+
def _get_sys_tags(self) -> list[str]:
333+
"""Get sys_tags via subprocess.
334+
Required if poetry-core is not run inside the build environment.
335+
"""
336+
try:
337+
output = subprocess.check_output(
338+
[
339+
self.executable.as_posix(),
340+
"-c",
341+
f"""
342+
import importlib.util
343+
import sys
344+
345+
from pathlib import Path
346+
347+
spec = importlib.util.spec_from_file_location(
348+
"packaging", Path(r"{packaging.__file__}")
349+
)
350+
351+
packaging = importlib.util.module_from_spec(spec)
352+
sys.modules[spec.name] = packaging
353+
354+
spec = importlib.util.spec_from_file_location(
355+
"packaging.tags", Path(r"{packaging.tags.__file__}")
356+
)
357+
packaging_tags = importlib.util.module_from_spec(spec)
358+
spec.loader.exec_module(packaging_tags)
359+
for t in packaging_tags.sys_tags():
360+
print(t.interpreter, t.abi, t.platform, sep="-")
361+
""",
362+
],
363+
stderr=subprocess.STDOUT,
364+
)
365+
except subprocess.CalledProcessError as e:
366+
raise RuntimeError(
367+
"Failed to get sys_tags for python interpreter"
368+
f" '{self.executable.as_posix()}':\n{decode(e.output)}"
369+
)
370+
return decode(output).strip().splitlines()
371+
330372
@property
331373
def tag(self) -> str:
332374
if self._package.build_script:
333-
sys_tag = next(sys_tags())
375+
if self.executable != Path(sys.executable):
376+
# poetry-core is not run in the build environment
377+
# -> this is probably not a PEP 517 build but a poetry build
378+
return self._get_sys_tags()[0]
379+
sys_tag = next(packaging.tags.sys_tags())
334380
tag = (sys_tag.interpreter, sys_tag.abi, sys_tag.platform)
335381
else:
336382
platform = "any"
337383
impl = "py2.py3" if self.supports_python2() else "py3"
338384
tag = (impl, "none", platform)
339-
340385
return "-".join(tag)
341386

342387
def _add_file(

src/poetry/core/utils/helpers.py

+14
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import warnings
1111

1212
from contextlib import contextmanager
13+
from contextlib import suppress
1314
from pathlib import Path
1415
from typing import TYPE_CHECKING
1516
from typing import Any
@@ -27,6 +28,19 @@ def combine_unicode(string: str) -> str:
2728
return unicodedata.normalize("NFC", string)
2829

2930

31+
def decode(string: bytes | str, encodings: list[str] | None = None) -> str:
32+
if not isinstance(string, bytes):
33+
return string
34+
35+
encodings = encodings or ["utf-8", "latin1", "ascii"]
36+
37+
for encoding in encodings:
38+
with suppress(UnicodeEncodeError, UnicodeDecodeError):
39+
return string.decode(encoding)
40+
41+
return string.decode(encodings[0], errors="ignore")
42+
43+
3044
def module_name(name: str) -> str:
3145
return canonicalize_name(name).replace("-", "_")
3246

tests/masonry/builders/test_wheel.py

+20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import os
4+
import re
45
import shutil
56
import zipfile
67

@@ -350,3 +351,22 @@ def capturing_fdopen(*args: Any, **kwargs: Any) -> TextIO | None:
350351

351352
assert fd_file[0] is not None
352353
assert fd_file[0].closed
354+
355+
356+
@pytest.mark.parametrize("in_venv_build", [True, False])
357+
def test_tag(in_venv_build: bool, mocker: MockerFixture) -> None:
358+
"""Tests that tag returns a valid tag if a build script is used,
359+
no matter if poetry-core lives inside the build environment or not.
360+
"""
361+
root = fixtures_dir / "extended"
362+
builder = WheelBuilder(Factory().create_poetry(root))
363+
364+
get_sys_tags_spy = mocker.spy(builder, "_get_sys_tags")
365+
if not in_venv_build:
366+
mocker.patch("sys.executable", "other/python")
367+
368+
assert re.match("^cp[23]_?\\d+-cp[23]_?\\d+m?u?-.+$", builder.tag)
369+
if in_venv_build:
370+
get_sys_tags_spy.assert_not_called()
371+
else:
372+
get_sys_tags_spy.assert_called()

0 commit comments

Comments
 (0)