From de343b84c1a58831fd711b1d70405aa574ae180a Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Sat, 18 Apr 2015 10:52:00 -0500 Subject: [PATCH 1/4] improve no_command rule --- tests/rules/test_no_command.py | 4 ++-- thefuck/rules/no_command.py | 25 ++++++++++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/tests/rules/test_no_command.py b/tests/rules/test_no_command.py index 5598378..8572785 100644 --- a/tests/rules/test_no_command.py +++ b/tests/rules/test_no_command.py @@ -39,7 +39,7 @@ def test_match(command_found, command_not_found, settings): with patch('thefuck.rules.no_command.Popen') as Popen: Popen.return_value.stderr.read.return_value = command_found assert match(Command('aptget install vim', '', ''), settings) - Popen.assert_called_once_with('/usr/lib/command-not-found aptget', + Popen.assert_called_with('/usr/lib/command-not-found aptget', shell=True, stderr=PIPE) Popen.return_value.stderr.read.return_value = command_not_found assert not match(Command('ls', '', ''), settings) @@ -48,7 +48,7 @@ def test_match(command_found, command_not_found, settings): Popen.return_value.stderr.read.return_value = command_found assert match(Command('sudo aptget install vim', '', ''), Mock(command_not_found='test')) - Popen.assert_called_once_with('test aptget', + Popen.assert_called_with('test aptget', shell=True, stderr=PIPE) diff --git a/thefuck/rules/no_command.py b/thefuck/rules/no_command.py index cf05837..ad778ac 100644 --- a/thefuck/rules/no_command.py +++ b/thefuck/rules/no_command.py @@ -2,7 +2,6 @@ from subprocess import Popen, PIPE import re from thefuck.utils import which, wrap_settings - local_settings = {'command_not_found': '/usr/lib/command-not-found'} @@ -12,12 +11,27 @@ def _get_output(command, settings): result = Popen(check_script, shell=True, stderr=PIPE) return result.stderr.read().decode() +def _count_history_uses(name): + script = 'history | grep {}'.format(name) + result = Popen(script, shell=True, stdout=PIPE) + return len(list(result.stdout)) + +def _get_candidate_commands(command, settings): + output = _get_output(command, settings) + if "No command" in output and "from package" in output: + fixed_names = re.findall(r"Command '([^']*)' from package", + output) + return filter(which, fixed_names) + return [] + + @wrap_settings(local_settings) def match(command, settings): if which(settings.command_not_found): output = _get_output(command, settings) - return "No command" in output and "from package" in output + return len(_get_candidate_commands(command, settings)) != 0 + @wrap_settings(local_settings) @@ -25,6 +39,7 @@ def get_new_command(command, settings): output = _get_output(command, settings) broken_name = re.findall(r"No command '([^']*)' found", output)[0] - fixed_name = re.findall(r"Command '([^']*)' from package", - output)[0] - return command.script.replace(broken_name, fixed_name, 1) + candidates = _get_candidate_commands(command, settings) + fixed_name = sorted(candidates, key=_count_history_uses)[0] + return command.script.replace(broken_name, fixed_name) + From ac545c6f0ae6012460b4bcc45e37ad604ee60b7e Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Sat, 18 Apr 2015 16:32:50 -0500 Subject: [PATCH 2/4] improve no_comamnd rule, test it --- tests/rules/test_no_command.py | 43 ++++++++++++++++++++++++++++++---- thefuck/rules/no_command.py | 9 +++---- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/tests/rules/test_no_command.py b/tests/rules/test_no_command.py index 8572785..015c70b 100644 --- a/tests/rules/test_no_command.py +++ b/tests/rules/test_no_command.py @@ -9,16 +9,27 @@ from thefuck.main import Command def command_found(): return b'''No command 'aptget' found, did you mean: Command 'apt-get' from package 'apt' (main) + Command 'not-installed' from package 'derp' (main) + Command 'not-really-used' from package 'whatever' (main) aptget: command not found ''' +@pytest.fixture +def uninstalled_command_found(): + return b'''No command 'pish' found, did you mean: + Command 'vish' from package 'vish' (universe) + Command 'wish' from package 'tk' (main) + Command 'fish' from package 'fish' (universe) + Command 'pdsh' from package 'pdsh' (universe) +pish: command not found +''' + @pytest.fixture def command_not_found(): return b'''No command 'vom' found, but there are 19 similar ones vom: command not found ''' - @pytest.fixture def bins_exists(request): p = patch('thefuck.rules.no_command.which', @@ -26,6 +37,27 @@ def bins_exists(request): p.start() request.addfinalizer(p.stop) +@pytest.fixture +def bin_might_exist(request): + def side_effect(name): + return name in ['not-really-used', 'apt-get', '/usr/lib/command-not-found', 'test'] + p = patch('thefuck.rules.no_command.which', + side_effect = side_effect) + p.start() + request.addfinalizer(p.stop) + + +@pytest.fixture +def patch_history(request): + def side_effect(name): + print("history('{}')".format(name)) + count = 2 if name == 'not-really-used' else 12 + p = patch('thefuck.rules.no_command._count_history_uses', + side_effect = side_effect) + p.start() + request.addfinalizer(p.stop) + + @pytest.fixture def settings(): @@ -34,8 +66,8 @@ def settings(): return _Settings -@pytest.mark.usefixtures('bins_exists') -def test_match(command_found, command_not_found, settings): +@pytest.mark.usefixtures('bin_might_exist', 'patch_history') +def test_match(command_found, command_not_found, uninstalled_command_found, settings): with patch('thefuck.rules.no_command.Popen') as Popen: Popen.return_value.stderr.read.return_value = command_found assert match(Command('aptget install vim', '', ''), settings) @@ -51,8 +83,11 @@ def test_match(command_found, command_not_found, settings): Popen.assert_called_with('test aptget', shell=True, stderr=PIPE) + with patch('thefuck.rules.no_command.Popen') as Popen: + Popen.return_value.stderr.read.return_value = uninstalled_command_found + assert not match(Command('pish bla blah', '', ''), settings) -@pytest.mark.usefixtures('bins_exists') +@pytest.mark.usefixtures('bin_might_exist', 'patch_history') def test_get_new_command(command_found): with patch('thefuck.rules.no_command._get_output', return_value=command_found.decode()): diff --git a/thefuck/rules/no_command.py b/thefuck/rules/no_command.py index ad778ac..7e7aa48 100644 --- a/thefuck/rules/no_command.py +++ b/thefuck/rules/no_command.py @@ -12,9 +12,10 @@ def _get_output(command, settings): return result.stderr.read().decode() def _count_history_uses(name): - script = 'history | grep {}'.format(name) - result = Popen(script, shell=True, stdout=PIPE) - return len(list(result.stdout)) + script = "history | egrep '\\b{}\\b' | wc -l".format(name) + result = Popen(script, shell=True, + stdout=PIPE) + return int(result.stdout.read()) def _get_candidate_commands(command, settings): output = _get_output(command, settings) @@ -40,6 +41,6 @@ def get_new_command(command, settings): broken_name = re.findall(r"No command '([^']*)' found", output)[0] candidates = _get_candidate_commands(command, settings) - fixed_name = sorted(candidates, key=_count_history_uses)[0] + fixed_name = sorted(candidates, key=_count_history_uses, reverse=True)[0] return command.script.replace(broken_name, fixed_name) From 8a2bc75e555cec399f02f51fcc04e0f4a88f8bdb Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Sat, 18 Apr 2015 16:46:02 -0500 Subject: [PATCH 3/4] make it python 3 friendly --- thefuck/rules/no_command.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thefuck/rules/no_command.py b/thefuck/rules/no_command.py index 7e7aa48..0b3f903 100644 --- a/thefuck/rules/no_command.py +++ b/thefuck/rules/no_command.py @@ -22,7 +22,7 @@ def _get_candidate_commands(command, settings): if "No command" in output and "from package" in output: fixed_names = re.findall(r"Command '([^']*)' from package", output) - return filter(which, fixed_names) + return [name for name in fixed_names if which(name)] return [] From cc1a69fb6526a6b9d0e3bcab3825496eded350d3 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Sat, 18 Apr 2015 16:49:26 -0500 Subject: [PATCH 4/4] another oopsie that was revealed in python3 --- tests/rules/test_no_command.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/rules/test_no_command.py b/tests/rules/test_no_command.py index 015c70b..0839213 100644 --- a/tests/rules/test_no_command.py +++ b/tests/rules/test_no_command.py @@ -50,8 +50,7 @@ def bin_might_exist(request): @pytest.fixture def patch_history(request): def side_effect(name): - print("history('{}')".format(name)) - count = 2 if name == 'not-really-used' else 12 + return 2 if name == 'not-really-used' else 12 p = patch('thefuck.rules.no_command._count_history_uses', side_effect = side_effect) p.start()