Make sure :bind/unbind works properly when bindings.commands is None

To make this work, we should never return None when trying to get bindings to
modify.

Fixes #3026
This commit is contained in:
Florian Bruhin 2017-10-01 21:20:30 +02:00
parent 0fbd914432
commit a273baf8a0
5 changed files with 66 additions and 1 deletions

View File

@ -384,7 +384,7 @@ class Config(QObject):
raise configexc.BackendError(objects.backend)
opt.typ.to_py(value) # for validation
self._values[opt.name] = value
self._values[opt.name] = opt.typ.from_obj(value)
self.changed.emit(opt.name)
log.config.debug("Config option changed: {} = {}".format(

View File

@ -227,6 +227,10 @@ class BaseType:
return None
return value
def from_obj(self, value):
"""Get the setting value from a config.py/YAML object."""
return value
def to_py(self, value):
"""Get the setting value from a Python value.
@ -441,6 +445,11 @@ class List(BaseType):
self.to_py(yaml_val)
return yaml_val
def from_obj(self, value):
if value is None:
return []
return value
def to_py(self, value):
self._basic_py_validation(value, list)
if not value:
@ -506,6 +515,11 @@ class ListOrValue(BaseType):
except configexc.ValidationError:
return self.valtype.from_str(value)
def from_obj(self, value):
if value is None:
return []
return value
def to_py(self, value):
try:
return [self.valtype.to_py(value)]
@ -1176,6 +1190,11 @@ class Dict(BaseType):
self.to_py(yaml_val)
return yaml_val
def from_obj(self, value):
if value is None:
return {}
return value
def _fill_fixed_keys(self, value):
"""Fill missing fixed keys with a None-value."""
if self.fixed_keys is None:

View File

@ -547,6 +547,14 @@ class TestBindConfigCommand:
commands.bind(key, 'message-info foo', mode='normal')
assert keyconf.get_command(key, 'normal') == 'nop'
def test_bind_none(self, commands, config_stub):
config_stub.val.bindings.commands = None
commands.bind(',x', 'nop')
def test_unbind_none(self, commands, config_stub):
config_stub.val.bindings.commands = None
commands.unbind('H')
@pytest.mark.parametrize('key, normalized', [
('a', 'a'), # default bindings
('b', 'b'), # custom bindings

View File

@ -378,6 +378,13 @@ class TestConfigPy:
expected = "Duplicate key H - use force=True to override!"
assert str(error.exception) == expected
def test_bind_none(self, confpy):
confpy.write("c.bindings.commands = None",
"config.bind(',x', 'nop')")
confpy.read()
expected = {'normal': {',x': 'nop'}}
assert config.instance._values['bindings.commands'] == expected
@pytest.mark.parametrize('line, key, mode', [
('config.unbind("o")', 'o', 'normal'),
('config.unbind("y", mode="prompt")', 'y', 'prompt'),

View File

@ -370,6 +370,10 @@ class TestBaseType:
def test_to_doc(self, klass, value, expected):
assert klass().to_doc(value) == expected
@pytest.mark.parametrize('obj', [42, '', None, 'foo'])
def test_from_obj(self, klass, obj):
assert klass(none_ok=True).from_obj(obj) == obj
class MappingSubclass(configtypes.MappingType):
@ -550,6 +554,14 @@ class TestList:
with pytest.raises(configexc.ValidationError):
klass().from_str(val)
@pytest.mark.parametrize('obj, expected', [
([1], [1]),
([], []),
(None, []),
])
def test_from_obj(self, klass, obj, expected):
assert klass(none_ok_outer=True).from_obj(obj) == expected
@pytest.mark.parametrize('val', [['foo'], ['foo', 'bar']])
def test_to_py_valid(self, klass, val):
assert klass().to_py(val) == val
@ -713,6 +725,15 @@ class TestListOrValue:
def test_to_py_length(self, strtype, klass, val):
klass(strtype, none_ok=True, length=2).to_py(val)
@pytest.mark.parametrize('obj, expected', [
(['a'], ['a']),
([], []),
(None, []),
])
def test_from_obj(self, klass, obj, expected):
typ = klass(none_ok=True, valtype=configtypes.String())
assert typ.from_obj(obj) == expected
@pytest.mark.parametrize('val', [['a'], ['a', 'b'], ['a', 'b', 'c', 'd']])
def test_wrong_length(self, strtype, klass, val):
with pytest.raises(configexc.ValidationError,
@ -1533,6 +1554,16 @@ class TestDict:
valtype=configtypes.Int())
assert typ.from_str('{"answer": 42}') == {"answer": 42}
@pytest.mark.parametrize('obj, expected', [
({'a': 'b'}, {'a': 'b'}),
({}, {}),
(None, {}),
])
def test_from_obj(self, klass, obj, expected):
d = klass(keytype=configtypes.String(), valtype=configtypes.String(),
none_ok=True)
assert d.from_obj(obj) == expected
@pytest.mark.parametrize('keytype, valtype, val', [
(configtypes.String(), configtypes.String(), {'hello': 'world'}),
(configtypes.String(), configtypes.Int(), {'hello': 42}),