From 3ade923edb132e17e443ab805ba2412c20298e21 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 20 Feb 2018 18:43:42 +0100 Subject: [PATCH] Add basic pattern support for config.py --- qutebrowser/config/configfiles.py | 24 +++++++---- tests/unit/config/test_configfiles.py | 62 ++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 9 deletions(-) diff --git a/qutebrowser/config/configfiles.py b/qutebrowser/config/configfiles.py index 9d76d4ee5..622e116fd 100644 --- a/qutebrowser/config/configfiles.py +++ b/qutebrowser/config/configfiles.py @@ -33,7 +33,7 @@ from PyQt5.QtCore import pyqtSignal, QObject, QSettings import qutebrowser from qutebrowser.config import configexc, config, configdata, configutils -from qutebrowser.utils import standarddir, utils, qtutils, log +from qutebrowser.utils import standarddir, utils, qtutils, log, urlmatch # The StateConfig instance @@ -308,6 +308,9 @@ class ConfigAPI: except configexc.Error as e: text = "While {} '{}'".format(action, name) self.errors.append(configexc.ConfigErrorDesc(text, e)) + except urlmatch.ParseError as e: + text = "While {} '{}' and parsing pattern".format(action, name) + self.errors.append(configexc.ConfigErrorDesc(text, e)) def finalize(self): """Do work which needs to be done after reading config.py.""" @@ -317,13 +320,15 @@ class ConfigAPI: with self._handle_error('reading', 'autoconfig.yml'): read_autoconfig() - def get(self, name): + def get(self, name, pattern=None): with self._handle_error('getting', name): - return self._config.get_mutable_obj(name) + urlpattern = urlmatch.UrlPattern(pattern) if pattern else None + return self._config.get_mutable_obj(name, pattern=urlpattern) - def set(self, name, value): + def set(self, name, value, pattern=None): with self._handle_error('setting', name): - self._config.set_obj(name, value) + urlpattern = urlmatch.UrlPattern(pattern) if pattern else None + self._config.set_obj(name, value, pattern=urlpattern) def bind(self, key, command, mode='normal'): with self._handle_error('binding', key): @@ -401,8 +406,7 @@ class ConfigPyWriter: def _gen_options(self): """Generate the options part of the config.""" - # FIXME:conf handle _pattern - for _pattern, opt, value in self._options: + for pattern, opt, value in self._options: if opt.name in ['bindings.commands', 'bindings.default']: continue @@ -421,7 +425,11 @@ class ConfigPyWriter: except KeyError: yield self._line("# - {}".format(val)) - yield self._line('c.{} = {!r}'.format(opt.name, value)) + if pattern is None: + yield self._line('c.{} = {!r}'.format(opt.name, value)) + else: + yield self._line('config.set({!r}, {!r}, {!r})'.format( + opt.name, value, str(pattern))) yield '' def _gen_bindings(self): diff --git a/tests/unit/config/test_configfiles.py b/tests/unit/config/test_configfiles.py index eadddf39b..56ed1c635 100644 --- a/tests/unit/config/test_configfiles.py +++ b/tests/unit/config/test_configfiles.py @@ -28,7 +28,7 @@ from PyQt5.QtCore import QSettings from qutebrowser.config import (config, configfiles, configexc, configdata, configtypes) -from qutebrowser.utils import utils, usertypes +from qutebrowser.utils import utils, usertypes, urlmatch @pytest.fixture(autouse=True) @@ -500,16 +500,29 @@ class TestConfigPy: @pytest.mark.parametrize('line', [ 'c.colors.hints.bg = "red"', 'config.set("colors.hints.bg", "red")', + 'config.set("colors.hints.bg", "red", pattern=None)', ]) def test_set(self, confpy, line): confpy.write(line) confpy.read() assert config.instance.get_obj('colors.hints.bg') == 'red' + def test_set_with_pattern(self, confpy): + option = 'content.javascript.enabled' + pattern = 'https://www.example.com/' + + confpy.write('config.set({!r}, False, {!r})'.format(option, pattern)) + confpy.read() + + assert config.instance.get_obj(option) + assert not config.instance.get_obj_for_pattern( + option, pattern=urlmatch.UrlPattern(pattern)) + @pytest.mark.parametrize('set_first', [True, False]) @pytest.mark.parametrize('get_line', [ 'c.colors.hints.fg', 'config.get("colors.hints.fg")', + 'config.get("colors.hints.fg", pattern=None)', ]) def test_get(self, confpy, set_first, get_line): """Test whether getting options works correctly.""" @@ -523,6 +536,24 @@ class TestConfigPy: confpy.write('assert {} == "green"'.format(get_line)) confpy.read() + def test_get_with_pattern(self, confpy): + """Test whether we get a matching value with a pattern.""" + option = 'content.javascript.enabled' + pattern = 'https://www.example.com/' + config.instance.set_obj(option, False, + pattern=urlmatch.UrlPattern(pattern)) + confpy.write('assert config.get({!r})'.format(option), + 'assert not config.get({!r}, pattern={!r})' + .format(option, pattern)) + confpy.read() + + def test_get_with_pattern_no_match(self, confpy): + confpy.write( + 'val = config.get("content.images", "https://www.example.com")', + 'assert val is True', + ) + confpy.read() + @pytest.mark.parametrize('line, mode', [ ('config.bind(",a", "message-info foo")', 'normal'), ('config.bind(",a", "message-info foo", "prompt")', 'prompt'), @@ -672,6 +703,21 @@ class TestConfigPy: "'qt.args')") assert str(error.exception) == expected + @pytest.mark.parametrize('line, action', [ + ('config.get("content.images", "://")', 'getting'), + ('config.set("content.images", False, "://")', 'setting'), + ]) + def test_invalid_pattern(self, confpy, line, action): + confpy.write(line) + + error = confpy.read(error=True) + + assert error.text == ("While {} 'content.images' and parsing pattern" + .format(action)) + assert isinstance(error.exception, urlmatch.ParseError) + assert str(error.exception) == "No scheme given" + assert error.traceback is None + def test_multiple_errors(self, confpy): confpy.write("c.foo = 42", "config.set('foo', 42)", "1/0") @@ -862,6 +908,20 @@ class TestConfigPyWriter: """).lstrip() assert text == expected + def test_pattern(self): + opt = configdata.Option( + name='opt', typ=configtypes.BoolAsk(), default='ask', + backends=[usertypes.Backend.QtWebEngine], raw_backends=None, + description='Hello World') + options = [ + (urlmatch.UrlPattern('https://www.example.com/'), opt, 'ask'), + ] + writer = configfiles.ConfigPyWriter(options=options, bindings={}, + commented=False) + text = '\n'.join(writer._gen_lines()) + expected = "config.set('opt', 'ask', 'https://www.example.com/')" + assert expected in text + def test_write(self, tmpdir): pyfile = tmpdir / 'config.py' writer = configfiles.ConfigPyWriter(options=[], bindings={},