Initial parsing
This commit is contained in:
parent
f965805099
commit
52f6ea2525
@ -73,10 +73,11 @@ class change_filter: # pylint: disable=invalid-name
|
||||
optname: The option to be filtered.
|
||||
function: Whether a function rather than a method is decorated.
|
||||
"""
|
||||
if sectname not in configdata.DATA:
|
||||
raise configexc.NoSectionError(sectname)
|
||||
if optname is not None and optname not in configdata.DATA[sectname]:
|
||||
raise configexc.NoOptionError(optname, sectname)
|
||||
# FIXME:conf
|
||||
# if sectname not in configdata.DATA:
|
||||
# raise configexc.NoSectionError(sectname)
|
||||
# if optname is not None and optname not in configdata.DATA[sectname]:
|
||||
# raise configexc.NoOptionError(optname, sectname)
|
||||
self._sectname = sectname
|
||||
self._optname = optname
|
||||
self._function = function
|
||||
@ -256,6 +257,7 @@ def init(parent=None):
|
||||
parent: The parent to pass to QObjects which get initialized.
|
||||
"""
|
||||
# _init_main_config(parent)
|
||||
configdata.init()
|
||||
_init_new_config(parent)
|
||||
_init_key_config(parent)
|
||||
_init_misc()
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,14 +8,14 @@ ignore_case:
|
||||
start_page:
|
||||
type:
|
||||
name: List
|
||||
elemtype: String
|
||||
valtype: String
|
||||
default: ["https://start.duckduckgo.com"]
|
||||
desc: The default page(s) to open at the start.
|
||||
|
||||
yank_ignored_url_parameters:
|
||||
type:
|
||||
name: List
|
||||
elemtype: String
|
||||
valtype: String
|
||||
default:
|
||||
- ref
|
||||
- utm_source
|
||||
@ -78,7 +78,7 @@ editor.command:
|
||||
editor.encoding:
|
||||
type: Encoding
|
||||
default: utf-8
|
||||
desc: Encoding to use for the editor.
|
||||
desc : Encoding to use for the editor.
|
||||
|
||||
content.private_browsing:
|
||||
type: Bool
|
||||
@ -198,7 +198,7 @@ history_session_interval:
|
||||
zoom.levels:
|
||||
type:
|
||||
name: List
|
||||
elemtype:
|
||||
valtype:
|
||||
name: Perc
|
||||
minval: 0
|
||||
default:
|
||||
@ -354,7 +354,7 @@ window.hide_wayland_decoration:
|
||||
keyhint.blacklist:
|
||||
type:
|
||||
name: List
|
||||
elemtype:
|
||||
valtype:
|
||||
name: String
|
||||
none_ok: true
|
||||
default: ""
|
||||
@ -417,11 +417,7 @@ content.user_agent:
|
||||
|
||||
content.proxy:
|
||||
default: system
|
||||
type:
|
||||
name: Proxy
|
||||
valid_values:
|
||||
- system: "Use the system wide proxy."
|
||||
- none: "Don't use any proxy"
|
||||
type: Proxy
|
||||
backend:
|
||||
QtWebKit: true
|
||||
QtWebEngine: Qt 5.8
|
||||
@ -1015,7 +1011,7 @@ content.host_blocking.lists:
|
||||
- "https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&mimetype=plaintext"
|
||||
type:
|
||||
name: List
|
||||
elemtype: Url
|
||||
valtype: Url
|
||||
none_ok: true
|
||||
desc: |
|
||||
List of URLs of lists which contain hosts to block.
|
||||
@ -1037,7 +1033,7 @@ content.host_blocking.whitelist:
|
||||
- piwik.org
|
||||
type:
|
||||
name: List
|
||||
valtype: string
|
||||
valtype: String
|
||||
none_ok: true
|
||||
desc: >-
|
||||
List of domains that should always be loaded, despite being ad-blocked.
|
||||
|
@ -35,7 +35,7 @@ from PyQt5.QtWidgets import QTabWidget, QTabBar
|
||||
|
||||
from qutebrowser.commands import cmdutils
|
||||
from qutebrowser.config import configexc
|
||||
from qutebrowser.utils import standarddir, utils
|
||||
from qutebrowser.utils import standarddir, utils, qtutils
|
||||
|
||||
|
||||
SYSTEM_PROXY = object() # Return value for Proxy type
|
||||
@ -313,27 +313,27 @@ class List(BaseType):
|
||||
|
||||
"""Base class for a (string-)list setting."""
|
||||
|
||||
_show_inner_type = True
|
||||
_show_valtype = True
|
||||
|
||||
def __init__(self, inner_type, none_ok=False, length=None):
|
||||
def __init__(self, valtype, none_ok=False, length=None):
|
||||
super().__init__(none_ok)
|
||||
self.inner_type = inner_type
|
||||
self.valtype = valtype
|
||||
self.length = length
|
||||
|
||||
def get_name(self):
|
||||
name = super().get_name()
|
||||
if self._show_inner_type:
|
||||
name += " of " + self.inner_type.get_name()
|
||||
if self._show_valtype:
|
||||
name += " of " + self.valtype.get_name()
|
||||
return name
|
||||
|
||||
def get_valid_values(self):
|
||||
return self.inner_type.get_valid_values()
|
||||
return self.valtype.get_valid_values()
|
||||
|
||||
def transform(self, value):
|
||||
if not value:
|
||||
return None
|
||||
else:
|
||||
return [self.inner_type.transform(v.strip())
|
||||
return [self.valtype.transform(v.strip())
|
||||
for v in value.split(',')]
|
||||
|
||||
def validate(self, value):
|
||||
@ -345,7 +345,7 @@ class List(BaseType):
|
||||
raise configexc.ValidationError(value, "Exactly {} values need to "
|
||||
"be set!".format(self.length))
|
||||
for val in vals:
|
||||
self.inner_type.validate(val.strip())
|
||||
self.valtype.validate(val.strip())
|
||||
|
||||
|
||||
class FlagList(List):
|
||||
@ -358,14 +358,14 @@ class FlagList(List):
|
||||
|
||||
combinable_values = None
|
||||
|
||||
_show_inner_type = False
|
||||
_show_valtype = False
|
||||
|
||||
def __init__(self, none_ok=False, valid_values=None):
|
||||
super().__init__(BaseType(), none_ok)
|
||||
self.inner_type.valid_values = valid_values
|
||||
self.valtype.valid_values = valid_values
|
||||
|
||||
def validate(self, value):
|
||||
if self.inner_type.valid_values is not None:
|
||||
if self.valtype.valid_values is not None:
|
||||
super().validate(value)
|
||||
else:
|
||||
self._basic_validation(value)
|
||||
@ -379,7 +379,7 @@ class FlagList(List):
|
||||
value, "List contains duplicate values!")
|
||||
|
||||
def complete(self):
|
||||
valid_values = self.inner_type.valid_values
|
||||
valid_values = self.valtype.valid_values
|
||||
if valid_values is None:
|
||||
return None
|
||||
|
||||
@ -453,11 +453,22 @@ class Int(BaseType):
|
||||
|
||||
def __init__(self, minval=None, maxval=None, none_ok=False):
|
||||
super().__init__(none_ok)
|
||||
if maxval is not None and minval is not None and maxval < minval:
|
||||
raise ValueError("minval ({}) needs to be <= maxval ({})!".format(
|
||||
minval, maxval))
|
||||
self.minval = minval
|
||||
self.maxval = maxval
|
||||
self.minval = self._parse_limit(minval)
|
||||
self.maxval = self._parse_limit(maxval)
|
||||
if self.maxval is not None and self.minval is not None:
|
||||
if self.maxval < self.minval:
|
||||
raise ValueError("minval ({}) needs to be <= maxval ({})!"
|
||||
.format(self.minval, self.maxval))
|
||||
|
||||
def _parse_limit(self, value):
|
||||
if value == 'maxint':
|
||||
return qtutils.MAXVALS['int']
|
||||
elif value == 'maxint64':
|
||||
return qtutils.MAXVALS['int64']
|
||||
else:
|
||||
if value is not None:
|
||||
assert isinstance(value, int), value
|
||||
return value
|
||||
|
||||
def transform(self, value):
|
||||
if not value:
|
||||
@ -1056,12 +1067,12 @@ class Padding(List):
|
||||
|
||||
"""Setting for paddings around elements."""
|
||||
|
||||
_show_inner_type = False
|
||||
_show_valtype = False
|
||||
|
||||
def __init__(self, none_ok=False, valid_values=None):
|
||||
super().__init__(Int(minval=0, none_ok=none_ok),
|
||||
none_ok=none_ok, length=4)
|
||||
self.inner_type.valid_values = valid_values
|
||||
self.valtype.valid_values = valid_values
|
||||
|
||||
def transform(self, value):
|
||||
elems = super().transform(value)
|
||||
@ -1179,10 +1190,17 @@ class Url(BaseType):
|
||||
"{}".format(val.errorString()))
|
||||
|
||||
|
||||
class HeaderDict(BaseType):
|
||||
class Dict(BaseType):
|
||||
|
||||
"""A JSON-like dictionary for custom HTTP headers."""
|
||||
|
||||
# FIXME:conf validate correctly
|
||||
|
||||
def __init__(self, keytype, valtype, none_ok=False):
|
||||
super().__init__(none_ok)
|
||||
self.keytype = keytype
|
||||
self.valtype = valtype
|
||||
|
||||
def _validate_str(self, value, what):
|
||||
"""Check if the given thing is an ascii-only string.
|
||||
|
||||
@ -1274,8 +1292,8 @@ class ConfirmQuit(FlagList):
|
||||
|
||||
def __init__(self, none_ok=False):
|
||||
super().__init__(none_ok)
|
||||
self.inner_type.none_ok = none_ok
|
||||
self.inner_type.valid_values = ValidValues(
|
||||
self.valtype.none_ok = none_ok
|
||||
self.valtype.valid_values = ValidValues(
|
||||
('always', "Always show a confirmation."),
|
||||
('multiple-tabs', "Show a confirmation if "
|
||||
"multiple tabs are opened."),
|
||||
|
@ -48,14 +48,16 @@ class NewConfigManager(QObject):
|
||||
super().__init__(parent)
|
||||
self._values = {}
|
||||
|
||||
def _key(self, sect, opt):
|
||||
return sect + ' -> ' + opt
|
||||
def _key(self, sect, opt=None):
|
||||
if opt is None:
|
||||
# New usage
|
||||
return sect
|
||||
return sect + '.' + opt
|
||||
|
||||
def read_defaults(self):
|
||||
for name, section in configdata.data().items():
|
||||
for key, value in section.items():
|
||||
self._values[self._key(name, key)] = value
|
||||
for name, option in configdata.DATA.items():
|
||||
self._values[name] = option
|
||||
|
||||
def get(self, section, option):
|
||||
val = self._values[self._key(section, option)]
|
||||
return val.typ.transform(val.value())
|
||||
return val.typ.transform(val.default)
|
||||
|
@ -23,16 +23,11 @@ import sys
|
||||
import os
|
||||
import os.path
|
||||
|
||||
import yaml
|
||||
import astroid
|
||||
from pylint import interfaces, checkers
|
||||
from pylint.checkers import utils
|
||||
|
||||
sys.path.insert(
|
||||
0, os.path.join(os.path.dirname(__file__), os.pardir, os.pardir,
|
||||
os.pardir))
|
||||
|
||||
from qutebrowser.config import configdata
|
||||
|
||||
|
||||
class ConfigChecker(checkers.BaseChecker):
|
||||
|
||||
|
@ -18,27 +18,198 @@
|
||||
|
||||
"""Tests for qutebrowser.config.configdata."""
|
||||
|
||||
import textwrap
|
||||
|
||||
import yaml
|
||||
import pytest
|
||||
|
||||
from qutebrowser.config import configdata
|
||||
from qutebrowser.config import configdata, configtypes
|
||||
from qutebrowser.utils import usertypes
|
||||
|
||||
|
||||
@pytest.mark.parametrize('sect', configdata.DATA.keys())
|
||||
def test_section_desc(sect):
|
||||
"""Make sure every section has a description."""
|
||||
desc = configdata.SECTION_DESC[sect]
|
||||
assert isinstance(desc, str)
|
||||
def test_init():
|
||||
"""Test reading the default yaml file."""
|
||||
configdata.init()
|
||||
assert isinstance(configdata.DATA, dict)
|
||||
assert 'ignore_case' in configdata.DATA
|
||||
|
||||
|
||||
def test_data():
|
||||
"""Some simple sanity tests on data()."""
|
||||
data = configdata.data()
|
||||
assert 'general' in data
|
||||
assert 'ignore-case' in data['general']
|
||||
class TestReadYaml:
|
||||
|
||||
|
||||
def test_readonly_data():
|
||||
"""Make sure DATA is readonly."""
|
||||
with pytest.raises(ValueError, match="Trying to modify a read-only "
|
||||
"config!"):
|
||||
configdata.DATA['general'].setv('temp', 'ignore-case', 'true', 'true')
|
||||
def test_valid(self):
|
||||
data = textwrap.dedent("""
|
||||
test1:
|
||||
type: Bool
|
||||
default: true
|
||||
desc: Hello World
|
||||
|
||||
test2:
|
||||
type: String
|
||||
default: foo
|
||||
backend: QtWebKit
|
||||
desc: Hello World 2
|
||||
""")
|
||||
data = configdata._read_yaml(data)
|
||||
assert data.keys() == {'test1', 'test2'}
|
||||
assert data['test1'].description == "Hello World"
|
||||
assert data['test2'].default == "foo"
|
||||
assert data['test2'].backends == [usertypes.Backend.QtWebKit]
|
||||
assert isinstance(data['test1'].typ, configtypes.Bool)
|
||||
|
||||
def test_invalid_keys(self):
|
||||
"""Test reading with unknown keys."""
|
||||
data = textwrap.dedent("""
|
||||
test:
|
||||
type: Bool
|
||||
default: true
|
||||
desc: Hello World
|
||||
hello: world
|
||||
""",)
|
||||
with pytest.raises(ValueError, match='Invalid keys'):
|
||||
configdata._read_yaml(data)
|
||||
|
||||
|
||||
class TestParseYamlType:
|
||||
|
||||
def _yaml(self, s):
|
||||
"""Get the type from parsed YAML data."""
|
||||
return yaml.load(textwrap.dedent(s))['type']
|
||||
|
||||
def test_simple(self):
|
||||
"""Test type which is only a name."""
|
||||
data = self._yaml("type: Bool")
|
||||
typ = configdata._parse_yaml_type('test', data)
|
||||
assert isinstance(typ, configtypes.Bool)
|
||||
assert not typ.none_ok
|
||||
|
||||
def test_complex(self):
|
||||
"""Test type parsing with arguments."""
|
||||
data = self._yaml("""
|
||||
type:
|
||||
name: String
|
||||
minlen: 2
|
||||
""")
|
||||
typ = configdata._parse_yaml_type('test', data)
|
||||
assert isinstance(typ, configtypes.String)
|
||||
assert not typ.none_ok
|
||||
assert typ.minlen == 2
|
||||
|
||||
def test_list(self):
|
||||
"""Test type parsing with a list and subtypes."""
|
||||
data = self._yaml("""
|
||||
type:
|
||||
name: List
|
||||
valtype: String
|
||||
""")
|
||||
typ = configdata._parse_yaml_type('test', data)
|
||||
assert isinstance(typ, configtypes.List)
|
||||
assert isinstance(typ.valtype, configtypes.String)
|
||||
assert not typ.none_ok
|
||||
assert not typ.valtype.none_ok
|
||||
|
||||
def test_dict(self):
|
||||
"""Test type parsing with a dict and subtypes."""
|
||||
data = self._yaml("""
|
||||
type:
|
||||
name: Dict
|
||||
keytype: String
|
||||
valtype:
|
||||
name: Int
|
||||
minval: 10
|
||||
""")
|
||||
typ = configdata._parse_yaml_type('test', data)
|
||||
assert isinstance(typ, configtypes.Dict)
|
||||
assert isinstance(typ.keytype, configtypes.String)
|
||||
assert isinstance(typ.valtype, configtypes.Int)
|
||||
assert not typ.none_ok
|
||||
assert typ.valtype.minval == 10
|
||||
|
||||
def test_invalid_node(self):
|
||||
"""Test type parsing with invalid node type."""
|
||||
data = self._yaml("type: 42")
|
||||
with pytest.raises(ValueError, match="Invalid node for test while "
|
||||
"reading type: 42"):
|
||||
configdata._parse_yaml_type('test', data)
|
||||
|
||||
def test_unknown_type(self):
|
||||
"""Test type parsing with type which doesn't exist."""
|
||||
data = self._yaml("type: Foobar")
|
||||
with pytest.raises(AttributeError,
|
||||
match="Did not find type Foobar for test"):
|
||||
configdata._parse_yaml_type('test', data)
|
||||
|
||||
def test_unknown_dict(self):
|
||||
"""Test type parsing with a dict without keytype."""
|
||||
data = self._yaml("type: Dict")
|
||||
with pytest.raises(ValueError, match="Invalid node for test while "
|
||||
"reading 'keytype': 'Dict'"):
|
||||
configdata._parse_yaml_type('test', data)
|
||||
|
||||
def test_unknown_args(self):
|
||||
"""Test type parsing with unknown type arguments."""
|
||||
data = self._yaml("""
|
||||
type:
|
||||
name: Int
|
||||
answer: 42
|
||||
""")
|
||||
with pytest.raises(TypeError, match="Error while creating Int"):
|
||||
configdata._parse_yaml_type('test', data)
|
||||
|
||||
|
||||
class TestParseYamlBackend:
|
||||
|
||||
def _yaml(self, s):
|
||||
"""Get the type from parsed YAML data."""
|
||||
return yaml.load(textwrap.dedent(s))['backend']
|
||||
|
||||
@pytest.mark.parametrize('backend, expected', [
|
||||
('QtWebKit', [usertypes.Backend.QtWebKit]),
|
||||
('QtWebEngine', [usertypes.Backend.QtWebEngine]),
|
||||
# This is also what _parse_yaml_backends gets when backend: is not given
|
||||
# at all
|
||||
('null', [usertypes.Backend.QtWebKit, usertypes.Backend.QtWebEngine]),
|
||||
])
|
||||
def test_simple(self, backend, expected):
|
||||
"""Check a simple "backend: QtWebKit"."""
|
||||
data = self._yaml("backend: {}".format(backend))
|
||||
backends = configdata._parse_yaml_backends('test', data)
|
||||
assert backends == expected
|
||||
|
||||
@pytest.mark.parametrize('webkit, has_new_version, expected', [
|
||||
(True, True, [usertypes.Backend.QtWebKit,
|
||||
usertypes.Backend.QtWebEngine]),
|
||||
(False, True, [usertypes.Backend.QtWebEngine]),
|
||||
(True, False, [usertypes.Backend.QtWebKit]),
|
||||
])
|
||||
def test_dict(self, monkeypatch, webkit, has_new_version, expected):
|
||||
data = self._yaml("""
|
||||
backend:
|
||||
QtWebKit: {}
|
||||
QtWebEngine: Qt 5.8
|
||||
""".format('true' if webkit else 'false'))
|
||||
monkeypatch.setattr(configdata.qtutils, 'version_check',
|
||||
lambda v: has_new_version)
|
||||
backends = configdata._parse_yaml_backends('test', data)
|
||||
assert backends == expected
|
||||
|
||||
@pytest.mark.parametrize('yaml_data', [
|
||||
# Wrong type
|
||||
"backend: 42",
|
||||
# Unknown key
|
||||
"""
|
||||
backend:
|
||||
QtWebKit: true
|
||||
QtWebEngine: true
|
||||
foo: bar
|
||||
""",
|
||||
# Missing key
|
||||
"""
|
||||
backend:
|
||||
QtWebKit: true
|
||||
""",
|
||||
])
|
||||
def test_invalid_backend(self, yaml_data):
|
||||
with pytest.raises(ValueError, match="Invalid node for test while "
|
||||
"reading backends:"):
|
||||
configdata._parse_yaml_backends('test', self._yaml(yaml_data))
|
||||
|
Loading…
Reference in New Issue
Block a user