pypa-hatch/tests/project/test_config.py

2948 lines
120 KiB
Python

from itertools import product
import pytest
from hatch.plugin.constants import DEFAULT_CUSTOM_SCRIPT
from hatch.plugin.manager import PluginManager
from hatch.project.config import ProjectConfig
from hatch.project.constants import DEFAULT_BUILD_DIRECTORY, BuildEnvVars
from hatch.project.env import RESERVED_OPTIONS
from hatch.utils.structures import EnvVars
ARRAY_OPTIONS = [o for o, t in RESERVED_OPTIONS.items() if t is list]
BOOLEAN_OPTIONS = [o for o, t in RESERVED_OPTIONS.items() if t is bool]
MAPPING_OPTIONS = [o for o, t in RESERVED_OPTIONS.items() if t is dict]
STRING_OPTIONS = [o for o, t in RESERVED_OPTIONS.items() if t is str and o != 'matrix-name-format']
def construct_matrix_data(env_name, config, overrides=None):
config = dict(config[env_name])
config.pop('overrides', None)
matrices = config.pop('matrix')
final_matrix_name_format = config.pop('matrix-name-format', '{value}')
# [{'version': ['9000']}, {'feature': ['bar']}]
envs = {}
for matrix_data in matrices:
matrix = dict(matrix_data)
variables = {}
python_selected = False
for variable in ('py', 'python'):
if variable in matrix:
python_selected = True
variables[variable] = matrix.pop(variable)
break
variables.update(matrix)
for result in product(*variables.values()):
variable_values = dict(zip(variables, result))
env_name_parts = []
for j, (variable, value) in enumerate(variable_values.items()):
if j == 0 and python_selected:
env_name_parts.append(value if value.startswith('py') else f'py{value}')
else:
env_name_parts.append(final_matrix_name_format.format(variable=variable, value=value))
new_env_name = '-'.join(env_name_parts)
if env_name != 'default':
new_env_name = f'{env_name}.{new_env_name}'
envs[new_env_name] = variable_values
if 'py' in variable_values:
envs[new_env_name] = {'python': variable_values.pop('py'), **variable_values}
config.update(overrides or {})
config.setdefault('type', 'virtual')
return {'config': config, 'envs': envs}
class TestEnv:
def test_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.env` must be a table'):
_ = ProjectConfig(isolation, {'env': 9000}).env
def test_default(self, isolation):
project_config = ProjectConfig(isolation, {})
assert project_config.env == project_config.env == {}
class TestEnvRequires:
def test_not_array(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.env.requires` must be an array'):
_ = ProjectConfig(isolation, {'env': {'requires': 9000}}).env_requires
def test_requirement_not_string(self, isolation):
with pytest.raises(TypeError, match='Requirement #1 in `tool.hatch.env.requires` must be a string'):
_ = ProjectConfig(isolation, {'env': {'requires': [9000]}}).env_requires
def test_requirement_invalid(self, isolation):
with pytest.raises(ValueError, match='Requirement #1 in `tool.hatch.env.requires` is invalid: .+'):
_ = ProjectConfig(isolation, {'env': {'requires': ['foo^1']}}).env_requires
def test_default(self, isolation):
project_config = ProjectConfig(isolation, {})
assert project_config.env_requires_complex == project_config.env_requires_complex == []
assert project_config.env_requires == project_config.env_requires == []
def test_defined(self, isolation):
project_config = ProjectConfig(isolation, {'env': {'requires': ['foo', 'bar', 'baz']}})
assert project_config.env_requires == ['foo', 'bar', 'baz']
class TestEnvCollectors:
def test_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.env.collectors` must be a table'):
_ = ProjectConfig(isolation, {'env': {'collectors': 9000}}).env_collectors
def test_collector_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.env.collectors.foo` must be a table'):
_ = ProjectConfig(isolation, {'env': {'collectors': {'foo': 9000}}}).env_collectors
def test_default(self, isolation):
project_config = ProjectConfig(isolation, {})
assert project_config.env_collectors == project_config.env_collectors == {'default': {}}
def test_defined(self, isolation):
project_config = ProjectConfig(isolation, {'env': {'collectors': {'foo': {'bar': {'baz': 9000}}}}})
assert project_config.env_collectors == {'default': {}, 'foo': {'bar': {'baz': 9000}}}
assert list(project_config.env_collectors) == ['default', 'foo']
class TestEnvs:
def test_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.envs` must be a table'):
_ = ProjectConfig(isolation, {'envs': 9000}, PluginManager()).envs
def test_config_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.envs.foo` must be a table'):
_ = ProjectConfig(isolation, {'envs': {'foo': 9000}}, PluginManager()).envs
def test_unknown_collector(self, isolation):
with pytest.raises(ValueError, match='Unknown environment collector: foo'):
_ = ProjectConfig(isolation, {'env': {'collectors': {'foo': {}}}}, PluginManager()).envs
def test_unknown_template(self, isolation):
with pytest.raises(
ValueError, match='Field `tool.hatch.envs.foo.template` refers to an unknown environment `bar`'
):
_ = ProjectConfig(isolation, {'envs': {'foo': {'template': 'bar'}}}, PluginManager()).envs
def test_default_undefined(self, isolation):
project_config = ProjectConfig(isolation, {}, PluginManager())
assert project_config.envs == project_config.envs == {'default': {'type': 'virtual'}}
assert project_config.matrices == project_config.matrices == {}
def test_default_partially_defined(self, isolation):
env_config = {'default': {'option': True}}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
assert project_config.envs == {'default': {'option': True, 'type': 'virtual'}}
def test_default_defined(self, isolation):
env_config = {'default': {'type': 'foo'}}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
assert project_config.envs == {'default': {'type': 'foo'}}
def test_basic(self, isolation):
env_config = {'foo': {'option': True}}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
assert project_config.envs == {'default': {'type': 'virtual'}, 'foo': {'option': True, 'type': 'virtual'}}
def test_basic_override(self, isolation):
env_config = {'foo': {'type': 'baz'}}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
assert project_config.envs == {'default': {'type': 'virtual'}, 'foo': {'type': 'baz'}}
def test_multiple_inheritance(self, isolation):
env_config = {
'foo': {'option1': 'foo'},
'bar': {'template': 'foo', 'option2': 'bar'},
'baz': {'template': 'bar', 'option3': 'baz'},
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
assert project_config.envs == {
'default': {'type': 'virtual'},
'foo': {'type': 'virtual', 'option1': 'foo'},
'bar': {'type': 'virtual', 'option1': 'foo', 'option2': 'bar'},
'baz': {'type': 'virtual', 'option1': 'foo', 'option2': 'bar', 'option3': 'baz'},
}
def test_circular_inheritance(self, isolation):
with pytest.raises(
ValueError, match='Circular inheritance detected for field `tool.hatch.envs.*.template`: foo -> bar -> foo'
):
_ = ProjectConfig(
isolation, {'envs': {'foo': {'template': 'bar'}, 'bar': {'template': 'foo'}}}, PluginManager()
).envs
def test_scripts_inheritance(self, isolation):
env_config = {
'default': {'scripts': {'cmd1': 'bar', 'cmd2': 'baz'}},
'foo': {'scripts': {'cmd1': 'foo'}},
'bar': {'template': 'foo', 'scripts': {'cmd3': 'bar'}},
'baz': {},
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
assert project_config.envs == {
'default': {'type': 'virtual', 'scripts': {'cmd1': 'bar', 'cmd2': 'baz'}},
'foo': {'type': 'virtual', 'scripts': {'cmd1': 'foo', 'cmd2': 'baz'}},
'bar': {'type': 'virtual', 'scripts': {'cmd1': 'foo', 'cmd2': 'baz', 'cmd3': 'bar'}},
'baz': {'type': 'virtual', 'scripts': {'cmd1': 'bar', 'cmd2': 'baz'}},
}
def test_self_referential(self, isolation):
env_config = {'default': {'option1': 'foo'}, 'bar': {'template': 'bar'}}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
assert project_config.envs == {
'default': {'type': 'virtual', 'option1': 'foo'},
'bar': {'type': 'virtual'},
}
def test_detached(self, isolation):
env_config = {'default': {'option1': 'foo'}, 'bar': {'detached': True}}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
assert project_config.envs == {
'default': {'type': 'virtual', 'option1': 'foo'},
'bar': {'type': 'virtual', 'skip-install': True},
}
def test_matrices_not_array(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.envs.foo.matrix` must be an array'):
_ = ProjectConfig(isolation, {'envs': {'foo': {'matrix': 9000}}}, PluginManager()).envs
def test_matrix_not_table(self, isolation):
with pytest.raises(TypeError, match='Entry #1 in field `tool.hatch.envs.foo.matrix` must be a table'):
_ = ProjectConfig(isolation, {'envs': {'foo': {'matrix': [9000]}}}, PluginManager()).envs
def test_matrix_empty(self, isolation):
with pytest.raises(ValueError, match='Matrix #1 in field `tool.hatch.envs.foo.matrix` cannot be empty'):
_ = ProjectConfig(isolation, {'envs': {'foo': {'matrix': [{}]}}}, PluginManager()).envs
def test_matrix_variable_empty_string(self, isolation):
with pytest.raises(
ValueError, match='Variable #1 in matrix #1 in field `tool.hatch.envs.foo.matrix` cannot be an empty string'
):
_ = ProjectConfig(isolation, {'envs': {'foo': {'matrix': [{'': []}]}}}, PluginManager()).envs
def test_matrix_variable_not_array(self, isolation):
with pytest.raises(
TypeError, match='Variable `bar` in matrix #1 in field `tool.hatch.envs.foo.matrix` must be an array'
):
_ = ProjectConfig(isolation, {'envs': {'foo': {'matrix': [{'bar': 9000}]}}}, PluginManager()).envs
def test_matrix_variable_array_empty(self, isolation):
with pytest.raises(
ValueError, match='Variable `bar` in matrix #1 in field `tool.hatch.envs.foo.matrix` cannot be empty'
):
_ = ProjectConfig(isolation, {'envs': {'foo': {'matrix': [{'bar': []}]}}}, PluginManager()).envs
def test_matrix_variable_entry_not_string(self, isolation):
with pytest.raises(
TypeError,
match='Value #1 of variable `bar` in matrix #1 in field `tool.hatch.envs.foo.matrix` must be a string',
):
_ = ProjectConfig(isolation, {'envs': {'foo': {'matrix': [{'bar': [9000]}]}}}, PluginManager()).envs
def test_matrix_variable_entry_empty_string(self, isolation):
with pytest.raises(
ValueError,
match=(
'Value #1 of variable `bar` in matrix #1 in field `tool.hatch.envs.foo.matrix` '
'cannot be an empty string'
),
):
_ = ProjectConfig(isolation, {'envs': {'foo': {'matrix': [{'bar': ['']}]}}}, PluginManager()).envs
def test_matrix_variable_entry_duplicate(self, isolation):
with pytest.raises(
ValueError,
match='Value #2 of variable `bar` in matrix #1 in field `tool.hatch.envs.foo.matrix` is a duplicate',
):
_ = ProjectConfig(isolation, {'envs': {'foo': {'matrix': [{'bar': ['1', '1']}]}}}, PluginManager()).envs
def test_matrix_multiple_python_variables(self, isolation):
with pytest.raises(
ValueError,
match='Matrix #1 in field `tool.hatch.envs.foo.matrix` cannot contain both `py` and `python` variables',
):
_ = ProjectConfig(
isolation,
{'envs': {'foo': {'matrix': [{'py': ['39', '310'], 'python': ['39', '311']}]}}},
PluginManager(),
).envs
def test_matrix_name_format_not_string(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.envs.foo.matrix-name-format` must be a string'):
_ = ProjectConfig(isolation, {'envs': {'foo': {'matrix-name-format': 9000}}}, PluginManager()).envs
def test_matrix_name_format_invalid(self, isolation):
with pytest.raises(
ValueError,
match='Field `tool.hatch.envs.foo.matrix-name-format` must contain at least the `{value}` placeholder',
):
_ = ProjectConfig(isolation, {'envs': {'foo': {'matrix-name-format': 'bar'}}}, PluginManager()).envs
def test_overrides_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.envs.foo.overrides` must be a table'):
_ = ProjectConfig(isolation, {'envs': {'foo': {'overrides': 9000}}}, PluginManager()).envs
def test_overrides_platform_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.envs.foo.overrides.platform` must be a table'):
_ = ProjectConfig(isolation, {'envs': {'foo': {'overrides': {'platform': 9000}}}}, PluginManager()).envs
def test_overrides_env_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.envs.foo.overrides.env` must be a table'):
_ = ProjectConfig(isolation, {'envs': {'foo': {'overrides': {'env': 9000}}}}, PluginManager()).envs
def test_overrides_matrix_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.envs.foo.overrides.matrix` must be a table'):
_ = ProjectConfig(
isolation,
{'envs': {'foo': {'matrix': [{'version': ['9000']}], 'overrides': {'matrix': 9000}}}},
PluginManager(),
).envs
def test_overrides_name_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.envs.foo.overrides.name` must be a table'):
_ = ProjectConfig(
isolation,
{'envs': {'foo': {'matrix': [{'version': ['9000']}], 'overrides': {'name': 9000}}}},
PluginManager(),
).envs
def test_overrides_platform_entry_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.envs.foo.overrides.platform.bar` must be a table'):
_ = ProjectConfig(
isolation, {'envs': {'foo': {'overrides': {'platform': {'bar': 9000}}}}}, PluginManager()
).envs
def test_overrides_env_entry_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.envs.foo.overrides.env.bar` must be a table'):
_ = ProjectConfig(isolation, {'envs': {'foo': {'overrides': {'env': {'bar': 9000}}}}}, PluginManager()).envs
def test_overrides_matrix_entry_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.envs.foo.overrides.matrix.bar` must be a table'):
_ = ProjectConfig(
isolation,
{'envs': {'foo': {'matrix': [{'version': ['9000']}], 'overrides': {'matrix': {'bar': 9000}}}}},
PluginManager(),
).envs
def test_overrides_name_entry_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.envs.foo.overrides.name.bar` must be a table'):
_ = ProjectConfig(
isolation,
{'envs': {'foo': {'matrix': [{'version': ['9000']}], 'overrides': {'name': {'bar': 9000}}}}},
PluginManager(),
).envs
def test_matrix_simple_no_python(self, isolation):
env_config = {'foo': {'option': True, 'matrix': [{'version': ['9000', '3.14']}]}}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', 'option': True},
'foo.3.14': {'type': 'virtual', 'option': True},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
def test_matrix_simple_no_python_custom_name_format(self, isolation):
env_config = {
'foo': {
'option': True,
'matrix-name-format': '{variable}_{value}',
'matrix': [{'version': ['9000', '3.14']}],
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.version_9000': {'type': 'virtual', 'option': True},
'foo.version_3.14': {'type': 'virtual', 'option': True},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('indicator', ['py', 'python'])
def test_matrix_simple_only_python(self, isolation, indicator):
env_config = {'foo': {'option': True, 'matrix': [{indicator: ['39', '310']}]}}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.py39': {'type': 'virtual', 'option': True, 'python': '39'},
'foo.py310': {'type': 'virtual', 'option': True, 'python': '310'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('indicator', ['py', 'python'])
def test_matrix_simple(self, isolation, indicator):
env_config = {'foo': {'option': True, 'matrix': [{'version': ['9000', '3.14'], indicator: ['39', '310']}]}}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.py39-9000': {'type': 'virtual', 'option': True, 'python': '39'},
'foo.py39-3.14': {'type': 'virtual', 'option': True, 'python': '39'},
'foo.py310-9000': {'type': 'virtual', 'option': True, 'python': '310'},
'foo.py310-3.14': {'type': 'virtual', 'option': True, 'python': '310'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('indicator', ['py', 'python'])
def test_matrix_simple_custom_name_format(self, isolation, indicator):
env_config = {
'foo': {
'option': True,
'matrix-name-format': '{variable}_{value}',
'matrix': [{'version': ['9000', '3.14'], indicator: ['39', '310']}],
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.py39-version_9000': {'type': 'virtual', 'option': True, 'python': '39'},
'foo.py39-version_3.14': {'type': 'virtual', 'option': True, 'python': '39'},
'foo.py310-version_9000': {'type': 'virtual', 'option': True, 'python': '310'},
'foo.py310-version_3.14': {'type': 'virtual', 'option': True, 'python': '310'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
def test_matrix_multiple_non_python(self, isolation):
env_config = {
'foo': {
'option': True,
'matrix': [{'version': ['9000', '3.14'], 'py': ['39', '310'], 'foo': ['baz', 'bar']}],
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.py39-9000-baz': {'type': 'virtual', 'option': True, 'python': '39'},
'foo.py39-9000-bar': {'type': 'virtual', 'option': True, 'python': '39'},
'foo.py39-3.14-baz': {'type': 'virtual', 'option': True, 'python': '39'},
'foo.py39-3.14-bar': {'type': 'virtual', 'option': True, 'python': '39'},
'foo.py310-9000-baz': {'type': 'virtual', 'option': True, 'python': '310'},
'foo.py310-9000-bar': {'type': 'virtual', 'option': True, 'python': '310'},
'foo.py310-3.14-baz': {'type': 'virtual', 'option': True, 'python': '310'},
'foo.py310-3.14-bar': {'type': 'virtual', 'option': True, 'python': '310'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
def test_matrix_series(self, isolation):
env_config = {
'foo': {
'option': True,
'matrix': [
{'version': ['9000', '3.14'], 'py': ['39', '310'], 'foo': ['baz', 'bar']},
{'version': ['9000'], 'py': ['310'], 'baz': ['foo', 'test'], 'bar': ['foobar']},
],
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.py39-9000-baz': {'type': 'virtual', 'option': True, 'python': '39'},
'foo.py39-9000-bar': {'type': 'virtual', 'option': True, 'python': '39'},
'foo.py39-3.14-baz': {'type': 'virtual', 'option': True, 'python': '39'},
'foo.py39-3.14-bar': {'type': 'virtual', 'option': True, 'python': '39'},
'foo.py310-9000-baz': {'type': 'virtual', 'option': True, 'python': '310'},
'foo.py310-9000-bar': {'type': 'virtual', 'option': True, 'python': '310'},
'foo.py310-3.14-baz': {'type': 'virtual', 'option': True, 'python': '310'},
'foo.py310-3.14-bar': {'type': 'virtual', 'option': True, 'python': '310'},
'foo.py310-9000-foo-foobar': {'type': 'virtual', 'option': True, 'python': '310'},
'foo.py310-9000-test-foobar': {'type': 'virtual', 'option': True, 'python': '310'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
def test_matrices_not_inherited(self, isolation):
env_config = {
'foo': {'option1': True, 'matrix': [{'py': ['39']}]},
'bar': {'template': 'foo', 'option2': False},
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.py39': {'type': 'virtual', 'option1': True, 'python': '39'},
'bar': {'type': 'virtual', 'option1': True, 'option2': False},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
def test_matrix_default_naming(self, isolation):
env_config = {'default': {'option': True, 'matrix': [{'version': ['9000', '3.14']}]}}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'9000': {'type': 'virtual', 'option': True},
'3.14': {'type': 'virtual', 'option': True},
}
assert project_config.envs == expected_envs
assert project_config.matrices['default'] == construct_matrix_data('default', env_config)
def test_matrix_pypy_naming(self, isolation):
env_config = {'foo': {'option': True, 'matrix': [{'py': ['python3.9', 'pypy3']}]}}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.python3.9': {'type': 'virtual', 'option': True, 'python': 'python3.9'},
'foo.pypy3': {'type': 'virtual', 'option': True, 'python': 'pypy3'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_invalid_type(self, isolation, option):
with pytest.raises(
TypeError,
match=f'Field `tool.hatch.envs.foo.overrides.matrix.version.{option}` must be a string or an array',
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {'matrix': [{'version': ['9000']}], 'overrides': {'matrix': {'version': {option: 9000}}}}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_array_entry_invalid_type(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be a string or an inline table'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [9000]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_table_entry_no_key(self, isolation, option):
with pytest.raises(
ValueError,
match=(
f'Entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must have an option named `key`'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {'matrix': [{'version': ['9000']}], 'overrides': {'matrix': {'version': {option: [{}]}}}}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_table_entry_key_not_string(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Option `key` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be a string'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [{'key': 9000}]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_table_entry_key_empty_string(self, isolation, option):
with pytest.raises(
ValueError,
match=(
f'Option `key` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'cannot be an empty string'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [{'key': ''}]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_table_entry_value_not_string(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Option `value` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be a string'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [{'key': 'foo', 'value': 9000}]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_table_entry_if_not_array(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Option `if` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be an array'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {
'matrix': {'version': {option: [{'key': 'foo', 'value': 'bar', 'if': 9000}]}}
},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_invalid_type(self, isolation, option):
with pytest.raises(
TypeError, match=f'Field `tool.hatch.envs.foo.overrides.matrix.version.{option}` must be an array'
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {'matrix': [{'version': ['9000']}], 'overrides': {'matrix': {'version': {option: 9000}}}}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_table_entry_no_value(self, isolation, option):
with pytest.raises(
ValueError,
match=(
f'Entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must have an option named `value`'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {'matrix': [{'version': ['9000']}], 'overrides': {'matrix': {'version': {option: [{}]}}}}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_table_entry_value_not_string(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Option `value` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be a string'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [{'value': 9000}]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_table_entry_value_empty_string(self, isolation, option):
with pytest.raises(
ValueError,
match=(
f'Option `value` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'cannot be an empty string'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [{'value': ''}]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_table_entry_if_not_array(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Option `if` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be an array'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [{'value': 'foo', 'if': 9000}]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_entry_invalid_type(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be a string or an inline table'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [9000]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_invalid_type(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be a string, inline table, or an array'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {'matrix': [{'version': ['9000']}], 'overrides': {'matrix': {'version': {option: 9000}}}}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_table_no_value(self, isolation, option):
with pytest.raises(
ValueError,
match=f'Field `tool.hatch.envs.foo.overrides.matrix.version.{option}` must have an option named `value`',
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {'matrix': [{'version': ['9000']}], 'overrides': {'matrix': {'version': {option: {}}}}}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_table_value_not_string(self, isolation, option):
with pytest.raises(
TypeError,
match=f'Option `value` in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` must be a string',
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: {'value': 9000}}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_array_entry_invalid_type(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be a string or an inline table'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [9000]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_array_table_no_value(self, isolation, option):
with pytest.raises(
ValueError,
match=(
f'Entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must have an option named `value`'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {'matrix': [{'version': ['9000']}], 'overrides': {'matrix': {'version': {option: [{}]}}}}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_array_table_value_not_string(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Option `value` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be a string'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [{'value': 9000}]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_array_table_if_not_array(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Option `if` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be an array'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [{'value': 'foo', 'if': 9000}]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_invalid_type(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be a boolean, inline table, or an array'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {'matrix': [{'version': ['9000']}], 'overrides': {'matrix': {'version': {option: 9000}}}}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_table_no_value(self, isolation, option):
with pytest.raises(
ValueError,
match=f'Field `tool.hatch.envs.foo.overrides.matrix.version.{option}` must have an option named `value`',
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {'matrix': [{'version': ['9000']}], 'overrides': {'matrix': {'version': {option: {}}}}}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_table_value_not_boolean(self, isolation, option):
with pytest.raises(
TypeError,
match=f'Option `value` in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` must be a boolean',
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: {'value': 9000}}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_array_entry_invalid_type(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be a boolean or an inline table'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [9000]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_array_table_no_value(self, isolation, option):
with pytest.raises(
ValueError,
match=(
f'Entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must have an option named `value`'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {'matrix': [{'version': ['9000']}], 'overrides': {'matrix': {'version': {option: [{}]}}}}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_array_table_value_not_boolean(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Option `value` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be a boolean'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [{'value': 9000}]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_array_table_if_not_array(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Option `if` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be an array'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [{'value': True, 'if': 9000}]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_array_table_platform_not_array(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Option `platform` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be an array'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [{'value': True, 'platform': 9000}]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_array_table_platform_item_not_string(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Item #1 in option `platform` in entry #1 in field '
f'`tool.hatch.envs.foo.overrides.matrix.version.{option}` must be a string'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [{'value': True, 'platform': [9000]}]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_array_table_env_not_array(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Option `env` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` '
f'must be an array'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [{'value': True, 'env': 9000}]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_array_table_env_item_not_string(self, isolation, option):
with pytest.raises(
TypeError,
match=(
f'Item #1 in option `env` in entry #1 in field '
f'`tool.hatch.envs.foo.overrides.matrix.version.{option}` must be a string'
),
):
_ = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000']}],
'overrides': {'matrix': {'version': {option: [{'value': True, 'env': [9000]}]}}},
}
}
},
PluginManager(),
).envs
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_string_with_value(self, isolation, option):
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: 'FOO=ok'}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: {'FOO': 'ok'}},
'foo.bar': {'type': 'virtual'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_string_without_value(self, isolation, option):
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: 'FOO'}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: {'FOO': '9000'}},
'foo.bar': {'type': 'virtual'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_string_override(self, isolation, option):
env_config = {
'foo': {
option: {'TEST': 'baz'},
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: 'TEST'}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: {'TEST': '9000'}},
'foo.bar': {'type': 'virtual', option: {'TEST': 'baz'}},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_array_string_with_value(self, isolation, option):
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: ['FOO=ok']}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: {'FOO': 'ok'}},
'foo.bar': {'type': 'virtual'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_array_string_without_value(self, isolation, option):
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: ['FOO']}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: {'FOO': '9000'}},
'foo.bar': {'type': 'virtual'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_array_string_override(self, isolation, option):
env_config = {
'foo': {
option: {'TEST': 'baz'},
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: ['TEST']}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: {'TEST': '9000'}},
'foo.bar': {'type': 'virtual', option: {'TEST': 'baz'}},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_array_table_key_with_value(self, isolation, option):
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [{'key': 'FOO', 'value': 'ok'}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: {'FOO': 'ok'}},
'foo.bar': {'type': 'virtual'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_array_table_key_without_value(self, isolation, option):
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [{'key': 'FOO'}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: {'FOO': '9000'}},
'foo.bar': {'type': 'virtual'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_array_table_override(self, isolation, option):
env_config = {
'foo': {
option: {'TEST': 'baz'},
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [{'key': 'TEST'}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: {'TEST': '9000'}},
'foo.bar': {'type': 'virtual', option: {'TEST': 'baz'}},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_array_table_conditional(self, isolation, option):
env_config = {
'foo': {
option: {'TEST': 'baz'},
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [{'key': 'TEST', 'if': ['42']}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: {'TEST': 'baz'}},
'foo.42': {'type': 'virtual', option: {'TEST': '42'}},
'foo.bar': {'type': 'virtual', option: {'TEST': 'baz'}},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', MAPPING_OPTIONS)
def test_overrides_matrix_mapping_overwrite(self, isolation, option):
env_config = {
'foo': {
option: {'TEST': 'baz'},
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {f'set-{option}': ['FOO=bar', {'key': 'BAZ'}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: {'FOO': 'bar', 'BAZ': '9000'}},
'foo.bar': {'type': 'virtual', option: {'TEST': 'baz'}},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_string(self, isolation, option):
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: ['run foo']}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: ['run foo']},
'foo.bar': {'type': 'virtual'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_string_existing_append(self, isolation, option):
env_config = {
'foo': {
option: ['run baz'],
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: ['run foo']}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: ['run baz', 'run foo']},
'foo.bar': {'type': 'virtual', option: ['run baz']},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_table(self, isolation, option):
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [{'value': 'run foo'}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: ['run foo']},
'foo.bar': {'type': 'virtual'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_table_existing_append(self, isolation, option):
env_config = {
'foo': {
option: ['run baz'],
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [{'value': 'run foo'}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: ['run baz', 'run foo']},
'foo.bar': {'type': 'virtual', option: ['run baz']},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_table_conditional(self, isolation, option):
env_config = {
'foo': {
option: ['run baz'],
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [{'value': 'run foo', 'if': ['42']}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: ['run baz']},
'foo.42': {'type': 'virtual', option: ['run baz', 'run foo']},
'foo.bar': {'type': 'virtual', option: ['run baz']},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_table_conditional_with_platform(self, isolation, option, current_platform):
env_config = {
'foo': {
option: ['run baz'],
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {
'matrix': {
'version': {option: [{'value': 'run foo', 'if': ['42'], 'platform': [current_platform]}]}
},
},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: ['run baz']},
'foo.42': {'type': 'virtual', option: ['run baz', 'run foo']},
'foo.bar': {'type': 'virtual', option: ['run baz']},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_table_conditional_with_wrong_platform(self, isolation, option):
env_config = {
'foo': {
option: ['run baz'],
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {
'matrix': {'version': {option: [{'value': 'run foo', 'if': ['42'], 'platform': ['bar']}]}},
},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: ['run baz']},
'foo.42': {'type': 'virtual', option: ['run baz']},
'foo.bar': {'type': 'virtual', option: ['run baz']},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_table_conditional_with_env_var_match(self, isolation, option):
env_var = 'OVERRIDES_ENV_FOO'
env_config = {
'foo': {
option: ['run baz'],
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {
'matrix': {'version': {option: [{'value': 'run foo', 'if': ['42'], 'env': [f'{env_var}=bar']}]}}
},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: ['run baz']},
'foo.42': {'type': 'virtual', option: ['run baz', 'run foo']},
'foo.bar': {'type': 'virtual', option: ['run baz']},
}
with EnvVars({env_var: 'bar'}):
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_table_conditional_with_env_var_match_empty_string(self, isolation, option):
env_var = 'OVERRIDES_ENV_FOO'
env_config = {
'foo': {
option: ['run baz'],
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {
'matrix': {'version': {option: [{'value': 'run foo', 'if': ['42'], 'env': [f'{env_var}=']}]}}
},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: ['run baz']},
'foo.42': {'type': 'virtual', option: ['run baz', 'run foo']},
'foo.bar': {'type': 'virtual', option: ['run baz']},
}
with EnvVars({env_var: ''}):
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_table_conditional_with_env_var_present(self, isolation, option):
env_var = 'OVERRIDES_ENV_FOO'
env_config = {
'foo': {
option: ['run baz'],
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [{'value': 'run foo', 'if': ['42'], 'env': [env_var]}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: ['run baz']},
'foo.42': {'type': 'virtual', option: ['run baz', 'run foo']},
'foo.bar': {'type': 'virtual', option: ['run baz']},
}
with EnvVars({env_var: 'any'}):
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_table_conditional_with_env_var_no_match(self, isolation, option):
env_var = 'OVERRIDES_ENV_FOO'
env_config = {
'foo': {
option: ['run baz'],
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {
'matrix': {'version': {option: [{'value': 'run foo', 'if': ['42'], 'env': [f'{env_var}=bar']}]}}
},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: ['run baz']},
'foo.42': {'type': 'virtual', option: ['run baz']},
'foo.bar': {'type': 'virtual', option: ['run baz']},
}
with EnvVars({env_var: 'baz'}):
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_table_conditional_with_env_var_missing(self, isolation, option):
env_var = 'OVERRIDES_ENV_FOO'
env_config = {
'foo': {
option: ['run baz'],
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {
'matrix': {'version': {option: [{'value': 'run foo', 'if': ['42'], 'env': [f'{env_var}=bar']}]}}
},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: ['run baz']},
'foo.42': {'type': 'virtual', option: ['run baz']},
'foo.bar': {'type': 'virtual', option: ['run baz']},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
def test_overrides_matrix_set_with_no_type_information(self, isolation):
env_var = 'OVERRIDES_ENV_FOO'
env_config = {
'foo': {
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {
'matrix': {'version': {'bar': {'value': ['baz'], 'if': ['42'], 'env': [f'{env_var}=bar']}}}
},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual'},
'foo.42': {'type': 'virtual', 'bar': ['baz']},
'foo.bar': {'type': 'virtual'},
}
with EnvVars({env_var: 'bar'}):
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
def test_overrides_matrix_set_with_no_type_information_not_table(self, isolation):
project_config = ProjectConfig(
isolation,
{
'envs': {
'foo': {
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {'bar': 9000}}},
}
}
},
PluginManager(),
)
_ = project_config.envs
with pytest.raises(
ValueError,
match=(
'Untyped option `tool.hatch.envs.foo.9000.overrides.matrix.version.bar` '
'must be defined as a table with a `value` key'
),
):
project_config.finalize_env_overrides({})
@pytest.mark.parametrize('option', ARRAY_OPTIONS)
def test_overrides_matrix_array_overwrite(self, isolation, option):
env_config = {
'foo': {
option: ['run baz'],
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {f'set-{option}': ['run foo', {'value': 'run bar'}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: ['run foo', 'run bar']},
'foo.bar': {'type': 'virtual', option: ['run baz']},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_string_create(self, isolation, option):
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: 'baz'}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: 'baz'},
'foo.bar': {'type': 'virtual'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_string_overwrite(self, isolation, option):
env_config = {
'foo': {
option: 'test',
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: 'baz'}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: 'baz'},
'foo.bar': {'type': 'virtual', option: 'test'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_table_create(self, isolation, option):
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: {'value': 'baz'}}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: 'baz'},
'foo.bar': {'type': 'virtual'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_table_override(self, isolation, option):
env_config = {
'foo': {
option: 'test',
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: {'value': 'baz'}}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: 'baz'},
'foo.bar': {'type': 'virtual', option: 'test'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_table_conditional(self, isolation, option):
env_config = {
'foo': {
option: 'test',
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: {'value': 'baz', 'if': ['42']}}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: 'test'},
'foo.42': {'type': 'virtual', option: 'baz'},
'foo.bar': {'type': 'virtual', option: 'test'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_array_table_create(self, isolation, option):
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [{'value': 'baz'}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: 'baz'},
'foo.bar': {'type': 'virtual'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_array_table_override(self, isolation, option):
env_config = {
'foo': {
option: 'test',
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [{'value': 'baz'}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: 'baz'},
'foo.bar': {'type': 'virtual', option: 'test'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_array_table_conditional(self, isolation, option):
env_config = {
'foo': {
option: 'test',
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [{'value': 'baz', 'if': ['42']}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: 'test'},
'foo.42': {'type': 'virtual', option: 'baz'},
'foo.bar': {'type': 'virtual', option: 'test'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_array_table_conditional_eager_string(self, isolation, option):
env_config = {
'foo': {
option: 'test',
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: ['baz', {'value': 'foo', 'if': ['42']}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: 'baz'},
'foo.42': {'type': 'virtual', option: 'baz'},
'foo.bar': {'type': 'virtual', option: 'test'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', STRING_OPTIONS)
def test_overrides_matrix_string_array_table_conditional_eager_table(self, isolation, option):
env_config = {
'foo': {
option: 'test',
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [{'value': 'baz', 'if': ['42']}, 'foo']}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: 'foo'},
'foo.42': {'type': 'virtual', option: 'baz'},
'foo.bar': {'type': 'virtual', option: 'test'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_boolean_create(self, isolation, option):
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: True}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: True},
'foo.bar': {'type': 'virtual'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_boolean_overwrite(self, isolation, option):
env_config = {
'foo': {
option: False,
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: True}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: True},
'foo.bar': {'type': 'virtual', option: False},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_table_create(self, isolation, option):
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: {'value': True}}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: True},
'foo.bar': {'type': 'virtual'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_table_override(self, isolation, option):
env_config = {
'foo': {
option: False,
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: {'value': True}}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: True},
'foo.bar': {'type': 'virtual', option: False},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_table_conditional(self, isolation, option):
env_config = {
'foo': {
option: False,
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: {'value': True, 'if': ['42']}}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: False},
'foo.42': {'type': 'virtual', option: True},
'foo.bar': {'type': 'virtual', option: False},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_array_table_create(self, isolation, option):
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [{'value': True}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: True},
'foo.bar': {'type': 'virtual'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_array_table_override(self, isolation, option):
env_config = {
'foo': {
option: False,
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [{'value': True}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: True},
'foo.bar': {'type': 'virtual', option: False},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_array_table_conditional(self, isolation, option):
env_config = {
'foo': {
option: False,
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [{'value': True, 'if': ['42']}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: False},
'foo.42': {'type': 'virtual', option: True},
'foo.bar': {'type': 'virtual', option: False},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_array_table_conditional_eager_boolean(self, isolation, option):
env_config = {
'foo': {
option: False,
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [True, {'value': False, 'if': ['42']}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: True},
'foo.42': {'type': 'virtual', option: True},
'foo.bar': {'type': 'virtual', option: False},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
@pytest.mark.parametrize('option', BOOLEAN_OPTIONS)
def test_overrides_matrix_boolean_array_table_conditional_eager_table(self, isolation, option):
env_config = {
'foo': {
option: False,
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {option: [{'value': True, 'if': ['42']}, False]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', option: False},
'foo.42': {'type': 'virtual', option: True},
'foo.bar': {'type': 'virtual', option: False},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
# We assert type coverage using matrix variable overrides, for the others just test one type
def test_overrides_platform_boolean_boolean_create(self, isolation, current_platform):
env_config = {
'foo': {
'overrides': {'platform': {'bar': {'dependencies': ['baz']}, current_platform: {'skip-install': True}}}
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo': {'type': 'virtual', 'skip-install': True},
}
assert project_config.envs == expected_envs
def test_overrides_platform_boolean_boolean_overwrite(self, isolation, current_platform):
env_config = {
'foo': {
'skip-install': True,
'overrides': {
'platform': {'bar': {'dependencies': ['baz']}, current_platform: {'skip-install': False}}
},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo': {'type': 'virtual', 'skip-install': False},
}
assert project_config.envs == expected_envs
def test_overrides_platform_boolean_table_create(self, isolation, current_platform):
env_config = {
'foo': {
'overrides': {
'platform': {
'bar': {'dependencies': ['baz']},
current_platform: {'skip-install': [{'value': True}]},
}
}
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo': {'type': 'virtual', 'skip-install': True},
}
assert project_config.envs == expected_envs
def test_overrides_platform_boolean_table_overwrite(self, isolation, current_platform):
env_config = {
'foo': {
'skip-install': True,
'overrides': {
'platform': {
'bar': {'dependencies': ['baz']},
current_platform: {'skip-install': [{'value': False}]},
}
},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo': {'type': 'virtual', 'skip-install': False},
}
assert project_config.envs == expected_envs
def test_overrides_env_boolean_boolean_create(self, isolation):
env_var_exists = 'OVERRIDES_ENV_FOO'
env_var_missing = 'OVERRIDES_ENV_BAR'
env_config = {
'foo': {
'overrides': {
'env': {env_var_missing: {'dependencies': ['baz']}, env_var_exists: {'skip-install': True}}
}
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo': {'type': 'virtual', 'skip-install': True},
}
with EnvVars({env_var_exists: 'any'}):
assert project_config.envs == expected_envs
def test_overrides_env_boolean_boolean_overwrite(self, isolation):
env_var_exists = 'OVERRIDES_ENV_FOO'
env_var_missing = 'OVERRIDES_ENV_BAR'
env_config = {
'foo': {
'skip-install': True,
'overrides': {
'env': {env_var_missing: {'dependencies': ['baz']}, env_var_exists: {'skip-install': False}}
},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo': {'type': 'virtual', 'skip-install': False},
}
with EnvVars({env_var_exists: 'any'}):
assert project_config.envs == expected_envs
def test_overrides_env_boolean_table_create(self, isolation):
env_var_exists = 'OVERRIDES_ENV_FOO'
env_var_missing = 'OVERRIDES_ENV_BAR'
env_config = {
'foo': {
'overrides': {
'env': {
env_var_missing: {'dependencies': ['baz']},
env_var_exists: {'skip-install': [{'value': True}]},
}
}
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo': {'type': 'virtual', 'skip-install': True},
}
with EnvVars({env_var_exists: 'any'}):
assert project_config.envs == expected_envs
def test_overrides_env_boolean_table_overwrite(self, isolation):
env_var_exists = 'OVERRIDES_ENV_FOO'
env_var_missing = 'OVERRIDES_ENV_BAR'
env_config = {
'foo': {
'skip-install': True,
'overrides': {
'env': {
env_var_missing: {'dependencies': ['baz']},
env_var_exists: {'skip-install': [{'value': False}]},
}
},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo': {'type': 'virtual', 'skip-install': False},
}
with EnvVars({env_var_exists: 'any'}):
assert project_config.envs == expected_envs
def test_overrides_env_boolean_conditional(self, isolation):
env_var_exists = 'OVERRIDES_ENV_FOO'
env_var_missing = 'OVERRIDES_ENV_BAR'
env_config = {
'foo': {
'overrides': {
'env': {
env_var_missing: {'dependencies': ['baz']},
env_var_exists: {'skip-install': [{'value': True, 'if': ['foo']}]},
}
}
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo': {'type': 'virtual', 'skip-install': True},
}
with EnvVars({env_var_exists: 'foo'}):
assert project_config.envs == expected_envs
def test_overrides_name_boolean_boolean_create(self, isolation):
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'name': {'bar$': {'skip-install': True}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual'},
'foo.bar': {'type': 'virtual', 'skip-install': True},
}
assert project_config.envs == expected_envs
def test_overrides_name_boolean_boolean_overwrite(self, isolation):
env_config = {
'foo': {
'skip-install': True,
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'name': {'bar$': {'skip-install': False}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', 'skip-install': True},
'foo.bar': {'type': 'virtual', 'skip-install': False},
}
assert project_config.envs == expected_envs
def test_overrides_name_boolean_table_create(self, isolation):
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'name': {'bar$': {'skip-install': [{'value': True}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual'},
'foo.bar': {'type': 'virtual', 'skip-install': True},
}
assert project_config.envs == expected_envs
def test_overrides_name_boolean_table_overwrite(self, isolation):
env_config = {
'foo': {
'skip-install': True,
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {'name': {'bar$': {'skip-install': [{'value': False}]}}},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', 'skip-install': True},
'foo.bar': {'type': 'virtual', 'skip-install': False},
}
assert project_config.envs == expected_envs
# Tests for source precedence
def test_overrides_name_precedence_over_matrix(self, isolation):
env_config = {
'foo': {
'skip-install': False,
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {
'name': {'42$': {'skip-install': False}},
'matrix': {'version': {'skip-install': [{'value': True, 'if': ['42']}]}},
},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', 'skip-install': False},
'foo.42': {'type': 'virtual', 'skip-install': False},
'foo.bar': {'type': 'virtual', 'skip-install': False},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config, {'skip-install': False})
def test_overrides_matrix_precedence_over_platform(self, isolation, current_platform):
env_config = {
'foo': {
'skip-install': False,
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {
'platform': {current_platform: {'skip-install': True}},
'matrix': {'version': {'skip-install': [{'value': False, 'if': ['42']}]}},
},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', 'skip-install': True},
'foo.42': {'type': 'virtual', 'skip-install': False},
'foo.bar': {'type': 'virtual', 'skip-install': True},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config, {'skip-install': True})
def test_overrides_matrix_precedence_over_env(self, isolation):
env_var = 'OVERRIDES_ENV_FOO'
env_config = {
'foo': {
'skip-install': False,
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {
'env': {env_var: {'skip-install': True}},
'matrix': {'version': {'skip-install': [{'value': False, 'if': ['42']}]}},
},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', 'skip-install': True},
'foo.42': {'type': 'virtual', 'skip-install': False},
'foo.bar': {'type': 'virtual', 'skip-install': True},
}
with EnvVars({env_var: 'any'}):
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config, {'skip-install': True})
def test_overrides_env_precedence_over_platform(self, isolation, current_platform):
env_var = 'OVERRIDES_ENV_FOO'
env_config = {
'foo': {
'overrides': {
'platform': {current_platform: {'skip-install': True}},
'env': {env_var: {'skip-install': [{'value': False, 'if': ['foo']}]}},
},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo': {'type': 'virtual', 'skip-install': False},
}
with EnvVars({env_var: 'foo'}):
assert project_config.envs == expected_envs
# Test for options defined by environment plugins
def test_overrides_for_environment_plugins(self, isolation, current_platform):
env_var = 'OVERRIDES_ENV_FOO'
env_config = {
'foo': {
'matrix': [{'version': ['9000']}, {'feature': ['bar']}],
'overrides': {
'platform': {current_platform: {'foo': True}},
'env': {env_var: {'bar': [{'value': 'foobar', 'if': ['foo']}]}},
'matrix': {'version': {'baz': 'BAR=ok'}},
},
}
}
project_config = ProjectConfig(isolation, {'envs': env_config}, PluginManager())
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual'},
'foo.bar': {'type': 'virtual'},
}
with EnvVars({env_var: 'foo'}):
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
project_config.finalize_env_overrides({'foo': bool, 'bar': str, 'baz': dict})
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual', 'foo': True, 'bar': 'foobar', 'baz': {'BAR': 'ok'}},
'foo.bar': {'type': 'virtual', 'foo': True, 'bar': 'foobar'},
}
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
# Test environment collectors
def test_environment_collector_finalize_config(self, helpers, temp_dir):
file_path = temp_dir / DEFAULT_CUSTOM_SCRIPT
file_path.write_text(
helpers.dedent(
"""
from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface
class CustomHook(EnvironmentCollectorInterface):
def finalize_config(self, config):
config['default']['type'] = 'foo'
"""
)
)
env_config = {
'foo': {
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {'type': {'value': 'baz', 'if': ['42']}}}},
}
}
project_config = ProjectConfig(
temp_dir, {'envs': env_config, 'env': {'collectors': {'custom': {}}}}, PluginManager()
)
expected_envs = {
'default': {'type': 'foo'},
'foo.9000': {'type': 'foo'},
'foo.42': {'type': 'baz'},
'foo.bar': {'type': 'foo'},
}
with temp_dir.as_cwd():
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config, {'type': 'foo'})
def test_environment_collector_finalize_environments(self, helpers, temp_dir):
file_path = temp_dir / DEFAULT_CUSTOM_SCRIPT
file_path.write_text(
helpers.dedent(
"""
from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface
class CustomHook(EnvironmentCollectorInterface):
def finalize_environments(self, config):
config['foo.42']['type'] = 'foo'
"""
)
)
env_config = {
'foo': {
'matrix': [{'version': ['9000', '42']}, {'feature': ['bar']}],
'overrides': {'matrix': {'version': {'type': {'value': 'baz', 'if': ['42']}}}},
}
}
project_config = ProjectConfig(
temp_dir, {'envs': env_config, 'env': {'collectors': {'custom': {}}}}, PluginManager()
)
expected_envs = {
'default': {'type': 'virtual'},
'foo.9000': {'type': 'virtual'},
'foo.42': {'type': 'foo'},
'foo.bar': {'type': 'virtual'},
}
with temp_dir.as_cwd():
assert project_config.envs == expected_envs
assert project_config.matrices['foo'] == construct_matrix_data('foo', env_config)
class TestPublish:
def test_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.publish` must be a table'):
_ = ProjectConfig(isolation, {'publish': 9000}).publish
def test_config_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.publish.foo` must be a table'):
_ = ProjectConfig(isolation, {'publish': {'foo': 9000}}).publish
def test_default(self, isolation):
project_config = ProjectConfig(isolation, {})
assert project_config.publish == project_config.publish == {}
def test_defined(self, isolation):
project_config = ProjectConfig(isolation, {'publish': {'foo': {'bar': 'baz'}}})
assert project_config.publish == {'foo': {'bar': 'baz'}}
class TestScripts:
def test_not_table(self, isolation):
config = {'scripts': 9000}
project_config = ProjectConfig(isolation, config)
with pytest.raises(TypeError, match='Field `tool.hatch.scripts` must be a table'):
_ = project_config.scripts
def test_name_contains_spaces(self, isolation):
config = {'scripts': {'foo bar': []}}
project_config = ProjectConfig(isolation, config)
with pytest.raises(
ValueError, match='Script name `foo bar` in field `tool.hatch.scripts` must not contain spaces'
):
_ = project_config.scripts
def test_default(self, isolation):
project_config = ProjectConfig(isolation, {})
assert project_config.scripts == project_config.scripts == {}
def test_single_commands(self, isolation):
config = {'scripts': {'foo': 'command1', 'bar': 'command2'}}
project_config = ProjectConfig(isolation, config)
assert project_config.scripts == {'foo': ['command1'], 'bar': ['command2']}
def test_multiple_commands(self, isolation):
config = {'scripts': {'foo': 'command1', 'bar': ['command3', 'command2']}}
project_config = ProjectConfig(isolation, config)
assert project_config.scripts == {'foo': ['command1'], 'bar': ['command3', 'command2']}
def test_multiple_commands_not_string(self, isolation):
config = {'scripts': {'foo': [9000]}}
project_config = ProjectConfig(isolation, config)
with pytest.raises(TypeError, match='Command #1 in field `tool.hatch.scripts.foo` must be a string'):
_ = project_config.scripts
def test_config_invalid_type(self, isolation):
config = {'scripts': {'foo': 9000}}
project_config = ProjectConfig(isolation, config)
with pytest.raises(TypeError, match='Field `tool.hatch.scripts.foo` must be a string or an array of strings'):
_ = project_config.scripts
def test_command_expansion_basic(self, isolation):
config = {'scripts': {'foo': 'command1', 'bar': ['command3', 'foo']}}
project_config = ProjectConfig(isolation, config)
assert project_config.scripts == {'foo': ['command1'], 'bar': ['command3', 'command1']}
def test_command_expansion_multiple_nested(self, isolation):
config = {
'scripts': {
'foo': 'command3',
'baz': ['command5', 'bar', 'foo', 'command1'],
'bar': ['command4', 'foo', 'command2'],
}
}
project_config = ProjectConfig(isolation, config)
assert project_config.scripts == {
'foo': ['command3'],
'baz': ['command5', 'command4', 'command3', 'command2', 'command3', 'command1'],
'bar': ['command4', 'command3', 'command2'],
}
def test_command_expansion_multiple_nested_ignore_exit_code(self, isolation):
config = {
'scripts': {
'foo': 'command3',
'baz': ['command5', '- bar', 'foo', 'command1'],
'bar': ['command4', '- foo', 'command2'],
}
}
project_config = ProjectConfig(isolation, config)
assert project_config.scripts == {
'foo': ['command3'],
'baz': ['command5', '- command4', '- command3', '- command2', 'command3', 'command1'],
'bar': ['command4', '- command3', 'command2'],
}
def test_command_expansion_modification(self, isolation):
config = {
'scripts': {
'foo': 'command3',
'baz': ['command5', 'bar world', 'foo', 'command1'],
'bar': ['command4', 'foo hello', 'command2'],
}
}
project_config = ProjectConfig(isolation, config)
assert project_config.scripts == {
'foo': ['command3'],
'baz': ['command5', 'command4 world', 'command3 hello world', 'command2 world', 'command3', 'command1'],
'bar': ['command4', 'command3 hello', 'command2'],
}
def test_command_expansion_circular_inheritance(self, isolation):
config = {'scripts': {'foo': 'bar', 'bar': 'foo'}}
project_config = ProjectConfig(isolation, config)
with pytest.raises(
ValueError, match='Circular expansion detected for field `tool.hatch.scripts`: foo -> bar -> foo'
):
_ = project_config.scripts
class TestBuild:
def test_not_table(self, isolation):
config = {'build': 9000}
project_config = ProjectConfig(isolation, config)
with pytest.raises(TypeError, match='Field `tool.hatch.build` must be a table'):
_ = project_config.build
def test_targets_not_table(self, isolation):
config = {'build': {'targets': 9000}}
project_config = ProjectConfig(isolation, config)
with pytest.raises(TypeError, match='Field `tool.hatch.build.targets` must be a table'):
_ = project_config.build.target('foo')
def test_target_not_table(self, isolation):
config = {'build': {'targets': {'foo': 9000}}}
project_config = ProjectConfig(isolation, config)
with pytest.raises(TypeError, match='Field `tool.hatch.build.targets.foo` must be a table'):
_ = project_config.build.target('foo')
def test_directory_global_not_table(self, isolation):
config = {'build': {'directory': 9000}}
project_config = ProjectConfig(isolation, config)
with pytest.raises(TypeError, match='Field `tool.hatch.build.directory` must be a string'):
_ = project_config.build.target('foo').directory
def test_directory_not_table(self, isolation):
config = {'build': {'targets': {'foo': {'directory': 9000}}}}
project_config = ProjectConfig(isolation, config)
with pytest.raises(TypeError, match='Field `tool.hatch.build.targets.foo.directory` must be a string'):
_ = project_config.build.target('foo').directory
def test_directory_default(self, isolation):
project_config = ProjectConfig(isolation, {})
assert project_config.build.target('foo').directory == DEFAULT_BUILD_DIRECTORY
def test_directory_global_correct(self, isolation):
config = {'build': {'directory': 'bar'}}
project_config = ProjectConfig(isolation, config)
assert project_config.build.target('foo').directory == 'bar'
def test_directory_target_override(self, isolation):
config = {'build': {'directory': 'bar', 'targets': {'foo': {'directory': 'baz'}}}}
project_config = ProjectConfig(isolation, config)
assert project_config.build.target('foo').directory == 'baz'
def test_dependencies_global_not_array(self, isolation):
config = {'build': {'dependencies': 9000}}
project_config = ProjectConfig(isolation, config)
with pytest.raises(TypeError, match='Field `tool.hatch.build.dependencies` must be an array'):
_ = project_config.build.target('foo').dependencies
def test_dependencies_global_entry_not_string(self, isolation):
config = {'build': {'dependencies': [9000]}}
project_config = ProjectConfig(isolation, config)
with pytest.raises(TypeError, match='Dependency #1 in field `tool.hatch.build.dependencies` must be a string'):
_ = project_config.build.target('foo').dependencies
def test_dependencies_not_array(self, isolation):
config = {'build': {'targets': {'foo': {'dependencies': 9000}}}}
project_config = ProjectConfig(isolation, config)
with pytest.raises(TypeError, match='Field `tool.hatch.build.targets.foo.dependencies` must be an array'):
_ = project_config.build.target('foo').dependencies
def test_dependencies_entry_not_string(self, isolation):
config = {'build': {'targets': {'foo': {'dependencies': [9000]}}}}
project_config = ProjectConfig(isolation, config)
with pytest.raises(
TypeError, match='Dependency #1 in field `tool.hatch.build.targets.foo.dependencies` must be a string'
):
_ = project_config.build.target('foo').dependencies
def test_dependencies_target_merge(self, isolation):
config = {'build': {'dependencies': ['baz'], 'targets': {'foo': {'dependencies': ['bar']}}}}
project_config = ProjectConfig(isolation, config)
assert project_config.build.target('foo').dependencies == ['baz', 'bar']
def test_hooks_global_not_table(self, isolation):
config = {'build': {'hooks': 9000}}
project_config = ProjectConfig(isolation, config)
with pytest.raises(TypeError, match='Field `tool.hatch.build.hooks` must be a table'):
_ = project_config.build.target('foo').hook_config
def test_hook_config_global_not_table(self, isolation):
config = {'build': {'hooks': {'hook1': 9000}}}
project_config = ProjectConfig(isolation, config)
with pytest.raises(TypeError, match='Field `tool.hatch.build.hooks.hook1` must be a table'):
_ = project_config.build.target('foo').hook_config
def test_hooks_not_table(self, isolation):
config = {'build': {'targets': {'foo': {'hooks': 9000}}}}
project_config = ProjectConfig(isolation, config)
with pytest.raises(TypeError, match='Field `tool.hatch.build.targets.foo.hooks` must be a table'):
_ = project_config.build.target('foo').hook_config
def test_hook_config_not_table(self, isolation):
config = {'build': {'targets': {'foo': {'hooks': {'hook1': 9000}}}}}
project_config = ProjectConfig(isolation, config)
with pytest.raises(TypeError, match='Field `tool.hatch.build.targets.foo.hooks.hook1` must be a table'):
_ = project_config.build.target('foo').hook_config
def test_hook_config_target_override(self, isolation):
config = {
'build': {
'hooks': {
'hook1': {'foo': 'bar', 'enable-by-default': False},
'hook2': {'foo': 'bar'},
'hook3': {'foo': 'bar'},
'hook4': {'foo': 'bar'},
},
'targets': {
'foo': {
'hooks': {
'hook3': {'bar': 'foo'},
'hook4': {'bar': 'foo', 'enable-by-default': False},
'hook5': {'bar': 'foo'},
'hook6': {'bar': 'foo', 'enable-by-default': False},
},
},
},
}
}
project_config = ProjectConfig(isolation, config)
hook_config = project_config.build.target('foo').hook_config
assert hook_config == {
'hook2': {'foo': 'bar'},
'hook3': {'bar': 'foo'},
'hook5': {'bar': 'foo'},
}
def test_hook_config_all_enabled(self, isolation):
config = {
'build': {
'hooks': {
'hook1': {'foo': 'bar', 'enable-by-default': False},
'hook2': {'foo': 'bar'},
'hook3': {'foo': 'bar'},
'hook4': {'foo': 'bar'},
},
'targets': {
'foo': {
'hooks': {
'hook3': {'bar': 'foo'},
'hook4': {'bar': 'foo', 'enable-by-default': False},
'hook5': {'bar': 'foo'},
'hook6': {'bar': 'foo', 'enable-by-default': False},
},
},
},
}
}
project_config = ProjectConfig(isolation, config)
with EnvVars({BuildEnvVars.HOOKS_ENABLE: 'true'}):
hook_config = project_config.build.target('foo').hook_config
assert hook_config == {
'hook1': {'foo': 'bar', 'enable-by-default': False},
'hook2': {'foo': 'bar'},
'hook3': {'bar': 'foo'},
'hook4': {'bar': 'foo', 'enable-by-default': False},
'hook5': {'bar': 'foo'},
'hook6': {'bar': 'foo', 'enable-by-default': False},
}
def test_hook_config_all_disabled(self, isolation):
config = {
'build': {
'hooks': {
'hook1': {'foo': 'bar', 'enable-by-default': False},
'hook2': {'foo': 'bar'},
'hook3': {'foo': 'bar'},
'hook4': {'foo': 'bar'},
},
'targets': {
'foo': {
'hooks': {
'hook3': {'bar': 'foo'},
'hook4': {'bar': 'foo', 'enable-by-default': False},
'hook5': {'bar': 'foo'},
'hook6': {'bar': 'foo', 'enable-by-default': False},
},
},
},
}
}
project_config = ProjectConfig(isolation, config)
with EnvVars({BuildEnvVars.NO_HOOKS: 'true'}):
hook_config = project_config.build.target('foo').hook_config
assert not hook_config
def test_hook_config_specific_enabled(self, isolation):
config = {
'build': {
'hooks': {
'hook1': {'foo': 'bar', 'enable-by-default': False},
'hook2': {'foo': 'bar'},
'hook3': {'foo': 'bar'},
'hook4': {'foo': 'bar'},
},
'targets': {
'foo': {
'hooks': {
'hook3': {'bar': 'foo'},
'hook4': {'bar': 'foo', 'enable-by-default': False},
'hook5': {'bar': 'foo'},
'hook6': {'bar': 'foo', 'enable-by-default': False},
},
},
},
}
}
project_config = ProjectConfig(isolation, config)
with EnvVars({f'{BuildEnvVars.HOOK_ENABLE_PREFIX}HOOK6': 'true'}):
hook_config = project_config.build.target('foo').hook_config
assert hook_config == {
'hook2': {'foo': 'bar'},
'hook3': {'bar': 'foo'},
'hook5': {'bar': 'foo'},
'hook6': {'bar': 'foo', 'enable-by-default': False},
}