From 05f594b918d2bf6b718754218af652286da35ebb Mon Sep 17 00:00:00 2001 From: nvbn Date: Thu, 7 May 2015 13:11:45 +0200 Subject: [PATCH] #154 Add ability to override priority in settings --- README.md | 9 +++++++-- tests/test_conf.py | 8 ++++++-- tests/test_main.py | 22 +++++++++++++++------- thefuck/conf.py | 27 +++++++++++++++++++++------ thefuck/main.py | 3 ++- 5 files changed, 51 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 07ec8bb0..ee52858f 100644 --- a/README.md +++ b/README.md @@ -213,7 +213,8 @@ The Fuck has a few settings parameters, they can be changed in `~/.thefuck/setti * `rules` – list of enabled rules, by default `thefuck.conf.DEFAULT_RULES`; * `require_confirmation` – require confirmation before running new command, by default `False`; * `wait_command` – max amount of time in seconds for getting previous command output; -* `no_colors` – disable colored output. +* `no_colors` – disable colored output; +* `priority` – dict with rules priorities, rule with lower `priority` will be matched first. Example of `settings.py`: @@ -222,6 +223,7 @@ rules = ['sudo', 'no_command'] require_confirmation = True wait_command = 10 no_colors = False +priority = {'sudo': 100, 'no_command': 9999} ``` Or via environment variables: @@ -229,7 +231,9 @@ Or via environment variables: * `THEFUCK_RULES` – list of enabled rules, like `DEFAULT_RULES:rm_root` or `sudo:no_command`; * `THEFUCK_REQUIRE_CONFIRMATION` – require confirmation before running new command, `true/false`; * `THEFUCK_WAIT_COMMAND` – max amount of time in seconds for getting previous command output; -* `THEFUCK_NO_COLORS` – disable colored output, `true/false`. +* `THEFUCK_NO_COLORS` – disable colored output, `true/false`; +* `THEFUCK_PRIORITY` – priority of the rules, like `no_command=9999:apt_get=100`, +rule with lower `priority` will be matched first. For example: @@ -238,6 +242,7 @@ export THEFUCK_RULES='sudo:no_command' export THEFUCK_REQUIRE_CONFIRMATION='true' export THEFUCK_WAIT_COMMAND=10 export THEFUCK_NO_COLORS='false' +export THEFUCK_PRIORITY='no_command=9999:apt_get=100' ``` ## Developing diff --git a/tests/test_conf.py b/tests/test_conf.py index c5a8333b..3363a5e2 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -40,12 +40,14 @@ class TestSettingsFromFile(object): load_source.return_value = Mock(rules=['test'], wait_command=10, require_confirmation=True, - no_colors=True) + no_colors=True, + priority={'vim': 100}) settings = conf.get_settings(Mock()) assert settings.rules == ['test'] assert settings.wait_command == 10 assert settings.require_confirmation is True assert settings.no_colors is True + assert settings.priority == {'vim': 100} def test_from_file_with_DEFAULT(self, load_source): load_source.return_value = Mock(rules=conf.DEFAULT_RULES + ['test'], @@ -62,12 +64,14 @@ class TestSettingsFromEnv(object): environ.update({'THEFUCK_RULES': 'bash:lisp', 'THEFUCK_WAIT_COMMAND': '55', 'THEFUCK_REQUIRE_CONFIRMATION': 'true', - 'THEFUCK_NO_COLORS': 'false'}) + 'THEFUCK_NO_COLORS': 'false', + 'THEFUCK_PRIORITY': 'bash=10:lisp=wrong:vim=15'}) settings = conf.get_settings(Mock()) assert settings.rules == ['bash', 'lisp'] assert settings.wait_command == 55 assert settings.require_confirmation is True assert settings.no_colors is False + assert settings.priority == {'bash': 10, 'vim': 15} def test_from_env_with_DEFAULT(self, environ): environ.update({'THEFUCK_RULES': 'DEFAULT_RULES:bash:lisp'}) diff --git a/tests/test_main.py b/tests/test_main.py index de750510..44b4beef 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -38,17 +38,25 @@ class TestGetRules(object): monkeypatch.setattr('thefuck.main.load_source', lambda x, _: Rule(x)) assert self._compare_names( - main.get_rules(Path('~'), Mock(rules=conf_rules)), rules) + main.get_rules(Path('~'), Mock(rules=conf_rules, priority={})), + rules) - @pytest.mark.parametrize('unordered, ordered', [ - ([Rule('bash', priority=100), Rule('python', priority=5)], + @pytest.mark.parametrize('priority, unordered, ordered', [ + ({}, + [Rule('bash', priority=100), Rule('python', priority=5)], ['python', 'bash']), - ([Rule('lisp', priority=9999), Rule('c', priority=conf.DEFAULT_PRIORITY)], - ['c', 'lisp'])]) - def test_ordered_by_priority(self, monkeypatch, unordered, ordered): + ({}, + [Rule('lisp', priority=9999), Rule('c', priority=conf.DEFAULT_PRIORITY)], + ['c', 'lisp']), + ({'python': 9999}, + [Rule('bash', priority=100), Rule('python', priority=5)], + ['bash', 'python'])]) + def test_ordered_by_priority(self, monkeypatch, priority, unordered, ordered): monkeypatch.setattr('thefuck.main._get_loaded_rules', lambda *_: unordered) - assert self._compare_names(main.get_rules(Path('~'), Mock()), ordered) + assert self._compare_names( + main.get_rules(Path('~'), Mock(priority=priority)), + ordered) class TestGetCommand(object): diff --git a/thefuck/conf.py b/thefuck/conf.py index 4bc01e70..916d216f 100644 --- a/thefuck/conf.py +++ b/thefuck/conf.py @@ -28,12 +28,14 @@ DEFAULT_PRIORITY = 1000 DEFAULT_SETTINGS = {'rules': DEFAULT_RULES, 'wait_command': 3, 'require_confirmation': False, - 'no_colors': False} + 'no_colors': False, + 'priority': {}} ENV_TO_ATTR = {'THEFUCK_RULES': 'rules', 'THEFUCK_WAIT_COMMAND': 'wait_command', 'THEFUCK_REQUIRE_CONFIRMATION': 'require_confirmation', - 'THEFUCK_NO_COLORS': 'no_colors'} + 'THEFUCK_NO_COLORS': 'no_colors', + 'THEFUCK_PRIORITY': 'priority'} SETTINGS_HEADER = u"""# ~/.thefuck/settings.py: The Fuck settings file @@ -66,16 +68,29 @@ def _rules_from_env(val): return val +def _priority_from_env(val): + """Gets priority pairs from env.""" + for part in val.split(':'): + try: + rule, priority = part.split('=') + yield rule, int(priority) + except ValueError: + continue + + def _val_from_env(env, attr): """Transforms env-strings to python.""" val = os.environ[env] if attr == 'rules': - val = _rules_from_env(val) + return _rules_from_env(val) + elif attr == 'priority': + return dict(_priority_from_env(val)) elif attr == 'wait_command': - val = int(val) + return int(val) elif attr in ('require_confirmation', 'no_colors'): - val = val.lower() == 'true' - return val + return val.lower() == 'true' + else: + return val def _settings_from_env(): diff --git a/thefuck/main.py b/thefuck/main.py index 434d7ebd..27a0095c 100644 --- a/thefuck/main.py +++ b/thefuck/main.py @@ -46,7 +46,8 @@ def get_rules(user_dir, settings): .glob('*.py') user = user_dir.joinpath('rules').glob('*.py') rules = _get_loaded_rules(sorted(bundled) + sorted(user), settings) - return sorted(rules, key=lambda rule: rule.priority) + return sorted(rules, key=lambda rule: settings.priority.get( + rule.name, rule.priority)) def wait_output(settings, popen):