diff options
author | Ćukasz Rogalski <rogalski.91@gmail.com> | 2017-03-01 20:46:24 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-03-01 20:46:24 +0100 |
commit | 7df8caaa3e1995018417ac2fd87afd89be6945ba (patch) | |
tree | ac7726a426464acd13a87f1beb18202f71b49f26 | |
parent | 56daa5c3a0d2d6592c673c2932c354b68679997f (diff) | |
download | pylint-git-7df8caaa3e1995018417ac2fd87afd89be6945ba.tar.gz |
Make cyclic import checker respect local disable clauses (#1286)
Fixes #59
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | doc/whatsnew/1.7.rst | 4 | ||||
-rw-r--r-- | pylint/checkers/imports.py | 42 | ||||
-rw-r--r-- | pylint/test/input/func_w0401_disabled.py | 9 | ||||
-rw-r--r-- | pylint/test/messages/func_w0401_disabled.txt | 1 |
5 files changed, 46 insertions, 16 deletions
@@ -293,6 +293,12 @@ Release date: tba Fixes #957 + * `cyclic-import` checker supports local disable clauses. When one + of cycle imports was done in scope where disable clause was active, + cycle is not reported as violation. + + Fixes #59 + What's new in Pylint 1.6.3? =========================== diff --git a/doc/whatsnew/1.7.rst b/doc/whatsnew/1.7.rst index a1f57c46a..3fa6ed3ab 100644 --- a/doc/whatsnew/1.7.rst +++ b/doc/whatsnew/1.7.rst @@ -888,6 +888,10 @@ Bug fixes meat = ['spam', 'ham'] print('%s%s%s' % ('eggs', *meat)) +* `cyclic-import` checker supports local disable clauses. When one + of cycle imports was done in scope where disable clause was active, + cycle is not reported as violation. + Removed Changes =============== diff --git a/pylint/checkers/imports.py b/pylint/checkers/imports.py index d2970eb86..4cae39dac 100644 --- a/pylint/checkers/imports.py +++ b/pylint/checkers/imports.py @@ -17,6 +17,7 @@ import collections from distutils import sysconfig import os import sys +import copy import six @@ -256,42 +257,43 @@ class ImportsChecker(BaseChecker): {'default' : deprecated_modules, 'type' : 'csv', 'metavar' : '<modules>', - 'help' : 'Deprecated modules which should not be used, \ -separated by a comma'} + 'help' : 'Deprecated modules which should not be used,' + ' separated by a comma'} ), ('import-graph', {'default' : '', 'type' : 'string', 'metavar' : '<file.dot>', - 'help' : 'Create a graph of every (i.e. internal and \ -external) dependencies in the given file (report RP0402 must not be disabled)'} + 'help' : 'Create a graph of every (i.e. internal and' + ' external) dependencies in the given file' + ' (report RP0402 must not be disabled)'} ), ('ext-import-graph', {'default' : '', 'type' : 'string', 'metavar' : '<file.dot>', - 'help' : 'Create a graph of external dependencies in the \ -given file (report RP0402 must not be disabled)'} + 'help' : 'Create a graph of external dependencies in the' + ' given file (report RP0402 must not be disabled)'} ), ('int-import-graph', {'default' : '', 'type' : 'string', 'metavar' : '<file.dot>', - 'help' : 'Create a graph of internal dependencies in the \ -given file (report RP0402 must not be disabled)'} + 'help' : 'Create a graph of internal dependencies in the' + ' given file (report RP0402 must not be disabled)'} ), ('known-standard-library', {'default': DEFAULT_STANDARD_LIBRARY, 'type': 'csv', 'metavar': '<modules>', - 'help': 'Force import order to recognize a module as part of' \ + 'help': 'Force import order to recognize a module as part of' ' the standard compatibility libraries.'} ), ('known-third-party', {'default': DEFAULT_KNOWN_THIRD_PARTY, 'type': 'csv', 'metavar': '<modules>', - 'help': 'Force import order to recognize a module as part of' \ + 'help': 'Force import order to recognize a module as part of' ' a third party library.'} ), ('analyse-fallback-blocks', @@ -352,15 +354,22 @@ given file (report RP0402 must not be disabled)'} self.linter.add_stats(cycles=[]) self.stats = self.linter.stats self.import_graph = collections.defaultdict(set) + self._excluded_edges = collections.defaultdict(set) self._ignored_modules = get_global_option( self, 'ignored-modules', default=[]) + def _import_graph_without_ignored_edges(self): + filtered_graph = copy.deepcopy(self.import_graph) + for node in filtered_graph: + filtered_graph[node].difference_update(self._excluded_edges[node]) + return filtered_graph + def close(self): """called before visiting project (i.e set of modules)""" - # don't try to compute cycles if the associated message is disabled if self.linter.is_message_enabled('cyclic-import'): - vertices = list(self.import_graph) - for cycle in get_cycles(self.import_graph, vertices=vertices): + graph = self._import_graph_without_ignored_edges() + vertices = list(graph) + for cycle in get_cycles(graph, vertices=vertices): self.add_message('cyclic-import', args=' -> '.join(cycle)) @check_messages('wrong-import-position', 'multiple-imports', @@ -656,10 +665,11 @@ given file (report RP0402 must not be disabled)'} importedmodname, set()) if context_name not in importedmodnames: importedmodnames.add(context_name) + # update import graph - mgraph = self.import_graph[context_name] - if importedmodname not in mgraph: - mgraph.add(importedmodname) + self.import_graph[context_name].add(importedmodname) + if not self.linter.is_message_enabled('cyclic-import'): + self._excluded_edges[context_name].add(importedmodname) def _check_deprecated_module(self, node, mod_path): """check if the module is deprecated""" diff --git a/pylint/test/input/func_w0401_disabled.py b/pylint/test/input/func_w0401_disabled.py new file mode 100644 index 000000000..966706caf --- /dev/null +++ b/pylint/test/input/func_w0401_disabled.py @@ -0,0 +1,9 @@ +"""test cyclic import +""" +# pylint: disable=no-absolute-import +from __future__ import print_function + +from . import w0401_cycle # pylint: disable=cyclic-import + +if w0401_cycle: + print(w0401_cycle) diff --git a/pylint/test/messages/func_w0401_disabled.txt b/pylint/test/messages/func_w0401_disabled.txt new file mode 100644 index 000000000..0f92bcc60 --- /dev/null +++ b/pylint/test/messages/func_w0401_disabled.txt @@ -0,0 +1 @@ +W: 8: Using a conditional statement with a constant value |