summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorƁukasz Rogalski <rogalski.91@gmail.com>2017-03-01 20:46:24 +0100
committerGitHub <noreply@github.com>2017-03-01 20:46:24 +0100
commit7df8caaa3e1995018417ac2fd87afd89be6945ba (patch)
treeac7726a426464acd13a87f1beb18202f71b49f26
parent56daa5c3a0d2d6592c673c2932c354b68679997f (diff)
downloadpylint-git-7df8caaa3e1995018417ac2fd87afd89be6945ba.tar.gz
Make cyclic import checker respect local disable clauses (#1286)
Fixes #59
-rw-r--r--ChangeLog6
-rw-r--r--doc/whatsnew/1.7.rst4
-rw-r--r--pylint/checkers/imports.py42
-rw-r--r--pylint/test/input/func_w0401_disabled.py9
-rw-r--r--pylint/test/messages/func_w0401_disabled.txt1
5 files changed, 46 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog
index 5a0402478..bd3aae262 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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