From 4a2f869c6d6ef03d8d7ada1121cc6631d7ef979e Mon Sep 17 00:00:00 2001 From: mcarton Date: Mon, 17 Aug 2015 14:11:06 +0200 Subject: [PATCH] Add support for stdout in the fix_file rule At least `pep8` and `py.test` consider errors as normal and print them on stdout. --- tests/rules/test_fix_file.py | 80 ++++++++++++++++++++++++------------ thefuck/rules/fix_file.py | 16 ++++---- 2 files changed, 62 insertions(+), 34 deletions(-) diff --git a/tests/rules/test_fix_file.py b/tests/rules/test_fix_file.py index bdbdebee..7cacd97e 100644 --- a/tests/rules/test_fix_file.py +++ b/tests/rules/test_fix_file.py @@ -4,9 +4,9 @@ from thefuck.rules.fix_file import match, get_new_command from tests.utils import Command -# (script, file, line, col (or None), stderr) +# (script, file, line, col (or None), stdout, stderr) tests = ( -('gcc a.c', 'a.c', 3, 1, +('gcc a.c', 'a.c', 3, 1, '', """ a.c: In function 'main': a.c:3:1: error: expected expression before '}' token @@ -14,47 +14,47 @@ a.c:3:1: error: expected expression before '}' token ^ """), -('clang a.c', 'a.c', 3, 1, +('clang a.c', 'a.c', 3, 1, '', """ a.c:3:1: error: expected expression } ^ """), -('perl a.pl', 'a.pl', 3, None, +('perl a.pl', 'a.pl', 3, None, '', """ syntax error at a.pl line 3, at EOF Execution of a.pl aborted due to compilation errors. """), -('perl a.pl', 'a.pl', 2, None, +('perl a.pl', 'a.pl', 2, None, '', """ Search pattern not terminated at a.pl line 2. """), -('sh a.sh', 'a.sh', 2, None, +('sh a.sh', 'a.sh', 2, None, '', """ a.sh: line 2: foo: command not found """), -('zsh a.sh', 'a.sh', 2, None, +('zsh a.sh', 'a.sh', 2, None, '', """ a.sh:2: command not found: foo """), -('bash a.sh', 'a.sh', 2, None, +('bash a.sh', 'a.sh', 2, None, '', """ a.sh: line 2: foo: command not found """), -('rustc a.rs', 'a.rs', 2, 5, +('rustc a.rs', 'a.rs', 2, 5, '', """ a.rs:2:5: 2:6 error: unexpected token: `+` a.rs:2 + ^ """), -('cargo build', 'src/lib.rs', 3, 5, +('cargo build', 'src/lib.rs', 3, 5, '', """ Compiling test v0.1.0 (file:///tmp/fix-error/test) src/lib.rs:3:5: 3:6 error: unexpected token: `+` @@ -65,7 +65,7 @@ Could not compile `test`. To learn more, run the command again with --verbose. """), -('python a.py', 'a.py', 2, None, +('python a.py', 'a.py', 2, None, '', """ File "a.py", line 2 + @@ -73,7 +73,7 @@ To learn more, run the command again with --verbose. SyntaxError: invalid syntax """), -('python a.py', 'a.py', 8, None, +('python a.py', 'a.py', 8, None, '', """ Traceback (most recent call last): File "a.py", line 8, in @@ -87,43 +87,43 @@ Traceback (most recent call last): TypeError: first argument must be string or compiled pattern """), -('ruby a.rb', 'a.rb', 3, None, +('ruby a.rb', 'a.rb', 3, None, '', """ a.rb:3: syntax error, unexpected keyword_end """), -('lua a.lua', 'a.lua', 2, None, +('lua a.lua', 'a.lua', 2, None, '', """ lua: a.lua:2: unexpected symbol near '+' """), -('fish a.sh', '/tmp/fix-error/a.sh', 2, None, +('fish a.sh', '/tmp/fix-error/a.sh', 2, None, '', """ fish: Unknown command 'foo' /tmp/fix-error/a.sh (line 2): foo ^ """), -('./a', './a', 2, None, +('./a', './a', 2, None, '', """ awk: ./a:2: BEGIN { print "Hello, world!" + } awk: ./a:2: ^ syntax error """), -('llc a.ll', 'a.ll', 1, None, +('llc a.ll', 'a.ll', 1, None, '', """ llc: a.ll:1:1: error: expected top-level entity + ^ """), -('go build a.go', 'a.go', 1, None, +('go build a.go', 'a.go', 1, None, '', """ can't load package: a.go:1:1: expected 'package', found '+' """), -('make', 'Makefile', 2, None, +('make', 'Makefile', 2, None, '', """ bidule make: bidule: Command not found @@ -131,12 +131,12 @@ Makefile:2: recipe for target 'target' failed make: *** [target] Error 127 """), -('git st', '/home/martin/.config/git/config', 1, None, +('git st', '/home/martin/.config/git/config', 1, None, '', """ fatal: bad config file line 1 in /home/martin/.config/git/config """), -('node fuck.js asdf qwer', '/Users/pablo/Workspace/barebones/fuck.js', '2', 5, +('node fuck.js asdf qwer', '/Users/pablo/Workspace/barebones/fuck.js', '2', 5, '', """ /Users/pablo/Workspace/barebones/fuck.js:2 conole.log(arg); // this should read console.log(arg); @@ -153,35 +153,63 @@ ReferenceError: conole is not defined at startup (node.js:129:16) at node.js:814:3 """), + +('pep8', './tests/rules/test_systemctl.py', 17, 80, +""" +./tests/rules/test_systemctl.py:17:80: E501 line too long (93 > 79 characters) +./tests/rules/test_systemctl.py:18:80: E501 line too long (103 > 79 characters) +./tests/rules/test_whois.py:20:80: E501 line too long (89 > 79 characters) +./tests/rules/test_whois.py:22:80: E501 line too long (83 > 79 characters) +""", ''), + +('py.test', '/home/thefuck/tests/rules/test_fix_file.py', 218, None, +""" +monkeypatch = <_pytest.monkeypatch.monkeypatch object at 0x7fdb76a25b38> +test = ('fish a.sh', '/tmp/fix-error/a.sh', 2, None, '', "\\nfish: Unknown command 'foo'\\n/tmp/fix-error/a.sh (line 2): foo\\n ^\\n") + + @pytest.mark.parametrize('test', tests) + @pytest.mark.usefixtures('no_memoize') + def test_get_new_command(monkeypatch, test): +> mocker.patch('os.path.isfile', return_value=True) +E NameError: name 'mocker' is not defined + +/home/thefuck/tests/rules/test_fix_file.py:218: NameError +""", ''), ) @pytest.mark.parametrize('test', tests) +@pytest.mark.usefixtures('no_memoize') def test_match(mocker, monkeypatch, test): mocker.patch('os.path.isfile', return_value=True) monkeypatch.setenv('EDITOR', 'dummy_editor') - assert match(Command(stderr=test[4]), None) + assert match(Command(stdout=test[4], stderr=test[5]), None) @pytest.mark.parametrize('test', tests) +@pytest.mark.usefixtures('no_memoize') def test_no_editor(mocker, monkeypatch, test): mocker.patch('os.path.isfile', return_value=True) if 'EDITOR' in os.environ: monkeypatch.delenv('EDITOR') - assert not match(Command(stderr=test[4]), None) + assert not match(Command(stdout=test[4], stderr=test[5]), None) @pytest.mark.parametrize('test', tests) +@pytest.mark.usefixtures('no_memoize') def test_not_file(mocker, monkeypatch, test): mocker.patch('os.path.isfile', return_value=False) monkeypatch.setenv('EDITOR', 'dummy_editor') - assert not match(Command(stderr=test[4]), None) + assert not match(Command(stdout=test[4], stderr=test[5]), None) @pytest.mark.parametrize('test', tests) -def test_get_new_command(monkeypatch, test): +@pytest.mark.usefixtures('no_memoize') +def test_get_new_command(mocker, monkeypatch, test): + mocker.patch('os.path.isfile', return_value=True) monkeypatch.setenv('EDITOR', 'dummy_editor') - assert (get_new_command(Command(script=test[0], stderr=test[4]), None) == + cmd = Command(script=test[0], stdout=test[4], stderr=test[5]) + assert (get_new_command(cmd, None) == 'dummy_editor {} +{} && {}'.format(test[1], test[2], test[0])) diff --git a/thefuck/rules/fix_file.py b/thefuck/rules/fix_file.py index 28b17ba1..a64b10c2 100644 --- a/thefuck/rules/fix_file.py +++ b/thefuck/rules/fix_file.py @@ -25,7 +25,7 @@ patterns = ( '^{file}: line {line}: ', # ghc, make, ruby, zsh: '^{file}:{line}:', - # cargo, clang, gcc, go, rustc: + # cargo, clang, gcc, go, pep8, rustc: '^{file}:{line}:{col}', # perl: 'at {file} line {line}', @@ -45,7 +45,7 @@ patterns = [_make_pattern(p) for p in patterns] def _search(stderr): for pattern in patterns: m = re.search(pattern, stderr) - if m: + if m and os.path.isfile(m.group('file')): return m @@ -53,15 +53,15 @@ def match(command, settings): if 'EDITOR' not in os.environ: return False - m = _search(command.stderr) - - return m and os.path.isfile(m.group('file')) + return _search(command.stderr) or _search(command.stdout) def get_new_command(command, settings): - m = _search(command.stderr) + m = _search(command.stderr) or _search(command.stdout) # Note: there does not seem to be a standard for columns, so they are just # ignored for now - return shells.and_('{} {} +{}'.format(os.environ['EDITOR'], m.group('file'), m.group('line')), - command.script) + editor_call = '{} {} +{}'.format(os.environ['EDITOR'], + m.group('file'), + m.group('line')) + return shells.and_(editor_call, command.script)