From 76ce7c13b4a3059cdad08ccd9264c3d52a6683c2 Mon Sep 17 00:00:00 2001 From: Scott Worley Date: Sun, 19 Aug 2018 15:17:20 -0700 Subject: Use ast to handle PEP 328 multi-line imports Closes #1422 Closes #2019 This fixes #1422 and fixes #2019. --- CONTRIBUTORS.txt | 2 ++ ChangeLog | 4 +++ pylint/checkers/similar.py | 21 +++++++++++-- pylint/test/input/hide_code_with_imports.py | 16 ++++++++++ pylint/test/input/multiline-import | 8 +++++ pylint/test/unittest_checker_similar.py | 47 +++++++++++++++++++++++++++-- 6 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 pylint/test/input/hide_code_with_imports.py create mode 100644 pylint/test/input/multiline-import diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 9fb8aeb17..729d92144 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -237,3 +237,5 @@ contributors: * Tomer Chachamu, Richard Goodman: simplifiable-if-expression * Benjamin Drung: contributing Debian Developer + +* Scott Worley: contributor diff --git a/ChangeLog b/ChangeLog index 0b30a87ff..1d95f4bb5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -140,6 +140,10 @@ Release date: TBA Close #2430 + * Fix --ignore-imports to understand multi-line imports + + Close #1422 + Close #2019 What's New in Pylint 2.1.1? =========================== diff --git a/pylint/checkers/similar.py b/pylint/checkers/similar.py index 369d0ce37..da2ab5b9d 100644 --- a/pylint/checkers/similar.py +++ b/pylint/checkers/similar.py @@ -20,6 +20,9 @@ from __future__ import print_function import sys from collections import defaultdict +from itertools import groupby + +import astroid from pylint.utils import decoding_stream from pylint.interfaces import IRawChecker @@ -153,10 +156,20 @@ def stripped_lines(lines, ignore_comments, ignore_docstrings, ignore_imports): """return lines with leading/trailing whitespace and any ignored code features removed """ + if ignore_imports: + tree = astroid.parse(''.join(lines)) + node_is_import_by_lineno = ( + (node.lineno, isinstance(node, (astroid.Import, astroid.ImportFrom))) + for node in tree.body) + line_begins_import = { + lineno: all(is_import for _, is_import in node_is_import_group) + for lineno, node_is_import_group + in groupby(node_is_import_by_lineno, key=lambda x: x[0])} + current_line_is_import = False strippedlines = [] docstring = None - for line in lines: + for lineno, line in enumerate(lines, start=1): line = line.strip() if ignore_docstrings: if not docstring and (line.startswith('"""') or line.startswith("'''")): @@ -167,8 +180,10 @@ def stripped_lines(lines, ignore_comments, ignore_docstrings, ignore_imports): docstring = None line = "" if ignore_imports: - if line.startswith("import ") or line.startswith("from "): - line = "" + current_line_is_import = line_begins_import.get( + lineno, current_line_is_import) + if current_line_is_import: + line = '' if ignore_comments: # XXX should use regex in checkers/format to avoid cutting # at a "#" in a string diff --git a/pylint/test/input/hide_code_with_imports.py b/pylint/test/input/hide_code_with_imports.py new file mode 100644 index 000000000..a8449c9b9 --- /dev/null +++ b/pylint/test/input/hide_code_with_imports.py @@ -0,0 +1,16 @@ +quicksort = lambda a: qs1(a,0,len(a)-1) ; import a +qs1 = lambda a,lo,hi: qs2(a,lo,hi) if lo