diff --git a/ChangeLog b/ChangeLog index c1955dff50..f69f0397a5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,10 @@ Release date: TBA Close #3148 +* ``import-outside-toplevel`` is emitted for ``ImportFrom`` nodes as well. + + Close #3175 + What's New in Pylint 2.4.2? =========================== diff --git a/pylint/__init__.py b/pylint/__init__.py index a5d43d123f..89809389bd 100644 --- a/pylint/__init__.py +++ b/pylint/__init__.py @@ -9,35 +9,35 @@ import sys -from .__pkginfo__ import version as __version__ +from pylint.__pkginfo__ import version as __version__ +from pylint.checkers.similar import Run as SimilarRun +from pylint.epylint import Run as EpylintRun +from pylint.lint import Run as PylintRun +from pylint.pyreverse.main import Run as PyreverseRun def run_pylint(): """run pylint""" - from pylint.lint import Run try: - Run(sys.argv[1:]) + PylintRun(sys.argv[1:]) except KeyboardInterrupt: sys.exit(1) def run_epylint(): """run pylint""" - from pylint.epylint import Run - Run() + EpylintRun() def run_pyreverse(): """run pyreverse""" - from pylint.pyreverse.main import Run - Run(sys.argv[1:]) + PyreverseRun(sys.argv[1:]) def run_symilar(): """run symilar""" - from pylint.checkers.similar import Run - Run(sys.argv[1:]) + SimilarRun(sys.argv[1:]) diff --git a/pylint/checkers/imports.py b/pylint/checkers/imports.py index 710eb28aee..42d4362df0 100644 --- a/pylint/checkers/imports.py +++ b/pylint/checkers/imports.py @@ -520,6 +520,7 @@ def visit_importfrom(self, node): self._check_wildcard_imports(node, imported_module) self._check_same_line_imports(node) self._check_reimport(node, basename=basename, level=node.level) + self._check_toplevel(node) if isinstance(node.parent, astroid.Module): # Allow imports nested diff --git a/pylint/checkers/similar.py b/pylint/checkers/similar.py index d87a2b1323..019b55fc56 100644 --- a/pylint/checkers/similar.py +++ b/pylint/checkers/similar.py @@ -19,6 +19,7 @@ import sys from collections import defaultdict +from getopt import getopt from itertools import groupby import astroid @@ -412,7 +413,6 @@ def Run(argv=None): """standalone command line access point""" if argv is None: argv = sys.argv[1:] - from getopt import getopt s_opts = "hdi" l_opts = ( diff --git a/pylint/lint.py b/pylint/lint.py index bbb01d35e5..a98970b782 100644 --- a/pylint/lint.py +++ b/pylint/lint.py @@ -73,7 +73,7 @@ from astroid.__pkginfo__ import version as astroid_version from astroid.builder import AstroidBuilder -from pylint import checkers, config, exceptions, interfaces, reporters +from pylint import __pkginfo__, checkers, config, exceptions, interfaces, reporters from pylint.__pkginfo__ import version from pylint.constants import MAIN_CHECKER_NAME, MSG_TYPES, OPTION_RGX from pylint.message import Message, MessageDefinitionStore, MessagesHandlerMixIn @@ -1761,8 +1761,6 @@ def cb_generate_config(self, *args, **kwargs): def cb_generate_manpage(self, *args, **kwargs): """optik callback for sample config file generation""" - from pylint import __pkginfo__ - self.linter.generate_manpage(__pkginfo__) sys.exit(0) diff --git a/pylint/reporters/__init__.py b/pylint/reporters/__init__.py index fe767bcc55..f01629bcec 100644 --- a/pylint/reporters/__init__.py +++ b/pylint/reporters/__init__.py @@ -19,6 +19,7 @@ """utilities methods and classes for reporters""" +from pylint import utils from pylint.reporters.base_reporter import BaseReporter from pylint.reporters.collecting_reporter import CollectingReporter from pylint.reporters.json_reporter import JSONReporter @@ -27,8 +28,6 @@ def initialize(linter): """initialize linter with reporters in this package """ - from pylint import utils - utils.register_plugins(linter, __path__[0]) diff --git a/tests/functional/b/bad_reversed_sequence.py b/tests/functional/b/bad_reversed_sequence.py index 6cfac5bedc..f423dd2d6c 100644 --- a/tests/functional/b/bad_reversed_sequence.py +++ b/tests/functional/b/bad_reversed_sequence.py @@ -1,9 +1,9 @@ """ Checks that reversed() receive proper argument """ # pylint: disable=missing-docstring, useless-object-inheritance # pylint: disable=too-few-public-methods,no-self-use,no-absolute-import -from collections import deque +from collections import deque, OrderedDict +from enum import IntEnum -__revision__ = 0 class GoodReversed(object): """ Implements __reversed__ """ @@ -61,8 +61,6 @@ def test(path): def test_dict_ancestor_and_reversed(): """Don't emit for subclasses of dict, with __reversed__ implemented.""" - from collections import OrderedDict - class Child(dict): def __reversed__(self): return reversed(range(10)) @@ -73,8 +71,6 @@ def __reversed__(self): def test_dont_emit_for_reversing_enums(): """Don't emit when reversing enum classes""" - from enum import IntEnum - class Color(IntEnum): RED = 1 GREEN = 2 diff --git a/tests/functional/b/bugfix_local_scope_metaclass_1177.py b/tests/functional/b/bugfix_local_scope_metaclass_1177.py index 8904f6fb28..22c07a330f 100644 --- a/tests/functional/b/bugfix_local_scope_metaclass_1177.py +++ b/tests/functional/b/bugfix_local_scope_metaclass_1177.py @@ -1,5 +1,5 @@ # pylint: disable=missing-docstring,too-few-public-methods,import-error -from UNINFERABLE import ImportedMetaclass +from UNINFERABLE import ImportedMetaclass, ImportedMetaclass2 class Meta(type): @@ -48,8 +48,6 @@ class ClassImp2(metaclass=ImportedMetaclass): def imported_and_nested_scope2(): - from UNINFERABLE import ImportedMetaclass2 - class ClassImp3(metaclass=ImportedMetaclass2): pass diff --git a/tests/functional/c/consider_using_enumerate.py b/tests/functional/c/consider_using_enumerate.py index 758375c371..cff00aeec3 100644 --- a/tests/functional/c/consider_using_enumerate.py +++ b/tests/functional/c/consider_using_enumerate.py @@ -49,6 +49,7 @@ def good(): for index in range(len(iterable)): yield other_obj[index] + # pylint: disable=import-outside-toplevel from unknown import unknown for index in range(unknown(iterable)): yield iterable[index] diff --git a/tests/functional/import_outside_toplevel.py b/tests/functional/import_outside_toplevel.py index 0575e59b29..762faa5511 100644 --- a/tests/functional/import_outside_toplevel.py +++ b/tests/functional/import_outside_toplevel.py @@ -32,3 +32,7 @@ def j(self): def k(flag): if flag: import tabnanny # [import-outside-toplevel] + + +def j(): + from collections import defaultdict # [import-outside-toplevel] diff --git a/tests/functional/import_outside_toplevel.txt b/tests/functional/import_outside_toplevel.txt index 53f9595d2c..d15db69476 100644 --- a/tests/functional/import_outside_toplevel.txt +++ b/tests/functional/import_outside_toplevel.txt @@ -5,3 +5,4 @@ import-outside-toplevel:22:i:Import outside toplevel (random, socket) import-outside-toplevel:26:C:Import outside toplevel (tokenize) import-outside-toplevel:29:C.j:Import outside toplevel (turtle) import-outside-toplevel:34:k:Import outside toplevel (tabnanny) +import-outside-toplevel:38:j:Import outside toplevel (collections) diff --git a/tests/functional/r/redefined_outer_name_type_checking.py b/tests/functional/r/redefined_outer_name_type_checking.py index b708902e0c..399fc8cea5 100644 --- a/tests/functional/r/redefined_outer_name_type_checking.py +++ b/tests/functional/r/redefined_outer_name_type_checking.py @@ -8,6 +8,7 @@ class Cls: def func(self, stuff: defaultdict): # This import makes the definition work. + # pylint: disable=import-outside-toplevel from collections import defaultdict obj = defaultdict() diff --git a/tests/functional/s/string_formatting.py b/tests/functional/s/string_formatting.py index 82f6d112d5..bb7166fdeb 100644 --- a/tests/functional/s/string_formatting.py +++ b/tests/functional/s/string_formatting.py @@ -134,7 +134,7 @@ def issue338(): trying to infer EmptyNodes (resulted after mocking the members of namedtuples). """ - from collections import namedtuple + from collections import namedtuple # pylint: disable=import-outside-toplevel class Crash(namedtuple("C", "foo bar")): """ Looking for attributes in __str__ will crash, diff --git a/tests/functional/s/string_formatting_py3.py b/tests/functional/s/string_formatting_py3.py index c27e9719e4..3cdd60eb25 100644 --- a/tests/functional/s/string_formatting_py3.py +++ b/tests/functional/s/string_formatting_py3.py @@ -17,5 +17,5 @@ def issue_957_bad2(): def issue_957_uninferable(): - from butchery import meat + from butchery import meat # pylint: disable=import-outside-toplevel print('%s%s%s' % ('eggs', *meat)) diff --git a/tests/functional/u/unbalanced_tuple_unpacking.py b/tests/functional/u/unbalanced_tuple_unpacking.py index d3887f4f35..ed807c0d7b 100644 --- a/tests/functional/u/unbalanced_tuple_unpacking.py +++ b/tests/functional/u/unbalanced_tuple_unpacking.py @@ -2,7 +2,7 @@ from __future__ import absolute_import from functional.u.unpacking import unpack -# pylint: disable=using-constant-test, useless-object-inheritance +# pylint: disable=using-constant-test, useless-object-inheritance,import-outside-toplevel def do_stuff(): """This is not right.""" diff --git a/tests/input/func_w0401_disabled_in_func.py b/tests/input/func_w0401_disabled_in_func.py index b9b0ced8d8..69f266863f 100644 --- a/tests/input/func_w0401_disabled_in_func.py +++ b/tests/input/func_w0401_disabled_in_func.py @@ -1,6 +1,6 @@ """Test disabling of cyclic import check inside a function """ -# pylint: disable=no-absolute-import +# pylint: disable=no-absolute-import,import-outside-toplevel from __future__ import print_function