pypa-hatch/tests/project/test_frontend.py

403 lines
12 KiB
Python

import json
import sys
import pytest
from hatch.env.plugin.interface import EnvironmentInterface
from hatch.project.core import Project
from hatchling.builders.constants import EDITABLES_REQUIREMENT
from hatchling.metadata.spec import project_metadata_from_core_metadata
BACKENDS = [('hatchling', 'hatchling.build'), ('flit-core', 'flit_core.buildapi')]
class MockEnvironment(EnvironmentInterface): # no cov
PLUGIN_NAME = 'mock'
def find(self):
pass
def create(self):
pass
def remove(self):
pass
def exists(self):
pass
def install_project(self):
pass
def install_project_dev_mode(self):
pass
def dependencies_in_sync(self):
pass
def sync_dependencies(self):
pass
class TestPrepareMetadata:
@pytest.mark.parametrize(
('backend_pkg', 'backend_api'),
[pytest.param(backend_pkg, backend_api, id=backend_pkg) for backend_pkg, backend_api in BACKENDS],
)
def test_wheel(self, temp_dir, temp_dir_data, platform, global_application, backend_pkg, backend_api):
project_dir = temp_dir / 'project'
project_dir.mkdir()
(project_dir / 'pyproject.toml').write_text(
f"""\
[build-system]
requires = ["{backend_pkg}"]
build-backend = "{backend_api}"
[project]
name = "foo"
version = "9000.42"
description = "text"
"""
)
package_dir = project_dir / 'foo'
package_dir.mkdir()
(package_dir / '__init__.py').touch()
project = Project(project_dir)
project.build_env = MockEnvironment(
temp_dir,
project.metadata,
'default',
project.config.envs['default'],
{},
temp_dir_data,
temp_dir_data,
platform,
0,
global_application,
)
output_dir = temp_dir / 'output'
output_dir.mkdir()
script = project.build_frontend.scripts.prepare_metadata(
output_dir=str(output_dir), project_root=str(project_dir)
)
platform.check_command([sys.executable, '-c', script])
work_dir = output_dir / 'work'
output = json.loads((output_dir / 'output.json').read_text())
metadata_file = work_dir / output['return_val'] / 'METADATA'
assert project_metadata_from_core_metadata(metadata_file.read_text()) == {
'name': 'foo',
'version': '9000.42',
'description': 'text',
}
@pytest.mark.parametrize(
('backend_pkg', 'backend_api'),
[pytest.param(backend_pkg, backend_api, id=backend_pkg) for backend_pkg, backend_api in BACKENDS],
)
def test_editable(self, temp_dir, temp_dir_data, platform, global_application, backend_pkg, backend_api):
project_dir = temp_dir / 'project'
project_dir.mkdir()
(project_dir / 'pyproject.toml').write_text(
f"""\
[build-system]
requires = ["{backend_pkg}"]
build-backend = "{backend_api}"
[project]
name = "foo"
version = "9000.42"
description = "text"
"""
)
package_dir = project_dir / 'foo'
package_dir.mkdir()
(package_dir / '__init__.py').touch()
project = Project(project_dir)
project.build_env = MockEnvironment(
temp_dir,
project.metadata,
'default',
project.config.envs['default'],
{},
temp_dir_data,
temp_dir_data,
platform,
0,
global_application,
)
output_dir = temp_dir / 'output'
output_dir.mkdir()
script = project.build_frontend.scripts.prepare_metadata(
output_dir=str(output_dir), project_root=str(project_dir), editable=True
)
platform.check_command([sys.executable, '-c', script])
work_dir = output_dir / 'work'
output = json.loads((output_dir / 'output.json').read_text())
metadata_file = work_dir / output['return_val'] / 'METADATA'
assert project_metadata_from_core_metadata(metadata_file.read_text()) == {
'name': 'foo',
'version': '9000.42',
'description': 'text',
}
class TestBuildWheel:
@pytest.mark.parametrize(
('backend_pkg', 'backend_api'),
[pytest.param(backend_pkg, backend_api, id=backend_pkg) for backend_pkg, backend_api in BACKENDS],
)
def test_standard(self, temp_dir, temp_dir_data, platform, global_application, backend_pkg, backend_api):
project_dir = temp_dir / 'project'
project_dir.mkdir()
(project_dir / 'pyproject.toml').write_text(
f"""\
[build-system]
requires = ["{backend_pkg}"]
build-backend = "{backend_api}"
[project]
name = "foo"
version = "9000.42"
description = "text"
"""
)
package_dir = project_dir / 'foo'
package_dir.mkdir()
(package_dir / '__init__.py').touch()
project = Project(project_dir)
project.build_env = MockEnvironment(
temp_dir,
project.metadata,
'default',
project.config.envs['default'],
{},
temp_dir_data,
temp_dir_data,
platform,
0,
global_application,
)
output_dir = temp_dir / 'output'
output_dir.mkdir()
script = project.build_frontend.scripts.build_wheel(output_dir=str(output_dir), project_root=str(project_dir))
platform.check_command([sys.executable, '-c', script])
work_dir = output_dir / 'work'
output = json.loads((output_dir / 'output.json').read_text())
wheel_path = work_dir / output['return_val']
assert wheel_path.is_file()
assert wheel_path.name.startswith('foo-9000.42-')
assert wheel_path.name.endswith('.whl')
@pytest.mark.parametrize(
('backend_pkg', 'backend_api'),
[pytest.param(backend_pkg, backend_api, id=backend_pkg) for backend_pkg, backend_api in BACKENDS],
)
def test_editable(self, temp_dir, temp_dir_data, platform, global_application, backend_pkg, backend_api):
project_dir = temp_dir / 'project'
project_dir.mkdir()
(project_dir / 'pyproject.toml').write_text(
f"""\
[build-system]
requires = ["{backend_pkg}"]
build-backend = "{backend_api}"
[project]
name = "foo"
version = "9000.42"
description = "text"
"""
)
package_dir = project_dir / 'foo'
package_dir.mkdir()
(package_dir / '__init__.py').touch()
project = Project(project_dir)
project.build_env = MockEnvironment(
temp_dir,
project.metadata,
'default',
project.config.envs['default'],
{},
temp_dir_data,
temp_dir_data,
platform,
0,
global_application,
)
output_dir = temp_dir / 'output'
output_dir.mkdir()
script = project.build_frontend.scripts.build_wheel(
output_dir=str(output_dir), project_root=str(project_dir), editable=True
)
platform.check_command([sys.executable, '-c', script])
work_dir = output_dir / 'work'
output = json.loads((output_dir / 'output.json').read_text())
wheel_path = work_dir / output['return_val']
assert wheel_path.is_file()
assert wheel_path.name.startswith('foo-9000.42-')
assert wheel_path.name.endswith('.whl')
class TestSourceDistribution:
@pytest.mark.parametrize(
('backend_pkg', 'backend_api'),
[pytest.param(backend_pkg, backend_api, id=backend_pkg) for backend_pkg, backend_api in BACKENDS],
)
def test_standard(self, temp_dir, temp_dir_data, platform, global_application, backend_pkg, backend_api):
project_dir = temp_dir / 'project'
project_dir.mkdir()
(project_dir / 'pyproject.toml').write_text(
f"""\
[build-system]
requires = ["{backend_pkg}"]
build-backend = "{backend_api}"
[project]
name = "foo"
version = "9000.42"
description = "text"
"""
)
package_dir = project_dir / 'foo'
package_dir.mkdir()
(package_dir / '__init__.py').touch()
project = Project(project_dir)
project.build_env = MockEnvironment(
temp_dir,
project.metadata,
'default',
project.config.envs['default'],
{},
temp_dir_data,
temp_dir_data,
platform,
0,
global_application,
)
output_dir = temp_dir / 'output'
output_dir.mkdir()
script = project.build_frontend.scripts.build_sdist(output_dir=str(output_dir), project_root=str(project_dir))
platform.check_command([sys.executable, '-c', script])
work_dir = output_dir / 'work'
output = json.loads((output_dir / 'output.json').read_text())
sdist_path = work_dir / output['return_val']
assert sdist_path.is_file()
assert sdist_path.name == 'foo-9000.42.tar.gz'
class TestGetRequires:
@pytest.mark.parametrize(
('backend_pkg', 'backend_api'),
[pytest.param(backend_pkg, backend_api, id=backend_pkg) for backend_pkg, backend_api in BACKENDS],
)
@pytest.mark.parametrize('build', ['sdist', 'wheel', 'editable'])
def test_default(self, temp_dir, temp_dir_data, platform, global_application, backend_pkg, backend_api, build):
project_dir = temp_dir / 'project'
project_dir.mkdir()
(project_dir / 'pyproject.toml').write_text(
f"""\
[build-system]
requires = ["{backend_pkg}"]
build-backend = "{backend_api}"
[project]
name = "foo"
version = "9000.42"
description = "text"
"""
)
package_dir = project_dir / 'foo'
package_dir.mkdir()
(package_dir / '__init__.py').touch()
project = Project(project_dir)
project.build_env = MockEnvironment(
temp_dir,
project.metadata,
'default',
project.config.envs['default'],
{},
temp_dir_data,
temp_dir_data,
platform,
0,
global_application,
)
output_dir = temp_dir / 'output'
output_dir.mkdir()
script = project.build_frontend.scripts.get_requires(
output_dir=str(output_dir), project_root=str(project_dir), build=build
)
platform.check_command([sys.executable, '-c', script])
output = json.loads((output_dir / 'output.json').read_text())
assert output['return_val'] == (
[EDITABLES_REQUIREMENT] if backend_pkg == 'hatchling' and build == 'editable' else []
)
class TestHatchGetBuildDeps:
def test_default(self, temp_dir, temp_dir_data, platform, global_application):
project_dir = temp_dir / 'project'
project_dir.mkdir()
(project_dir / 'pyproject.toml').write_text(
"""\
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "foo"
version = "9000.42"
"""
)
package_dir = project_dir / 'foo'
package_dir.mkdir()
(package_dir / '__init__.py').touch()
project = Project(project_dir)
project.build_env = MockEnvironment(
temp_dir,
project.metadata,
'default',
project.config.envs['default'],
{},
temp_dir_data,
temp_dir_data,
platform,
0,
global_application,
)
output_dir = temp_dir / 'output'
output_dir.mkdir()
script = project.build_frontend.hatch.scripts.get_build_deps(
output_dir=str(output_dir), project_root=str(project_dir), targets=['sdist', 'wheel']
)
platform.check_command([sys.executable, '-c', script])
output = json.loads((output_dir / 'output.json').read_text())
assert output == []