mirror of
https://github.com/PyCQA/flake8.git
synced 2026-04-07 21:44:18 +00:00
Lint Python files with a shebang
When a pattern is not passed to flake8 (--filename), look for all files that end with .py as well as extension-less files that start with a Python shebang. Helps project lint scripts that may not have an extension. Fixes #409
This commit is contained in:
parent
a2b7a7e4c5
commit
36a70fd110
4 changed files with 79 additions and 3 deletions
|
|
@ -3,6 +3,7 @@ import collections
|
|||
import errno
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import signal
|
||||
import sys
|
||||
import tokenize
|
||||
|
|
@ -54,6 +55,8 @@ class Manager(object):
|
|||
together and make our output deterministic.
|
||||
"""
|
||||
|
||||
SHEBANG_RE = re.compile(br'^#!.*\bpython[23w]?\b')
|
||||
|
||||
def __init__(self, style_guide, arguments, checker_plugins):
|
||||
"""Initialize our Manager instance.
|
||||
|
||||
|
|
@ -199,9 +202,26 @@ class Manager(object):
|
|||
paths = ['.']
|
||||
|
||||
filename_patterns = self.options.filename
|
||||
patterns_exist = True
|
||||
if not filename_patterns:
|
||||
filename_patterns = ['*.py']
|
||||
patterns_exist = False
|
||||
running_from_vcs = self.options._running_from_vcs
|
||||
running_from_diff = self.options.diff
|
||||
|
||||
def has_shebang(filename):
|
||||
if patterns_exist:
|
||||
# If a user explicitly specifies something, e.g. ``*.py``,
|
||||
# don't inspect the shebang.
|
||||
return False
|
||||
|
||||
if not os.path.isfile(filename):
|
||||
return False
|
||||
|
||||
with open(filename, 'rb') as fp:
|
||||
line = fp.readline(100)
|
||||
return bool(self.SHEBANG_RE.match(line))
|
||||
|
||||
# NOTE(sigmavirus24): Yes this is a little unsightly, but it's our
|
||||
# best solution right now.
|
||||
def should_create_file_checker(filename, argument):
|
||||
|
|
@ -220,8 +240,8 @@ class Manager(object):
|
|||
explicitly_provided = (not running_from_vcs and
|
||||
not running_from_diff and
|
||||
(argument == filename))
|
||||
return ((explicitly_provided or matches_filename_patterns) or
|
||||
is_stdin)
|
||||
return (explicitly_provided or matches_filename_patterns or
|
||||
is_stdin or has_shebang(filename))
|
||||
|
||||
checks = self.checks.to_dictionary()
|
||||
checkers = (
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ def register_default_options(option_manager):
|
|||
)
|
||||
|
||||
add_option(
|
||||
'--filename', metavar='patterns', default='*.py',
|
||||
'--filename', metavar='patterns',
|
||||
parse_from_config=True, comma_separated_list=True,
|
||||
help='Only check for filenames matching the patterns in this comma-'
|
||||
'separated list. (Default: %default)',
|
||||
|
|
|
|||
1
tests/fixtures/example-code/script
vendored
Normal file
1
tests/fixtures/example-code/script
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
#!/usr/bin/env python
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
"""Tests for the Manager object for FileCheckers."""
|
||||
import errno
|
||||
import os
|
||||
|
||||
import mock
|
||||
import pytest
|
||||
|
|
@ -70,3 +71,57 @@ def test_make_checkers():
|
|||
|
||||
for file_checker in manager.checkers:
|
||||
assert file_checker.filename in files
|
||||
|
||||
|
||||
def test_make_checkers_shebang():
|
||||
"""Verify that extension-less files with a Python shebang are checked."""
|
||||
style_guide = style_guide_mock(
|
||||
filename=[],
|
||||
exclude=[],
|
||||
)
|
||||
checkplugins = mock.Mock()
|
||||
checkplugins.to_dictionary.return_value = {
|
||||
'ast_plugins': [],
|
||||
'logical_line_plugins': [],
|
||||
'physical_line_plugins': [],
|
||||
}
|
||||
with mock.patch('flake8.checker.multiprocessing', None):
|
||||
manager = checker.Manager(style_guide, [], checkplugins)
|
||||
|
||||
path = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), '..', 'fixtures')
|
||||
)
|
||||
manager.make_checkers([path])
|
||||
|
||||
filenames = [
|
||||
os.path.relpath(file_checker.filename, path)
|
||||
for file_checker in manager.checkers
|
||||
]
|
||||
assert 'example-code/script' in filenames
|
||||
|
||||
|
||||
def test_make_checkers_explicit_pattern_ignore_shebang():
|
||||
"""Verify that shebangs are ignored when passing a pattern."""
|
||||
style_guide = style_guide_mock(
|
||||
filename=['*.py'],
|
||||
exclude=[],
|
||||
)
|
||||
checkplugins = mock.Mock()
|
||||
checkplugins.to_dictionary.return_value = {
|
||||
'ast_plugins': [],
|
||||
'logical_line_plugins': [],
|
||||
'physical_line_plugins': [],
|
||||
}
|
||||
with mock.patch('flake8.checker.multiprocessing', None):
|
||||
manager = checker.Manager(style_guide, [], checkplugins)
|
||||
|
||||
path = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), '..', 'fixtures')
|
||||
)
|
||||
manager.make_checkers([path])
|
||||
|
||||
filenames = [
|
||||
os.path.relpath(file_checker.filename, path)
|
||||
for file_checker in manager.checkers
|
||||
]
|
||||
assert 'example-code/script' not in filenames
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue