gecko-dev/tools/lint/flake8.lint
Andrew Halberstadt 7c3487a2d7 Bug 1277851 - [mozlint] Run flake8 directories that contain a .flake8 file separately, r=maja_zf
This is a crude workaround to get subdirectory .flake8 files working. Hopefully
this is temporary until flake8 3.0 is released with support for multiple config
files.

Note that .flake8 files that live outside of a directory that is explicitly
listed in the 'include' directive, will not be considered.

MozReview-Commit-ID: GtpUZHJKq52

--HG--
extra : rebase_source : 0294e135673a3b580316a46ec13e37749422edba
2016-06-03 10:39:32 -04:00

133 lines
3.4 KiB
Python

# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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 signal
import which
from mozprocess import ProcessHandler
from mozlint import result
FLAKE8_NOT_FOUND = """
Could not find flake8! Install flake8 and try again.
$ pip install flake8
""".strip()
LINE_OFFSETS = {
# continuation line under-indented for hanging indent
'E121': (-1, 2),
# continuation line missing indentation or outdented
'E122': (-1, 2),
# continuation line over-indented for hanging indent
'E126': (-1, 2),
# continuation line over-indented for visual indent
'E127': (-1, 2),
# continuation line under-indented for visual indent
'E128': (-1, 2),
# continuation line unaligned for hanging indend
'E131': (-1, 2),
# expected 1 blank line, found 0
'E301': (-1, 2),
# expected 2 blank lines, found 1
'E302': (-2, 3),
}
"""Maps a flake8 error to a lineoffset tuple.
The offset is of the form (lineno_offset, num_lines) and is passed
to the lineoffset property of `ResultContainer`.
"""
results = []
def process_line(line):
try:
res = json.loads(line)
except ValueError:
return
if 'code' in res:
if res['code'].startswith('W'):
res['level'] = 'warning'
if res['code'] in LINE_OFFSETS:
res['lineoffset'] = LINE_OFFSETS[res['code']]
results.append(result.from_linter(LINTER, **res))
def run_process(cmdargs):
# flake8 seems to handle SIGINT poorly. Handle it here instead
# so we can kill the process without a cryptic traceback.
orig = signal.signal(signal.SIGINT, signal.SIG_IGN)
proc = ProcessHandler(cmdargs, env=os.environ,
processOutputLine=process_line)
proc.run()
signal.signal(signal.SIGINT, orig)
try:
proc.wait()
except KeyboardInterrupt:
proc.kill()
def lint(files, **lintargs):
binary = os.environ.get('FLAKE8')
if not binary:
try:
binary = which.which('flake8')
except which.WhichError:
pass
if not binary:
print(FLAKE8_NOT_FOUND)
return []
cmdargs = [
binary,
'--format', '{"path":"%(path)s","lineno":%(row)s,'
'"column":%(col)s,"rule":"%(code)s","message":"%(text)s"}',
]
exclude = lintargs.get('exclude')
if exclude:
cmdargs += ['--exclude', ','.join(lintargs['exclude'])]
# Run any paths with a .flake8 file in the directory separately so
# it gets picked up. This means only .flake8 files that live in
# directories that are explicitly included will be considered.
# See bug 1277851
no_config = []
for f in files:
if not os.path.isfile(os.path.join(f, '.flake8')):
no_config.append(f)
continue
run_process(cmdargs+[f])
if no_config:
run_process(cmdargs+no_config)
return results
LINTER = {
'name': "flake8",
'description': "Python linter",
'include': [
'python/mozlint',
'tools/lint',
'testing/marionette/client'
],
'exclude': [],
'type': 'external',
'payload': lint,
}