Add required_keys for configtypes.Dict
This commit is contained in:
parent
bc526cf0ce
commit
2ba637891a
@ -83,10 +83,10 @@ new_instance_open_target_window:
|
|||||||
|
|
||||||
searchengines:
|
searchengines:
|
||||||
default:
|
default:
|
||||||
# FIXME:conf what if the user deletes/renames DEFAULT?
|
|
||||||
DEFAULT: https://duckduckgo.com/?q={}
|
DEFAULT: https://duckduckgo.com/?q={}
|
||||||
type:
|
type:
|
||||||
name: Dict
|
name: Dict
|
||||||
|
required_keys: ['DEFAULT']
|
||||||
keytype: String
|
keytype: String
|
||||||
valtype: SearchEngineUrl
|
valtype: SearchEngineUrl
|
||||||
desc: >-
|
desc: >-
|
||||||
|
@ -1030,7 +1030,8 @@ class Dict(BaseType):
|
|||||||
|
|
||||||
"""A dictionary of values."""
|
"""A dictionary of values."""
|
||||||
|
|
||||||
def __init__(self, keytype, valtype, *, fixed_keys=None, none_ok=False):
|
def __init__(self, keytype, valtype, *, fixed_keys=None,
|
||||||
|
required_keys=None, none_ok=False):
|
||||||
super().__init__(none_ok)
|
super().__init__(none_ok)
|
||||||
# If the keytype is not a string, we'll get problems with showing it as
|
# If the keytype is not a string, we'll get problems with showing it as
|
||||||
# json in to_str() as json converts keys to strings.
|
# json in to_str() as json converts keys to strings.
|
||||||
@ -1038,12 +1039,17 @@ class Dict(BaseType):
|
|||||||
self.keytype = keytype
|
self.keytype = keytype
|
||||||
self.valtype = valtype
|
self.valtype = valtype
|
||||||
self.fixed_keys = fixed_keys
|
self.fixed_keys = fixed_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
|
||||||
value.keys() != set(self.fixed_keys)):
|
value.keys() != set(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
|
||||||
|
set(self.required_keys).issubset(value.keys())):
|
||||||
|
raise configexc.ValidationError(
|
||||||
|
value, "Required keys {}".format(self.required_keys))
|
||||||
|
|
||||||
def _none_value(self, value=None):
|
def _none_value(self, value=None):
|
||||||
"""Return the value to be used when the setting is None.
|
"""Return the value to be used when the setting is None.
|
||||||
|
@ -73,3 +73,8 @@ def test_partial_compare_not_equal(val1, val2, error):
|
|||||||
])
|
])
|
||||||
def test_pattern_match(pattern, value, expected):
|
def test_pattern_match(pattern, value, expected):
|
||||||
assert utils.pattern_match(pattern=pattern, value=value) == expected
|
assert utils.pattern_match(pattern=pattern, value=value) == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_nop_contextmanager():
|
||||||
|
with utils.nop_contextmanager():
|
||||||
|
pass
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
import re
|
import re
|
||||||
import pprint
|
import pprint
|
||||||
import os.path
|
import os.path
|
||||||
|
import contextlib
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -170,3 +171,8 @@ def abs_datapath():
|
|||||||
"""Get the absolute path to the end2end data directory."""
|
"""Get the absolute path to the end2end data directory."""
|
||||||
file_abs = os.path.abspath(os.path.dirname(__file__))
|
file_abs = os.path.abspath(os.path.dirname(__file__))
|
||||||
return os.path.join(file_abs, '..', 'end2end', 'data')
|
return os.path.join(file_abs, '..', 'end2end', 'data')
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def nop_contextmanager():
|
||||||
|
yield
|
||||||
|
@ -40,6 +40,7 @@ from PyQt5.QtNetwork import QNetworkProxy
|
|||||||
from qutebrowser.config import configtypes, configexc
|
from qutebrowser.config import configtypes, configexc
|
||||||
from qutebrowser.utils import debug, utils, qtutils
|
from qutebrowser.utils import debug, utils, qtutils
|
||||||
from qutebrowser.browser.network import pac
|
from qutebrowser.browser.network import pac
|
||||||
|
from tests.helpers import utils as testutils
|
||||||
|
|
||||||
|
|
||||||
class Font(QFont):
|
class Font(QFont):
|
||||||
@ -1390,16 +1391,35 @@ class TestDict:
|
|||||||
valtype=configtypes.Int())
|
valtype=configtypes.Int())
|
||||||
assert typ.from_str('{"answer": 42}') == {"answer": 42}
|
assert typ.from_str('{"answer": 42}') == {"answer": 42}
|
||||||
|
|
||||||
@pytest.mark.parametrize('val', [
|
@pytest.mark.parametrize('kind, val, ok', [
|
||||||
{"one": "1"}, # missing key
|
('fixed', {"one": "1"}, False), # missing key
|
||||||
{"one": "1", "two": "2", "three": "3"}, # extra key
|
('fixed', {"one": "1", "two": "2", "three": "3"}, False), # extra key
|
||||||
|
('fixed', {"one": "1", "two": "2"}, True),
|
||||||
|
|
||||||
|
('required', {"one": "1"}, False), # missing key
|
||||||
|
('required', {"one": "1", "two": "2", "three": "3"}, True), # extra
|
||||||
|
('required', {"one": "1", "two": "2"}, True),
|
||||||
])
|
])
|
||||||
@pytest.mark.parametrize('from_str', [True, False])
|
@pytest.mark.parametrize('from_str', [True, False])
|
||||||
def test_fixed_keys(self, klass, val, from_str):
|
def test_keys(self, klass, kind, val, ok, from_str):
|
||||||
d = klass(keytype=configtypes.String(), valtype=configtypes.String(),
|
if kind == 'fixed':
|
||||||
|
d = klass(keytype=configtypes.String(),
|
||||||
|
valtype=configtypes.String(),
|
||||||
fixed_keys=['one', 'two'])
|
fixed_keys=['one', 'two'])
|
||||||
|
message = 'Expected keys .*'
|
||||||
|
elif kind == 'required':
|
||||||
|
d = klass(keytype=configtypes.String(),
|
||||||
|
valtype=configtypes.String(),
|
||||||
|
required_keys=['one', 'two'])
|
||||||
|
message = 'Required keys .*'
|
||||||
|
|
||||||
with pytest.raises(configexc.ValidationError):
|
if ok:
|
||||||
|
expectation = testutils.nop_contextmanager()
|
||||||
|
else:
|
||||||
|
expectation = pytest.raises(configexc.ValidationError,
|
||||||
|
match=message)
|
||||||
|
|
||||||
|
with expectation:
|
||||||
if from_str:
|
if from_str:
|
||||||
d.from_str(json.dumps(val))
|
d.from_str(json.dumps(val))
|
||||||
else:
|
else:
|
||||||
|
Loading…
Reference in New Issue
Block a user