Skip to content

Commit

Permalink
Fix Python resolution of variants (#1175)
Browse files Browse the repository at this point in the history
  • Loading branch information
ofek authored Dec 25, 2023
1 parent 9aa2c70 commit d17d8aa
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 19 deletions.
1 change: 1 addition & 0 deletions docs/history/hatch.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
***Fixed:***

- Ensure that the `dependency_hash` method of the `environment` interface is called after `sync_dependencies` for cases where the hash is only known at that point, such as for dependency lockers
- Only acknowledge the `HATCH_PYTHON_VARIANT_*` environment variables for Python resolution for supported platforms and architectures

## [1.9.0](https://github.com/pypa/hatch/releases/tag/hatch-v1.9.0) - 2023-12-19 ## {: #hatch-v1.9.0 }

Expand Down
21 changes: 15 additions & 6 deletions src/hatch/python/resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,24 @@ def get_compatible_distributions() -> dict[str, Distribution]:


def _get_default_variant(name: str, system: str, arch: str, abi: str) -> str:
variant = os.environ.get(f'HATCH_PYTHON_VARIANT_{system.upper()}', '').lower()
if variant:
return variant

# not PyPy
if name[0].isdigit():
if system == 'windows' and abi == 'msvc':
return 'shared'
# https://gregoryszorc.com/docs/python-build-standalone/main/running.html
variant = os.environ.get(f'HATCH_PYTHON_VARIANT_{system.upper()}', '').lower()

if system == 'windows':
# Shared versus static
if variant:
return variant

if abi == 'msvc':
return 'shared'

if system == 'linux' and arch == 'x86_64':
# Intel-specific optimizations depending on age of release
if variant:
return variant

if name == '3.8':
return 'v1'

Expand Down
14 changes: 7 additions & 7 deletions tests/cli/python/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

import pytest

from hatch.errors import PythonDistributionResolutionError
from hatch.python.core import InstalledDistribution
from hatch.python.distributions import ORDERED_DISTRIBUTIONS
from hatch.python.resolve import get_distribution
from hatch.utils.structures import EnvVars


def test_unknown(hatch, helpers, path_append, mocker):
Expand All @@ -25,11 +25,11 @@ def test_unknown(hatch, helpers, path_append, mocker):
path_append.assert_not_called()


def test_incompatible_single(hatch, helpers, path_append, platform, dist_name, mocker):
def test_incompatible_single(hatch, helpers, path_append, dist_name, mocker):
mocker.patch('hatch.python.resolve.get_distribution', side_effect=PythonDistributionResolutionError)
install = mocker.patch('hatch.python.core.PythonManager.install')

with EnvVars({f'HATCH_PYTHON_VARIANT_{platform.name.upper()}': 'foo'}):
result = hatch('python', 'install', dist_name)
result = hatch('python', 'install', dist_name)

assert result.exit_code == 1, result.output
assert result.output == helpers.dedent(
Expand All @@ -42,11 +42,11 @@ def test_incompatible_single(hatch, helpers, path_append, platform, dist_name, m
path_append.assert_not_called()


def test_incompatible_all(hatch, helpers, path_append, platform, mocker):
def test_incompatible_all(hatch, helpers, path_append, mocker):
mocker.patch('hatch.python.resolve.get_distribution', side_effect=PythonDistributionResolutionError)
install = mocker.patch('hatch.python.core.PythonManager.install')

with EnvVars({f'HATCH_PYTHON_VARIANT_{platform.name.upper()}': 'foo'}):
result = hatch('python', 'install', 'all')
result = hatch('python', 'install', 'all')

assert result.exit_code == 1, result.output
assert result.output == helpers.dedent(
Expand Down
7 changes: 7 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ def current_platform():
return PLATFORM.name


@pytest.fixture(scope='session')
def current_arch():
import platform

return platform.machine().lower()


@pytest.fixture(scope='session')
def uri_slash_prefix():
return '//' if os.sep == '/' else '///'
Expand Down
8 changes: 4 additions & 4 deletions tests/python/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import pytest

from hatch.python.core import InstalledDistribution, PythonManager
from hatch.python.distributions import DISTRIBUTIONS, ORDERED_DISTRIBUTIONS
from hatch.python.distributions import ORDERED_DISTRIBUTIONS
from hatch.python.resolve import get_distribution


Expand Down Expand Up @@ -64,10 +64,10 @@ def test_no_python_path(self, temp_dir):

assert manager.get_installed() == {}

def test_order(self, temp_dir):
def test_order(self, temp_dir, compatible_python_distributions):
manager = PythonManager(temp_dir)

for name in DISTRIBUTIONS:
for name in compatible_python_distributions:
dist = get_distribution(name)
path = temp_dir / dist.name
path.mkdir()
Expand All @@ -77,4 +77,4 @@ def test_order(self, temp_dir):
python_path.parent.ensure_dir_exists()
python_path.touch()

assert tuple(manager.get_installed()) == ORDERED_DISTRIBUTIONS
assert tuple(manager.get_installed()) == compatible_python_distributions
7 changes: 5 additions & 2 deletions tests/python/test_resolve.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import sys

import pytest

from hatch.errors import PythonDistributionResolutionError, PythonDistributionUnknownError
Expand All @@ -10,6 +12,7 @@ def test_unknown_distribution(self):
with pytest.raises(PythonDistributionUnknownError, match='Unknown distribution: foo'):
get_distribution('foo')

@pytest.mark.skipif(sys.platform == 'darwin', reason='No variants for macOS')
def test_resolution_error(self, platform):
with EnvVars({f'HATCH_PYTHON_VARIANT_{platform.name.upper()}': 'foo'}), pytest.raises(
PythonDistributionResolutionError,
Expand Down Expand Up @@ -47,14 +50,14 @@ def test_pypy(self):
('linux', 'v4'),
],
)
def test_variants(platform, system, variant):
def test_variants(platform, system, variant, current_arch):
if platform.name != system:
pytest.skip(f'Skipping test for: {system}')

with EnvVars({f'HATCH_PYTHON_VARIANT_{system.upper()}': variant}):
dist = get_distribution('3.11')

if system == 'linux' and variant == 'v1':
if system == 'linux' and (current_arch != 'x86_64' or variant == 'v1'):
assert variant not in dist.source
else:
assert variant in dist.source

0 comments on commit d17d8aa

Please sign in to comment.