mirror of https://github.com/pypa/hatch.git
1136 lines
48 KiB
Python
1136 lines
48 KiB
Python
import re
|
|
from os.path import join as pjoin
|
|
from os.path import sep as path_sep
|
|
|
|
import pathspec
|
|
import pytest
|
|
|
|
from hatchling.builders.plugin.interface import BuilderInterface
|
|
from hatchling.metadata.core import ProjectMetadata
|
|
from hatchling.plugin.manager import PluginManager
|
|
|
|
|
|
class TestClean:
|
|
def test_default(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
builder.clean(None, None)
|
|
|
|
|
|
class TestVersionAPI:
|
|
def test_error(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
with pytest.raises(NotImplementedError):
|
|
builder.get_version_api()
|
|
|
|
|
|
class TestPluginManager:
|
|
def test_default(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
assert isinstance(builder.plugin_manager, PluginManager)
|
|
|
|
def test_reuse(self, isolation):
|
|
plugin_manager = PluginManager()
|
|
builder = BuilderInterface(str(isolation), plugin_manager=plugin_manager)
|
|
|
|
assert builder.plugin_manager is plugin_manager
|
|
|
|
|
|
class TestConfig:
|
|
def test_default(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
assert builder.config == builder.config == {}
|
|
|
|
def test_reuse(self, isolation):
|
|
config = {}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.config is builder.config is config
|
|
|
|
def test_read(self, temp_dir):
|
|
project_file = temp_dir / 'pyproject.toml'
|
|
project_file.write_text('foo = 5')
|
|
|
|
with temp_dir.as_cwd():
|
|
builder = BuilderInterface(str(temp_dir))
|
|
|
|
assert builder.config == builder.config == {'foo': 5}
|
|
|
|
|
|
class TestMetadata:
|
|
def test_base(self, isolation):
|
|
config = {'project': {'name': 'foo'}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert isinstance(builder.metadata, ProjectMetadata)
|
|
assert builder.metadata.core.name == 'foo'
|
|
|
|
def test_core(self, isolation):
|
|
config = {'project': {}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.project_config is builder.project_config is config['project']
|
|
|
|
def test_hatch(self, isolation):
|
|
config = {'tool': {'hatch': {}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.hatch_config is builder.hatch_config is config['tool']['hatch']
|
|
|
|
def test_build_config(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.build_config is builder.build_config is config['tool']['hatch']['build']
|
|
|
|
def test_build_config_not_table(self, isolation):
|
|
config = {'tool': {'hatch': {'build': 'foo'}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
with pytest.raises(TypeError, match='Field `tool.hatch.build` must be a table'):
|
|
_ = builder.build_config
|
|
|
|
def test_target_config(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.target_config is builder.target_config is config['tool']['hatch']['build']['targets']['foo']
|
|
|
|
def test_target_config_not_table(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': 'bar'}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(TypeError, match='Field `tool.hatch.build.targets.foo` must be a table'):
|
|
_ = builder.target_config
|
|
|
|
|
|
class TestProjectID:
|
|
def test_normalization(self, isolation):
|
|
config = {'project': {'name': 'my-app', 'version': '1.0.0-rc.1'}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.project_id == builder.project_id == 'my_app-1rc1'
|
|
|
|
|
|
class TestDirectory:
|
|
def test_default(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
assert builder.directory == builder.directory == str(isolation / 'dist')
|
|
|
|
def test_target(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'directory': 'bar'}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.directory == str(isolation / 'bar')
|
|
|
|
def test_target_not_boolean(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'directory': 9000}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(TypeError, match='Field `tool.hatch.build.targets.foo.directory` must be a string'):
|
|
_ = builder.directory
|
|
|
|
def test_global(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'directory': 'bar'}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.directory == str(isolation / 'bar')
|
|
|
|
def test_global_not_boolean(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'directory': 9000}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(TypeError, match='Field `tool.hatch.build.directory` must be a string'):
|
|
_ = builder.directory
|
|
|
|
def test_target_overrides_global(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'directory': 'bar', 'targets': {'foo': {'directory': 'baz'}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.directory == str(isolation / 'baz')
|
|
|
|
def test_absolute_path(self, isolation):
|
|
absolute_path = str(isolation)
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'directory': absolute_path}}}}}}
|
|
builder = BuilderInterface(absolute_path, config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.directory == absolute_path
|
|
|
|
|
|
class TestIgnoreVCS:
|
|
def test_default(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
assert builder.ignore_vcs is builder.ignore_vcs is False
|
|
|
|
def test_target(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'ignore-vcs': True}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.ignore_vcs is True
|
|
|
|
def test_target_not_boolean(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'ignore-vcs': 9000}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(TypeError, match='Field `tool.hatch.build.targets.foo.ignore-vcs` must be a boolean'):
|
|
_ = builder.ignore_vcs
|
|
|
|
def test_global(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'ignore-vcs': True}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.ignore_vcs is True
|
|
|
|
def test_global_not_boolean(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'ignore-vcs': 9000}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(TypeError, match='Field `tool.hatch.build.ignore-vcs` must be a boolean'):
|
|
_ = builder.ignore_vcs
|
|
|
|
def test_target_overrides_global(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'ignore-vcs': True, 'targets': {'foo': {'ignore-vcs': False}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.ignore_vcs is False
|
|
|
|
|
|
class TestReproducible:
|
|
def test_default(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
assert builder.reproducible is builder.reproducible is True
|
|
|
|
def test_target(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'reproducible': False}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.reproducible is False
|
|
|
|
def test_target_not_boolean(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'reproducible': 9000}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(TypeError, match='Field `tool.hatch.build.targets.foo.reproducible` must be a boolean'):
|
|
_ = builder.reproducible
|
|
|
|
def test_global(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'reproducible': False}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.reproducible is False
|
|
|
|
def test_global_not_boolean(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'reproducible': 9000}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(TypeError, match='Field `tool.hatch.build.reproducible` must be a boolean'):
|
|
_ = builder.reproducible
|
|
|
|
def test_target_overrides_global(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'reproducible': False, 'targets': {'foo': {'reproducible': True}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.reproducible is True
|
|
|
|
|
|
class TestDevModeDirs:
|
|
def test_default(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
assert builder.dev_mode_dirs == builder.dev_mode_dirs == []
|
|
|
|
def test_global_invalid_type(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'dev-mode-dirs': 3}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
with pytest.raises(
|
|
TypeError,
|
|
match='Field `tool.hatch.build.dev-mode-dirs` must be a comma-separated string or an array of strings',
|
|
):
|
|
_ = builder.dev_mode_dirs
|
|
|
|
def test_global_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'dev-mode-dirs': 'foo,bar/baz,'}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.dev_mode_dirs == ['foo', 'bar/baz']
|
|
|
|
def test_global_array(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'dev-mode-dirs': ['foo', 'bar/baz', '']}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.dev_mode_dirs == ['foo', 'bar/baz']
|
|
|
|
def test_global_array_pattern_not_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'dev-mode-dirs': [0]}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
with pytest.raises(TypeError, match='Directory #1 in field `tool.hatch.build.dev-mode-dirs` must be a string'):
|
|
_ = builder.dev_mode_dirs
|
|
|
|
def test_target_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'dev-mode-dirs': 'foo,bar/baz,'}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.dev_mode_dirs == ['foo', 'bar/baz']
|
|
|
|
def test_target_array(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'dev-mode-dirs': ['foo', 'bar/baz', '']}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.dev_mode_dirs == ['foo', 'bar/baz']
|
|
|
|
def test_target_array_pattern_not_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'dev-mode-dirs': [0]}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(
|
|
TypeError, match='Directory #1 in field `tool.hatch.build.targets.foo.dev-mode-dirs` must be a string'
|
|
):
|
|
_ = builder.dev_mode_dirs
|
|
|
|
def test_target_overrides_global(self, isolation):
|
|
config = {
|
|
'tool': {'hatch': {'build': {'dev-mode-dirs': ['foo'], 'targets': {'foo': {'dev-mode-dirs': ['bar']}}}}}
|
|
}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.dev_mode_dirs == ['bar']
|
|
|
|
|
|
class TestPackages:
|
|
def test_default(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
assert builder.packages == builder.packages == []
|
|
assert builder.get_distribution_path(pjoin('src', 'foo', 'bar.py')) == pjoin('src', 'foo', 'bar.py')
|
|
|
|
def test_global_invalid_type(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'packages': 3}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
with pytest.raises(
|
|
TypeError,
|
|
match='Field `tool.hatch.build.packages` must be a comma-separated string or an array of strings',
|
|
):
|
|
_ = builder.packages
|
|
|
|
def test_global_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'packages': 'src/foo,'}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert len(builder.packages) == 1
|
|
assert builder.packages[0][0] == pjoin('src', 'foo', '')
|
|
assert builder.get_distribution_path(pjoin('src', 'foo', 'bar.py')) == pjoin('foo', 'bar.py')
|
|
|
|
def test_global_array(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'packages': ['src/foo', '']}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert len(builder.packages) == 1
|
|
assert builder.packages[0][0] == pjoin('src', 'foo', '')
|
|
assert builder.get_distribution_path(pjoin('src', 'foo', 'bar.py')) == pjoin('foo', 'bar.py')
|
|
|
|
def test_global_array_package_not_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'packages': [0]}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
with pytest.raises(TypeError, match='Package #1 in field `tool.hatch.build.packages` must be a string'):
|
|
_ = builder.packages
|
|
|
|
def test_global_duplicate_package_name(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'packages': ['src/foo', 'pkg/foo']}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
with pytest.raises(
|
|
ValueError,
|
|
match=re.escape(
|
|
f'Package `foo` of field `tool.hatch.build.packages` is already defined '
|
|
f'by path `{pjoin("pkg", "foo")}`'
|
|
),
|
|
):
|
|
_ = builder.packages
|
|
|
|
def test_target_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'packages': 'src/foo,'}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert len(builder.packages) == 1
|
|
assert builder.packages[0][0] == pjoin('src', 'foo', '')
|
|
assert builder.get_distribution_path(pjoin('src', 'foo', 'bar.py')) == pjoin('foo', 'bar.py')
|
|
|
|
def test_target_array(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'packages': ['src/foo', '']}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert len(builder.packages) == 1
|
|
assert builder.packages[0][0] == pjoin('src', 'foo', '')
|
|
assert builder.get_distribution_path(pjoin('src', 'foo', 'bar.py')) == pjoin('foo', 'bar.py')
|
|
|
|
def test_target_array_package_not_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'packages': [0]}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(
|
|
TypeError, match='Package #1 in field `tool.hatch.build.targets.foo.packages` must be a string'
|
|
):
|
|
_ = builder.packages
|
|
|
|
def test_target_duplicate_package_name(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'packages': ['src/foo', 'pkg/foo']}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(
|
|
ValueError,
|
|
match=re.escape(
|
|
f'Package `foo` of field `tool.hatch.build.targets.foo.packages` is already defined '
|
|
f'by path `{pjoin("pkg", "foo")}`'
|
|
),
|
|
):
|
|
_ = builder.packages
|
|
|
|
def test_target_overrides_global(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'packages': 'src/foo', 'targets': {'foo': {'packages': 'pkg/foo'}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert len(builder.packages) == 1
|
|
assert builder.packages[0][0] == pjoin('pkg', 'foo', '')
|
|
assert builder.get_distribution_path(pjoin('pkg', 'foo', 'bar.py')) == pjoin('foo', 'bar.py')
|
|
assert builder.get_distribution_path(pjoin('src', 'foo', 'bar.py')) == pjoin('src', 'foo', 'bar.py')
|
|
|
|
def test_no_source(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'packages': 'foo'}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert len(builder.packages) == 1
|
|
assert builder.packages[0][0] == pjoin('foo', '')
|
|
assert builder.get_distribution_path(pjoin('foo', 'bar.py')) == pjoin('foo', 'bar.py')
|
|
|
|
|
|
class TestVersions:
|
|
def test_default_known(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
builder.PLUGIN_NAME = 'foo'
|
|
builder.get_version_api = lambda: {'2': str, '1': str}
|
|
|
|
assert builder.versions == builder.versions == ['2', '1']
|
|
|
|
def test_default_override(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
builder.PLUGIN_NAME = 'foo'
|
|
builder.get_default_versions = lambda: ['old', 'new', 'new']
|
|
|
|
assert builder.versions == builder.versions == ['old', 'new']
|
|
|
|
def test_invalid_type(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'versions': 1}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(
|
|
TypeError,
|
|
match=(
|
|
'Field `tool.hatch.build.targets.foo.versions` must be a '
|
|
'comma-separated string or an array of strings'
|
|
),
|
|
):
|
|
_ = builder.versions
|
|
|
|
def test_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'versions': '3.14,1,3.14,'}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
builder.get_version_api = lambda: {'3.14': str, '42': str, '1': str}
|
|
|
|
assert builder.versions == builder.versions == ['3.14', '1']
|
|
|
|
def test_string_empty_default(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'versions': ''}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
builder.get_default_versions = lambda: ['old', 'new']
|
|
|
|
assert builder.versions == builder.versions == ['old', 'new']
|
|
|
|
def test_string_unknown_version(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'versions': '9000,1,42'}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
builder.get_version_api = lambda: {'1': str}
|
|
|
|
with pytest.raises(
|
|
ValueError, match='Unknown versions in field `tool.hatch.build.targets.foo.versions`: 42, 9000'
|
|
):
|
|
_ = builder.versions
|
|
|
|
def test_array(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'versions': ['3.14', '1', '3.14', '']}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
builder.get_version_api = lambda: {'3.14': str, '42': str, '1': str}
|
|
|
|
assert builder.versions == builder.versions == ['3.14', '1']
|
|
|
|
def test_array_empty_default(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'versions': []}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
builder.get_default_versions = lambda: ['old', 'new']
|
|
|
|
assert builder.versions == builder.versions == ['old', 'new']
|
|
|
|
def test_array_version_not_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'versions': [1]}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(
|
|
TypeError, match='Version #1 in field `tool.hatch.build.targets.foo.versions` must be a string'
|
|
):
|
|
_ = builder.versions
|
|
|
|
def test_array_unknown_version(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'versions': ['9000', '1', '42']}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
builder.get_version_api = lambda: {'1': str}
|
|
|
|
with pytest.raises(
|
|
ValueError, match='Unknown versions in field `tool.hatch.build.targets.foo.versions`: 42, 9000'
|
|
):
|
|
_ = builder.versions
|
|
|
|
def test_build_validation(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'versions': ['1']}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
builder.get_version_api = lambda: {'1': str}
|
|
|
|
with pytest.raises(ValueError, match='Unknown versions for target `foo`: 42, 9000'):
|
|
next(builder.build(str(isolation), versions=['9000', '42']))
|
|
|
|
|
|
class TestHookConfig:
|
|
def test_default(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
assert builder.hook_config == builder.hook_config == {}
|
|
|
|
def test_target_not_table(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'hooks': 'bar'}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(TypeError, match='Field `tool.hatch.build.targets.foo.hooks` must be a table'):
|
|
_ = builder.hook_config
|
|
|
|
def test_target_hook_not_table(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'hooks': {'bar': 'baz'}}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(TypeError, match='Field `tool.hatch.build.targets.foo.hooks.bar` must be a table'):
|
|
_ = builder.hook_config
|
|
|
|
def test_global_not_table(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'hooks': 'foo'}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
with pytest.raises(TypeError, match='Field `tool.hatch.build.hooks` must be a table'):
|
|
_ = builder.hook_config
|
|
|
|
def test_global_hook_not_table(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'hooks': {'foo': 'bar'}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
with pytest.raises(TypeError, match='Field `tool.hatch.build.hooks.foo` must be a table'):
|
|
_ = builder.hook_config
|
|
|
|
def test_global(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'hooks': {'foo': {'bar': 'baz'}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.hook_config['foo']['bar'] == 'baz'
|
|
|
|
def test_target_overrides_global(self, isolation):
|
|
config = {
|
|
'tool': {
|
|
'hatch': {
|
|
'build': {'hooks': {'foo': {'bar': 'baz'}}, 'targets': {'foo': {'hooks': {'foo': {'baz': 'bar'}}}}}
|
|
}
|
|
},
|
|
}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.hook_config['foo']['baz'] == 'bar'
|
|
|
|
def test_unknown(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'hooks': {'foo': {'bar': 'baz'}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
with pytest.raises(ValueError, match='Unknown build hook: foo'):
|
|
_ = builder.get_build_hooks(str(isolation))
|
|
|
|
|
|
class TestDependencies:
|
|
def test_default(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
assert builder.dependencies == builder.dependencies == []
|
|
|
|
def test_target_not_array(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'dependencies': 9000}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(TypeError, match='Field `tool.hatch.build.targets.foo.dependencies` must be an array'):
|
|
_ = builder.dependencies
|
|
|
|
def test_target_dependency_not_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'dependencies': [9000]}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(
|
|
TypeError, match='Dependency #1 of field `tool.hatch.build.targets.foo.dependencies` must be a string'
|
|
):
|
|
_ = builder.dependencies
|
|
|
|
def test_global_not_array(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'dependencies': 9000}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(TypeError, match='Field `tool.hatch.build.dependencies` must be an array'):
|
|
_ = builder.dependencies
|
|
|
|
def test_global_dependency_not_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'dependencies': [9000]}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(TypeError, match='Dependency #1 of field `tool.hatch.build.dependencies` must be a string'):
|
|
_ = builder.dependencies
|
|
|
|
def test_hook_not_array(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'hooks': {'foo': {'dependencies': 9000}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(TypeError, match='Option `dependencies` of build hook `foo` must be an array'):
|
|
_ = builder.dependencies
|
|
|
|
def test_hook_dependency_not_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'hooks': {'foo': {'dependencies': [9000]}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(
|
|
TypeError, match='Dependency #1 of option `dependencies` of build hook `foo` must be a string'
|
|
):
|
|
_ = builder.dependencies
|
|
|
|
def test_correct(self, isolation):
|
|
config = {
|
|
'tool': {
|
|
'hatch': {
|
|
'build': {
|
|
'dependencies': ['bar'],
|
|
'hooks': {'foobar': {'dependencies': ['test1']}},
|
|
'targets': {'foo': {'dependencies': ['baz'], 'hooks': {'foobar': {'dependencies': ['test2']}}}},
|
|
}
|
|
}
|
|
}
|
|
}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.dependencies == ['baz', 'bar', 'test2']
|
|
|
|
|
|
class TestPatternDefaults:
|
|
def test_include(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
assert builder.default_include_patterns() == []
|
|
|
|
def test_exclude(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
assert builder.default_exclude_patterns() == []
|
|
|
|
def test_global_exclude(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
assert builder.default_global_exclude_patterns() == ['.git']
|
|
|
|
|
|
class TestPatternInclude:
|
|
def test_default(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
assert builder.include_spec is None
|
|
|
|
def test_global_becomes_spec(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'include': 'foo'}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert isinstance(builder.include_spec, pathspec.PathSpec)
|
|
|
|
def test_global_invalid_type(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'include': 3}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
with pytest.raises(
|
|
TypeError,
|
|
match='Field `tool.hatch.build.include` must be a comma-separated string or an array of strings',
|
|
):
|
|
_ = builder.include_spec
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_global_string(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'include': 'foo,bar/baz,'}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.include_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.include_spec.match_file(f'bar{separator}baz{separator}file.py')
|
|
assert not builder.include_spec.match_file(f'bar{separator}file.py')
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_global_array(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'include': ['foo', 'bar/baz', '']}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.include_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.include_spec.match_file(f'bar{separator}baz{separator}file.py')
|
|
assert not builder.include_spec.match_file(f'bar{separator}file.py')
|
|
|
|
def test_global_array_pattern_not_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'include': [0]}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
with pytest.raises(TypeError, match='Pattern #1 in field `tool.hatch.build.include` must be a string'):
|
|
_ = builder.include_spec
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_global_packages_included(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'packages': 'bar', 'include': 'foo'}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.include_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.include_spec.match_file(f'bar{separator}baz{separator}file.py')
|
|
assert not builder.include_spec.match_file(f'baz{separator}bar{separator}file.py')
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_target_string(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'include': 'foo,bar/baz,'}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.include_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.include_spec.match_file(f'bar{separator}baz{separator}file.py')
|
|
assert not builder.include_spec.match_file(f'bar{separator}file.py')
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_target_array(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'include': ['foo', 'bar/baz', '']}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.include_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.include_spec.match_file(f'bar{separator}baz{separator}file.py')
|
|
assert not builder.include_spec.match_file(f'bar{separator}file.py')
|
|
|
|
def test_target_array_pattern_not_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'include': [0]}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(
|
|
TypeError, match='Pattern #1 in field `tool.hatch.build.targets.foo.include` must be a string'
|
|
):
|
|
_ = builder.include_spec
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_target_overrides_global(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'include': ['foo'], 'targets': {'foo': {'include': ['bar']}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert not builder.include_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.include_spec.match_file(f'bar{separator}file.py')
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_target_packages_included(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'packages': 'bar', 'include': 'foo'}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.include_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.include_spec.match_file(f'bar{separator}baz{separator}file.py')
|
|
assert not builder.include_spec.match_file(f'baz{separator}bar{separator}file.py')
|
|
|
|
|
|
class TestPatternExclude:
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_default(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
assert isinstance(builder.exclude_spec, pathspec.PathSpec)
|
|
assert builder.exclude_spec.match_file(f'.git{separator}file.py')
|
|
|
|
def test_global_invalid_type(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'exclude': 3}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
with pytest.raises(
|
|
TypeError,
|
|
match='Field `tool.hatch.build.exclude` must be a comma-separated string or an array of strings',
|
|
):
|
|
_ = builder.exclude_spec
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_global_string(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'exclude': 'foo,bar/baz,'}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.exclude_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.exclude_spec.match_file(f'bar{separator}baz{separator}file.py')
|
|
assert not builder.exclude_spec.match_file(f'bar{separator}file.py')
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_global_array(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'exclude': ['foo', 'bar/baz', '']}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.exclude_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.exclude_spec.match_file(f'bar{separator}baz{separator}file.py')
|
|
assert not builder.exclude_spec.match_file(f'bar{separator}file.py')
|
|
|
|
def test_global_array_pattern_not_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'exclude': [0]}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
with pytest.raises(TypeError, match='Pattern #1 in field `tool.hatch.build.exclude` must be a string'):
|
|
_ = builder.exclude_spec
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_target_string(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'exclude': 'foo,bar/baz,'}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.exclude_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.exclude_spec.match_file(f'bar{separator}baz{separator}file.py')
|
|
assert not builder.exclude_spec.match_file(f'bar{separator}file.py')
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_target_array(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'exclude': ['foo', 'bar/baz', '']}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.exclude_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.exclude_spec.match_file(f'bar{separator}baz{separator}file.py')
|
|
assert not builder.exclude_spec.match_file(f'bar{separator}file.py')
|
|
|
|
def test_target_array_pattern_not_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'exclude': [0]}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(
|
|
TypeError, match='Pattern #1 in field `tool.hatch.build.targets.foo.exclude` must be a string'
|
|
):
|
|
_ = builder.exclude_spec
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_target_overrides_global(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'exclude': ['foo'], 'targets': {'foo': {'exclude': ['bar']}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert not builder.exclude_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.exclude_spec.match_file(f'bar{separator}file.py')
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_vcs(self, temp_dir, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
with temp_dir.as_cwd():
|
|
config = {'tool': {'hatch': {'build': {'exclude': ['foo']}}}}
|
|
builder = BuilderInterface(str(temp_dir), config=config)
|
|
|
|
vcs_ignore_file = temp_dir / '.gitignore'
|
|
vcs_ignore_file.write_text('/bar\n*.pyc')
|
|
|
|
assert builder.exclude_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.exclude_spec.match_file(f'bar{separator}file.py')
|
|
assert builder.exclude_spec.match_file(f'baz{separator}bar{separator}file.pyc')
|
|
assert not builder.exclude_spec.match_file(f'baz{separator}bar{separator}file.py')
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_ignore_vcs(self, temp_dir, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
with temp_dir.as_cwd():
|
|
config = {'tool': {'hatch': {'build': {'ignore-vcs': True, 'exclude': ['foo']}}}}
|
|
builder = BuilderInterface(str(temp_dir), config=config)
|
|
|
|
vcs_ignore_file = temp_dir / '.gitignore'
|
|
vcs_ignore_file.write_text('/bar\n*.pyc')
|
|
|
|
assert builder.exclude_spec.match_file(f'foo{separator}file.py')
|
|
assert not builder.exclude_spec.match_file(f'bar{separator}file.py')
|
|
|
|
def test_override_default_global_exclude_patterns(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
builder.default_global_exclude_patterns = lambda: []
|
|
|
|
assert builder.exclude_spec is None
|
|
assert not builder.path_is_excluded('.git/file')
|
|
|
|
|
|
class TestPatternArtifacts:
|
|
def test_default(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
assert builder.artifact_spec is None
|
|
|
|
def test_global_becomes_spec(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'artifacts': 'foo'}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert isinstance(builder.artifact_spec, pathspec.PathSpec)
|
|
|
|
def test_global_invalid_type(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'artifacts': 3}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
with pytest.raises(
|
|
TypeError,
|
|
match='Field `tool.hatch.build.artifacts` must be a comma-separated string or an array of strings',
|
|
):
|
|
_ = builder.artifact_spec
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_global_string(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'artifacts': 'foo,bar/baz,'}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.artifact_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.artifact_spec.match_file(f'bar{separator}baz{separator}file.py')
|
|
assert not builder.artifact_spec.match_file(f'bar{separator}file.py')
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_global_array(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'artifacts': ['foo', 'bar/baz', '']}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.artifact_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.artifact_spec.match_file(f'bar{separator}baz{separator}file.py')
|
|
assert not builder.artifact_spec.match_file(f'bar{separator}file.py')
|
|
|
|
def test_global_array_pattern_not_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'artifacts': [0]}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
with pytest.raises(TypeError, match='Pattern #1 in field `tool.hatch.build.artifacts` must be a string'):
|
|
_ = builder.artifact_spec
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_target_string(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'artifacts': 'foo,bar/baz,'}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.artifact_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.artifact_spec.match_file(f'bar{separator}baz{separator}file.py')
|
|
assert not builder.artifact_spec.match_file(f'bar{separator}file.py')
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_target_array(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'artifacts': ['foo', 'bar/baz', '']}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert builder.artifact_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.artifact_spec.match_file(f'bar{separator}baz{separator}file.py')
|
|
assert not builder.artifact_spec.match_file(f'bar{separator}file.py')
|
|
|
|
def test_target_array_pattern_not_string(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'artifacts': [0]}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
with pytest.raises(
|
|
TypeError, match='Pattern #1 in field `tool.hatch.build.targets.foo.artifacts` must be a string'
|
|
):
|
|
_ = builder.artifact_spec
|
|
|
|
@pytest.mark.parametrize('separator', ['/', '\\'])
|
|
def test_target_overrides_global(self, isolation, separator, platform):
|
|
if separator == '\\' and not platform.windows:
|
|
pytest.skip('Not running on Windows')
|
|
|
|
config = {'tool': {'hatch': {'build': {'artifacts': ['foo'], 'targets': {'foo': {'artifacts': ['bar']}}}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
builder.PLUGIN_NAME = 'foo'
|
|
|
|
assert not builder.artifact_spec.match_file(f'foo{separator}file.py')
|
|
assert builder.artifact_spec.match_file(f'bar{separator}file.py')
|
|
|
|
|
|
class TestPatternMatching:
|
|
def test_include_explicit(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'include': 'foo'}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.include_path('foo/file.py')
|
|
assert not builder.include_path('bar/file.py')
|
|
|
|
def test_no_include_greedy(self, isolation):
|
|
builder = BuilderInterface(str(isolation))
|
|
|
|
assert builder.include_path('foo/file.py')
|
|
assert builder.include_path('bar/file.py')
|
|
|
|
def test_exclude_precedence(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'include': 'foo', 'exclude': 'foo'}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert not builder.include_path('foo/file.py')
|
|
assert not builder.include_path('bar/file.py')
|
|
|
|
def test_artifact_super_precedence(self, isolation):
|
|
config = {'tool': {'hatch': {'build': {'include': 'foo', 'exclude': 'foo', 'artifacts': 'foo'}}}}
|
|
builder = BuilderInterface(str(isolation), config=config)
|
|
|
|
assert builder.include_path('foo/file.py')
|
|
assert not builder.include_path('bar/file.py')
|
|
|
|
|
|
class TestDirectoryRecursion:
|
|
def test_order(self, temp_dir):
|
|
with temp_dir.as_cwd():
|
|
config = {
|
|
'tool': {
|
|
'hatch': {
|
|
'build': {
|
|
'packages': 'src/foo',
|
|
'include': 'bar,README.md,tox.ini',
|
|
'exclude': '**/foo/baz.txt',
|
|
}
|
|
}
|
|
}
|
|
}
|
|
builder = BuilderInterface(str(temp_dir), config=config)
|
|
|
|
foo = temp_dir / 'src' / 'foo'
|
|
foo.ensure_dir_exists()
|
|
(foo / 'bar.txt').touch()
|
|
(foo / 'baz.txt').touch()
|
|
|
|
bar = temp_dir / 'bar'
|
|
bar.ensure_dir_exists()
|
|
(bar / 'foo.txt').touch()
|
|
|
|
(temp_dir / 'README.md').touch()
|
|
(temp_dir / 'tox.ini').touch()
|
|
|
|
assert [(f.path, f.distribution_path) for f in builder.recurse_project_files()] == [
|
|
(str(temp_dir / 'README.md'), 'README.md'),
|
|
(str(temp_dir / 'tox.ini'), 'tox.ini'),
|
|
(
|
|
str(temp_dir / 'bar' / 'foo.txt'),
|
|
f'bar{path_sep}foo.txt',
|
|
),
|
|
(str(temp_dir / 'src' / 'foo' / 'bar.txt'), f'foo{path_sep}bar.txt'),
|
|
]
|