tools: Not detecting the type of python files. Assuming python3.
- Also now not using any tools that depend on python2. - Simplifies installation. - Personally not using python2. - Eris is not used widely enough to justify supporting python2 files. - The way of determining whether a source file was python2 or python3 was not very good.
This commit is contained in:
parent
7d412ec8f1
commit
85a5840cff
17 changed files with 53 additions and 140 deletions
111
eris/tools.py
111
eris/tools.py
|
|
@ -239,7 +239,7 @@ def metadata(path):
|
|||
return (Status.normal, fill3.Text(fill3.join("", text)))
|
||||
|
||||
|
||||
@deps(deps={"pip3/pygments"}, url="python3-pygments")
|
||||
@deps(deps={"pip/pygments"}, url="python3-pygments")
|
||||
def contents(path):
|
||||
with open(path) as file_:
|
||||
try:
|
||||
|
|
@ -254,35 +254,17 @@ def contents(path):
|
|||
return Status.normal, text_widget
|
||||
|
||||
|
||||
def _is_python_syntax_correct(path, python_version):
|
||||
if python_version == "python":
|
||||
stdin, stdout, returncode = _do_command(
|
||||
["python", "-c",
|
||||
f"__import__('compiler').parse(open('{path}').read())"])
|
||||
return returncode == 0
|
||||
else: # python3
|
||||
@deps(url="https://en.wikipedia.org/wiki/Python_syntax_and_semantics")
|
||||
def python_syntax(path):
|
||||
with open(path) as f:
|
||||
source = f.read()
|
||||
try:
|
||||
ast.parse(source)
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _python_version(path): # Need a better hueristic
|
||||
for version in [PYTHON_EXECUTABLE, "python"]:
|
||||
if _is_python_syntax_correct(path, version):
|
||||
return version
|
||||
return PYTHON_EXECUTABLE
|
||||
|
||||
|
||||
@deps(deps={"python"},
|
||||
url="https://en.wikipedia.org/wiki/Python_syntax_and_semantics")
|
||||
def python_syntax(path):
|
||||
status = (Status.ok if _is_python_syntax_correct(path, "python") or
|
||||
_is_python_syntax_correct(path, "python3") else Status.problem)
|
||||
return status, fill3.Text("")
|
||||
except SyntaxError:
|
||||
is_correct = False
|
||||
else:
|
||||
is_correct = True
|
||||
return (Status.ok if is_correct else Status.problem), fill3.Text("")
|
||||
|
||||
|
||||
def _has_shebang_line(path):
|
||||
|
|
@ -295,12 +277,11 @@ def _is_python_test_file(path):
|
|||
return path.endswith("_test.py") or path.startswith("test_")
|
||||
|
||||
|
||||
@deps(deps={"python", "python3"},
|
||||
url="https://docs.python.org/3/library/unittest.html")
|
||||
@deps(url="https://docs.python.org/3/library/unittest.html")
|
||||
def python_unittests(path):
|
||||
if _is_python_test_file(path):
|
||||
command = ([path] if _has_shebang_line(path)
|
||||
else [_python_version(path), path])
|
||||
else [PYTHON_EXECUTABLE, path])
|
||||
stdout, stderr, returncode = _do_command(command, timeout=TIMEOUT)
|
||||
status = Status.ok if returncode == 0 else Status.problem
|
||||
return status, fill3.Text(stdout + "\n" + stderr)
|
||||
|
|
@ -308,11 +289,10 @@ def python_unittests(path):
|
|||
return Status.not_applicable, fill3.Text("No tests.")
|
||||
|
||||
|
||||
@deps(deps={"python", "python3"},
|
||||
url="https://docs.python.org/3/library/pydoc.html")
|
||||
@deps(url="https://docs.python.org/3/library/pydoc.html")
|
||||
def pydoc(path):
|
||||
stdout, stderr, returncode = _do_command(
|
||||
[_python_version(path), "-m", "pydoc", path], timeout=TIMEOUT)
|
||||
[PYTHON_EXECUTABLE, "-m", "pydoc", path], timeout=TIMEOUT)
|
||||
status = Status.normal if returncode == 0 else Status.not_applicable
|
||||
if not stdout.startswith("Help on module"):
|
||||
status = Status.not_applicable
|
||||
|
|
@ -320,7 +300,7 @@ def pydoc(path):
|
|||
return status, fill3.Text(_fix_input(stdout))
|
||||
|
||||
|
||||
@deps(deps={"pip3/mypy"}, url="http://mypy-lang.org/", executables={"mypy"})
|
||||
@deps(deps={"pip/mypy"}, url="http://mypy-lang.org/", executables={"mypy"})
|
||||
def mypy(path):
|
||||
stdout, stderr, returncode = _do_command(
|
||||
[PYTHON_EXECUTABLE, "-m", "mypy", path], timeout=TIMEOUT)
|
||||
|
|
@ -335,14 +315,13 @@ def _colorize_coverage_report(text):
|
|||
for line in text.splitlines(keepends=True)])
|
||||
|
||||
|
||||
@deps(deps={"pip/coverage", "pip3/coverage"},
|
||||
url="https://coverage.readthedocs.io/")
|
||||
@deps(deps={"pip/coverage"}, url="https://coverage.readthedocs.io/")
|
||||
def python_coverage(path):
|
||||
# FIX: Also use test_*.py files.
|
||||
test_path = path[:-(len(".py"))] + "_test.py"
|
||||
if os.path.exists(test_path):
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
coverage_cmd = [_python_version(path), "-m", "coverage"]
|
||||
coverage_cmd = [PYTHON_EXECUTABLE, "-m", "coverage"]
|
||||
coverage_path = os.path.join(temp_dir, "coverage")
|
||||
env = os.environ.copy()
|
||||
env["COVERAGE_FILE"] = coverage_path
|
||||
|
|
@ -361,28 +340,25 @@ def python_coverage(path):
|
|||
"No corresponding test file: " + os.path.normpath(test_path))
|
||||
|
||||
|
||||
@deps(deps={"pip/pycodestyle", "pip3/pycodestyle"},
|
||||
url="http://pycodestyle.pycqa.org/en/latest/")
|
||||
@deps(deps={"pip/pycodestyle"}, url="http://pycodestyle.pycqa.org/en/latest/")
|
||||
def pycodestyle(path):
|
||||
return _run_command([_python_version(path), "-m", "pycodestyle", path])
|
||||
return _run_command([PYTHON_EXECUTABLE, "-m", "pycodestyle", path])
|
||||
|
||||
|
||||
@deps(deps={"pip/pydocstyle", "pip3/pydocstyle"},
|
||||
url="http://pycodestyle.pycqa.org/en/latest/")
|
||||
@deps(deps={"pip/pydocstyle"}, url="http://pycodestyle.pycqa.org/en/latest/")
|
||||
def pydocstyle(path):
|
||||
return _run_command([_python_version(path), "-m", "pydocstyle", path])
|
||||
return _run_command([PYTHON_EXECUTABLE, "-m", "pydocstyle", path])
|
||||
|
||||
|
||||
@deps(deps={"pip/pyflakes", "pip3/pyflakes"},
|
||||
url="https://pypi.org/project/pyflakes/")
|
||||
@deps(deps={"pip/pyflakes"}, url="https://pypi.org/project/pyflakes/")
|
||||
def pyflakes(path):
|
||||
return _run_command([_python_version(path), "-m", "pyflakes", path])
|
||||
return _run_command([PYTHON_EXECUTABLE, "-m", "pyflakes", path])
|
||||
|
||||
|
||||
@deps(deps={"pip/pylint", "pip3/pylint"}, url="https://www.pylint.org/")
|
||||
@deps(deps={"pip/pylint"}, url="https://www.pylint.org/")
|
||||
def pylint(path):
|
||||
return _run_command([_python_version(path), "-m", "pylint",
|
||||
"--errors-only", path])
|
||||
return _run_command([PYTHON_EXECUTABLE, "-m", "pylint", "--errors-only",
|
||||
path])
|
||||
|
||||
|
||||
@deps(url="https://github.com/ahamilton/eris/blob/master/gut.py")
|
||||
|
|
@ -393,59 +369,52 @@ def python_gut(path):
|
|||
return Status.normal, source_widget
|
||||
|
||||
|
||||
@deps(deps={"python", "python3"},
|
||||
url="https://docs.python.org/3/library/modulefinder.html")
|
||||
@deps(url="https://docs.python.org/3/library/modulefinder.html")
|
||||
def python_modulefinder(path):
|
||||
return _run_command([_python_version(path), "-m", "modulefinder", path],
|
||||
return _run_command([PYTHON_EXECUTABLE, "-m", "modulefinder", path],
|
||||
Status.normal)
|
||||
|
||||
|
||||
@deps(deps={"python", "python3"},
|
||||
url="https://docs.python.org/3/library/dis.html")
|
||||
@deps(url="https://docs.python.org/3/library/dis.html")
|
||||
def dis(path):
|
||||
return _run_command([_python_version(path), "-m", "dis", path],
|
||||
Status.normal)
|
||||
return _run_command([PYTHON_EXECUTABLE, "-m", "dis", path], Status.normal)
|
||||
|
||||
|
||||
def _get_mccabe_line_score(line, python_version):
|
||||
def _get_mccabe_line_score(line):
|
||||
position, function_name, score = line.split()
|
||||
return int(score if python_version == PYTHON_EXECUTABLE else score[:-1])
|
||||
return int(score)
|
||||
|
||||
|
||||
def _colorize_mccabe(text, python_version):
|
||||
def _colorize_mccabe(text):
|
||||
return fill3.join("", [
|
||||
termstr.TermStr(line).fg_color(termstr.Color.yellow)
|
||||
if _get_mccabe_line_score(line, python_version) > 10 else line
|
||||
if _get_mccabe_line_score(line) > 10 else line
|
||||
for line in text.splitlines(keepends=True)])
|
||||
|
||||
|
||||
@deps(deps={"pip/mccabe", "pip3/mccabe"},
|
||||
url="https://pypi.org/project/mccabe/")
|
||||
@deps(deps={"pip/mccabe"}, url="https://pypi.org/project/mccabe/")
|
||||
def python_mccabe(path):
|
||||
python_version = _python_version(path)
|
||||
stdout, *rest = _do_command([python_version, "-m", "mccabe", path])
|
||||
stdout, *rest = _do_command([PYTHON_EXECUTABLE, "-m", "mccabe", path])
|
||||
max_score = 0
|
||||
with contextlib.suppress(ValueError): # When there are no lines
|
||||
max_score = max(_get_mccabe_line_score(line, python_version)
|
||||
max_score = max(_get_mccabe_line_score(line)
|
||||
for line in stdout.splitlines())
|
||||
status = Status.problem if max_score > 10 else Status.ok
|
||||
return status, fill3.Text(_colorize_mccabe(stdout, python_version))
|
||||
return status, fill3.Text(_colorize_mccabe(stdout))
|
||||
|
||||
|
||||
# FIX: Reenable when pydisasm is not causing problems
|
||||
# @deps(deps={"pip3/xdis"}, executables={"pydisasm"},
|
||||
# @deps(deps={"pip/xdis"}, executables={"pydisasm"},
|
||||
# url="https://pypi.python.org/pypi/xdis")
|
||||
# def pydisasm(path):
|
||||
# return _run_command(["pydisasm", path], Status.normal,
|
||||
# Status.not_applicable)
|
||||
|
||||
|
||||
@deps(deps={"pip/bandit", "pip3/bandit"},
|
||||
url="https://pypi.org/project/bandit/")
|
||||
@deps(deps={"pip/bandit"}, url="https://pypi.org/project/bandit/")
|
||||
def bandit(path):
|
||||
python_version = _python_version(path)
|
||||
stdout, stderr, returncode = _do_command(
|
||||
[python_version, "-m", "bandit.cli.main", "-f", "txt", path],
|
||||
[PYTHON_EXECUTABLE, "-m", "bandit.cli.main", "-f", "txt", path],
|
||||
timeout=TIMEOUT)
|
||||
status = Status.ok if returncode == 0 else Status.problem
|
||||
text_without_timestamp = "".join(stdout.splitlines(keepends=True)[2:])
|
||||
|
|
@ -534,7 +503,7 @@ def _resize_image(image, new_width):
|
|||
PIL.Image.ANTIALIAS)
|
||||
|
||||
|
||||
@deps(deps={"pip3/pillow"}, url="python3-pil")
|
||||
@deps(deps={"pip/pillow"}, url="python3-pil")
|
||||
def pil(path):
|
||||
import PIL.Image
|
||||
with open(path, "rb") as image_file:
|
||||
|
|
|
|||
|
|
@ -136,8 +136,8 @@ tools_for_extensions = [
|
|||
success_status = "normal"
|
||||
|
||||
[pdf2txt]
|
||||
dependencies = ["pip/pdfminer"]
|
||||
url = "https://euske.github.io/pdfminer/"
|
||||
dependencies = ["pip/pdfminer.six"]
|
||||
url = "https://github.com/pdfminer/pdfminer.six"
|
||||
command = "pdf2txt.py"
|
||||
success_status = "normal"
|
||||
|
||||
|
|
@ -216,7 +216,7 @@ tools_for_extensions = [
|
|||
command = "golint -set_exit_status"
|
||||
|
||||
[yamllint]
|
||||
dependencies = ["pip3/yamllint"]
|
||||
dependencies = ["pip/yamllint"]
|
||||
url = "https://github.com/adrienverge/yamllint"
|
||||
command = "python3.7 -m yamllint"
|
||||
|
||||
|
|
|
|||
|
|
@ -8,21 +8,16 @@ import subprocess
|
|||
import eris.tools
|
||||
|
||||
|
||||
pip_deps, pip3_deps, dist_deps = set(), set(), set()
|
||||
pip_deps, dist_deps = set(), set()
|
||||
for dependency in eris.tools.dependencies():
|
||||
if "/" in dependency:
|
||||
pip_version, pip_dependency = dependency.split("/")
|
||||
(pip_deps if pip_version == "pip" else pip3_deps).add(pip_dependency)
|
||||
pip_deps.add(pip_dependency)
|
||||
else:
|
||||
dist_deps.add(dependency)
|
||||
if pip_deps:
|
||||
dist_deps.add("python-pip")
|
||||
if dist_deps:
|
||||
subprocess.run(["sudo", "apt-get", "-y", "install"] + list(dist_deps),
|
||||
check=True)
|
||||
if pip_deps:
|
||||
subprocess.run(["python", "-m", "pip", "install"] + list(pip_deps),
|
||||
check=True)
|
||||
if pip3_deps:
|
||||
subprocess.run(["python" + eris.tools.PYTHON_VERSION, "-m", "pip",
|
||||
"install"] + list(pip3_deps), check=True)
|
||||
"install"] + list(pip_deps), check=True)
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
|
||||
def hi():
|
||||
print "hi"
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
Test results:
|
||||
No issues identified.
|
||||
|
||||
Code scanned:
|
||||
Total lines of code: 2
|
||||
Total lines skipped (#nosec): 0
|
||||
|
||||
Run metrics:
|
||||
Total issues (by severity):
|
||||
Undefined: 0
|
||||
Low: 0
|
||||
Medium: 0
|
||||
High: 0
|
||||
Total issues (by confidence):
|
||||
Undefined: 0
|
||||
Low: 0
|
||||
Medium: 0
|
||||
High: 0
|
||||
Files skipped (0):
|
||||
|
|
@ -1 +0,0 @@
|
|||
input/hi.py:4: error: Missing parentheses in call to 'print'. Did you mean print("hi")?
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
Help on module hi:
|
||||
|
||||
NAME
|
||||
hi
|
||||
|
||||
FILE
|
||||
input/hi.py
|
||||
|
||||
FUNCTIONS
|
||||
hi()
|
||||
|
||||
|
||||
|
|
@ -1 +0,0 @@
|
|||
No config file found, using default configuration
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
(B[m[38;2;255;255;255m[48;2;0;0;0m
|
||||
|
||||
(B[m[38;2;0;159;107m[48;2;0;0;0m> def hi():(B[m[38;2;255;255;255m[48;2;0;0;0m
|
||||
(B[m[38;2;0;159;107m[48;2;0;0;0m> print "hi"(B[m
|
||||
|
|
@ -1 +0,0 @@
|
|||
(B[m[38;2;106;184;37m[48;2;32;32;32m[1mdef(B[m[38;2;208;208;208m[48;2;32;32;32m (B[m[38;2;68;127;207m[48;2;32;32;32mhi(B[m[38;2;208;208;208m[48;2;32;32;32m():(B[m
|
||||
|
|
@ -1 +0,0 @@
|
|||
("3:0: 'hi'", 1)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
Name File
|
||||
---- ----
|
||||
m __main__ ./input/hi.py
|
||||
|
|
@ -1 +0,0 @@
|
|||
No tests.
|
||||
|
|
@ -81,7 +81,7 @@ class ToolsTestCase(unittest.TestCase):
|
|||
def test_contents(self):
|
||||
self._test_tool(tools.contents, [("hi3.py", tools.Status.normal)])
|
||||
|
||||
HI_OK = [("hi3.py", tools.Status.ok), ("hi.py", tools.Status.ok)]
|
||||
HI_OK = [("hi3.py", tools.Status.ok)]
|
||||
|
||||
def test_python_syntax(self):
|
||||
self._test_tool(tools.python_syntax, self.HI_OK)
|
||||
|
|
@ -94,8 +94,7 @@ class ToolsTestCase(unittest.TestCase):
|
|||
# ("hi3_test.py", tools.Status.ok),
|
||||
# ("test_foo.py", tools.Status.ok)])
|
||||
|
||||
HI_NORMAL = [("hi3.py", tools.Status.normal),
|
||||
("hi.py", tools.Status.normal)]
|
||||
HI_NORMAL = [("hi3.py", tools.Status.normal)]
|
||||
|
||||
def test_pydoc(self):
|
||||
# FIX: This is failing inside AppImages.
|
||||
|
|
@ -103,8 +102,7 @@ class ToolsTestCase(unittest.TestCase):
|
|||
self._test_tool(tools.pydoc, self.HI_NORMAL)
|
||||
|
||||
def test_mypy(self):
|
||||
self._test_tool(tools.mypy, [("hi3.py", tools.Status.ok),
|
||||
("hi.py", tools.Status.problem)])
|
||||
self._test_tool(tools.mypy, self.HI_OK)
|
||||
|
||||
def test_python_coverage(self):
|
||||
self._test_tool(tools.python_coverage, self.HI_NORMAL)
|
||||
|
|
@ -128,8 +126,7 @@ class ToolsTestCase(unittest.TestCase):
|
|||
self._test_tool(tools.python_mccabe, self.HI_OK)
|
||||
|
||||
def test_bandit(self):
|
||||
self._test_tool(tools.bandit, [("hi3.py", tools.Status.ok),
|
||||
("hi.py", tools.Status.ok)])
|
||||
self._test_tool(tools.bandit, self.HI_OK)
|
||||
|
||||
# FIX: Make the golden-file deterministic
|
||||
# def test_pydisasm(self):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue