Allow missing fixed_keys for configtypes.Dict

We just fill them up with a None value for the value type, so we can e.g. only
specify a subset of modes for bindings and the rest is {}.
This commit is contained in:
Florian Bruhin 2017-07-01 16:19:12 +02:00
parent 9d8b76e497
commit 441b3a4df4
3 changed files with 19 additions and 11 deletions

View File

@ -2095,6 +2095,7 @@ bindings.commands:
'prompt', 'caret', 'register'] 'prompt', 'caret', 'register']
valtype: valtype:
name: Dict name: Dict
none_ok: true
keytype: Key keytype: Key
valtype: valtype:
name: Command name: Command

View File

@ -1031,10 +1031,11 @@ class Dict(BaseType):
self.required_keys = required_keys self.required_keys = required_keys
def _validate_keys(self, value): def _validate_keys(self, value):
if (self.fixed_keys is not None and if (self.fixed_keys is not None and not
value.keys() != set(self.fixed_keys)): set(value.keys()).issubset(self.fixed_keys)):
raise configexc.ValidationError( raise configexc.ValidationError(
value, "Expected keys {}".format(self.fixed_keys)) value, "Expected keys {}".format(self.fixed_keys))
if (self.required_keys is not None and not if (self.required_keys is not None and not
set(self.required_keys).issubset(value.keys())): set(self.required_keys).issubset(value.keys())):
raise configexc.ValidationError( raise configexc.ValidationError(
@ -1055,19 +1056,25 @@ class Dict(BaseType):
self.to_py(yaml_val) self.to_py(yaml_val)
return yaml_val return yaml_val
def _fill_fixed_keys(self, value):
"""Fill missing fixed keys with a None-value."""
if self.fixed_keys is None:
return value
for key in self.fixed_keys:
if key not in value:
value[key] = self.valtype.to_py(None)
return value
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, dict) self._basic_py_validation(value, dict)
if not value: if not value:
if self.fixed_keys is None: return self._fill_fixed_keys({})
return {}
else:
return {key: self.valtype.to_py(None)
for key in self.fixed_keys}
self._validate_keys(value) self._validate_keys(value)
return {self.keytype.to_py(key): self.valtype.to_py(val) d = {self.keytype.to_py(key): self.valtype.to_py(val)
for key, val in value.items()} for key, val in value.items()}
return self._fill_fixed_keys(d)
def to_str(self, value): def to_str(self, value):
if not value: if not value:

View File

@ -1398,7 +1398,7 @@ class TestDict:
assert typ.from_str('{"answer": 42}') == {"answer": 42} assert typ.from_str('{"answer": 42}') == {"answer": 42}
@pytest.mark.parametrize('kind, val, ok', [ @pytest.mark.parametrize('kind, val, ok', [
('fixed', {"one": "1"}, False), # missing key ('fixed', {"one": "1"}, True), # missing key (gets filled with None)
('fixed', {"one": "1", "two": "2", "three": "3"}, False), # extra key ('fixed', {"one": "1", "two": "2", "three": "3"}, False), # extra key
('fixed', {"one": "1", "two": "2"}, True), ('fixed', {"one": "1", "two": "2"}, True),
@ -1410,7 +1410,7 @@ class TestDict:
def test_keys(self, klass, kind, val, ok, from_str): def test_keys(self, klass, kind, val, ok, from_str):
if kind == 'fixed': if kind == 'fixed':
d = klass(keytype=configtypes.String(), d = klass(keytype=configtypes.String(),
valtype=configtypes.String(), valtype=configtypes.String(none_ok=True),
fixed_keys=['one', 'two']) fixed_keys=['one', 'two'])
message = 'Expected keys .*' message = 'Expected keys .*'
elif kind == 'required': elif kind == 'required':