Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: PDM installs wrong architecture of pywin32 wheel on Windows #2467

Merged
merged 1 commit into from
Dec 7, 2023
Merged
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
fix: PDM installs wrong architecture of pywin32 wheel on Windows
Fixes #2464

Signed-off-by: Frost Ming <[email protected]>
  • Loading branch information
frostming committed Dec 7, 2023
commit cb071f9e68fdde0660533bfd3be2e9c08c205b07
1 change: 1 addition & 0 deletions news/2464.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix the wrong installation candidates for different architectures on Windows.
64 changes: 36 additions & 28 deletions src/pdm/environments/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
import sys
import tempfile
from contextlib import contextmanager
from functools import cached_property
from functools import cached_property, partial
from pathlib import Path
from typing import TYPE_CHECKING, Generator

from pdm.exceptions import BuildError, PdmUsageError
from pdm.models.in_process import get_pep508_environment, get_python_abi_tag, get_uname
from pdm.models.in_process import get_pep508_environment, get_python_abi_tag, get_uname, sysconfig_get_platform
from pdm.models.python import PythonInfo
from pdm.models.working_set import WorkingSet
from pdm.utils import get_trusted_hosts, is_pip_compatible_with_python
Expand Down Expand Up @@ -74,7 +74,11 @@ def target_python(self) -> unearth.TargetPython:

python_version = self.interpreter.version_tuple
python_abi_tag = get_python_abi_tag(str(self.interpreter.executable))
return TargetPython(python_version, [python_abi_tag])
tp = TargetPython(python_version, [python_abi_tag])
# calculate the target platform tags
with self._patch_target_python():
tp.supported_tags()
return tp

def _build_session(self, trusted_hosts: list[str]) -> PDMSession:
from pdm.models.session import PDMSession
Expand All @@ -96,21 +100,26 @@ def _build_session(self, trusted_hosts: list[str]) -> PDMSession:
@contextmanager
def _patch_target_python(self) -> Generator[None, None, None]:
"""Patch the packaging modules to respect the arch of target python."""
import sysconfig

import packaging.tags

old_32bit = packaging.tags._32_BIT_INTERPRETER
old_os_uname = getattr(os, "uname", None)
old_get_platform = sysconfig.get_platform

if old_os_uname is not None:

def uname() -> os.uname_result:
return get_uname(str(self.interpreter.executable))
return get_uname(str(self.interpreter.path))

os.uname = uname
packaging.tags._32_BIT_INTERPRETER = self.interpreter.is_32bit
sysconfig.get_platform = partial(sysconfig_get_platform, str(self.interpreter.path))
try:
yield
finally:
sysconfig.get_platform = old_get_platform
packaging.tags._32_BIT_INTERPRETER = old_32bit
if old_os_uname is not None:
os.uname = old_os_uname
Expand Down Expand Up @@ -142,30 +151,29 @@ def get_finder(
trusted_hosts = get_trusted_hosts(sources)

session = self._build_session(trusted_hosts)
with self._patch_target_python():
finder = PDMPackageFinder(
session=session,
target_python=self.target_python,
ignore_compatibility=ignore_compatibility,
no_binary=os.getenv("PDM_NO_BINARY", "").split(","),
only_binary=os.getenv("PDM_ONLY_BINARY", "").split(","),
prefer_binary=os.getenv("PDM_PREFER_BINARY", "").split(","),
respect_source_order=self.project.pyproject.settings.get("resolution", {}).get(
"respect-source-order", False
),
verbosity=self.project.core.ui.verbosity,
minimal_version=minimal_version,
)
for source in sources:
assert source.url
if source.type == "find_links":
finder.add_find_links(source.url)
else:
finder.add_index_url(source.url)
try:
yield finder
finally:
session.close()
finder = PDMPackageFinder(
session=session,
target_python=self.target_python,
ignore_compatibility=ignore_compatibility,
no_binary=os.getenv("PDM_NO_BINARY", "").split(","),
only_binary=os.getenv("PDM_ONLY_BINARY", "").split(","),
prefer_binary=os.getenv("PDM_PREFER_BINARY", "").split(","),
respect_source_order=self.project.pyproject.settings.get("resolution", {}).get(
"respect-source-order", False
),
verbosity=self.project.core.ui.verbosity,
minimal_version=minimal_version,
)
for source in sources:
assert source.url
if source.type == "find_links":
finder.add_find_links(source.url)
else:
finder.add_index_url(source.url)
try:
yield finder
finally:
session.close()

def get_working_set(self) -> WorkingSet:
"""Get the working set based on local packages directory."""
Expand Down
7 changes: 7 additions & 0 deletions src/pdm/models/in_process/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,10 @@ def get_uname(executable: str) -> os.uname_result:
"""Get uname of the system"""
script = "import os, json; print(json.dumps(os.uname()))"
return os.uname_result(json.loads(subprocess.check_output([executable, "-EsSc", script])))


@functools.lru_cache
def sysconfig_get_platform(executable: str) -> str:
"""Get platform from sysconfig"""
script = "import sysconfig; print(sysconfig.get_platform())"
return subprocess.check_output([executable, "-EsSc", script]).decode().strip()