Allow fallback=False with config.get/get_obj

This commit is contained in:
Florian Bruhin 2018-09-28 13:33:42 +02:00
parent 5527d27ba7
commit f780974d07
4 changed files with 114 additions and 34 deletions

View File

@ -312,10 +312,14 @@ class Config(QObject):
name, deleted=deleted, renamed=renamed) name, deleted=deleted, renamed=renamed)
raise exception from None raise exception from None
def get(self, name, url=None): def get(self, name, url=None, *, fallback=True):
"""Get the given setting converted for Python code.""" """Get the given setting converted for Python code.
Args:
fallback: Use the global value if there's no URL-specific one.
"""
opt = self.get_opt(name) opt = self.get_opt(name)
obj = self.get_obj(name, url=url) obj = self.get_obj(name, url=url, fallback=fallback)
return opt.typ.to_py(obj) return opt.typ.to_py(obj)
def _maybe_copy(self, value): def _maybe_copy(self, value):
@ -329,14 +333,14 @@ class Config(QObject):
assert value.__hash__ is not None, value assert value.__hash__ is not None, value
return value return value
def get_obj(self, name, *, url=None): def get_obj(self, name, *, url=None, fallback=True):
"""Get the given setting as object (for YAML/config.py). """Get the given setting as object (for YAML/config.py).
Note that the returned values are not watched for mutation. Note that the returned values are not watched for mutation.
If a URL is given, return the value which should be used for that URL. If a URL is given, return the value which should be used for that URL.
""" """
self.get_opt(name) # To make sure it exists self.get_opt(name) # To make sure it exists
value = self._values[name].get_for_url(url) value = self._values[name].get_for_url(url, fallback=fallback)
return self._maybe_copy(value) return self._maybe_copy(value)
def get_obj_for_pattern(self, name, *, pattern): def get_obj_for_pattern(self, name, *, pattern):

View File

@ -60,7 +60,7 @@ from PyQt5.QtGui import QColor, QFont
from PyQt5.QtWidgets import QTabWidget, QTabBar from PyQt5.QtWidgets import QTabWidget, QTabBar
from qutebrowser.commands import cmdutils from qutebrowser.commands import cmdutils
from qutebrowser.config import configexc from qutebrowser.config import configexc, configutils
from qutebrowser.utils import standarddir, utils, qtutils, urlutils, urlmatch from qutebrowser.utils import standarddir, utils, qtutils, urlutils, urlmatch
from qutebrowser.keyinput import keyutils from qutebrowser.keyinput import keyutils
@ -149,6 +149,9 @@ class BaseType:
value: The value to check. value: The value to check.
pytype: A Python type to check the value against. pytype: A Python type to check the value against.
""" """
if value is configutils.UNSET:
return
if (value is None or (pytype == list and value == []) or if (value is None or (pytype == list and value == []) or
(pytype == dict and value == {})): (pytype == dict and value == {})):
if not self.none_ok: if not self.none_ok:
@ -309,7 +312,9 @@ class MappingType(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
self._validate_valid_values(value.lower()) self._validate_valid_values(value.lower())
return self.MAPPING[value.lower()] return self.MAPPING[value.lower()]
@ -367,7 +372,9 @@ class String(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
self._validate_encoding(value) self._validate_encoding(value)
@ -399,7 +406,9 @@ class UniqueCharString(String):
def to_py(self, value): def to_py(self, value):
value = super().to_py(value) value = super().to_py(value)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
# Check for duplicate values # Check for duplicate values
@ -455,7 +464,9 @@ class List(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, list) self._basic_py_validation(value, list)
if not value: if value is configutils.UNSET:
return value
elif not value:
return [] return []
for val in value: for val in value:
@ -534,6 +545,9 @@ class ListOrValue(BaseType):
return value return value
def to_py(self, value): def to_py(self, value):
if value is configutils.UNSET:
return value
try: try:
return [self.valtype.to_py(value)] return [self.valtype.to_py(value)]
except configexc.ValidationError: except configexc.ValidationError:
@ -577,7 +591,8 @@ class FlagList(List):
def to_py(self, value): def to_py(self, value):
vals = super().to_py(value) vals = super().to_py(value)
self._check_duplicates(vals) if vals is not configutils.UNSET:
self._check_duplicates(vals)
return vals return vals
def complete(self): def complete(self):
@ -764,7 +779,9 @@ class Perc(_Numeric):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, (float, int, str)) self._basic_py_validation(value, (float, int, str))
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
if isinstance(value, str): if isinstance(value, str):
@ -907,7 +924,9 @@ class QtColor(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
color = QColor(value) color = QColor(value)
@ -936,7 +955,9 @@ class QssColor(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
functions = ['rgb', 'rgba', 'hsv', 'hsva', 'qlineargradient', functions = ['rgb', 'rgba', 'hsv', 'hsva', 'qlineargradient',
@ -981,7 +1002,9 @@ class Font(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
if not self.font_regex.fullmatch(value): # pragma: no cover if not self.font_regex.fullmatch(value): # pragma: no cover
@ -1000,7 +1023,9 @@ class FontFamily(Font):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
match = self.font_regex.fullmatch(value) match = self.font_regex.fullmatch(value)
@ -1024,7 +1049,9 @@ class QtFont(Font):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
style_map = { style_map = {
@ -1136,7 +1163,9 @@ class Regex(BaseType):
def to_py(self, value): def to_py(self, value):
"""Get a compiled regex from either a string or a regex object.""" """Get a compiled regex from either a string or a regex object."""
self._basic_py_validation(value, (str, self._regex_type)) self._basic_py_validation(value, (str, self._regex_type))
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
elif isinstance(value, str): elif isinstance(value, str):
return self._compile_regex(value) return self._compile_regex(value)
@ -1214,7 +1243,9 @@ class Dict(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, dict) self._basic_py_validation(value, dict)
if not value: if value is configutils.UNSET:
return value
elif not value:
return self._fill_fixed_keys({}) return self._fill_fixed_keys({})
self._validate_keys(value) self._validate_keys(value)
@ -1256,7 +1287,9 @@ class File(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
value = os.path.expanduser(value) value = os.path.expanduser(value)
@ -1282,7 +1315,9 @@ class Directory(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
value = os.path.expandvars(value) value = os.path.expandvars(value)
value = os.path.expanduser(value) value = os.path.expanduser(value)
@ -1309,7 +1344,9 @@ class FormatString(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
try: try:
@ -1341,7 +1378,9 @@ class ShellCommand(List):
def to_py(self, value): def to_py(self, value):
value = super().to_py(value) value = super().to_py(value)
if not value: if value is configutils.UNSET:
return value
elif not value:
return value return value
if (self.placeholder and if (self.placeholder and
@ -1365,7 +1404,9 @@ class Proxy(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
try: try:
@ -1401,7 +1442,9 @@ class SearchEngineUrl(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
if not ('{}' in value or '{0}' in value): if not ('{}' in value or '{0}' in value):
@ -1429,7 +1472,9 @@ class FuzzyUrl(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
try: try:
@ -1463,6 +1508,9 @@ class Padding(Dict):
def to_py(self, value): def to_py(self, value):
d = super().to_py(value) d = super().to_py(value)
if d is configutils.UNSET:
return d
return PaddingValues(**d) return PaddingValues(**d)
@ -1472,7 +1520,9 @@ class Encoding(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
try: try:
codecs.lookup(value) codecs.lookup(value)
@ -1529,7 +1579,9 @@ class Url(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
qurl = QUrl.fromUserInput(value) qurl = QUrl.fromUserInput(value)
@ -1545,7 +1597,9 @@ class SessionName(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
if value.startswith('_'): if value.startswith('_'):
raise configexc.ValidationError(value, "may not start with '_'!") raise configexc.ValidationError(value, "may not start with '_'!")
@ -1593,7 +1647,7 @@ class ConfirmQuit(FlagList):
def to_py(self, value): def to_py(self, value):
values = super().to_py(value) values = super().to_py(value)
if not values: if not values or values is configutils.UNSET:
return values return values
# Never can't be set with other options # Never can't be set with other options
@ -1630,7 +1684,9 @@ class TimestampTemplate(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
try: try:
@ -1654,7 +1710,9 @@ class Key(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
try: try:
@ -1673,7 +1731,9 @@ class UrlPattern(BaseType):
def to_py(self, value): def to_py(self, value):
self._basic_py_validation(value, str) self._basic_py_validation(value, str)
if not value: if value is configutils.UNSET:
return value
elif not value:
return None return None
try: try:

View File

@ -480,6 +480,17 @@ class TestConfig:
conf.set_obj(name, False, pattern=pattern) conf.set_obj(name, False, pattern=pattern)
assert conf.get(name, url=QUrl('https://example.com/')) is False assert conf.get(name, url=QUrl('https://example.com/')) is False
@pytest.mark.parametrize('fallback, expected', [
(True, True),
(False, configutils.UNSET)
])
def test_get_for_url_fallback(self, conf, fallback, expected):
"""Test conf.get() with an URL and fallback."""
value = conf.get('content.javascript.enabled',
url=QUrl('https://example.com/'),
fallback=fallback)
assert value is expected
@pytest.mark.parametrize('value', [{}, {'normal': {'a': 'nop'}}]) @pytest.mark.parametrize('value', [{}, {'normal': {'a': 'nop'}}])
def test_get_bindings(self, config_stub, conf, value): def test_get_bindings(self, config_stub, conf, value):
"""Test conf.get() with bindings which have missing keys.""" """Test conf.get() with bindings which have missing keys."""

View File

@ -34,7 +34,7 @@ from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QColor, QFont from PyQt5.QtGui import QColor, QFont
from PyQt5.QtNetwork import QNetworkProxy from PyQt5.QtNetwork import QNetworkProxy
from qutebrowser.config import configtypes, configexc from qutebrowser.config import configtypes, configexc, configutils
from qutebrowser.utils import debug, utils, qtutils, urlmatch from qutebrowser.utils import debug, utils, qtutils, urlmatch
from qutebrowser.browser.network import pac from qutebrowser.browser.network import pac
from qutebrowser.keyinput import keyutils from qutebrowser.keyinput import keyutils
@ -274,6 +274,11 @@ class TestAll:
with pytest.raises(configexc.ValidationError): with pytest.raises(configexc.ValidationError):
meth(value) meth(value)
@pytest.mark.parametrize('none_ok', [True, False])
def test_unset(self, klass, none_ok):
typ = klass(none_ok=none_ok)
assert typ.to_py(configutils.UNSET) is configutils.UNSET
def test_to_str_none(self, klass): def test_to_str_none(self, klass):
assert klass().to_str(None) == '' assert klass().to_str(None) == ''