pypa-hatch/tests/project/test_config.py

2200 lines
89 KiB
Python

import pytest
from hatch.plugin.manager import PluginManager
from hatch.project.config import ProjectConfig
from hatch.project.env import RESERVED_OPTIONS
from hatch.utils.structures import EnvVars
from hatch.version.scheme.standard import StandardScheme
from hatchling.version.source.regex import RegexSource
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']
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 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_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_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_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'] == list(expected_envs)[1:]
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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
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'] == list(expected_envs)[1:]
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'] == list(expected_envs)[1:]
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'] == list(expected_envs)[1:2]
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'] == list(expected_envs)
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'] == list(expected_envs)[1:]
@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', 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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
@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'] == list(expected_envs)[1:]
# 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
# Tests for source precedence
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'] == list(expected_envs)[1:]
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'] == list(expected_envs)[1:]
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'] == list(expected_envs)[1:]
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'] == list(expected_envs)[1:]
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_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 TestVersionConfig:
def test_missing(self, isolation):
with pytest.raises(ValueError, match='Missing `tool.hatch.version` configuration'):
_ = ProjectConfig(isolation, {}).version
def test_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.version` must be a table'):
_ = ProjectConfig(isolation, {'version': 9000}).version
def test_parse(self, isolation):
project_config = ProjectConfig(isolation, {'version': {'foo': 'bar'}})
assert project_config.version.config == project_config.version.config == {'foo': 'bar'}
class TestVersionSourceName:
def test_empty(self, isolation):
with pytest.raises(
ValueError, match='The `source` option under the `tool.hatch.version` table must not be empty if defined'
):
_ = ProjectConfig(isolation, {'version': {'source': ''}}).version.source_name
def test_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.version.source` must be a string'):
_ = ProjectConfig(isolation, {'version': {'source': 9000}}).version.source_name
def test_correct(self, isolation):
project_config = ProjectConfig(isolation, {'version': {'source': 'foo'}})
assert project_config.version.source_name == project_config.version.source_name == 'foo'
def test_default(self, isolation):
project_config = ProjectConfig(isolation, {'version': {}})
assert project_config.version.source_name == project_config.version.source_name == 'regex'
class TestVersionSchemeName:
def test_missing(self, isolation):
with pytest.raises(
ValueError, match='The `scheme` option under the `tool.hatch.version` table must not be empty if defined'
):
_ = ProjectConfig(isolation, {'version': {'scheme': ''}}).version.scheme_name
def test_not_table(self, isolation):
with pytest.raises(TypeError, match='Field `tool.hatch.version.scheme` must be a string'):
_ = ProjectConfig(isolation, {'version': {'scheme': 9000}}).version.scheme_name
def test_correct(self, isolation):
project_config = ProjectConfig(isolation, {'version': {'scheme': 'foo'}})
assert project_config.version.scheme_name == project_config.version.scheme_name == 'foo'
def test_default(self, isolation):
project_config = ProjectConfig(isolation, {'version': {}})
assert project_config.version.scheme_name == project_config.version.scheme_name == 'standard'
class TestVersionSource:
def test_unknown(self, isolation):
with pytest.raises(ValueError, match='Unknown version source: foo'):
_ = ProjectConfig(isolation, {'version': {'source': 'foo'}}, PluginManager()).version.source
def test_cached(self, isolation):
project_config = ProjectConfig(isolation, {'version': {}}, PluginManager())
assert project_config.version.source is project_config.version.source
assert isinstance(project_config.version.source, RegexSource)
class TestVersionScheme:
def test_unknown(self, isolation):
with pytest.raises(ValueError, match='Unknown version scheme: foo'):
_ = ProjectConfig(isolation, {'version': {'scheme': 'foo'}}, PluginManager()).version.scheme
def test_cached(self, isolation):
project_config = ProjectConfig(isolation, {'version': {}}, PluginManager())
assert project_config.version.scheme is project_config.version.scheme
assert isinstance(project_config.version.scheme, StandardScheme)