Merge branch 'fix_linting_end_of_file' into 'master'

fix skipping of physical checks when file does not end in newline

See merge request pycqa/flake8!451
This commit is contained in:
Anthony Sottile 2020-09-15 23:46:05 +00:00
commit 93209ffac9
3 changed files with 46 additions and 4 deletions

View file

@ -2,6 +2,8 @@ repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.3.0 rev: v2.3.0
hooks: hooks:
- id: debug-statements
exclude: ^tests/fixtures/example-code/invalid-syntax.py$
- id: end-of-file-fixer - id: end-of-file-fixer
- id: trailing-whitespace - id: trailing-whitespace
exclude: ^tests/fixtures/diffs/ exclude: ^tests/fixtures/diffs/

View file

@ -564,9 +564,10 @@ class FileChecker(object):
parens = 0 parens = 0
statistics = self.statistics statistics = self.statistics
file_processor = self.processor file_processor = self.processor
prev_physical = ""
for token in file_processor.generate_tokens(): for token in file_processor.generate_tokens():
statistics["tokens"] += 1 statistics["tokens"] += 1
self.check_physical_eol(token) self.check_physical_eol(token, prev_physical)
token_type, text = token[0:2] token_type, text = token[0:2]
processor.log_token(LOG, token) processor.log_token(LOG, token)
if token_type == tokenize.OP: if token_type == tokenize.OP:
@ -574,6 +575,7 @@ class FileChecker(object):
elif parens == 0: elif parens == 0:
if processor.token_is_newline(token): if processor.token_is_newline(token):
self.handle_newline(token_type) self.handle_newline(token_type)
prev_physical = token[4]
if file_processor.tokens: if file_processor.tokens:
# If any tokens are left over, process them # If any tokens are left over, process them
@ -609,10 +611,17 @@ class FileChecker(object):
else: else:
self.run_logical_checks() self.run_logical_checks()
def check_physical_eol(self, token): def check_physical_eol(self, token, prev_physical):
# type: (processor._Token, str) -> None
"""Run physical checks if and only if it is at the end of the line.""" """Run physical checks if and only if it is at the end of the line."""
# a newline token ends a single physical line.
if processor.is_eol_token(token): if processor.is_eol_token(token):
# Obviously, a newline token ends a single physical line. # if the file does not end with a newline, the NEWLINE
# token is inserted by the parser, but it does not contain
# the previous physical line in `token[4]`
if token[4] == "":
self.run_physical_checks(prev_physical)
else:
self.run_physical_checks(token[4]) self.run_physical_checks(token[4])
elif processor.is_multiline_string(token): elif processor.is_multiline_string(token):
# Less obviously, a string that contains newlines is a # Less obviously, a string that contains newlines is a

View file

@ -212,6 +212,37 @@ x = """
assert out == err == '' assert out == err == ''
def test_physical_line_file_not_ending_in_newline(tmpdir, capsys):
"""See https://github.com/PyCQA/pycodestyle/issues/960."""
t_py_src = 'def f():\n\tpass'
with tmpdir.as_cwd():
tmpdir.join('t.py').write(t_py_src)
_call_main(['t.py'], retv=1)
out, err = capsys.readouterr()
assert out == '''\
t.py:2:1: W191 indentation contains tabs
t.py:2:6: W292 no newline at end of file
'''
@pytest.mark.xfail(strict=True) # currently awaiting fix in pycodestyle
def test_physical_line_file_not_ending_in_newline_trailing_ws(tmpdir, capsys):
"""See https://github.com/PyCQA/pycodestyle/issues/960."""
t_py_src = 'x = 1 '
with tmpdir.as_cwd():
tmpdir.join('t.py').write(t_py_src)
_call_main(['t.py'], retv=1)
out, err = capsys.readouterr()
assert out == '''\
t.py:1:6: W291 trailing whitespace
t.py:1:10: W292 no newline at end of file
'''
def test_obtaining_args_from_sys_argv_when_not_explicity_provided(capsys): def test_obtaining_args_from_sys_argv_when_not_explicity_provided(capsys):
"""Test that arguments are obtained from 'sys.argv'.""" """Test that arguments are obtained from 'sys.argv'."""
with mock.patch('sys.argv', ['flake8', '--help']): with mock.patch('sys.argv', ['flake8', '--help']):