Skip to content

Commit

Permalink
Fix Python resolution when there are metadata hooks (#1176)
Browse files Browse the repository at this point in the history
  • Loading branch information
ofek authored Dec 25, 2023
1 parent d17d8aa commit 637a53f
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 2 deletions.
1 change: 1 addition & 0 deletions docs/history/hatch.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

- 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
- Fix Python resolution when there are metadata hooks with unsatisfied dependencies

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

Expand Down
7 changes: 6 additions & 1 deletion src/hatch/env/virtual.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,12 @@ def _get_available_distribution(self, python_version: str = '') -> str | None:
return None

for available_distribution in available_distributions:
if not self.metadata.core.python_constraint.contains(available_distribution):
minor_version = (
available_distribution.replace('pypy', '', 1)
if available_distribution.startswith('pypy')
else available_distribution
)
if not self._python_constraint.contains(minor_version):
continue

return available_distribution
Expand Down
89 changes: 88 additions & 1 deletion tests/cli/run/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from hatch.python.resolve import get_compatible_distributions
from hatch.utils.fs import Path
from hatch.utils.structures import EnvVars
from hatchling.utils.constants import DEFAULT_CONFIG_FILE
from hatchling.utils.constants import DEFAULT_BUILD_SCRIPT, DEFAULT_CONFIG_FILE


@pytest.fixture(scope='module')
Expand Down Expand Up @@ -2235,3 +2235,90 @@ def test_update_python_max_compatible(hatch, helpers, temp_dir, config_file, moc
assert env_path.name == project_path.name

assert str(env_path) in str(output_file.read_text())


@pytest.mark.requires_internet
def test_python_installation_with_metadata_hook(
hatch, helpers, temp_dir, config_file, mocker, available_python_version
):
config_file.model.template.plugins['default']['tests'] = False
config_file.save()

project_name = 'My.App'

with temp_dir.as_cwd():
result = hatch('new', project_name)

assert result.exit_code == 0, result.output

project_path = temp_dir / 'my-app'
data_path = temp_dir / 'data'
data_path.mkdir()

project = Project(project_path)
config = dict(project.raw_config)
config['build-system']['requires'].append('foo')
config['tool']['hatch']['metadata'] = {'hooks': {'custom': {'dependencies': ['binary']}}}
project.save_config(config)

helpers.update_project_environment(
project,
'default',
{'skip-install': True, 'python': available_python_version, **project.config.envs['default']},
)

build_script = project_path / DEFAULT_BUILD_SCRIPT
build_script.write_text(
helpers.dedent(
"""
from hatchling.metadata.plugin.interface import MetadataHookInterface
class CustomMetadataHook(MetadataHookInterface):
def update(self, metadata):
import binary
"""
)
)

mocker.patch('hatch.env.virtual.VirtualEnvironment._interpreter_is_compatible', return_value=False)
manager = PythonManager(data_path / 'env' / 'virtual' / '.pythons')
assert not manager.get_installed()

with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
result = hatch(
'run', 'python', '-c', "import os,sys;open('test.txt', 'a').write(sys.executable+os.linesep[-1])"
)

assert result.exit_code == 0, result.output
assert result.output == helpers.dedent(
f"""
Creating environment: default
Installing Python distribution: {available_python_version}
Checking dependencies
"""
)
output_file = project_path / 'test.txt'
assert output_file.is_file()

env_data_path = data_path / 'env' / 'virtual'
assert env_data_path.is_dir()

project_data_path = env_data_path / project_path.name
assert project_data_path.is_dir()

storage_dirs = list(project_data_path.iterdir())
assert len(storage_dirs) == 1

storage_path = storage_dirs[0]
assert len(storage_path.name) == 8

env_dirs = list(storage_path.iterdir())
assert len(env_dirs) == 1

env_path = env_dirs[0]

assert env_path.name == project_path.name

assert str(env_path) in str(output_file.read_text())

assert list(manager.get_installed()) == [available_python_version]

0 comments on commit 637a53f

Please sign in to comment.