pypa-hatch/tests/cli/project/test_metadata.py

420 lines
13 KiB
Python

import os
import pytest
from hatch.config.constants import ConfigEnvVars
from hatch.project.core import Project
from hatchling.utils.constants import DEFAULT_CONFIG_FILE
pytestmark = [pytest.mark.usefixtures('mock_backend_process_output')]
def read_readme(project_dir):
return repr((project_dir / 'README.txt').read_text())[1:-1]
def test_other_backend(hatch, temp_dir, helpers):
project_name = 'My.App'
with temp_dir.as_cwd():
result = hatch('new', project_name)
assert result.exit_code == 0, result.output
path = temp_dir / 'my-app'
data_path = temp_dir / 'data'
data_path.mkdir()
(path / 'README.md').replace(path / 'README.txt')
project = Project(path)
config = dict(project.raw_config)
config['build-system']['requires'] = ['flit-core']
config['build-system']['build-backend'] = 'flit_core.buildapi'
config['project']['version'] = '0.0.1'
config['project']['dynamic'] = []
config['project']['readme'] = 'README.txt'
del config['project']['license']
project.save_config(config)
with path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
result = hatch('project', 'metadata')
assert result.exit_code == 0, result.output
assert result.output == helpers.dedent(
f"""
Creating environment: hatch-build
Checking dependencies
Syncing dependencies
Inspecting build dependencies
{{
"name": "my-app",
"version": "0.0.1",
"readme": {{
"content-type": "text/plain",
"text": "{read_readme(path)}\\n"
}},
"keywords": [
""
],
"classifiers": [
"Development Status :: 4 - Beta",
"Programming Language :: Python",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy"
],
"urls": {{
"Documentation": "https://github.com/Foo Bar/my-app#readme",
"Issues": "https://github.com/Foo Bar/my-app/issues",
"Source": "https://github.com/Foo Bar/my-app"
}},
"authors": [
{{
"email": "foo@bar.baz",
"name": "Foo Bar"
}}
],
"requires-python": ">=3.8"
}}
"""
)
def test_default_all(hatch, temp_dir, helpers):
project_name = 'My.App'
with temp_dir.as_cwd():
result = hatch('new', project_name)
assert result.exit_code == 0, result.output
path = temp_dir / 'my-app'
data_path = temp_dir / 'data'
data_path.mkdir()
(path / 'README.md').replace(path / 'README.txt')
project = Project(path)
config = dict(project.raw_config)
config['project']['readme'] = 'README.txt'
project.save_config(config)
with path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
result = hatch('project', 'metadata')
assert result.exit_code == 0, result.output
assert result.output == helpers.dedent(
f"""
Creating environment: hatch-build
Checking dependencies
Syncing dependencies
Inspecting build dependencies
{{
"name": "my-app",
"version": "0.0.1",
"readme": {{
"content-type": "text/plain",
"text": "{read_readme(path)}"
}},
"requires-python": ">=3.8",
"license": "MIT",
"authors": [
{{
"name": "Foo Bar",
"email": "foo@bar.baz"
}}
],
"classifiers": [
"Development Status :: 4 - Beta",
"Programming Language :: Python",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy"
],
"urls": {{
"Documentation": "https://github.com/Foo Bar/my-app#readme",
"Issues": "https://github.com/Foo Bar/my-app/issues",
"Source": "https://github.com/Foo Bar/my-app"
}}
}}
"""
)
def test_field_readme(hatch, temp_dir):
project_name = 'My.App'
with temp_dir.as_cwd():
result = hatch('new', project_name)
assert result.exit_code == 0, result.output
path = temp_dir / 'my-app'
data_path = temp_dir / 'data'
data_path.mkdir()
(path / 'README.md').replace(path / 'README.txt')
project = Project(path)
config = dict(project.raw_config)
config['project']['readme'] = 'README.txt'
project.save_config(config)
with path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
result = hatch('project', 'metadata', 'readme')
assert result.exit_code == 0, result.output
assert result.output == (
f"""\
Creating environment: hatch-build
Checking dependencies
Syncing dependencies
Inspecting build dependencies
{(path / 'README.txt').read_text()}
"""
)
def test_field_string(hatch, temp_dir, helpers):
project_name = 'My.App'
with temp_dir.as_cwd():
result = hatch('new', project_name)
assert result.exit_code == 0, result.output
path = temp_dir / 'my-app'
data_path = temp_dir / 'data'
data_path.mkdir()
with path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
result = hatch('project', 'metadata', 'license')
assert result.exit_code == 0, result.output
assert result.output == helpers.dedent(
"""
Creating environment: hatch-build
Checking dependencies
Syncing dependencies
Inspecting build dependencies
MIT
"""
)
def test_field_complex(hatch, temp_dir, helpers):
project_name = 'My.App'
with temp_dir.as_cwd():
result = hatch('new', project_name)
assert result.exit_code == 0, result.output
path = temp_dir / 'my-app'
data_path = temp_dir / 'data'
data_path.mkdir()
with path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
result = hatch('project', 'metadata', 'urls')
assert result.exit_code == 0, result.output
assert result.output == helpers.dedent(
"""
Creating environment: hatch-build
Checking dependencies
Syncing dependencies
Inspecting build dependencies
{
"Documentation": "https://github.com/Foo Bar/my-app#readme",
"Issues": "https://github.com/Foo Bar/my-app/issues",
"Source": "https://github.com/Foo Bar/my-app"
}
"""
)
@pytest.mark.allow_backend_process
def test_incompatible_environment(hatch, temp_dir, helpers, build_env_config):
project_name = 'My.App'
with temp_dir.as_cwd():
result = hatch('new', project_name)
assert result.exit_code == 0, result.output
path = temp_dir / 'my-app'
data_path = temp_dir / 'data'
data_path.mkdir()
project = Project(path)
helpers.update_project_environment(project, 'hatch-build', {'python': '9000', **build_env_config})
with path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
result = hatch('project', 'metadata')
assert result.exit_code == 1, result.output
assert result.output == helpers.dedent(
"""
Environment `hatch-build` is incompatible: cannot locate Python: 9000
"""
)
def test_plugin_dependencies_unmet(hatch, temp_dir, helpers, mock_plugin_installation):
project_name = 'My.App'
with temp_dir.as_cwd():
result = hatch('new', project_name)
assert result.exit_code == 0, result.output
path = temp_dir / 'my-app'
data_path = temp_dir / 'data'
data_path.mkdir()
dependency = os.urandom(16).hex()
(path / DEFAULT_CONFIG_FILE).write_text(
helpers.dedent(
f"""
[env]
requires = ["{dependency}"]
"""
)
)
(path / 'README.md').replace(path / 'README.txt')
project = Project(path)
config = dict(project.raw_config)
config['project']['readme'] = 'README.txt'
project.save_config(config)
with path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
result = hatch('project', 'metadata')
assert result.exit_code == 0, result.output
assert result.output == helpers.dedent(
f"""
Syncing environment plugin requirements
Creating environment: hatch-build
Checking dependencies
Syncing dependencies
Inspecting build dependencies
{{
"name": "my-app",
"version": "0.0.1",
"readme": {{
"content-type": "text/plain",
"text": "{read_readme(path)}"
}},
"requires-python": ">=3.8",
"license": "MIT",
"authors": [
{{
"name": "Foo Bar",
"email": "foo@bar.baz"
}}
],
"classifiers": [
"Development Status :: 4 - Beta",
"Programming Language :: Python",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy"
],
"urls": {{
"Documentation": "https://github.com/Foo Bar/my-app#readme",
"Issues": "https://github.com/Foo Bar/my-app/issues",
"Source": "https://github.com/Foo Bar/my-app"
}}
}}
"""
)
helpers.assert_plugin_installation(mock_plugin_installation, [dependency])
def test_build_dependencies_unmet(hatch, temp_dir, helpers):
project_name = 'My.App'
with temp_dir.as_cwd():
result = hatch('new', project_name)
assert result.exit_code == 0, result.output
path = temp_dir / 'my-app'
data_path = temp_dir / 'data'
data_path.mkdir()
(path / 'README.md').replace(path / 'README.txt')
project = Project(path)
config = dict(project.raw_config)
config['project']['readme'] = 'README.txt'
config['tool']['hatch']['build'] = {'dependencies': ['binary']}
project.save_config(config)
with path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
result = hatch('project', 'metadata', 'license')
assert result.exit_code == 0, result.output
assert result.output == helpers.dedent(
"""
Creating environment: hatch-build
Checking dependencies
Syncing dependencies
Inspecting build dependencies
Syncing dependencies
MIT
"""
)
@pytest.mark.allow_backend_process
@pytest.mark.requires_internet
def test_no_compatibility_check_if_exists(hatch, temp_dir, helpers, mocker):
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('binary')
project.save_config(config)
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
result = hatch('project', 'metadata', 'license')
assert result.exit_code == 0, result.output
assert result.output == helpers.dedent(
"""
Creating environment: hatch-build
Checking dependencies
Syncing dependencies
Inspecting build dependencies
MIT
"""
)
mocker.patch('hatch.env.virtual.VirtualEnvironment.check_compatibility', side_effect=Exception('incompatible'))
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
result = hatch('project', 'metadata', 'license')
assert result.exit_code == 0, result.output
assert result.output == helpers.dedent(
"""
Inspecting build dependencies
MIT
"""
)