From 888756d519ba1915c37e2da3e137f35c2e5e3cea Mon Sep 17 00:00:00 2001 From: nvbn Date: Tue, 21 Apr 2015 14:40:52 +0200 Subject: [PATCH] #74 Don't fail when rule throws exception --- tests/test_main.py | 27 +++++++++++++++------------ thefuck/main.py | 14 ++++++++++---- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index af8c09aa..0345bc2e 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -24,7 +24,7 @@ def test_load_rule(): return_value=Mock( match=match, get_new_command=get_new_command)) as load_source: - assert main.load_rule(Path('/rules/bash.py')) == main.Rule(match, get_new_command) + assert main.load_rule(Path('/rules/bash.py')) == main.Rule('bash', match, get_new_command) load_source.assert_called_once_with('bash', '/rules/bash.py') @@ -35,14 +35,14 @@ def test_get_rules(): glob.return_value = [PosixPath('bash.py'), PosixPath('lisp.py')] assert main.get_rules( Path('~'), - Mock(rules=None)) == [main.Rule('bash', 'bash'), - main.Rule('lisp', 'lisp'), - main.Rule('bash', 'bash'), - main.Rule('lisp', 'lisp')] + Mock(rules=None)) == [main.Rule('bash', 'bash', 'bash'), + main.Rule('lisp', 'lisp', 'lisp'), + main.Rule('bash', 'bash', 'bash'), + main.Rule('lisp', 'lisp', 'lisp')] assert main.get_rules( Path('~'), - Mock(rules=['bash'])) == [main.Rule('bash', 'bash'), - main.Rule('bash', 'bash')] + Mock(rules=['bash'])) == [main.Rule('bash', 'bash', 'bash'), + main.Rule('bash', 'bash', 'bash')] def test_get_command(): @@ -64,22 +64,25 @@ def test_get_command(): assert main.get_command(Mock(), ['']) is None -def test_get_matched_rule(): - rules = [main.Rule(lambda x, _: x.script == 'cd ..', None), - main.Rule(lambda *_: False, None)] +def test_get_matched_rule(capsys): + rules = [main.Rule('', lambda x, _: x.script == 'cd ..', None), + main.Rule('', lambda *_: False, None), + main.Rule('rule', Mock(side_effect=OSError('Denied')), None)] assert main.get_matched_rule(main.Command('ls', '', ''), rules, None) is None assert main.get_matched_rule(main.Command('cd ..', '', ''), rules, None) == rules[0] + assert capsys.readouterr()[1].split('\n')[0]\ + == '[WARN] rule: Traceback (most recent call last):' def test_run_rule(capsys): with patch('thefuck.main.confirm', return_value=True): - main.run_rule(main.Rule(None, lambda *_: 'new-command'), + main.run_rule(main.Rule('', None, lambda *_: 'new-command'), None, None) assert capsys.readouterr() == ('new-command\n', '') with patch('thefuck.main.confirm', return_value=False): - main.run_rule(main.Rule(None, lambda *_: 'new-command'), + main.run_rule(main.Rule('', None, lambda *_: 'new-command'), None, None) assert capsys.readouterr() == ('', '') diff --git a/thefuck/main.py b/thefuck/main.py index b3e0ee27..3c034d8f 100644 --- a/thefuck/main.py +++ b/thefuck/main.py @@ -5,11 +5,12 @@ from os.path import expanduser from subprocess import Popen, PIPE import os import sys +from traceback import format_exception from psutil import Process, TimeoutExpired Command = namedtuple('Command', ('script', 'stdout', 'stderr')) -Rule = namedtuple('Rule', ('match', 'get_new_command')) +Rule = namedtuple('Rule', ('name', 'match', 'get_new_command')) def setup_user_dir(): @@ -43,7 +44,8 @@ def is_rule_enabled(settings, rule): def load_rule(rule): """Imports rule module and returns it.""" rule_module = load_source(rule.name[:-3], str(rule)) - return Rule(rule_module.match, rule_module.get_new_command) + return Rule(rule.name[:-3], rule_module.match, + rule_module.get_new_command) def get_rules(user_dir, settings): @@ -94,8 +96,12 @@ def get_command(settings, args): def get_matched_rule(command, rules, settings): """Returns first matched rule for command.""" for rule in rules: - if rule.match(command, settings): - return rule + try: + if rule.match(command, settings): + return rule + except Exception: + sys.stderr.write(u'[WARN] {}: {}---------------------\n\n'.format( + rule.name, ''.join(format_exception(*sys.exc_info())))) def confirm(new_command, settings):