Allow direct values for url.start_pages and content.user_stylesheets
This commit is contained in:
parent
2dfcf9c506
commit
c694bff902
@ -1944,7 +1944,7 @@ Default: +pass:[ask]+
|
||||
=== content.user_stylesheets
|
||||
A list of user stylesheet filenames to use.
|
||||
|
||||
Type: <<types,List>>
|
||||
Type: <<types,ListOrValue>>
|
||||
|
||||
Default: empty
|
||||
|
||||
@ -3056,11 +3056,9 @@ Default:
|
||||
=== url.start_pages
|
||||
The page(s) to open at the start.
|
||||
|
||||
Type: <<types,List>>
|
||||
Type: <<types,ListOrValue>>
|
||||
|
||||
Default:
|
||||
|
||||
- +pass:[https://start.duckduckgo.com]+
|
||||
Default: +pass:[https://start.duckduckgo.com]+
|
||||
|
||||
[[url.yank_ignored_parameters]]
|
||||
=== url.yank_ignored_parameters
|
||||
@ -3199,6 +3197,7 @@ Lists with duplicate flags are invalid. Each item is checked against the valid v
|
||||
|List|A list of values.
|
||||
|
||||
When setting from a string, pass a json-like list, e.g. `["one", "two"]`.
|
||||
|ListOrValue|A list of values, or a single value.
|
||||
|NewTabPosition|How new tabs are positioned.
|
||||
|Padding|Setting for paddings around elements.
|
||||
|Perc|A percentage.
|
||||
|
@ -93,7 +93,7 @@ def _parse_yaml_type(name, node):
|
||||
if typ is configtypes.Dict:
|
||||
kwargs['keytype'] = _parse_yaml_type(name, kwargs['keytype'])
|
||||
kwargs['valtype'] = _parse_yaml_type(name, kwargs['valtype'])
|
||||
elif typ is configtypes.List:
|
||||
elif typ is configtypes.List or typ is configtypes.ListOrValue:
|
||||
kwargs['valtype'] = _parse_yaml_type(name, kwargs['valtype'])
|
||||
except KeyError as e:
|
||||
_raise_invalid_node(name, str(e), node)
|
||||
|
@ -545,7 +545,7 @@ content.ssl_strict:
|
||||
|
||||
content.user_stylesheets:
|
||||
type:
|
||||
name: List
|
||||
name: ListOrValue
|
||||
valtype: File
|
||||
none_ok: True
|
||||
default: null
|
||||
@ -1240,9 +1240,9 @@ url.searchengines:
|
||||
|
||||
url.start_pages:
|
||||
type:
|
||||
name: List
|
||||
name: ListOrValue
|
||||
valtype: FuzzyUrl
|
||||
default: ["https://start.duckduckgo.com"]
|
||||
default: "https://start.duckduckgo.com"
|
||||
desc: The page(s) to open at the start.
|
||||
|
||||
url.yank_ignored_parameters:
|
||||
|
@ -476,6 +476,67 @@ class List(BaseType):
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
class ListOrValue(BaseType):
|
||||
|
||||
"""A list of values, or a single value.
|
||||
|
||||
//
|
||||
|
||||
Internally, the value is stored as either a value (of valtype), or a list.
|
||||
to_py() then ensures that it's always a list.
|
||||
"""
|
||||
|
||||
_show_valtype = True
|
||||
|
||||
def __init__(self, valtype, none_ok=False, *args, **kwargs):
|
||||
super().__init__(none_ok)
|
||||
assert not isinstance(valtype, (List, ListOrValue)), valtype
|
||||
self.listtype = List(valtype, none_ok=none_ok, *args, **kwargs)
|
||||
self.valtype = valtype
|
||||
|
||||
def get_name(self):
|
||||
return self.listtype.get_name() + ' or ' + self.valtype.get_name()
|
||||
|
||||
def get_valid_values(self):
|
||||
return self.valtype.get_valid_values()
|
||||
|
||||
def from_str(self, value):
|
||||
try:
|
||||
return self.listtype.from_str(value)
|
||||
except configexc.ValidationError:
|
||||
return self.valtype.from_str(value)
|
||||
|
||||
def to_py(self, value):
|
||||
try:
|
||||
return [self.valtype.to_py(value)]
|
||||
except configexc.ValidationError:
|
||||
return self.listtype.to_py(value)
|
||||
|
||||
def to_str(self, value):
|
||||
if value is None:
|
||||
return ''
|
||||
|
||||
if isinstance(value, list):
|
||||
if len(value) == 1:
|
||||
return self.valtype.to_str(value[0])
|
||||
else:
|
||||
return self.listtype.to_str(value)
|
||||
else:
|
||||
return self.valtype.to_str(value)
|
||||
|
||||
def to_doc(self, value):
|
||||
if value is None:
|
||||
return 'empty'
|
||||
|
||||
if isinstance(value, list):
|
||||
if len(value) == 1:
|
||||
return self.valtype.to_doc(value[0])
|
||||
else:
|
||||
return self.listtype.to_doc(value)
|
||||
else:
|
||||
return self.valtype.to_doc(value)
|
||||
|
||||
|
||||
class FlagList(List):
|
||||
|
||||
"""A list of flags.
|
||||
|
@ -193,7 +193,8 @@ class TestAll:
|
||||
if member in [configtypes.BaseType, configtypes.MappingType,
|
||||
configtypes._Numeric]:
|
||||
pass
|
||||
elif member is configtypes.List:
|
||||
elif (member is configtypes.List or
|
||||
member is configtypes.ListOrValue):
|
||||
yield functools.partial(member, valtype=configtypes.Int())
|
||||
yield functools.partial(member, valtype=configtypes.Url())
|
||||
elif member is configtypes.Dict:
|
||||
@ -240,6 +241,9 @@ class TestAll:
|
||||
configtypes.PercOrInt, # ditto
|
||||
]:
|
||||
return
|
||||
if (isinstance(typ, configtypes.ListOrValue) and
|
||||
isinstance(typ.valtype, configtypes.Int)):
|
||||
return
|
||||
|
||||
assert converted == s
|
||||
|
||||
@ -250,7 +254,7 @@ class TestAll:
|
||||
to_py_expected = configtypes.PaddingValues(None, None, None, None)
|
||||
elif isinstance(typ, configtypes.Dict):
|
||||
to_py_expected = {}
|
||||
elif isinstance(typ, configtypes.List):
|
||||
elif isinstance(typ, (configtypes.List, configtypes.ListOrValue)):
|
||||
to_py_expected = []
|
||||
else:
|
||||
to_py_expected = None
|
||||
@ -670,6 +674,99 @@ class TestFlagList:
|
||||
assert klass().complete() is None
|
||||
|
||||
|
||||
class TestListOrValue:
|
||||
|
||||
@pytest.fixture
|
||||
def klass(self):
|
||||
return configtypes.ListOrValue
|
||||
|
||||
@pytest.fixture
|
||||
def strtype(self):
|
||||
return configtypes.String()
|
||||
|
||||
@pytest.mark.parametrize('val, expected', [
|
||||
('["foo"]', ['foo']),
|
||||
('["foo", "bar"]', ['foo', 'bar']),
|
||||
('foo', 'foo'),
|
||||
])
|
||||
def test_from_str(self, klass, strtype, val, expected):
|
||||
assert klass(strtype).from_str(val) == expected
|
||||
|
||||
def test_from_str_invalid(self, klass):
|
||||
valtype = configtypes.String(minlen=10)
|
||||
with pytest.raises(configexc.ValidationError):
|
||||
klass(valtype).from_str('123')
|
||||
|
||||
@pytest.mark.parametrize('val, expected', [
|
||||
(['foo'], ['foo']),
|
||||
('foo', ['foo']),
|
||||
])
|
||||
def test_to_py_valid(self, klass, strtype, val, expected):
|
||||
assert klass(strtype).to_py(val) == expected
|
||||
|
||||
@pytest.mark.parametrize('val', [[42], ['\U00010000']])
|
||||
def test_to_py_invalid(self, klass, strtype, val):
|
||||
with pytest.raises(configexc.ValidationError):
|
||||
klass(strtype).to_py(val)
|
||||
|
||||
@pytest.mark.parametrize('val', [None, ['foo', 'bar'], 'abcd'])
|
||||
def test_to_py_length(self, strtype, klass, val):
|
||||
klass(strtype, none_ok=True, length=2).to_py(val)
|
||||
|
||||
@pytest.mark.parametrize('val', [['a'], ['a', 'b'], ['a', 'b', 'c', 'd']])
|
||||
def test_wrong_length(self, strtype, klass, val):
|
||||
with pytest.raises(configexc.ValidationError,
|
||||
match='Exactly 3 values need to be set!'):
|
||||
klass(strtype, length=3).to_py(val)
|
||||
|
||||
def test_get_name(self, strtype, klass):
|
||||
assert klass(strtype).get_name() == 'List of String or String'
|
||||
|
||||
def test_get_valid_values(self, klass):
|
||||
valid_values = configtypes.ValidValues('foo', 'bar', 'baz')
|
||||
valtype = configtypes.String(valid_values=valid_values)
|
||||
assert klass(valtype).get_valid_values() == valid_values
|
||||
|
||||
def test_to_str(self, strtype, klass):
|
||||
assert klass(strtype).to_str(["a", True]) == '["a", true]'
|
||||
|
||||
@hypothesis.given(val=strategies.lists(strategies.just('foo')))
|
||||
def test_hypothesis(self, strtype, klass, val):
|
||||
typ = klass(strtype, none_ok=True)
|
||||
try:
|
||||
converted = typ.to_py(val)
|
||||
except configexc.ValidationError:
|
||||
pass
|
||||
else:
|
||||
expected = converted if converted else []
|
||||
assert typ.to_py(typ.from_str(typ.to_str(converted))) == expected
|
||||
|
||||
@hypothesis.given(val=strategies.lists(strategies.just('foo')))
|
||||
def test_hypothesis_text(self, strtype, klass, val):
|
||||
typ = klass(strtype)
|
||||
text = json.dumps(val)
|
||||
try:
|
||||
typ.to_str(typ.from_str(text))
|
||||
except configexc.ValidationError:
|
||||
pass
|
||||
|
||||
@pytest.mark.parametrize('val, expected', [
|
||||
# simple list
|
||||
(['foo', 'bar'], '\n\n- +pass:[foo]+\n- +pass:[bar]+'),
|
||||
# only one value
|
||||
(['foo'], '+pass:[foo]+'),
|
||||
# value without list
|
||||
('foo', '+pass:[foo]+'),
|
||||
# empty
|
||||
([], 'empty'),
|
||||
(None, 'empty'),
|
||||
])
|
||||
def test_to_doc(self, klass, strtype, val, expected):
|
||||
doc = klass(strtype).to_doc(val)
|
||||
print(doc)
|
||||
assert doc == expected
|
||||
|
||||
|
||||
class TestBool:
|
||||
|
||||
TESTS = {
|
||||
|
Loading…
Reference in New Issue
Block a user