Revert "Add types for most of qutebrowser.config"
It breaks 'tsh' because of the *values annotation.
This reverts commit 208d3db475
.
This commit is contained in:
parent
208d3db475
commit
7494d238ce
36
mypy.ini
36
mypy.ini
@ -61,39 +61,3 @@ disallow_incomplete_defs = True
|
||||
[mypy-qutebrowser.commands.cmdutils]
|
||||
disallow_untyped_defs = True
|
||||
disallow_incomplete_defs = True
|
||||
|
||||
[mypy-qutebrowser.config.config]
|
||||
disallow_untyped_defs = True
|
||||
disallow_incomplete_defs = True
|
||||
|
||||
[mypy-qutebrowser.config.configcache]
|
||||
disallow_untyped_defs = True
|
||||
disallow_incomplete_defs = True
|
||||
|
||||
[mypy-qutebrowser.config.configcommands]
|
||||
disallow_untyped_defs = True
|
||||
disallow_incomplete_defs = True
|
||||
|
||||
[mypy-qutebrowser.config.configdata]
|
||||
disallow_untyped_defs = True
|
||||
disallow_incomplete_defs = True
|
||||
|
||||
[mypy-qutebrowser.config.configdiff]
|
||||
disallow_untyped_defs = True
|
||||
disallow_incomplete_defs = True
|
||||
|
||||
[mypy-qutebrowser.config.configexc]
|
||||
disallow_untyped_defs = True
|
||||
disallow_incomplete_defs = True
|
||||
|
||||
[mypy-qutebrowser.config.configfiles]
|
||||
disallow_untyped_defs = True
|
||||
disallow_incomplete_defs = True
|
||||
|
||||
[mypy-qutebrowser.config.configinit]
|
||||
disallow_untyped_defs = True
|
||||
disallow_incomplete_defs = True
|
||||
|
||||
[mypy-qutebrowser.config.configutils]
|
||||
disallow_untyped_defs = True
|
||||
disallow_incomplete_defs = True
|
||||
|
@ -23,21 +23,18 @@ import copy
|
||||
import contextlib
|
||||
import functools
|
||||
import typing
|
||||
from typing import Any
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QUrl
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject
|
||||
|
||||
from qutebrowser.config import configdata, configexc, configutils
|
||||
from qutebrowser.utils import utils, log, jinja, urlmatch
|
||||
from qutebrowser.utils import utils, log, jinja
|
||||
from qutebrowser.misc import objects
|
||||
from qutebrowser.keyinput import keyutils
|
||||
|
||||
MYPY = False
|
||||
if MYPY: # pragma: no cover
|
||||
# pylint: disable=unused-import,useless-suppression
|
||||
from typing import Tuple, MutableMapping
|
||||
from qutebrowser.config import configcache, configfiles
|
||||
from qutebrowser.misc import savemanager
|
||||
if MYPY:
|
||||
# pylint: disable=unused-import
|
||||
from qutebrowser.config import configcache # pragma: no cover
|
||||
|
||||
# An easy way to access the config from other code via config.val.foo
|
||||
val = typing.cast('ConfigContainer', None)
|
||||
@ -64,7 +61,7 @@ class change_filter: # noqa: N801,N806 pylint: disable=invalid-name
|
||||
_function: Whether a function rather than a method is decorated.
|
||||
"""
|
||||
|
||||
def __init__(self, option: str, function: bool = False) -> None:
|
||||
def __init__(self, option, function=False):
|
||||
"""Save decorator arguments.
|
||||
|
||||
Gets called on parse-time with the decorator arguments.
|
||||
@ -77,7 +74,7 @@ class change_filter: # noqa: N801,N806 pylint: disable=invalid-name
|
||||
self._function = function
|
||||
change_filters.append(self)
|
||||
|
||||
def validate(self) -> None:
|
||||
def validate(self):
|
||||
"""Make sure the configured option or prefix exists.
|
||||
|
||||
We can't do this in __init__ as configdata isn't ready yet.
|
||||
@ -86,7 +83,7 @@ class change_filter: # noqa: N801,N806 pylint: disable=invalid-name
|
||||
not configdata.is_valid_prefix(self._option)):
|
||||
raise configexc.NoOptionError(self._option)
|
||||
|
||||
def _check_match(self, option: typing.Optional[str]) -> bool:
|
||||
def _check_match(self, option):
|
||||
"""Check if the given option matches the filter."""
|
||||
if option is None:
|
||||
# Called directly, not from a config change event.
|
||||
@ -99,7 +96,7 @@ class change_filter: # noqa: N801,N806 pylint: disable=invalid-name
|
||||
else:
|
||||
return False
|
||||
|
||||
def __call__(self, func: typing.Callable) -> typing.Callable:
|
||||
def __call__(self, func):
|
||||
"""Filter calls to the decorated function.
|
||||
|
||||
Gets called when a function should be decorated.
|
||||
@ -117,21 +114,20 @@ class change_filter: # noqa: N801,N806 pylint: disable=invalid-name
|
||||
"""
|
||||
if self._function:
|
||||
@functools.wraps(func)
|
||||
def func_wrapper(option: str = None) -> typing.Any:
|
||||
def wrapper(option=None):
|
||||
"""Call the underlying function."""
|
||||
if self._check_match(option):
|
||||
return func()
|
||||
return None
|
||||
return func_wrapper
|
||||
else:
|
||||
@functools.wraps(func)
|
||||
def meth_wrapper(wrapper_self: typing.Any,
|
||||
option: str = None) -> typing.Any:
|
||||
def wrapper(wrapper_self, option=None):
|
||||
"""Call the underlying function."""
|
||||
if self._check_match(option):
|
||||
return func(wrapper_self)
|
||||
return None
|
||||
return meth_wrapper
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class KeyConfig:
|
||||
@ -144,22 +140,17 @@ class KeyConfig:
|
||||
_config: The Config object to be used.
|
||||
"""
|
||||
|
||||
_ReverseBindings = typing.Dict[str, typing.MutableSequence[str]]
|
||||
|
||||
def __init__(self, config: 'Config') -> None:
|
||||
def __init__(self, config):
|
||||
self._config = config
|
||||
|
||||
def _validate(self, key: keyutils.KeySequence, mode: str) -> None:
|
||||
def _validate(self, key, mode):
|
||||
"""Validate the given key and mode."""
|
||||
# Catch old usage of this code
|
||||
assert isinstance(key, keyutils.KeySequence), key
|
||||
if mode not in configdata.DATA['bindings.default'].default:
|
||||
raise configexc.KeybindingError("Invalid mode {}!".format(mode))
|
||||
|
||||
def get_bindings_for(
|
||||
self,
|
||||
mode: str
|
||||
) -> typing.Dict[keyutils.KeySequence, str]:
|
||||
def get_bindings_for(self, mode):
|
||||
"""Get the combined bindings for the given mode."""
|
||||
bindings = dict(val.bindings.default[mode])
|
||||
for key, binding in val.bindings.commands[mode].items():
|
||||
@ -169,9 +160,9 @@ class KeyConfig:
|
||||
bindings[key] = binding
|
||||
return bindings
|
||||
|
||||
def get_reverse_bindings_for(self, mode: str) -> '_ReverseBindings':
|
||||
def get_reverse_bindings_for(self, mode):
|
||||
"""Get a dict of commands to a list of bindings for the mode."""
|
||||
cmd_to_keys = {} # type: KeyConfig._ReverseBindings
|
||||
cmd_to_keys = {}
|
||||
bindings = self.get_bindings_for(mode)
|
||||
for seq, full_cmd in sorted(bindings.items()):
|
||||
for cmd in full_cmd.split(';;'):
|
||||
@ -184,10 +175,7 @@ class KeyConfig:
|
||||
cmd_to_keys[cmd].insert(0, str(seq))
|
||||
return cmd_to_keys
|
||||
|
||||
def get_command(self,
|
||||
key: keyutils.KeySequence,
|
||||
mode: str,
|
||||
default: bool = False) -> str:
|
||||
def get_command(self, key, mode, default=False):
|
||||
"""Get the command for a given key (or None)."""
|
||||
self._validate(key, mode)
|
||||
if default:
|
||||
@ -196,11 +184,7 @@ class KeyConfig:
|
||||
bindings = self.get_bindings_for(mode)
|
||||
return bindings.get(key, None)
|
||||
|
||||
def bind(self,
|
||||
key: keyutils.KeySequence,
|
||||
command: str, *,
|
||||
mode: str,
|
||||
save_yaml: bool = False) -> None:
|
||||
def bind(self, key, command, *, mode, save_yaml=False):
|
||||
"""Add a new binding from key to command."""
|
||||
if command is not None and not command.strip():
|
||||
raise configexc.KeybindingError(
|
||||
@ -208,8 +192,8 @@ class KeyConfig:
|
||||
'mode'.format(key, mode))
|
||||
|
||||
self._validate(key, mode)
|
||||
log.keyboard.vdebug( # type: ignore
|
||||
"Adding binding {} -> {} in mode {}.".format(key, command, mode))
|
||||
log.keyboard.vdebug("Adding binding {} -> {} in mode {}.".format(
|
||||
key, command, mode))
|
||||
|
||||
bindings = self._config.get_mutable_obj('bindings.commands')
|
||||
if mode not in bindings:
|
||||
@ -217,10 +201,7 @@ class KeyConfig:
|
||||
bindings[mode][str(key)] = command
|
||||
self._config.update_mutables(save_yaml=save_yaml)
|
||||
|
||||
def bind_default(self,
|
||||
key: keyutils.KeySequence, *,
|
||||
mode: str = 'normal',
|
||||
save_yaml: bool = False) -> None:
|
||||
def bind_default(self, key, *, mode='normal', save_yaml=False):
|
||||
"""Restore a default keybinding."""
|
||||
self._validate(key, mode)
|
||||
|
||||
@ -232,10 +213,7 @@ class KeyConfig:
|
||||
"Can't find binding '{}' in {} mode".format(key, mode))
|
||||
self._config.update_mutables(save_yaml=save_yaml)
|
||||
|
||||
def unbind(self,
|
||||
key: keyutils.KeySequence, *,
|
||||
mode: str = 'normal',
|
||||
save_yaml: bool = False) -> None:
|
||||
def unbind(self, key, *, mode='normal', save_yaml=False):
|
||||
"""Unbind the given key in the given mode."""
|
||||
self._validate(key, mode)
|
||||
|
||||
@ -276,27 +254,24 @@ class Config(QObject):
|
||||
MUTABLE_TYPES = (dict, list)
|
||||
changed = pyqtSignal(str)
|
||||
|
||||
def __init__(self,
|
||||
yaml_config: 'configfiles.YamlConfig',
|
||||
parent: QObject = None) -> None:
|
||||
def __init__(self, yaml_config, parent=None):
|
||||
super().__init__(parent)
|
||||
self.changed.connect(_render_stylesheet.cache_clear)
|
||||
self._mutables = {} # type: MutableMapping[str, Tuple[Any, Any]]
|
||||
self._mutables = {}
|
||||
self._yaml = yaml_config
|
||||
self._init_values()
|
||||
|
||||
def _init_values(self) -> None:
|
||||
def _init_values(self):
|
||||
"""Populate the self._values dict."""
|
||||
self._values = {} # type: typing.Mapping
|
||||
self._values = {}
|
||||
for name, opt in configdata.DATA.items():
|
||||
self._values[name] = configutils.Values(opt)
|
||||
|
||||
def __iter__(self) -> typing.Iterator[configutils.Values]:
|
||||
def __iter__(self):
|
||||
"""Iterate over configutils.Values items."""
|
||||
yield from self._values.values()
|
||||
|
||||
def init_save_manager(self,
|
||||
save_manager: 'savemanager.SaveManager') -> None:
|
||||
def init_save_manager(self, save_manager):
|
||||
"""Make sure the config gets saved properly.
|
||||
|
||||
We do this outside of __init__ because the config gets created before
|
||||
@ -304,10 +279,7 @@ class Config(QObject):
|
||||
"""
|
||||
self._yaml.init_save_manager(save_manager)
|
||||
|
||||
def _set_value(self,
|
||||
opt: 'configdata.Option',
|
||||
value: Any,
|
||||
pattern: urlmatch.UrlPattern = None) -> None:
|
||||
def _set_value(self, opt, value, pattern=None):
|
||||
"""Set the given option to the given value."""
|
||||
if not isinstance(objects.backend, objects.NoBackend):
|
||||
if objects.backend not in opt.backends:
|
||||
@ -322,12 +294,12 @@ class Config(QObject):
|
||||
log.config.debug("Config option changed: {} = {}".format(
|
||||
opt.name, value))
|
||||
|
||||
def _check_yaml(self, opt: 'configdata.Option', save_yaml: bool) -> None:
|
||||
def _check_yaml(self, opt, save_yaml):
|
||||
"""Make sure the given option may be set in autoconfig.yml."""
|
||||
if save_yaml and opt.no_autoconfig:
|
||||
raise configexc.NoAutoconfigError(opt.name)
|
||||
|
||||
def read_yaml(self) -> None:
|
||||
def read_yaml(self):
|
||||
"""Read the YAML settings from self._yaml."""
|
||||
self._yaml.load()
|
||||
for values in self._yaml:
|
||||
@ -335,7 +307,7 @@ class Config(QObject):
|
||||
self._set_value(values.opt, scoped.value,
|
||||
pattern=scoped.pattern)
|
||||
|
||||
def get_opt(self, name: str) -> 'configdata.Option':
|
||||
def get_opt(self, name):
|
||||
"""Get a configdata.Option object for the given setting."""
|
||||
try:
|
||||
return configdata.DATA[name]
|
||||
@ -346,10 +318,7 @@ class Config(QObject):
|
||||
name, deleted=deleted, renamed=renamed)
|
||||
raise exception from None
|
||||
|
||||
def get(self,
|
||||
name: str,
|
||||
url: QUrl = None, *,
|
||||
fallback: bool = True) -> Any:
|
||||
def get(self, name, url=None, *, fallback=True):
|
||||
"""Get the given setting converted for Python code.
|
||||
|
||||
Args:
|
||||
@ -359,7 +328,7 @@ class Config(QObject):
|
||||
obj = self.get_obj(name, url=url, fallback=fallback)
|
||||
return opt.typ.to_py(obj)
|
||||
|
||||
def _maybe_copy(self, value: Any) -> Any:
|
||||
def _maybe_copy(self, value):
|
||||
"""Copy the value if it could potentially be mutated."""
|
||||
if isinstance(value, self.MUTABLE_TYPES):
|
||||
# For mutable objects, create a copy so we don't accidentally
|
||||
@ -370,10 +339,7 @@ class Config(QObject):
|
||||
assert value.__hash__ is not None, value
|
||||
return value
|
||||
|
||||
def get_obj(self,
|
||||
name: str, *,
|
||||
url: QUrl = None,
|
||||
fallback: bool = True) -> Any:
|
||||
def get_obj(self, name, *, url=None, fallback=True):
|
||||
"""Get the given setting as object (for YAML/config.py).
|
||||
|
||||
Note that the returned values are not watched for mutation.
|
||||
@ -383,10 +349,7 @@ class Config(QObject):
|
||||
value = self._values[name].get_for_url(url, fallback=fallback)
|
||||
return self._maybe_copy(value)
|
||||
|
||||
def get_obj_for_pattern(
|
||||
self, name: str, *,
|
||||
pattern: typing.Optional[urlmatch.UrlPattern]
|
||||
) -> Any:
|
||||
def get_obj_for_pattern(self, name, *, pattern):
|
||||
"""Get the given setting as object (for YAML/config.py).
|
||||
|
||||
This gets the overridden value for a given pattern, or
|
||||
@ -396,8 +359,7 @@ class Config(QObject):
|
||||
value = self._values[name].get_for_pattern(pattern, fallback=False)
|
||||
return self._maybe_copy(value)
|
||||
|
||||
def get_mutable_obj(self, name: str, *,
|
||||
pattern: urlmatch.UrlPattern = None) -> Any:
|
||||
def get_mutable_obj(self, name, *, pattern=None):
|
||||
"""Get an object which can be mutated, e.g. in a config.py.
|
||||
|
||||
If a pattern is given, return the value for that pattern.
|
||||
@ -422,8 +384,7 @@ class Config(QObject):
|
||||
|
||||
return copy_value
|
||||
|
||||
def get_str(self, name: str, *,
|
||||
pattern: urlmatch.UrlPattern = None) -> str:
|
||||
def get_str(self, name, *, pattern=None):
|
||||
"""Get the given setting as string.
|
||||
|
||||
If a pattern is given, get the setting for the given pattern or
|
||||
@ -434,10 +395,7 @@ class Config(QObject):
|
||||
value = values.get_for_pattern(pattern)
|
||||
return opt.typ.to_str(value)
|
||||
|
||||
def set_obj(self, name: str,
|
||||
value: Any, *,
|
||||
pattern: urlmatch.UrlPattern = None,
|
||||
save_yaml: bool = False) -> None:
|
||||
def set_obj(self, name, value, *, pattern=None, save_yaml=False):
|
||||
"""Set the given setting from a YAML/config.py object.
|
||||
|
||||
If save_yaml=True is given, store the new value to YAML.
|
||||
@ -448,10 +406,7 @@ class Config(QObject):
|
||||
if save_yaml:
|
||||
self._yaml.set_obj(name, value, pattern=pattern)
|
||||
|
||||
def set_str(self, name: str,
|
||||
value: str, *,
|
||||
pattern: urlmatch.UrlPattern = None,
|
||||
save_yaml: bool = False) -> None:
|
||||
def set_str(self, name, value, *, pattern=None, save_yaml=False):
|
||||
"""Set the given setting from a string.
|
||||
|
||||
If save_yaml=True is given, store the new value to YAML.
|
||||
@ -466,9 +421,7 @@ class Config(QObject):
|
||||
if save_yaml:
|
||||
self._yaml.set_obj(name, converted, pattern=pattern)
|
||||
|
||||
def unset(self, name: str, *,
|
||||
save_yaml: bool = False,
|
||||
pattern: urlmatch.UrlPattern = None) -> None:
|
||||
def unset(self, name, *, save_yaml=False, pattern=None):
|
||||
"""Set the given setting back to its default."""
|
||||
opt = self.get_opt(name)
|
||||
self._check_yaml(opt, save_yaml)
|
||||
@ -479,7 +432,7 @@ class Config(QObject):
|
||||
if save_yaml:
|
||||
self._yaml.unset(name, pattern=pattern)
|
||||
|
||||
def clear(self, *, save_yaml: bool = False) -> None:
|
||||
def clear(self, *, save_yaml=False):
|
||||
"""Clear all settings in the config.
|
||||
|
||||
If save_yaml=True is given, also remove all customization from the YAML
|
||||
@ -493,7 +446,7 @@ class Config(QObject):
|
||||
if save_yaml:
|
||||
self._yaml.clear()
|
||||
|
||||
def update_mutables(self, *, save_yaml: bool = False) -> None:
|
||||
def update_mutables(self, *, save_yaml=False):
|
||||
"""Update mutable settings if they changed.
|
||||
|
||||
Every time someone calls get_obj() on a mutable object, we save a
|
||||
@ -508,7 +461,7 @@ class Config(QObject):
|
||||
self.set_obj(name, new_value, save_yaml=save_yaml)
|
||||
self._mutables = {}
|
||||
|
||||
def dump_userconfig(self) -> str:
|
||||
def dump_userconfig(self):
|
||||
"""Get the part of the config which was changed by the user.
|
||||
|
||||
Return:
|
||||
@ -537,10 +490,7 @@ class ConfigContainer:
|
||||
_pattern: The URL pattern to be used.
|
||||
"""
|
||||
|
||||
def __init__(self, config: Config,
|
||||
configapi: 'configfiles.ConfigAPI' = None,
|
||||
prefix: str = '',
|
||||
pattern: urlmatch.UrlPattern = None) -> None:
|
||||
def __init__(self, config, configapi=None, prefix='', pattern=None):
|
||||
self._config = config
|
||||
self._prefix = prefix
|
||||
self._configapi = configapi
|
||||
@ -548,13 +498,13 @@ class ConfigContainer:
|
||||
if configapi is None and pattern is not None:
|
||||
raise TypeError("Can't use pattern without configapi!")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
def __repr__(self):
|
||||
return utils.get_repr(self, constructor=True, config=self._config,
|
||||
configapi=self._configapi, prefix=self._prefix,
|
||||
pattern=self._pattern)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _handle_error(self, action: str, name: str) -> typing.Iterator[None]:
|
||||
def _handle_error(self, action, name):
|
||||
try:
|
||||
yield
|
||||
except configexc.Error as e:
|
||||
@ -563,7 +513,7 @@ class ConfigContainer:
|
||||
text = "While {} '{}'".format(action, name)
|
||||
self._configapi.errors.append(configexc.ConfigErrorDesc(text, e))
|
||||
|
||||
def __getattr__(self, attr: str) -> Any:
|
||||
def __getattr__(self, attr):
|
||||
"""Get an option or a new ConfigContainer with the added prefix.
|
||||
|
||||
If we get an option which exists, we return the value for it.
|
||||
@ -590,7 +540,7 @@ class ConfigContainer:
|
||||
return self._config.get_mutable_obj(
|
||||
name, pattern=self._pattern)
|
||||
|
||||
def __setattr__(self, attr: str, value: Any) -> None:
|
||||
def __setattr__(self, attr, value):
|
||||
"""Set the given option in the config."""
|
||||
if attr.startswith('_'):
|
||||
super().__setattr__(attr, value)
|
||||
@ -600,7 +550,7 @@ class ConfigContainer:
|
||||
with self._handle_error('setting', name):
|
||||
self._config.set_obj(name, value, pattern=self._pattern)
|
||||
|
||||
def _join(self, attr: str) -> str:
|
||||
def _join(self, attr):
|
||||
"""Get the prefix joined with the given attribute."""
|
||||
if self._prefix:
|
||||
return '{}.{}'.format(self._prefix, attr)
|
||||
@ -608,10 +558,8 @@ class ConfigContainer:
|
||||
return attr
|
||||
|
||||
|
||||
def set_register_stylesheet(obj: QObject, *,
|
||||
stylesheet: str = None,
|
||||
update: bool = True) -> None:
|
||||
"""Set the stylesheet for an object.
|
||||
def set_register_stylesheet(obj, *, stylesheet=None, update=True):
|
||||
"""Set the stylesheet for an object based on it's STYLESHEET attribute.
|
||||
|
||||
Also, register an update when the config is changed.
|
||||
|
||||
@ -626,7 +574,7 @@ def set_register_stylesheet(obj: QObject, *,
|
||||
|
||||
|
||||
@functools.lru_cache()
|
||||
def _render_stylesheet(stylesheet: str) -> str:
|
||||
def _render_stylesheet(stylesheet):
|
||||
"""Render the given stylesheet jinja template."""
|
||||
with jinja.environment.no_autoescape():
|
||||
template = jinja.environment.from_string(stylesheet)
|
||||
@ -642,9 +590,7 @@ class StyleSheetObserver(QObject):
|
||||
_stylesheet: The stylesheet template to use.
|
||||
"""
|
||||
|
||||
def __init__(self, obj: QObject,
|
||||
stylesheet: typing.Optional[str],
|
||||
update: bool) -> None:
|
||||
def __init__(self, obj, stylesheet, update):
|
||||
super().__init__()
|
||||
self._obj = obj
|
||||
self._update = update
|
||||
@ -653,11 +599,11 @@ class StyleSheetObserver(QObject):
|
||||
if self._update:
|
||||
self.setParent(self._obj)
|
||||
if stylesheet is None:
|
||||
self._stylesheet = obj.STYLESHEET # type: str
|
||||
self._stylesheet = obj.STYLESHEET
|
||||
else:
|
||||
self._stylesheet = stylesheet
|
||||
|
||||
def _get_stylesheet(self) -> str:
|
||||
def _get_stylesheet(self):
|
||||
"""Format a stylesheet based on a template.
|
||||
|
||||
Return:
|
||||
@ -666,15 +612,19 @@ class StyleSheetObserver(QObject):
|
||||
return _render_stylesheet(self._stylesheet)
|
||||
|
||||
@pyqtSlot()
|
||||
def _update_stylesheet(self) -> None:
|
||||
def _update_stylesheet(self):
|
||||
"""Update the stylesheet for obj."""
|
||||
self._obj.setStyleSheet(self._get_stylesheet())
|
||||
|
||||
def register(self) -> None:
|
||||
"""Do a first update and listen for more."""
|
||||
def register(self):
|
||||
"""Do a first update and listen for more.
|
||||
|
||||
Args:
|
||||
update: if False, don't listen for future updates.
|
||||
"""
|
||||
qss = self._get_stylesheet()
|
||||
log.config.vdebug( # type: ignore
|
||||
"stylesheet for {}: {}".format(self._obj.__class__.__name__, qss))
|
||||
log.config.vdebug("stylesheet for {}: {}".format(
|
||||
self._obj.__class__.__name__, qss))
|
||||
self._obj.setStyleSheet(qss)
|
||||
if self._update:
|
||||
instance.changed.connect(self._update_stylesheet)
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
"""Commands related to the configuration."""
|
||||
|
||||
import typing
|
||||
import os.path
|
||||
import contextlib
|
||||
|
||||
@ -32,34 +31,24 @@ from qutebrowser.config import configtypes, configexc, configfiles, configdata
|
||||
from qutebrowser.misc import editor
|
||||
from qutebrowser.keyinput import keyutils
|
||||
|
||||
MYPY = False
|
||||
if MYPY: # pragma: no cover
|
||||
# pylint: disable=unused-import,useless-suppression
|
||||
from qutebrowser.config.config import Config, KeyConfig
|
||||
|
||||
|
||||
class ConfigCommands:
|
||||
|
||||
"""qutebrowser commands related to the configuration."""
|
||||
|
||||
def __init__(self,
|
||||
config: 'Config',
|
||||
keyconfig: 'KeyConfig') -> None:
|
||||
def __init__(self, config, keyconfig):
|
||||
self._config = config
|
||||
self._keyconfig = keyconfig
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _handle_config_error(self) -> typing.Iterator[None]:
|
||||
def _handle_config_error(self):
|
||||
"""Catch errors in set_command and raise CommandError."""
|
||||
try:
|
||||
yield
|
||||
except configexc.Error as e:
|
||||
raise cmdutils.CommandError(str(e))
|
||||
|
||||
def _parse_pattern(
|
||||
self,
|
||||
pattern: typing.Optional[str]
|
||||
) -> typing.Optional[urlmatch.UrlPattern]:
|
||||
def _parse_pattern(self, pattern):
|
||||
"""Parse a pattern string argument to a pattern."""
|
||||
if pattern is None:
|
||||
return None
|
||||
@ -70,15 +59,14 @@ class ConfigCommands:
|
||||
raise cmdutils.CommandError("Error while parsing {}: {}"
|
||||
.format(pattern, str(e)))
|
||||
|
||||
def _parse_key(self, key: str) -> keyutils.KeySequence:
|
||||
def _parse_key(self, key):
|
||||
"""Parse a key argument."""
|
||||
try:
|
||||
return keyutils.KeySequence.parse(key)
|
||||
except keyutils.KeyParseError as e:
|
||||
raise cmdutils.CommandError(str(e))
|
||||
|
||||
def _print_value(self, option: str,
|
||||
pattern: typing.Optional[urlmatch.UrlPattern]) -> None:
|
||||
def _print_value(self, option, pattern):
|
||||
"""Print the value of the given option."""
|
||||
with self._handle_config_error():
|
||||
value = self._config.get_str(option, pattern=pattern)
|
||||
@ -93,9 +81,8 @@ class ConfigCommands:
|
||||
@cmdutils.argument('value', completion=configmodel.value)
|
||||
@cmdutils.argument('win_id', value=cmdutils.Value.win_id)
|
||||
@cmdutils.argument('pattern', flag='u')
|
||||
def set(self, win_id: int, option: str = None, value: str = None,
|
||||
temp: bool = False, print_: bool = False,
|
||||
*, pattern: str = None) -> None:
|
||||
def set(self, win_id, option=None, value=None, temp=False, print_=False,
|
||||
*, pattern=None):
|
||||
"""Set an option.
|
||||
|
||||
If the option name ends with '?' or no value is provided, the
|
||||
@ -121,28 +108,28 @@ class ConfigCommands:
|
||||
raise cmdutils.CommandError("Toggling values was moved to the "
|
||||
":config-cycle command")
|
||||
|
||||
parsed_pattern = self._parse_pattern(pattern)
|
||||
pattern = self._parse_pattern(pattern)
|
||||
|
||||
if option.endswith('?') and option != '?':
|
||||
self._print_value(option[:-1], pattern=parsed_pattern)
|
||||
self._print_value(option[:-1], pattern=pattern)
|
||||
return
|
||||
|
||||
with self._handle_config_error():
|
||||
if value is None:
|
||||
self._print_value(option, pattern=parsed_pattern)
|
||||
self._print_value(option, pattern=pattern)
|
||||
else:
|
||||
self._config.set_str(option, value, pattern=parsed_pattern,
|
||||
self._config.set_str(option, value, pattern=pattern,
|
||||
save_yaml=not temp)
|
||||
|
||||
if print_:
|
||||
self._print_value(option, pattern=parsed_pattern)
|
||||
self._print_value(option, pattern=pattern)
|
||||
|
||||
@cmdutils.register(instance='config-commands', maxsplit=1,
|
||||
no_cmd_split=True, no_replace_variables=True)
|
||||
@cmdutils.argument('command', completion=configmodel.bind)
|
||||
@cmdutils.argument('win_id', value=cmdutils.Value.win_id)
|
||||
def bind(self, win_id: str, key: str = None, command: str = None, *,
|
||||
mode: str = 'normal', default: bool = False) -> None:
|
||||
def bind(self, win_id, key=None, command=None, *, mode='normal',
|
||||
default=False):
|
||||
"""Bind a key to a command.
|
||||
|
||||
If no command is given, show the current binding for the given key.
|
||||
@ -187,7 +174,7 @@ class ConfigCommands:
|
||||
self._keyconfig.bind(seq, command, mode=mode, save_yaml=True)
|
||||
|
||||
@cmdutils.register(instance='config-commands')
|
||||
def unbind(self, key: str, *, mode: str = 'normal') -> None:
|
||||
def unbind(self, key, *, mode='normal'):
|
||||
"""Unbind a keychain.
|
||||
|
||||
Args:
|
||||
@ -204,9 +191,8 @@ class ConfigCommands:
|
||||
@cmdutils.argument('option', completion=configmodel.option)
|
||||
@cmdutils.argument('values', completion=configmodel.value)
|
||||
@cmdutils.argument('pattern', flag='u')
|
||||
def config_cycle(self, option: str, *values: str,
|
||||
pattern: str = None,
|
||||
temp: bool = False, print_: bool = False) -> None:
|
||||
def config_cycle(self, option, *values, pattern=None, temp=False,
|
||||
print_=False):
|
||||
"""Cycle an option between multiple values.
|
||||
|
||||
Args:
|
||||
@ -216,15 +202,15 @@ class ConfigCommands:
|
||||
temp: Set value temporarily until qutebrowser is closed.
|
||||
print_: Print the value after setting.
|
||||
"""
|
||||
parsed_pattern = self._parse_pattern(pattern)
|
||||
pattern = self._parse_pattern(pattern)
|
||||
|
||||
with self._handle_config_error():
|
||||
opt = self._config.get_opt(option)
|
||||
old_value = self._config.get_obj_for_pattern(
|
||||
option, pattern=parsed_pattern)
|
||||
old_value = self._config.get_obj_for_pattern(option,
|
||||
pattern=pattern)
|
||||
|
||||
if not values and isinstance(opt.typ, configtypes.Bool):
|
||||
values = ('true', 'false')
|
||||
values = ['true', 'false']
|
||||
|
||||
if len(values) < 2:
|
||||
raise cmdutils.CommandError("Need at least two values for "
|
||||
@ -233,25 +219,25 @@ class ConfigCommands:
|
||||
# Use the next valid value from values, or the first if the current
|
||||
# value does not appear in the list
|
||||
with self._handle_config_error():
|
||||
cycle_values = [opt.typ.from_str(val) for val in values]
|
||||
values = [opt.typ.from_str(val) for val in values]
|
||||
|
||||
try:
|
||||
idx = cycle_values.index(old_value)
|
||||
idx = (idx + 1) % len(cycle_values)
|
||||
value = cycle_values[idx]
|
||||
idx = values.index(old_value)
|
||||
idx = (idx + 1) % len(values)
|
||||
value = values[idx]
|
||||
except ValueError:
|
||||
value = cycle_values[0]
|
||||
value = values[0]
|
||||
|
||||
with self._handle_config_error():
|
||||
self._config.set_obj(option, value, pattern=parsed_pattern,
|
||||
self._config.set_obj(option, value, pattern=pattern,
|
||||
save_yaml=not temp)
|
||||
|
||||
if print_:
|
||||
self._print_value(option, pattern=parsed_pattern)
|
||||
self._print_value(option, pattern=pattern)
|
||||
|
||||
@cmdutils.register(instance='config-commands')
|
||||
@cmdutils.argument('option', completion=configmodel.customized_option)
|
||||
def config_unset(self, option: str, temp: bool = False) -> None:
|
||||
def config_unset(self, option, temp=False):
|
||||
"""Unset an option.
|
||||
|
||||
This sets an option back to its default and removes it from
|
||||
@ -266,8 +252,7 @@ class ConfigCommands:
|
||||
|
||||
@cmdutils.register(instance='config-commands')
|
||||
@cmdutils.argument('option', completion=configmodel.list_option)
|
||||
def config_list_add(self, option: str, value: str,
|
||||
temp: bool = False) -> None:
|
||||
def config_list_add(self, option, value, temp=False):
|
||||
"""Append a value to a config option that is a list.
|
||||
|
||||
Args:
|
||||
@ -288,8 +273,7 @@ class ConfigCommands:
|
||||
|
||||
@cmdutils.register(instance='config-commands')
|
||||
@cmdutils.argument('option', completion=configmodel.dict_option)
|
||||
def config_dict_add(self, option: str, key: str, value: str,
|
||||
temp: bool = False, replace: bool = False) -> None:
|
||||
def config_dict_add(self, option, key, value, temp=False, replace=False):
|
||||
"""Add a key/value pair to a dictionary option.
|
||||
|
||||
Args:
|
||||
@ -318,8 +302,7 @@ class ConfigCommands:
|
||||
|
||||
@cmdutils.register(instance='config-commands')
|
||||
@cmdutils.argument('option', completion=configmodel.list_option)
|
||||
def config_list_remove(self, option: str, value: str,
|
||||
temp: bool = False) -> None:
|
||||
def config_list_remove(self, option, value, temp=False):
|
||||
"""Remove a value from a list.
|
||||
|
||||
Args:
|
||||
@ -346,8 +329,7 @@ class ConfigCommands:
|
||||
|
||||
@cmdutils.register(instance='config-commands')
|
||||
@cmdutils.argument('option', completion=configmodel.dict_option)
|
||||
def config_dict_remove(self, option: str, key: str,
|
||||
temp: bool = False) -> None:
|
||||
def config_dict_remove(self, option, key, temp=False):
|
||||
"""Remove a key from a dict.
|
||||
|
||||
Args:
|
||||
@ -372,7 +354,7 @@ class ConfigCommands:
|
||||
self._config.update_mutables(save_yaml=not temp)
|
||||
|
||||
@cmdutils.register(instance='config-commands')
|
||||
def config_clear(self, save: bool = False) -> None:
|
||||
def config_clear(self, save=False):
|
||||
"""Set all settings back to their default.
|
||||
|
||||
Args:
|
||||
@ -382,7 +364,7 @@ class ConfigCommands:
|
||||
self._config.clear(save_yaml=save)
|
||||
|
||||
@cmdutils.register(instance='config-commands')
|
||||
def config_source(self, filename: str = None, clear: bool = False) -> None:
|
||||
def config_source(self, filename=None, clear=False):
|
||||
"""Read a config.py file.
|
||||
|
||||
Args:
|
||||
@ -404,13 +386,13 @@ class ConfigCommands:
|
||||
raise cmdutils.CommandError(e)
|
||||
|
||||
@cmdutils.register(instance='config-commands')
|
||||
def config_edit(self, no_source: bool = False) -> None:
|
||||
def config_edit(self, no_source=False):
|
||||
"""Open the config.py file in the editor.
|
||||
|
||||
Args:
|
||||
no_source: Don't re-source the config file after editing.
|
||||
"""
|
||||
def on_file_updated() -> None:
|
||||
def on_file_updated():
|
||||
"""Source the new config when editing finished.
|
||||
|
||||
This can't use cmdutils.CommandError as it's run async.
|
||||
@ -428,8 +410,7 @@ class ConfigCommands:
|
||||
ed.edit_file(filename)
|
||||
|
||||
@cmdutils.register(instance='config-commands')
|
||||
def config_write_py(self, filename: str = None,
|
||||
force: bool = False, defaults: bool = False) -> None:
|
||||
def config_write_py(self, filename=None, force=False, defaults=False):
|
||||
"""Write the current configuration to a config.py file.
|
||||
|
||||
Args:
|
||||
@ -448,13 +429,13 @@ class ConfigCommands:
|
||||
raise cmdutils.CommandError("{} already exists - use --force to "
|
||||
"overwrite!".format(filename))
|
||||
|
||||
options = [] # type: typing.List
|
||||
if defaults:
|
||||
options = [(None, opt, opt.default)
|
||||
for _name, opt in sorted(configdata.DATA.items())]
|
||||
bindings = dict(configdata.DATA['bindings.default'].default)
|
||||
commented = True
|
||||
else:
|
||||
options = []
|
||||
for values in self._config:
|
||||
for scoped in values:
|
||||
options.append((scoped.pattern, values.opt, scoped.value))
|
||||
|
@ -24,18 +24,14 @@ Module attributes:
|
||||
DATA: A dict of Option objects after init() has been called.
|
||||
"""
|
||||
|
||||
import typing
|
||||
from typing import Optional # pylint: disable=unused-import
|
||||
import functools
|
||||
|
||||
import attr
|
||||
from qutebrowser.config import configtypes
|
||||
from qutebrowser.utils import usertypes, qtutils, utils
|
||||
|
||||
DATA = typing.cast(typing.Mapping[str, 'Option'], None)
|
||||
MIGRATIONS = typing.cast('Migrations', None)
|
||||
|
||||
_BackendDict = typing.Mapping[str, typing.Union[str, bool]]
|
||||
DATA = None
|
||||
MIGRATIONS = None
|
||||
|
||||
|
||||
@attr.s
|
||||
@ -46,15 +42,15 @@ class Option:
|
||||
Note that this is just an option which exists, with no value associated.
|
||||
"""
|
||||
|
||||
name = attr.ib() # type: str
|
||||
typ = attr.ib() # type: configtypes.BaseType
|
||||
default = attr.ib() # type: typing.Any
|
||||
backends = attr.ib() # type: typing.Iterable[usertypes.Backend]
|
||||
raw_backends = attr.ib() # type: Optional[typing.Mapping[str, bool]]
|
||||
description = attr.ib() # type: str
|
||||
supports_pattern = attr.ib(default=False) # type: bool
|
||||
restart = attr.ib(default=False) # type: bool
|
||||
no_autoconfig = attr.ib(default=False) # type: bool
|
||||
name = attr.ib()
|
||||
typ = attr.ib()
|
||||
default = attr.ib()
|
||||
backends = attr.ib()
|
||||
raw_backends = attr.ib()
|
||||
description = attr.ib()
|
||||
supports_pattern = attr.ib(default=False)
|
||||
restart = attr.ib(default=False)
|
||||
no_autoconfig = attr.ib(default=False)
|
||||
|
||||
|
||||
@attr.s
|
||||
@ -67,13 +63,11 @@ class Migrations:
|
||||
deleted: A list of option names which have been removed.
|
||||
"""
|
||||
|
||||
renamed = attr.ib(
|
||||
default=attr.Factory(dict)) # type: typing.Dict[str, str]
|
||||
deleted = attr.ib(
|
||||
default=attr.Factory(list)) # type: typing.List[str]
|
||||
renamed = attr.ib(default=attr.Factory(dict))
|
||||
deleted = attr.ib(default=attr.Factory(list))
|
||||
|
||||
|
||||
def _raise_invalid_node(name: str, what: str, node: typing.Any) -> None:
|
||||
def _raise_invalid_node(name, what, node):
|
||||
"""Raise an exception for an invalid configdata YAML node.
|
||||
|
||||
Args:
|
||||
@ -85,16 +79,13 @@ def _raise_invalid_node(name: str, what: str, node: typing.Any) -> None:
|
||||
name, what, node))
|
||||
|
||||
|
||||
def _parse_yaml_type(
|
||||
name: str,
|
||||
node: typing.Union[str, typing.Mapping[str, typing.Any]],
|
||||
) -> configtypes.BaseType:
|
||||
def _parse_yaml_type(name, node):
|
||||
if isinstance(node, str):
|
||||
# e.g:
|
||||
# type: Bool
|
||||
# -> create the type object without any arguments
|
||||
type_name = node
|
||||
kwargs = {} # type: typing.MutableMapping[str, typing.Any]
|
||||
kwargs = {}
|
||||
elif isinstance(node, dict):
|
||||
# e.g:
|
||||
# type:
|
||||
@ -132,10 +123,7 @@ def _parse_yaml_type(
|
||||
type_name, node, e))
|
||||
|
||||
|
||||
def _parse_yaml_backends_dict(
|
||||
name: str,
|
||||
node: _BackendDict,
|
||||
) -> typing.Sequence[usertypes.Backend]:
|
||||
def _parse_yaml_backends_dict(name, node):
|
||||
"""Parse a dict definition for backends.
|
||||
|
||||
Example:
|
||||
@ -172,10 +160,7 @@ def _parse_yaml_backends_dict(
|
||||
return backends
|
||||
|
||||
|
||||
def _parse_yaml_backends(
|
||||
name: str,
|
||||
node: typing.Union[None, str, _BackendDict],
|
||||
) -> typing.Sequence[usertypes.Backend]:
|
||||
def _parse_yaml_backends(name, node):
|
||||
"""Parse a backend node in the yaml.
|
||||
|
||||
It can have one of those four forms:
|
||||
@ -202,9 +187,7 @@ def _parse_yaml_backends(
|
||||
raise utils.Unreachable
|
||||
|
||||
|
||||
def _read_yaml(
|
||||
yaml_data: str,
|
||||
) -> typing.Tuple[typing.Mapping[str, Option], Migrations]:
|
||||
def _read_yaml(yaml_data):
|
||||
"""Read config data from a YAML file.
|
||||
|
||||
Args:
|
||||
@ -266,12 +249,12 @@ def _read_yaml(
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=256)
|
||||
def is_valid_prefix(prefix: str) -> bool:
|
||||
def is_valid_prefix(prefix):
|
||||
"""Check whether the given prefix is a valid prefix for some option."""
|
||||
return any(key.startswith(prefix + '.') for key in DATA)
|
||||
|
||||
|
||||
def init() -> None:
|
||||
def init():
|
||||
"""Initialize configdata from the YAML file."""
|
||||
global DATA, MIGRATIONS
|
||||
DATA, MIGRATIONS = _read_yaml(utils.read_file('config/configdata.yml'))
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
"""Code to show a diff of the legacy config format."""
|
||||
|
||||
import typing # pylint: disable=unused-import,useless-suppression
|
||||
import difflib
|
||||
import os.path
|
||||
|
||||
@ -728,10 +727,10 @@ scroll right
|
||||
"""
|
||||
|
||||
|
||||
def get_diff() -> str:
|
||||
def get_diff():
|
||||
"""Get a HTML diff for the old config files."""
|
||||
old_conf_lines = [] # type: typing.MutableSequence[str]
|
||||
old_key_lines = [] # type: typing.MutableSequence[str]
|
||||
old_conf_lines = []
|
||||
old_key_lines = []
|
||||
|
||||
for filename, dest in [('qutebrowser.conf', old_conf_lines),
|
||||
('keys.conf', old_key_lines)]:
|
||||
|
@ -19,10 +19,9 @@
|
||||
|
||||
"""Exceptions related to config parsing."""
|
||||
|
||||
import typing
|
||||
import attr
|
||||
|
||||
from qutebrowser.utils import jinja, usertypes
|
||||
from qutebrowser.utils import jinja
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
@ -34,7 +33,7 @@ class NoAutoconfigError(Error):
|
||||
|
||||
"""Raised when this option can't be set in autoconfig.yml."""
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
def __init__(self, name):
|
||||
super().__init__("The {} setting can only be set in config.py!"
|
||||
.format(name))
|
||||
|
||||
@ -43,11 +42,7 @@ class BackendError(Error):
|
||||
|
||||
"""Raised when this setting is unavailable with the current backend."""
|
||||
|
||||
def __init__(
|
||||
self, name: str,
|
||||
backend: usertypes.Backend,
|
||||
raw_backends: typing.Optional[typing.Mapping[str, bool]]
|
||||
) -> None:
|
||||
def __init__(self, name, backend, raw_backends):
|
||||
if raw_backends is None or not raw_backends[backend.name]:
|
||||
msg = ("The {} setting is not available with the {} backend!"
|
||||
.format(name, backend.name))
|
||||
@ -62,7 +57,7 @@ class NoPatternError(Error):
|
||||
|
||||
"""Raised when the given setting does not support URL patterns."""
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
def __init__(self, name):
|
||||
super().__init__("The {} setting does not support URL patterns!"
|
||||
.format(name))
|
||||
|
||||
@ -76,7 +71,7 @@ class ValidationError(Error):
|
||||
msg: Additional error message.
|
||||
"""
|
||||
|
||||
def __init__(self, value: typing.Any, msg: str) -> None:
|
||||
def __init__(self, value, msg):
|
||||
super().__init__("Invalid value '{}' - {}".format(value, msg))
|
||||
self.option = None
|
||||
|
||||
@ -90,9 +85,7 @@ class NoOptionError(Error):
|
||||
|
||||
"""Raised when an option was not found."""
|
||||
|
||||
def __init__(self, option: str, *,
|
||||
deleted: bool = False,
|
||||
renamed: str = None) -> None:
|
||||
def __init__(self, option, *, deleted=False, renamed=None):
|
||||
if deleted:
|
||||
assert renamed is None
|
||||
suffix = ' (this option was removed from qutebrowser)'
|
||||
@ -116,18 +109,18 @@ class ConfigErrorDesc:
|
||||
traceback: The formatted traceback of the exception.
|
||||
"""
|
||||
|
||||
text = attr.ib() # type: str
|
||||
exception = attr.ib() # type: typing.Union[str, Exception]
|
||||
traceback = attr.ib(None) # type: str
|
||||
text = attr.ib()
|
||||
exception = attr.ib()
|
||||
traceback = attr.ib(None)
|
||||
|
||||
def __str__(self) -> str:
|
||||
def __str__(self):
|
||||
if self.traceback:
|
||||
return '{} - {}: {}'.format(self.text,
|
||||
self.exception.__class__.__name__,
|
||||
self.exception)
|
||||
return '{}: {}'.format(self.text, self.exception)
|
||||
|
||||
def with_text(self, text: str) -> 'ConfigErrorDesc':
|
||||
def with_text(self, text):
|
||||
"""Get a new ConfigErrorDesc with the given text appended."""
|
||||
return self.__class__(text='{} ({})'.format(self.text, text),
|
||||
exception=self.exception,
|
||||
@ -138,15 +131,13 @@ class ConfigFileErrors(Error):
|
||||
|
||||
"""Raised when multiple errors occurred inside the config."""
|
||||
|
||||
def __init__(self,
|
||||
basename: str,
|
||||
errors: typing.Sequence[ConfigErrorDesc]) -> None:
|
||||
def __init__(self, basename, errors):
|
||||
super().__init__("Errors occurred while reading {}:\n{}".format(
|
||||
basename, '\n'.join(' {}'.format(e) for e in errors)))
|
||||
self.basename = basename
|
||||
self.errors = errors
|
||||
|
||||
def to_html(self) -> str:
|
||||
def to_html(self):
|
||||
"""Get the error texts as a HTML snippet."""
|
||||
template = jinja.environment.from_string("""
|
||||
Errors occurred while reading {{ basename }}:
|
||||
|
@ -27,7 +27,6 @@ import textwrap
|
||||
import traceback
|
||||
import configparser
|
||||
import contextlib
|
||||
import typing
|
||||
|
||||
import yaml
|
||||
from PyQt5.QtCore import pyqtSignal, QObject, QSettings
|
||||
@ -37,21 +36,16 @@ from qutebrowser.config import configexc, config, configdata, configutils
|
||||
from qutebrowser.keyinput import keyutils
|
||||
from qutebrowser.utils import standarddir, utils, qtutils, log, urlmatch
|
||||
|
||||
MYPY = False
|
||||
if MYPY:
|
||||
# pylint: disable=unused-import, useless-suppression
|
||||
from qutebrowser.misc import savemanager
|
||||
|
||||
|
||||
# The StateConfig instance
|
||||
state = typing.cast('StateConfig', None)
|
||||
state = None
|
||||
|
||||
|
||||
class StateConfig(configparser.ConfigParser):
|
||||
|
||||
"""The "state" file saving various application state."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._filename = os.path.join(standarddir.data(), 'state')
|
||||
self.read(self._filename, encoding='utf-8')
|
||||
@ -65,8 +59,7 @@ class StateConfig(configparser.ConfigParser):
|
||||
for key in deleted_keys:
|
||||
self['general'].pop(key, None)
|
||||
|
||||
def init_save_manager(self,
|
||||
save_manager: 'savemanager.SaveManager') -> None:
|
||||
def init_save_manager(self, save_manager):
|
||||
"""Make sure the config gets saved properly.
|
||||
|
||||
We do this outside of __init__ because the config gets created before
|
||||
@ -74,7 +67,7 @@ class StateConfig(configparser.ConfigParser):
|
||||
"""
|
||||
save_manager.add_saveable('state-config', self._save)
|
||||
|
||||
def _save(self) -> None:
|
||||
def _save(self):
|
||||
"""Save the state file to the configured location."""
|
||||
with open(self._filename, 'w', encoding='utf-8') as f:
|
||||
self.write(f)
|
||||
@ -91,20 +84,17 @@ class YamlConfig(QObject):
|
||||
VERSION = 2
|
||||
changed = pyqtSignal()
|
||||
|
||||
_SettingsType = typing.Dict[str, typing.Dict[str, typing.Any]]
|
||||
|
||||
def __init__(self, parent: QObject = None) -> None:
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self._filename = os.path.join(standarddir.config(auto=True),
|
||||
'autoconfig.yml')
|
||||
self._dirty = False
|
||||
self._dirty = None
|
||||
|
||||
self._values = {} # type: typing.Dict[str, configutils.Values]
|
||||
self._values = {}
|
||||
for name, opt in configdata.DATA.items():
|
||||
self._values[name] = configutils.Values(opt)
|
||||
|
||||
def init_save_manager(self,
|
||||
save_manager: 'savemanager.SaveManager') -> None:
|
||||
def init_save_manager(self, save_manager):
|
||||
"""Make sure the config gets saved properly.
|
||||
|
||||
We do this outside of __init__ because the config gets created before
|
||||
@ -112,21 +102,21 @@ class YamlConfig(QObject):
|
||||
"""
|
||||
save_manager.add_saveable('yaml-config', self._save, self.changed)
|
||||
|
||||
def __iter__(self) -> typing.Iterator[configutils.Values]:
|
||||
def __iter__(self):
|
||||
"""Iterate over configutils.Values items."""
|
||||
yield from self._values.values()
|
||||
|
||||
def _mark_changed(self) -> None:
|
||||
def _mark_changed(self):
|
||||
"""Mark the YAML config as changed."""
|
||||
self._dirty = True
|
||||
self.changed.emit()
|
||||
|
||||
def _save(self) -> None:
|
||||
def _save(self):
|
||||
"""Save the settings to the YAML file if they've changed."""
|
||||
if not self._dirty:
|
||||
return
|
||||
|
||||
settings = {} # type: YamlConfig._SettingsType
|
||||
settings = {}
|
||||
for name, values in sorted(self._values.items()):
|
||||
if not values:
|
||||
continue
|
||||
@ -145,10 +135,7 @@ class YamlConfig(QObject):
|
||||
""".lstrip('\n')))
|
||||
utils.yaml_dump(data, f)
|
||||
|
||||
def _pop_object(self,
|
||||
yaml_data: typing.Any,
|
||||
key: str,
|
||||
typ: type) -> typing.Any:
|
||||
def _pop_object(self, yaml_data, key, typ):
|
||||
"""Get a global object from the given data."""
|
||||
if not isinstance(yaml_data, dict):
|
||||
desc = configexc.ConfigErrorDesc("While loading data",
|
||||
@ -171,7 +158,7 @@ class YamlConfig(QObject):
|
||||
|
||||
return data
|
||||
|
||||
def load(self) -> None:
|
||||
def load(self):
|
||||
"""Load configuration from the configured YAML file."""
|
||||
try:
|
||||
with open(self._filename, 'r', encoding='utf-8') as f:
|
||||
@ -202,19 +189,18 @@ class YamlConfig(QObject):
|
||||
self._validate(settings)
|
||||
self._build_values(settings)
|
||||
|
||||
def _load_settings_object(self, yaml_data: typing.Any) -> '_SettingsType':
|
||||
def _load_settings_object(self, yaml_data):
|
||||
"""Load the settings from the settings: key."""
|
||||
return self._pop_object(yaml_data, 'settings', dict)
|
||||
|
||||
def _load_legacy_settings_object(self,
|
||||
yaml_data: typing.Any) -> '_SettingsType':
|
||||
def _load_legacy_settings_object(self, yaml_data):
|
||||
data = self._pop_object(yaml_data, 'global', dict)
|
||||
settings = {}
|
||||
for name, value in data.items():
|
||||
settings[name] = {'global': value}
|
||||
return settings
|
||||
|
||||
def _build_values(self, settings: typing.Mapping) -> None:
|
||||
def _build_values(self, settings):
|
||||
"""Build up self._values from the values in the given dict."""
|
||||
errors = []
|
||||
for name, yaml_values in settings.items():
|
||||
@ -247,8 +233,7 @@ class YamlConfig(QObject):
|
||||
if errors:
|
||||
raise configexc.ConfigFileErrors('autoconfig.yml', errors)
|
||||
|
||||
def _migrate_bool(self, settings: _SettingsType, name: str,
|
||||
true_value: str, false_value: str) -> None:
|
||||
def _migrate_bool(self, settings, name, true_value, false_value):
|
||||
"""Migrate a boolean in the settings."""
|
||||
if name in settings:
|
||||
for scope, val in settings[name].items():
|
||||
@ -256,7 +241,7 @@ class YamlConfig(QObject):
|
||||
settings[name][scope] = true_value if val else false_value
|
||||
self._mark_changed()
|
||||
|
||||
def _handle_migrations(self, settings: _SettingsType) -> '_SettingsType':
|
||||
def _handle_migrations(self, settings):
|
||||
"""Migrate older configs to the newest format."""
|
||||
# Simple renamed/deleted options
|
||||
for name in list(settings):
|
||||
@ -314,7 +299,7 @@ class YamlConfig(QObject):
|
||||
|
||||
return settings
|
||||
|
||||
def _validate(self, settings: _SettingsType) -> None:
|
||||
def _validate(self, settings):
|
||||
"""Make sure all settings exist."""
|
||||
unknown = []
|
||||
for name in settings:
|
||||
@ -327,19 +312,18 @@ class YamlConfig(QObject):
|
||||
for e in sorted(unknown)]
|
||||
raise configexc.ConfigFileErrors('autoconfig.yml', errors)
|
||||
|
||||
def set_obj(self, name: str, value: typing.Any, *,
|
||||
pattern: urlmatch.UrlPattern = None) -> None:
|
||||
def set_obj(self, name, value, *, pattern=None):
|
||||
"""Set the given setting to the given value."""
|
||||
self._values[name].add(value, pattern)
|
||||
self._mark_changed()
|
||||
|
||||
def unset(self, name: str, *, pattern: urlmatch.UrlPattern = None) -> None:
|
||||
def unset(self, name, *, pattern=None):
|
||||
"""Remove the given option name if it's configured."""
|
||||
changed = self._values[name].remove(pattern)
|
||||
if changed:
|
||||
self._mark_changed()
|
||||
|
||||
def clear(self) -> None:
|
||||
def clear(self):
|
||||
"""Clear all values from the YAML file."""
|
||||
for values in self._values.values():
|
||||
values.clear()
|
||||
@ -362,15 +346,15 @@ class ConfigAPI:
|
||||
datadir: The qutebrowser data directory, as pathlib.Path.
|
||||
"""
|
||||
|
||||
def __init__(self, conf: config.Config, keyconfig: config.KeyConfig):
|
||||
def __init__(self, conf, keyconfig):
|
||||
self._config = conf
|
||||
self._keyconfig = keyconfig
|
||||
self.errors = [] # type: typing.List[configexc.ConfigErrorDesc]
|
||||
self.errors = []
|
||||
self.configdir = pathlib.Path(standarddir.config())
|
||||
self.datadir = pathlib.Path(standarddir.data())
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _handle_error(self, action: str, name: str) -> typing.Iterator[None]:
|
||||
def _handle_error(self, action, name):
|
||||
"""Catch config-related exceptions and save them in self.errors."""
|
||||
try:
|
||||
yield
|
||||
@ -388,40 +372,40 @@ class ConfigAPI:
|
||||
text = "While {} '{}' and parsing key".format(action, name)
|
||||
self.errors.append(configexc.ConfigErrorDesc(text, e))
|
||||
|
||||
def finalize(self) -> None:
|
||||
def finalize(self):
|
||||
"""Do work which needs to be done after reading config.py."""
|
||||
self._config.update_mutables()
|
||||
|
||||
def load_autoconfig(self) -> None:
|
||||
def load_autoconfig(self):
|
||||
"""Load the autoconfig.yml file which is used for :set/:bind/etc."""
|
||||
with self._handle_error('reading', 'autoconfig.yml'):
|
||||
read_autoconfig()
|
||||
|
||||
def get(self, name: str, pattern: str = None) -> typing.Any:
|
||||
def get(self, name, pattern=None):
|
||||
"""Get a setting value from the config, optionally with a pattern."""
|
||||
with self._handle_error('getting', name):
|
||||
urlpattern = urlmatch.UrlPattern(pattern) if pattern else None
|
||||
return self._config.get_mutable_obj(name, pattern=urlpattern)
|
||||
|
||||
def set(self, name: str, value: typing.Any, pattern: str = None) -> None:
|
||||
def set(self, name, value, pattern=None):
|
||||
"""Set a setting value in the config, optionally with a pattern."""
|
||||
with self._handle_error('setting', name):
|
||||
urlpattern = urlmatch.UrlPattern(pattern) if pattern else None
|
||||
self._config.set_obj(name, value, pattern=urlpattern)
|
||||
|
||||
def bind(self, key: str, command: str, mode: str = 'normal') -> None:
|
||||
def bind(self, key, command, mode='normal'):
|
||||
"""Bind a key to a command, with an optional key mode."""
|
||||
with self._handle_error('binding', key):
|
||||
seq = keyutils.KeySequence.parse(key)
|
||||
self._keyconfig.bind(seq, command, mode=mode)
|
||||
|
||||
def unbind(self, key: str, mode: str = 'normal') -> None:
|
||||
def unbind(self, key, mode='normal'):
|
||||
"""Unbind a key from a command, with an optional key mode."""
|
||||
with self._handle_error('unbinding', key):
|
||||
seq = keyutils.KeySequence.parse(key)
|
||||
self._keyconfig.unbind(seq, mode=mode)
|
||||
|
||||
def source(self, filename: str) -> None:
|
||||
def source(self, filename):
|
||||
"""Read the given config file from disk."""
|
||||
if not os.path.isabs(filename):
|
||||
filename = str(self.configdir / filename)
|
||||
@ -432,7 +416,7 @@ class ConfigAPI:
|
||||
self.errors += e.errors
|
||||
|
||||
@contextlib.contextmanager
|
||||
def pattern(self, pattern: str) -> typing.Iterator[config.ConfigContainer]:
|
||||
def pattern(self, pattern):
|
||||
"""Get a ConfigContainer for the given pattern."""
|
||||
# We need to propagate the exception so we don't need to return
|
||||
# something.
|
||||
@ -446,21 +430,17 @@ class ConfigPyWriter:
|
||||
|
||||
"""Writer for config.py files from given settings."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
options: typing.List,
|
||||
bindings: typing.MutableMapping[str, typing.Mapping[str, str]], *,
|
||||
commented: bool) -> None:
|
||||
def __init__(self, options, bindings, *, commented):
|
||||
self._options = options
|
||||
self._bindings = bindings
|
||||
self._commented = commented
|
||||
|
||||
def write(self, filename: str) -> None:
|
||||
def write(self, filename):
|
||||
"""Write the config to the given file."""
|
||||
with open(filename, 'w', encoding='utf-8') as f:
|
||||
f.write('\n'.join(self._gen_lines()))
|
||||
|
||||
def _line(self, line: str) -> str:
|
||||
def _line(self, line):
|
||||
"""Get an (optionally commented) line."""
|
||||
if self._commented:
|
||||
if line.startswith('#'):
|
||||
@ -470,7 +450,7 @@ class ConfigPyWriter:
|
||||
else:
|
||||
return line
|
||||
|
||||
def _gen_lines(self) -> typing.Iterator[str]:
|
||||
def _gen_lines(self):
|
||||
"""Generate a config.py with the given settings/bindings.
|
||||
|
||||
Yields individual lines.
|
||||
@ -479,7 +459,7 @@ class ConfigPyWriter:
|
||||
yield from self._gen_options()
|
||||
yield from self._gen_bindings()
|
||||
|
||||
def _gen_header(self) -> typing.Iterator[str]:
|
||||
def _gen_header(self):
|
||||
"""Generate the initial header of the config."""
|
||||
yield self._line("# Autogenerated config.py")
|
||||
yield self._line("# Documentation:")
|
||||
@ -501,7 +481,7 @@ class ConfigPyWriter:
|
||||
yield self._line("# config.load_autoconfig()")
|
||||
yield ''
|
||||
|
||||
def _gen_options(self) -> typing.Iterator[str]:
|
||||
def _gen_options(self):
|
||||
"""Generate the options part of the config."""
|
||||
for pattern, opt, value in self._options:
|
||||
if opt.name in ['bindings.commands', 'bindings.default']:
|
||||
@ -529,7 +509,7 @@ class ConfigPyWriter:
|
||||
opt.name, value, str(pattern)))
|
||||
yield ''
|
||||
|
||||
def _gen_bindings(self) -> typing.Iterator[str]:
|
||||
def _gen_bindings(self):
|
||||
"""Generate the bindings part of the config."""
|
||||
normal_bindings = self._bindings.pop('normal', {})
|
||||
if normal_bindings:
|
||||
@ -547,7 +527,7 @@ class ConfigPyWriter:
|
||||
yield ''
|
||||
|
||||
|
||||
def read_config_py(filename: str, raising: bool = False) -> None:
|
||||
def read_config_py(filename, raising=False):
|
||||
"""Read a config.py file.
|
||||
|
||||
Arguments;
|
||||
@ -563,8 +543,8 @@ def read_config_py(filename: str, raising: bool = False) -> None:
|
||||
basename = os.path.basename(filename)
|
||||
|
||||
module = types.ModuleType('config')
|
||||
module.config = api # type: ignore
|
||||
module.c = container # type: ignore
|
||||
module.config = api
|
||||
module.c = container
|
||||
module.__file__ = filename
|
||||
|
||||
try:
|
||||
@ -609,7 +589,7 @@ def read_config_py(filename: str, raising: bool = False) -> None:
|
||||
raise configexc.ConfigFileErrors('config.py', api.errors)
|
||||
|
||||
|
||||
def read_autoconfig() -> None:
|
||||
def read_autoconfig():
|
||||
"""Read the autoconfig.yml file."""
|
||||
try:
|
||||
config.instance.read_yaml()
|
||||
@ -621,7 +601,7 @@ def read_autoconfig() -> None:
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def saved_sys_properties() -> typing.Iterator[None]:
|
||||
def saved_sys_properties():
|
||||
"""Save various sys properties such as sys.path and sys.modules."""
|
||||
old_path = sys.path.copy()
|
||||
old_modules = sys.modules.copy()
|
||||
@ -634,7 +614,7 @@ def saved_sys_properties() -> typing.Iterator[None]:
|
||||
del sys.modules[module]
|
||||
|
||||
|
||||
def init() -> None:
|
||||
def init():
|
||||
"""Initialize config storage not related to the main config."""
|
||||
global state
|
||||
state = StateConfig()
|
||||
|
@ -19,10 +19,8 @@
|
||||
|
||||
"""Initialization of the configuration."""
|
||||
|
||||
import argparse
|
||||
import os.path
|
||||
import sys
|
||||
import typing
|
||||
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
|
||||
@ -32,14 +30,14 @@ from qutebrowser.config import (config, configdata, configfiles, configtypes,
|
||||
from qutebrowser.utils import (objreg, usertypes, log, standarddir, message,
|
||||
qtutils)
|
||||
from qutebrowser.config import configcache
|
||||
from qutebrowser.misc import msgbox, objects, savemanager
|
||||
from qutebrowser.misc import msgbox, objects
|
||||
|
||||
|
||||
# Error which happened during init, so we can show a message box.
|
||||
_init_errors = None
|
||||
|
||||
|
||||
def early_init(args: argparse.Namespace) -> None:
|
||||
def early_init(args):
|
||||
"""Initialize the part of the config which works without a QApplication."""
|
||||
configdata.init()
|
||||
|
||||
@ -87,7 +85,7 @@ def early_init(args: argparse.Namespace) -> None:
|
||||
_init_envvars()
|
||||
|
||||
|
||||
def _init_envvars() -> None:
|
||||
def _init_envvars():
|
||||
"""Initialize environment variables which need to be set early."""
|
||||
if objects.backend == usertypes.Backend.QtWebEngine:
|
||||
software_rendering = config.val.qt.force_software_rendering
|
||||
@ -109,7 +107,7 @@ def _init_envvars() -> None:
|
||||
|
||||
|
||||
@config.change_filter('fonts.monospace', function=True)
|
||||
def _update_monospace_fonts() -> None:
|
||||
def _update_monospace_fonts():
|
||||
"""Update all fonts if fonts.monospace was set."""
|
||||
configtypes.Font.monospace_fonts = config.val.fonts.monospace
|
||||
for name, opt in configdata.DATA.items():
|
||||
@ -125,7 +123,7 @@ def _update_monospace_fonts() -> None:
|
||||
config.instance.changed.emit(name)
|
||||
|
||||
|
||||
def get_backend(args: argparse.Namespace) -> usertypes.Backend:
|
||||
def get_backend(args):
|
||||
"""Find out what backend to use based on available libraries."""
|
||||
str_to_backend = {
|
||||
'webkit': usertypes.Backend.QtWebKit,
|
||||
@ -138,7 +136,7 @@ def get_backend(args: argparse.Namespace) -> usertypes.Backend:
|
||||
return str_to_backend[config.val.backend]
|
||||
|
||||
|
||||
def late_init(save_manager: savemanager.SaveManager) -> None:
|
||||
def late_init(save_manager):
|
||||
"""Initialize the rest of the config after the QApplication is created."""
|
||||
global _init_errors
|
||||
if _init_errors is not None:
|
||||
@ -154,7 +152,7 @@ def late_init(save_manager: savemanager.SaveManager) -> None:
|
||||
configfiles.state.init_save_manager(save_manager)
|
||||
|
||||
|
||||
def qt_args(namespace: argparse.Namespace) -> typing.List[str]:
|
||||
def qt_args(namespace):
|
||||
"""Get the Qt QApplication arguments based on an argparse namespace.
|
||||
|
||||
Args:
|
||||
@ -180,7 +178,7 @@ def qt_args(namespace: argparse.Namespace) -> typing.List[str]:
|
||||
return argv
|
||||
|
||||
|
||||
def _qtwebengine_args() -> typing.Iterator[str]:
|
||||
def _qtwebengine_args():
|
||||
"""Get the QtWebEngine arguments to use based on the config."""
|
||||
if not qtutils.version_check('5.11', compiled=False):
|
||||
# WORKAROUND equivalent to
|
||||
@ -226,7 +224,7 @@ def _qtwebengine_args() -> typing.Iterator[str]:
|
||||
'never': '--no-referrers',
|
||||
'same-domain': '--reduced-referrer-granularity',
|
||||
}
|
||||
} # type: typing.Dict[str, typing.Dict[typing.Any, typing.Optional[str]]]
|
||||
}
|
||||
|
||||
if not qtutils.version_check('5.11'):
|
||||
# On Qt 5.11, we can control this via QWebEngineSettings
|
||||
|
@ -21,19 +21,11 @@
|
||||
"""Utilities and data structures used by various config code."""
|
||||
|
||||
|
||||
import typing
|
||||
|
||||
import attr
|
||||
from PyQt5.QtCore import QUrl
|
||||
|
||||
from qutebrowser.utils import utils, urlmatch
|
||||
from qutebrowser.utils import utils
|
||||
from qutebrowser.config import configexc
|
||||
|
||||
MYPY = False
|
||||
if MYPY: # pragma: no cover
|
||||
# pylint: disable=unused-import,useless-suppression
|
||||
from qutebrowser.config import configdata
|
||||
|
||||
|
||||
class _UnsetObject:
|
||||
|
||||
@ -41,7 +33,7 @@ class _UnsetObject:
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
def __repr__(self):
|
||||
return '<UNSET>'
|
||||
|
||||
|
||||
@ -58,8 +50,8 @@ class ScopedValue:
|
||||
pattern: The UrlPattern for the value, or None for global values.
|
||||
"""
|
||||
|
||||
value = attr.ib() # type: typing.Any
|
||||
pattern = attr.ib() # type: typing.Optional[urlmatch.UrlPattern]
|
||||
value = attr.ib()
|
||||
pattern = attr.ib()
|
||||
|
||||
|
||||
class Values:
|
||||
@ -81,17 +73,15 @@ class Values:
|
||||
opt: The Option being customized.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
opt: 'configdata.Option',
|
||||
values: typing.MutableSequence = None) -> None:
|
||||
def __init__(self, opt, values=None):
|
||||
self.opt = opt
|
||||
self._values = values or []
|
||||
|
||||
def __repr__(self) -> str:
|
||||
def __repr__(self):
|
||||
return utils.get_repr(self, opt=self.opt, values=self._values,
|
||||
constructor=True)
|
||||
|
||||
def __str__(self) -> str:
|
||||
def __str__(self):
|
||||
"""Get the values as human-readable string."""
|
||||
if not self:
|
||||
return '{}: <unchanged>'.format(self.opt.name)
|
||||
@ -106,7 +96,7 @@ class Values:
|
||||
scoped.pattern, self.opt.name, str_value))
|
||||
return '\n'.join(lines)
|
||||
|
||||
def __iter__(self) -> typing.Iterator['ScopedValue']:
|
||||
def __iter__(self):
|
||||
"""Yield ScopedValue elements.
|
||||
|
||||
This yields in "normal" order, i.e. global and then first-set settings
|
||||
@ -114,25 +104,23 @@ class Values:
|
||||
"""
|
||||
yield from self._values
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
def __bool__(self):
|
||||
"""Check whether this value is customized."""
|
||||
return bool(self._values)
|
||||
|
||||
def _check_pattern_support(
|
||||
self, arg: typing.Optional[urlmatch.UrlPattern]) -> None:
|
||||
def _check_pattern_support(self, arg):
|
||||
"""Make sure patterns are supported if one was given."""
|
||||
if arg is not None and not self.opt.supports_pattern:
|
||||
raise configexc.NoPatternError(self.opt.name)
|
||||
|
||||
def add(self, value: typing.Any,
|
||||
pattern: urlmatch.UrlPattern = None) -> None:
|
||||
def add(self, value, pattern=None):
|
||||
"""Add a value with the given pattern to the list of values."""
|
||||
self._check_pattern_support(pattern)
|
||||
self.remove(pattern)
|
||||
scoped = ScopedValue(value, pattern)
|
||||
self._values.append(scoped)
|
||||
|
||||
def remove(self, pattern: urlmatch.UrlPattern = None) -> bool:
|
||||
def remove(self, pattern=None):
|
||||
"""Remove the value with the given pattern.
|
||||
|
||||
If a matching pattern was removed, True is returned.
|
||||
@ -143,11 +131,11 @@ class Values:
|
||||
self._values = [v for v in self._values if v.pattern != pattern]
|
||||
return old_len != len(self._values)
|
||||
|
||||
def clear(self) -> None:
|
||||
def clear(self):
|
||||
"""Clear all customization for this value."""
|
||||
self._values = []
|
||||
|
||||
def _get_fallback(self, fallback: typing.Any) -> typing.Any:
|
||||
def _get_fallback(self, fallback):
|
||||
"""Get the fallback global/default value."""
|
||||
for scoped in self._values:
|
||||
if scoped.pattern is None:
|
||||
@ -158,8 +146,7 @@ class Values:
|
||||
else:
|
||||
return UNSET
|
||||
|
||||
def get_for_url(self, url: QUrl = None, *,
|
||||
fallback: bool = True) -> typing.Any:
|
||||
def get_for_url(self, url=None, *, fallback=True):
|
||||
"""Get a config value, falling back when needed.
|
||||
|
||||
This first tries to find a value matching the URL (if given).
|
||||
@ -178,9 +165,7 @@ class Values:
|
||||
|
||||
return self._get_fallback(fallback)
|
||||
|
||||
def get_for_pattern(self,
|
||||
pattern: typing.Optional[urlmatch.UrlPattern], *,
|
||||
fallback: bool = True) -> typing.Any:
|
||||
def get_for_pattern(self, pattern, *, fallback=True):
|
||||
"""Get a value only if it's been overridden for the given pattern.
|
||||
|
||||
This is useful when showing values to the user.
|
||||
|
Loading…
Reference in New Issue
Block a user