d2326eadb9
Persistent setting groups allow settings that are not declared to survive normalization and other operations that would normally remove any unknown keys in a group. Calling normalize or get_namespace with persistent=False will remove unknown keys even from persistent groups. Currently the only way to retrieve the defaults for a config and preserve unknown keys is to manually get the defaults and update each existing group with the default values.
305 lines
12 KiB
Python
305 lines
12 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
|
|
import pytest
|
|
|
|
import settngs
|
|
from settngs import Group
|
|
from testing.settngs import example
|
|
from testing.settngs import failure
|
|
from testing.settngs import success
|
|
|
|
|
|
@pytest.fixture
|
|
def settngs_manager():
|
|
manager = settngs.Manager()
|
|
yield manager
|
|
|
|
|
|
def test_settngs_manager():
|
|
manager = settngs.Manager()
|
|
defaults = manager.defaults()
|
|
assert manager is not None and defaults is not None
|
|
|
|
|
|
def test_settngs_manager_config():
|
|
manager = settngs.Manager(
|
|
definitions=settngs.Config[settngs.Namespace](
|
|
settngs.Namespace(),
|
|
{'tst': Group(False, {'test': settngs.Setting('--test', default='hello', group='tst', exclusive=False)})},
|
|
),
|
|
)
|
|
|
|
defaults = manager.defaults()
|
|
assert manager is not None and defaults is not None
|
|
assert defaults.values['tst']['test'] == 'hello'
|
|
|
|
|
|
@pytest.mark.parametrize('arguments, expected', success)
|
|
def test_setting_success(arguments, expected):
|
|
assert vars(settngs.Setting(*arguments[0], **arguments[1])) == expected
|
|
|
|
|
|
@pytest.mark.parametrize('arguments, exception', failure)
|
|
def test_setting_failure(arguments, exception):
|
|
with exception:
|
|
settngs.Setting(*arguments[0], **arguments[1])
|
|
|
|
|
|
def test_add_setting(settngs_manager):
|
|
assert settngs_manager.add_setting('--test') is None
|
|
|
|
|
|
def test_get_defaults(settngs_manager):
|
|
settngs_manager.add_setting('--test', default='hello')
|
|
defaults, _ = settngs_manager.defaults()
|
|
assert defaults['']['test'] == 'hello'
|
|
|
|
|
|
def test_get_namespace(settngs_manager):
|
|
settngs_manager.add_setting('--test', default='hello')
|
|
defaults, _ = settngs_manager.get_namespace(settngs_manager.defaults())
|
|
assert defaults.test == 'hello'
|
|
|
|
|
|
def test_get_namespace_with_namespace(settngs_manager):
|
|
settngs_manager.add_setting('--test', default='hello')
|
|
defaults, _ = settngs_manager.get_namespace(argparse.Namespace(test='hello'))
|
|
assert defaults.test == 'hello'
|
|
|
|
|
|
def test_get_defaults_group(settngs_manager):
|
|
settngs_manager.add_group('tst', lambda parser: parser.add_setting('--test', default='hello'))
|
|
defaults, _ = settngs_manager.defaults()
|
|
assert defaults['tst']['test'] == 'hello'
|
|
|
|
|
|
def test_get_namespace_group(settngs_manager):
|
|
settngs_manager.add_group('tst', lambda parser: parser.add_setting('--test', default='hello'))
|
|
defaults, _ = settngs_manager.get_namespace(settngs_manager.defaults())
|
|
assert defaults.tst_test == 'hello'
|
|
|
|
|
|
def test_cmdline_only(settngs_manager):
|
|
settngs_manager.add_group('tst', lambda parser: parser.add_setting('--test', default='hello', file=False))
|
|
settngs_manager.add_group('tst2', lambda parser: parser.add_setting('--test2', default='hello', cmdline=False))
|
|
|
|
file_normalized, _ = settngs_manager.normalize_config(settngs_manager.defaults(), file=True)
|
|
cmdline_normalized, _ = settngs_manager.normalize_config(settngs_manager.defaults(), cmdline=True)
|
|
|
|
assert 'test' in cmdline_normalized['tst']
|
|
assert 'test2' not in cmdline_normalized['tst2']
|
|
|
|
assert 'test' not in file_normalized['tst']
|
|
assert 'test2' in file_normalized['tst2']
|
|
|
|
|
|
def test_normalize(settngs_manager):
|
|
settngs_manager.add_group('tst', lambda parser: parser.add_setting('--test', default='hello'))
|
|
settngs_manager.add_persistent_group('persistent', lambda parser: parser.add_setting('--world', default='world'))
|
|
|
|
defaults = settngs_manager.defaults()
|
|
defaults.values['test'] = 'fail' # Not defined in settngs_manager, should be removed
|
|
defaults.values['persistent']['hello'] = 'success' # Not defined in settngs_manager, should stay
|
|
|
|
defaults_namespace = settngs_manager.get_namespace(settngs_manager.defaults())
|
|
defaults_namespace.values.test = 'fail' # Not defined in settngs_manager, should be removed
|
|
defaults_namespace.values.persistent_hello = 'success' # Not defined in settngs_manager, should stay
|
|
|
|
normalized, _ = settngs_manager.normalize_config(defaults, file=True)
|
|
normalized_from_namespace = settngs_manager.normalize_config(defaults_namespace, file=True)
|
|
normalized_namespace, _ = settngs_manager.get_namespace(normalized_from_namespace)
|
|
|
|
assert 'test' not in normalized
|
|
assert 'tst' in normalized
|
|
assert 'test' in normalized['tst']
|
|
assert normalized['tst']['test'] == 'hello'
|
|
assert normalized['persistent']['hello'] == 'success'
|
|
|
|
assert not hasattr(normalized_namespace, 'test')
|
|
assert hasattr(normalized_namespace, 'tst_test')
|
|
assert normalized_namespace.tst_test == 'hello'
|
|
assert normalized_namespace.persistent_hello == 'success'
|
|
|
|
|
|
def test_clean_config(settngs_manager):
|
|
settngs_manager.add_group('tst', lambda parser: parser.add_setting('--test', default='hello', cmdline=False))
|
|
settngs_manager.add_group('tst2', lambda parser: parser.add_setting('--test2', default='hello', file=False))
|
|
settngs_manager.add_persistent_group('persistent', lambda parser: parser.add_setting('--world', default='world'))
|
|
normalized, _ = settngs_manager.defaults()
|
|
normalized['tst']['test'] = 'success'
|
|
normalized['persistent']['hello'] = 'success'
|
|
normalized['fail'] = 'fail'
|
|
|
|
cleaned = settngs_manager.clean_config(normalized, file=True)
|
|
|
|
assert 'fail' not in cleaned
|
|
assert 'tst2' not in cleaned
|
|
assert cleaned['tst']['test'] == 'success'
|
|
assert cleaned['persistent']['hello'] == 'success'
|
|
|
|
|
|
def test_parse_cmdline(settngs_manager, tmp_path):
|
|
settngs_manager.add_group('tst', lambda parser: parser.add_setting('--test', default='hello', cmdline=True))
|
|
|
|
normalized, _ = settngs_manager.parse_cmdline(['--test', 'success'])
|
|
|
|
assert 'test' in normalized['tst']
|
|
assert normalized['tst']['test'] == 'success'
|
|
|
|
|
|
def test_parse_cmdline_with_namespace(settngs_manager, tmp_path):
|
|
settngs_manager.add_group('tst', lambda parser: parser.add_setting('--test', default='hello', cmdline=True))
|
|
|
|
normalized, _ = settngs_manager.parse_cmdline(
|
|
['--test', 'success'], namespace=settngs.Config({'tst': {'test': 'fail'}}, settngs_manager.definitions),
|
|
)
|
|
|
|
assert 'test' in normalized['tst']
|
|
assert normalized['tst']['test'] == 'success'
|
|
|
|
|
|
def test_parse_file(settngs_manager, tmp_path):
|
|
settngs_file = tmp_path / 'settngs.json'
|
|
settngs_file.write_text(json.dumps({'tst': {'test': 'success'}, 'persistent': {'hello': 'success'}}))
|
|
settngs_manager.add_group('tst', lambda parser: parser.add_setting('--test', default='hello', cmdline=False))
|
|
settngs_manager.add_persistent_group('persistent', lambda parser: parser.add_setting('--world', default='world'))
|
|
|
|
normalized, success = settngs_manager.parse_file(settngs_file)
|
|
|
|
assert success
|
|
assert 'test' in normalized[0]['tst']
|
|
assert normalized[0]['tst']['test'] == 'success'
|
|
assert normalized[0]['persistent']['hello'] == 'success'
|
|
|
|
|
|
def test_parse_non_existent_file(settngs_manager, tmp_path):
|
|
settngs_file = tmp_path / 'settngs.json'
|
|
settngs_manager.add_group('tst', lambda parser: parser.add_setting('--test', default='hello', cmdline=False))
|
|
|
|
normalized, success = settngs_manager.parse_file(settngs_file)
|
|
|
|
assert success
|
|
assert 'test' in normalized[0]['tst']
|
|
assert normalized[0]['tst']['test'] == 'hello'
|
|
|
|
|
|
def test_parse_corrupt_file(settngs_manager, tmp_path):
|
|
settngs_file = tmp_path / 'settngs.json'
|
|
settngs_file.write_text('{')
|
|
settngs_manager.add_group('tst', lambda parser: parser.add_setting('--test', default='hello', cmdline=False))
|
|
|
|
normalized, success = settngs_manager.parse_file(settngs_file)
|
|
|
|
assert not success
|
|
assert 'test' in normalized[0]['tst']
|
|
assert normalized[0]['tst']['test'] == 'hello'
|
|
|
|
|
|
def test_save_file(settngs_manager, tmp_path):
|
|
settngs_file = tmp_path / 'settngs.json'
|
|
settngs_manager.add_group('tst', lambda parser: parser.add_setting('--test', default='hello', cmdline=False))
|
|
settngs_manager.add_persistent_group('persistent', lambda parser: parser.add_setting('--world', default='world'))
|
|
normalized, _ = settngs_manager.defaults()
|
|
normalized['tst']['test'] = 'success'
|
|
normalized['persistent']['hello'] = 'success'
|
|
|
|
success = settngs_manager.save_file(normalized, settngs_file)
|
|
normalized_r, success_r = settngs_manager.parse_file(settngs_file)
|
|
|
|
assert success and success_r
|
|
assert 'test' in normalized_r[0]['tst']
|
|
assert normalized_r[0]['tst']['test'] == 'success'
|
|
assert normalized_r[0]['persistent']['hello'] == 'success'
|
|
|
|
|
|
def test_save_file_not_seriazable(settngs_manager, tmp_path):
|
|
settngs_file = tmp_path / 'settngs.json'
|
|
settngs_manager.add_group('tst', lambda parser: parser.add_setting('--test', default='hello', cmdline=False))
|
|
normalized, _ = settngs_manager.defaults()
|
|
normalized['tst']['test'] = {'fail'} # Sets are not serializabl
|
|
|
|
success = settngs_manager.save_file(normalized, settngs_file)
|
|
normalized_r, success_r = settngs_manager.parse_file(settngs_file)
|
|
# normalized_r will be the default settings
|
|
|
|
assert not success
|
|
assert not success_r
|
|
assert 'test' in normalized['tst']
|
|
assert normalized['tst']['test'] == {'fail'}
|
|
|
|
assert 'test' in normalized_r[0]['tst']
|
|
assert normalized_r[0]['tst']['test'] == 'hello'
|
|
|
|
|
|
def test_cli_set(settngs_manager, tmp_path):
|
|
settngs_file = tmp_path / 'settngs.json'
|
|
settngs_file.write_text(json.dumps({}))
|
|
settngs_manager.add_group('tst', lambda parser: parser.add_setting('--test', default='hello', file=False))
|
|
|
|
config, success = settngs_manager.parse_config(settngs_file, ['--test', 'success'])
|
|
normalized = config[0]
|
|
|
|
assert success
|
|
assert 'test' in normalized['tst']
|
|
assert normalized['tst']['test'] == 'success'
|
|
|
|
|
|
def test_file_set(settngs_manager, tmp_path):
|
|
settngs_file = tmp_path / 'settngs.json'
|
|
settngs_file.write_text(json.dumps({'tst': {'test': 'success'}}))
|
|
settngs_manager.add_group('tst', lambda parser: parser.add_setting('--test', default='hello', cmdline=False))
|
|
|
|
config, success = settngs_manager.parse_config(settngs_file, [])
|
|
normalized = config[0]
|
|
|
|
assert success
|
|
assert 'test' in normalized['tst']
|
|
assert normalized['tst']['test'] == 'success'
|
|
|
|
|
|
def test_cli_override_file(settngs_manager, tmp_path):
|
|
settngs_file = tmp_path / 'settngs.json'
|
|
settngs_file.write_text(json.dumps({'tst': {'test': 'fail'}}))
|
|
settngs_manager.add_group('tst', lambda parser: parser.add_setting('--test', default='hello'))
|
|
|
|
config, success = settngs_manager.parse_config(settngs_file, ['--test', 'success'])
|
|
normalized = config[0]
|
|
|
|
assert success
|
|
assert 'test' in normalized['tst']
|
|
assert normalized['tst']['test'] == 'success'
|
|
|
|
|
|
def test_cli_explicit_default(settngs_manager, tmp_path):
|
|
settngs_file = tmp_path / 'settngs.json'
|
|
settngs_file.write_text(json.dumps({'tst': {'test': 'fail'}}))
|
|
settngs_manager.add_group('tst', lambda parser: parser.add_setting('--test', default='success'))
|
|
|
|
config, success = settngs_manager.parse_config(settngs_file, ['--test', 'success'])
|
|
normalized = config[0]
|
|
|
|
assert success
|
|
assert 'test' in normalized['tst']
|
|
assert normalized['tst']['test'] == 'success'
|
|
|
|
|
|
def test_example(capsys, tmp_path, monkeypatch):
|
|
monkeypatch.chdir(tmp_path)
|
|
settings_file = tmp_path / 'settings.json'
|
|
settings_file.touch()
|
|
|
|
i = 0
|
|
for args, expected_out, expected_file in example:
|
|
if args == ['manual settings.json']:
|
|
settings_file.unlink()
|
|
settings_file.write_text('{\n "example": {\n "hello": "lordwelch",\n "verbose": true\n },\n "persistent": {\n "test": false,\n "hello": "world"\n }\n}\n')
|
|
else:
|
|
settngs._main(args)
|
|
captured = capsys.readouterr()
|
|
assert captured.out == expected_out, f'{i}, {args}'
|
|
assert settings_file.read_text() == expected_file, f'{i}, {args}'
|
|
i += 1
|