Skip to content

Commit adcc033

Browse files
committed
add python-module-error rule
1 parent 40dd659 commit adcc033

File tree

3 files changed

+74
-0
lines changed

3 files changed

+74
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ following rules are enabled by default:
281281
* `pyenv_no_such_command` – fixes wrong pyenv commands like `pyenv isntall` or `pyenv list`;
282282
* `python_command` – prepends `python` when you try to run non-executable/without `./` python script;
283283
* `python_execute` – appends missing `.py` when executing Python files;
284+
* `python_module_error` – fixes ModuleNotFoundError by trying to `pip install` that module;
284285
* `quotation_marks` – fixes uneven usage of `'` and `"` when containing args';
285286
* `path_from_history` – replaces not found path with similar absolute path from history;
286287
* `react_native_command_unrecognized` – fixes unrecognized `react-native` commands;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import pytest
2+
from thefuck.rules.python_module_error import match, get_new_command
3+
from thefuck.types import Command
4+
from thefuck.shells import shell
5+
6+
from collections import namedtuple
7+
8+
ModuleNotFoundTest = namedtuple("ModuleNotFoundTest", ["script", "corrected"])
9+
10+
positive_tests = [
11+
ModuleNotFoundTest(
12+
Command(
13+
"python some_script.py",
14+
"""Traceback (most recent call last):
15+
File "some_script.py", line 1, in <module>
16+
import more_itertools
17+
ModuleNotFoundError: No module named 'more_itertools'""",
18+
),
19+
shell.and_("pip install more_itertools", "python some_script.py"),
20+
),
21+
ModuleNotFoundTest(
22+
Command(
23+
"./some_other_script.py",
24+
"""Traceback (most recent call last):
25+
File "some_other_script.py", line 1, in <module>
26+
from a_module import a_function
27+
ModuleNotFoundError: No module named 'a_module'""",
28+
),
29+
shell.and_("pip install a_module", "./some_other_script.py"),
30+
),
31+
]
32+
33+
negative_tests = [
34+
ModuleNotFoundTest(Command("python hello_world.py", "Hello World"), None),
35+
ModuleNotFoundTest(
36+
Command(
37+
"./hello_world.py",
38+
"""Traceback (most recent call last):
39+
File "hello_world.py", line 1, in <module>
40+
pritn("Hello World")
41+
NameError: name 'pritn' is not defined""",
42+
),
43+
None,
44+
),
45+
]
46+
47+
48+
@pytest.mark.parametrize("test", negative_tests)
49+
def test_not_match(test):
50+
assert not match(test.script)
51+
52+
53+
@pytest.mark.parametrize("test", positive_tests)
54+
def test_match(test):
55+
assert match(test.script)
56+
57+
58+
@pytest.mark.parametrize("test", positive_tests)
59+
def test_get_new_command(test):
60+
assert get_new_command(test.script) == test.corrected
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import re
2+
from thefuck.shells import shell
3+
4+
MISSING_MODULE = r"ModuleNotFoundError: No module named '([^']+)'"
5+
6+
7+
def match(command):
8+
return "ModuleNotFoundError: No module named '" in command.output
9+
10+
11+
def get_new_command(command):
12+
missing_module = re.findall(MISSING_MODULE, command.output)[0]
13+
return shell.and_("pip install {}".format(missing_module), command.script)

0 commit comments

Comments
 (0)