Add required_keys for configtypes.Dict

This commit is contained in:
Florian Bruhin 2017-06-30 22:03:34 +02:00
parent bc526cf0ce
commit 2ba637891a
5 changed files with 46 additions and 9 deletions

View File

@ -83,10 +83,10 @@ new_instance_open_target_window:
searchengines:
default:
# FIXME:conf what if the user deletes/renames DEFAULT?
DEFAULT: https://duckduckgo.com/?q={}
type:
name: Dict
required_keys: ['DEFAULT']
keytype: String
valtype: SearchEngineUrl
desc: >-

View File

@ -1030,7 +1030,8 @@ class Dict(BaseType):
"""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)
# 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.
@ -1038,12 +1039,17 @@ class Dict(BaseType):
self.keytype = keytype
self.valtype = valtype
self.fixed_keys = fixed_keys
self.required_keys = required_keys
def _validate_keys(self, value):
if (self.fixed_keys is not None and
value.keys() != set(self.fixed_keys)):
raise configexc.ValidationError(
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):
"""Return the value to be used when the setting is None.

View File

@ -73,3 +73,8 @@ def test_partial_compare_not_equal(val1, val2, error):
])
def test_pattern_match(pattern, value, expected):
assert utils.pattern_match(pattern=pattern, value=value) == expected
def test_nop_contextmanager():
with utils.nop_contextmanager():
pass

View File

@ -23,6 +23,7 @@
import re
import pprint
import os.path
import contextlib
import pytest
@ -170,3 +171,8 @@ def abs_datapath():
"""Get the absolute path to the end2end data directory."""
file_abs = os.path.abspath(os.path.dirname(__file__))
return os.path.join(file_abs, '..', 'end2end', 'data')
@contextlib.contextmanager
def nop_contextmanager():
yield

View File

@ -40,6 +40,7 @@ from PyQt5.QtNetwork import QNetworkProxy
from qutebrowser.config import configtypes, configexc
from qutebrowser.utils import debug, utils, qtutils
from qutebrowser.browser.network import pac
from tests.helpers import utils as testutils
class Font(QFont):
@ -1390,16 +1391,35 @@ class TestDict:
valtype=configtypes.Int())
assert typ.from_str('{"answer": 42}') == {"answer": 42}
@pytest.mark.parametrize('val', [
{"one": "1"}, # missing key
{"one": "1", "two": "2", "three": "3"}, # extra key
@pytest.mark.parametrize('kind, val, ok', [
('fixed', {"one": "1"}, False), # missing 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])
def test_fixed_keys(self, klass, val, from_str):
d = klass(keytype=configtypes.String(), valtype=configtypes.String(),
fixed_keys=['one', 'two'])
def test_keys(self, klass, kind, val, ok, from_str):
if kind == 'fixed':
d = klass(keytype=configtypes.String(),
valtype=configtypes.String(),
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:
d.from_str(json.dumps(val))
else: