Source code

Revision control

Other Tools

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import json
import os
import subprocess
import signal
from mozprocess import ProcessHandler
from mozlint import result
from mozlint.pathutils import expand_exclusions
from mach.site import InstallPipRequirementsException
here = os.path.abspath(os.path.dirname(__file__))
PYLINT_REQUIREMENTS_PATH = os.path.join(here, "pylint_requirements.txt")
PYLINT_NOT_FOUND = """
Could not find pylint! Install pylint and try again.
$ pip install -U --require-hashes -r {}
""".strip().format(
PYLINT_REQUIREMENTS_PATH
)
PYLINT_INSTALL_ERROR = """
Unable to install correct version of pylint
Try to install it manually with:
$ pip install -U --require-hashes -r {}
""".strip().format(
PYLINT_REQUIREMENTS_PATH
)
class PylintProcess(ProcessHandler):
def __init__(self, config, *args, **kwargs):
self.config = config
kwargs["stream"] = False
kwargs["universal_newlines"] = True
ProcessHandler.__init__(self, *args, **kwargs)
def run(self, *args, **kwargs):
orig = signal.signal(signal.SIGINT, signal.SIG_IGN)
ProcessHandler.run(self, *args, **kwargs)
signal.signal(signal.SIGINT, orig)
def setup(root, **lintargs):
virtualenv_manager = lintargs["virtualenv_manager"]
try:
virtualenv_manager.install_pip_requirements(
PYLINT_REQUIREMENTS_PATH,
quiet=True,
)
except (subprocess.CalledProcessError, InstallPipRequirementsException):
print(PYLINT_INSTALL_ERROR)
return 1
def get_pylint_binary():
return "pylint"
def run_process(config, cmd):
proc = PylintProcess(config, cmd)
proc.run()
try:
proc.wait()
except KeyboardInterrupt:
proc.kill()
return proc.output
def parse_issues(log, config, issues_json, path):
results = []
try:
issues = json.loads(issues_json)
except json.decoder.JSONDecodeError:
log.debug("Could not parse the output:")
log.debug("pylint output: {}".format(issues_json))
return []
for issue in issues:
res = {
"path": issue["path"],
"level": issue["type"],
"lineno": issue["line"],
"column": issue["column"],
"message": issue["message"],
"rule": issue["message-id"],
}
results.append(result.from_config(config, **res))
return results
def get_pylint_version(binary):
return subprocess.check_output(
[binary, "--version"],
universal_newlines=True,
stderr=subprocess.STDOUT,
)
def lint(paths, config, **lintargs):
log = lintargs["log"]
binary = get_pylint_binary()
log = lintargs["log"]
paths = list(expand_exclusions(paths, config, lintargs["root"]))
cmd_args = [binary]
results = []
# And ignore a bit more elements
cmd_args += [
"-fjson",
"--disable=all",
"--enable=F,E,unreachable,duplicate-key,unnecessary-semicolon,global-variable-not-assigned,unused-variable,binary-op-exception,bad-format-string,anomalous-backslash-in-string,bad-open-mode,no-else-return", # NOQA: E501
"--disable=import-error,no-member",
]
base_command = cmd_args + paths
log.debug("Command: {}".format(" ".join(cmd_args)))
log.debug("pylint version: {}".format(get_pylint_version(binary)))
output = " ".join(run_process(config, base_command))
results = parse_issues(log, config, str(output), [])
return results