Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(40)

Side by Side Diff: third_party/pylint/checkers/imports.py

Issue 739393004: Revert "Revert "pylint: upgrade to 1.3.1"" (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools/
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/pylint/checkers/format.py ('k') | third_party/pylint/checkers/logging.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2003-2010 LOGILAB S.A. (Paris, FRANCE). 1 # Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE).
2 # http://www.logilab.fr/ -- mailto:contact@logilab.fr 2 # http://www.logilab.fr/ -- mailto:contact@logilab.fr
3 # 3 #
4 # This program is free software; you can redistribute it and/or modify it under 4 # This program is free software; you can redistribute it and/or modify it under
5 # the terms of the GNU General Public License as published by the Free Software 5 # the terms of the GNU General Public License as published by the Free Software
6 # Foundation; either version 2 of the License, or (at your option) any later 6 # Foundation; either version 2 of the License, or (at your option) any later
7 # version. 7 # version.
8 # 8 #
9 # This program is distributed in the hope that it will be useful, but WITHOUT 9 # This program is distributed in the hope that it will be useful, but WITHOUT
10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 11 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 # 12 #
13 # You should have received a copy of the GNU General Public License along with 13 # You should have received a copy of the GNU General Public License along with
14 # this program; if not, write to the Free Software Foundation, Inc., 14 # this program; if not, write to the Free Software Foundation, Inc.,
15 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 15 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 """imports checkers for Python code""" 16 """imports checkers for Python code"""
17 17
18 import sys
19
18 from logilab.common.graph import get_cycles, DotBackend 20 from logilab.common.graph import get_cycles, DotBackend
19 from logilab.common.modutils import is_standard_module
20 from logilab.common.ureports import VerbatimText, Paragraph 21 from logilab.common.ureports import VerbatimText, Paragraph
21 22
22 from logilab import astng 23 import astroid
23 from logilab.astng import are_exclusive 24 from astroid import are_exclusive
25 from astroid.modutils import get_module_part, is_standard_module
24 26
25 from pylint.interfaces import IASTNGChecker 27 from pylint.interfaces import IAstroidChecker
26 from pylint.checkers import BaseChecker, EmptyReport 28 from pylint.utils import EmptyReport
29 from pylint.checkers import BaseChecker
30 from pylint.checkers.utils import check_messages
27 31
28 32
29 def get_first_import(node, context, name, base, level): 33 def get_first_import(node, context, name, base, level):
30 """return the node where [base.]<name> is imported or None if not found 34 """return the node where [base.]<name> is imported or None if not found
31 """ 35 """
36 fullname = '%s.%s' % (base, name) if base else name
37
32 first = None 38 first = None
33 found = False 39 found = False
34 for first in context.values(): 40 for first in context.body:
35 if isinstance(first, astng.Import): 41 if first is node:
36 if name in [iname[0] for iname in first.names]: 42 continue
43 if first.scope() is node.scope() and first.fromlineno > node.fromlineno:
44 continue
45 if isinstance(first, astroid.Import):
46 if any(fullname == iname[0] for iname in first.names):
37 found = True 47 found = True
38 break 48 break
39 elif isinstance(first, astng.From): 49 elif isinstance(first, astroid.From):
40 if base == first.modname and level == first.level and \ 50 if level == first.level and any(
41 name in [iname[0] for iname in first.names]: 51 fullname == '%s.%s' % (first.modname, iname[0])
52 for iname in first.names):
42 found = True 53 found = True
43 break 54 break
44 if found and first is not node and not are_exclusive(first, node): 55 if found and not are_exclusive(first, node):
45 return first 56 return first
46 57
47 # utilities to represents import dependencies as tree and dot graph ########### 58 # utilities to represents import dependencies as tree and dot graph ###########
48 59
49 def filter_dependencies_info(dep_info, package_dir, mode='external'):
50 """filter external or internal dependencies from dep_info (return a
51 new dictionary containing the filtered modules only)
52 """
53 if mode == 'external':
54 filter_func = lambda x: not is_standard_module(x, (package_dir,))
55 else:
56 assert mode == 'internal'
57 filter_func = lambda x: is_standard_module(x, (package_dir,))
58 result = {}
59 for importee, importers in dep_info.items():
60 if filter_func(importee):
61 result[importee] = importers
62 return result
63
64 def make_tree_defs(mod_files_list): 60 def make_tree_defs(mod_files_list):
65 """get a list of 2-uple (module, list_of_files_which_import_this_module), 61 """get a list of 2-uple (module, list_of_files_which_import_this_module),
66 it will return a dictionary to represent this as a tree 62 it will return a dictionary to represent this as a tree
67 """ 63 """
68 tree_defs = {} 64 tree_defs = {}
69 for mod, files in mod_files_list: 65 for mod, files in mod_files_list:
70 node = (tree_defs, ()) 66 node = (tree_defs, ())
71 for prefix in mod.split('.'): 67 for prefix in mod.split('.'):
72 node = node[0].setdefault(prefix, [{}, []]) 68 node = node[0].setdefault(prefix, [{}, []])
73 node[1] += files 69 node[1] += files
74 return tree_defs 70 return tree_defs
75 71
76 def repr_tree_defs(data, indent_str=None): 72 def repr_tree_defs(data, indent_str=None):
77 """return a string which represents imports as a tree""" 73 """return a string which represents imports as a tree"""
78 lines = [] 74 lines = []
79 nodes = data.items() 75 nodes = data.items()
80 for i, (mod, (sub, files)) in enumerate(sorted(nodes, key=lambda x: x[0])): 76 for i, (mod, (sub, files)) in enumerate(sorted(nodes, key=lambda x: x[0])):
81 if not files: 77 if not files:
82 files = '' 78 files = ''
83 else: 79 else:
84 files = '(%s)' % ','.join(files) 80 files = '(%s)' % ','.join(files)
85 if indent_str is None: 81 if indent_str is None:
86 lines.append('%s %s' % (mod, files)) 82 lines.append('%s %s' % (mod, files))
87 sub_indent_str = ' ' 83 sub_indent_str = ' '
88 else: 84 else:
89 lines.append('%s\-%s %s' % (indent_str, mod, files)) 85 lines.append(r'%s\-%s %s' % (indent_str, mod, files))
90 if i == len(nodes)-1: 86 if i == len(nodes)-1:
91 sub_indent_str = '%s ' % indent_str 87 sub_indent_str = '%s ' % indent_str
92 else: 88 else:
93 sub_indent_str = '%s| ' % indent_str 89 sub_indent_str = '%s| ' % indent_str
94 if sub: 90 if sub:
95 lines.append(repr_tree_defs(sub, sub_indent_str)) 91 lines.append(repr_tree_defs(sub, sub_indent_str))
96 return '\n'.join(lines) 92 return '\n'.join(lines)
97 93
98 94
99 def dependencies_graph(filename, dep_info): 95 def dependencies_graph(filename, dep_info):
100 """write dependencies as a dot (graphviz) file 96 """write dependencies as a dot (graphviz) file
101 """ 97 """
102 done = {} 98 done = {}
103 printer = DotBackend(filename[:-4], rankdir = "LR") 99 printer = DotBackend(filename[:-4], rankdir='LR')
104 printer.emit('URL="." node[shape="box"]') 100 printer.emit('URL="." node[shape="box"]')
105 for modname, dependencies in dep_info.items(): 101 for modname, dependencies in sorted(dep_info.iteritems()):
106 done[modname] = 1 102 done[modname] = 1
107 printer.emit_node(modname) 103 printer.emit_node(modname)
108 for modname in dependencies: 104 for modname in dependencies:
109 if modname not in done: 105 if modname not in done:
110 done[modname] = 1 106 done[modname] = 1
111 printer.emit_node(modname) 107 printer.emit_node(modname)
112 for depmodname, dependencies in dep_info.items(): 108 for depmodname, dependencies in sorted(dep_info.iteritems()):
113 for modname in dependencies: 109 for modname in dependencies:
114 printer.emit_edge(modname, depmodname) 110 printer.emit_edge(modname, depmodname)
115 printer.generate(filename) 111 printer.generate(filename)
116 112
117 113
118 def make_graph(filename, dep_info, sect, gtype): 114 def make_graph(filename, dep_info, sect, gtype):
119 """generate a dependencies graph and add some information about it in the 115 """generate a dependencies graph and add some information about it in the
120 report's section 116 report's section
121 """ 117 """
122 dependencies_graph(filename, dep_info) 118 dependencies_graph(filename, dep_info)
123 sect.append(Paragraph('%simports graph has been written to %s' 119 sect.append(Paragraph('%simports graph has been written to %s'
124 % (gtype, filename))) 120 % (gtype, filename)))
125 121
126 122
127 # the import checker itself ################################################### 123 # the import checker itself ###################################################
128 124
129 MSGS = { 125 MSGS = {
130 'F0401': ('Unable to import %s', 126 'F0401': ('Unable to import %s',
127 'import-error',
131 'Used when pylint has been unable to import a module.'), 128 'Used when pylint has been unable to import a module.'),
132 'R0401': ('Cyclic import (%s)', 129 'R0401': ('Cyclic import (%s)',
130 'cyclic-import',
133 'Used when a cyclic import between two or more modules is \ 131 'Used when a cyclic import between two or more modules is \
134 detected.'), 132 detected.'),
135 133
136 'W0401': ('Wildcard import %s', 134 'W0401': ('Wildcard import %s',
135 'wildcard-import',
137 'Used when `from module import *` is detected.'), 136 'Used when `from module import *` is detected.'),
138 'W0402': ('Uses of a deprecated module %r', 137 'W0402': ('Uses of a deprecated module %r',
138 'deprecated-module',
139 'Used a module marked as deprecated is imported.'), 139 'Used a module marked as deprecated is imported.'),
140 'W0403': ('Relative import %r, should be %r', 140 'W0403': ('Relative import %r, should be %r',
141 'Used when an import relative to the package directory is \ 141 'relative-import',
142 detected.'), 142 'Used when an import relative to the package directory is '
143 'detected.',
144 {'maxversion': (3, 0)}),
143 'W0404': ('Reimport %r (imported line %s)', 145 'W0404': ('Reimport %r (imported line %s)',
146 'reimported',
144 'Used when a module is reimported multiple times.'), 147 'Used when a module is reimported multiple times.'),
145 'W0406': ('Module import itself', 148 'W0406': ('Module import itself',
149 'import-self',
146 'Used when a module is importing itself.'), 150 'Used when a module is importing itself.'),
147 151
148 'W0410': ('__future__ import is not the first non docstring statement', 152 'W0410': ('__future__ import is not the first non docstring statement',
153 'misplaced-future',
149 'Python 2.5 and greater require __future__ import to be the \ 154 'Python 2.5 and greater require __future__ import to be the \
150 first non docstring statement in the module.'), 155 first non docstring statement in the module.',
156 {'maxversion': (3, 0)}),
151 } 157 }
152 158
153 class ImportsChecker(BaseChecker): 159 class ImportsChecker(BaseChecker):
154 """checks for 160 """checks for
155 * external modules dependencies 161 * external modules dependencies
156 * relative / wildcard imports 162 * relative / wildcard imports
157 * cyclic imports 163 * cyclic imports
158 * uses of deprecated modules 164 * uses of deprecated modules
159 """ 165 """
160 166
161 __implements__ = IASTNGChecker 167 __implements__ = IAstroidChecker
162 168
163 name = 'imports' 169 name = 'imports'
164 msgs = MSGS 170 msgs = MSGS
165 priority = -2 171 priority = -2
166 172
173 if sys.version_info < (3,):
174 deprecated_modules = ('regsub', 'TERMIOS', 'Bastion', 'rexec')
175 else:
176 deprecated_modules = ('stringprep', 'optparse')
167 options = (('deprecated-modules', 177 options = (('deprecated-modules',
168 {'default' : ('regsub', 'string', 'TERMIOS', 178 {'default' : deprecated_modules,
169 'Bastion', 'rexec'),
170 'type' : 'csv', 179 'type' : 'csv',
171 'metavar' : '<modules>', 180 'metavar' : '<modules>',
172 'help' : 'Deprecated modules which should not be used, \ 181 'help' : 'Deprecated modules which should not be used, \
173 separated by a comma'} 182 separated by a comma'}
174 ), 183 ),
175 ('import-graph', 184 ('import-graph',
176 {'default' : '', 185 {'default' : '',
177 'type' : 'string', 186 'type' : 'string',
178 'metavar' : '<file.dot>', 187 'metavar' : '<file.dot>',
179 'help' : 'Create a graph of every (i.e. internal and \ 188 'help' : 'Create a graph of every (i.e. internal and \
180 external) dependencies in the given file (report RP0402 must not be disabled)'} 189 external) dependencies in the given file (report RP0402 must not be disabled)'}
181 ), 190 ),
182 ('ext-import-graph', 191 ('ext-import-graph',
183 {'default' : '', 192 {'default' : '',
184 'type' : 'string', 193 'type' : 'string',
185 'metavar' : '<file.dot>', 194 'metavar' : '<file.dot>',
186 'help' : 'Create a graph of external dependencies in the \ 195 'help' : 'Create a graph of external dependencies in the \
187 given file (report RP0402 must not be disabled)'} 196 given file (report RP0402 must not be disabled)'}
188 ), 197 ),
189 ('int-import-graph', 198 ('int-import-graph',
190 {'default' : '', 199 {'default' : '',
191 'type' : 'string', 200 'type' : 'string',
192 'metavar' : '<file.dot>', 201 'metavar' : '<file.dot>',
193 'help' : 'Create a graph of internal dependencies in the \ 202 'help' : 'Create a graph of internal dependencies in the \
194 given file (report RP0402 must not be disabled)'} 203 given file (report RP0402 must not be disabled)'}
195 ), 204 ),
196 205 )
197 )
198 206
199 def __init__(self, linter=None): 207 def __init__(self, linter=None):
200 BaseChecker.__init__(self, linter) 208 BaseChecker.__init__(self, linter)
201 self.stats = None 209 self.stats = None
202 self.import_graph = None 210 self.import_graph = None
203 self.__int_dep_info = self.__ext_dep_info = None 211 self.__int_dep_info = self.__ext_dep_info = None
204 self.reports = (('RP0401', 'External dependencies', 212 self.reports = (('RP0401', 'External dependencies',
205 self.report_external_dependencies), 213 self.report_external_dependencies),
206 ('RP0402', 'Modules dependencies graph', 214 ('RP0402', 'Modules dependencies graph',
207 self.report_dependencies_graph), 215 self.report_dependencies_graph),
208 ) 216 )
209 217
210 def open(self): 218 def open(self):
211 """called before visiting project (i.e set of modules)""" 219 """called before visiting project (i.e set of modules)"""
212 self.linter.add_stats(dependencies={}) 220 self.linter.add_stats(dependencies={})
213 self.linter.add_stats(cycles=[]) 221 self.linter.add_stats(cycles=[])
214 self.stats = self.linter.stats 222 self.stats = self.linter.stats
215 self.import_graph = {} 223 self.import_graph = {}
216 224
217 def close(self): 225 def close(self):
218 """called before visiting project (i.e set of modules)""" 226 """called before visiting project (i.e set of modules)"""
219 # don't try to compute cycles if the associated message is disabled 227 # don't try to compute cycles if the associated message is disabled
220 if self.linter.is_message_enabled('R0401'): 228 if self.linter.is_message_enabled('cyclic-import'):
221 for cycle in get_cycles(self.import_graph): 229 for cycle in get_cycles(self.import_graph):
222 self.add_message('R0401', args=' -> '.join(cycle)) 230 self.add_message('cyclic-import', args=' -> '.join(cycle))
223 231
224 def visit_import(self, node): 232 def visit_import(self, node):
225 """triggered when an import statement is seen""" 233 """triggered when an import statement is seen"""
226 modnode = node.root() 234 modnode = node.root()
227 for name, _ in node.names: 235 for name, _ in node.names:
228 importedmodnode = self.get_imported_module(modnode, node, name) 236 importedmodnode = self.get_imported_module(modnode, node, name)
229 if importedmodnode is None: 237 if importedmodnode is None:
230 continue 238 continue
231 self._check_relative_import(modnode, node, importedmodnode, name) 239 self._check_relative_import(modnode, node, importedmodnode, name)
232 self._add_imported_module(node, importedmodnode.name) 240 self._add_imported_module(node, importedmodnode.name)
233 self._check_deprecated_module(node, name) 241 self._check_deprecated_module(node, name)
234 self._check_reimport(node, name) 242 self._check_reimport(node, name)
235 243
236 244 # TODO This appears to be the list of all messages of the checker...
245 # @check_messages('W0410', 'W0401', 'W0403', 'W0402', 'W0404', 'W0406', 'F04 01')
246 @check_messages(*(MSGS.keys()))
237 def visit_from(self, node): 247 def visit_from(self, node):
238 """triggered when a from statement is seen""" 248 """triggered when a from statement is seen"""
239 basename = node.modname 249 basename = node.modname
240 if basename == '__future__': 250 if basename == '__future__':
241 # check if this is the first non-docstring statement in the module 251 # check if this is the first non-docstring statement in the module
242 prev = node.previous_sibling() 252 prev = node.previous_sibling()
243 if prev: 253 if prev:
244 # consecutive future statements are possible 254 # consecutive future statements are possible
245 if not (isinstance(prev, astng.From) 255 if not (isinstance(prev, astroid.From)
246 and prev.modname == '__future__'): 256 and prev.modname == '__future__'):
247 self.add_message('W0410', node=node) 257 self.add_message('misplaced-future', node=node)
248 return 258 return
259 for name, _ in node.names:
260 if name == '*':
261 self.add_message('wildcard-import', args=basename, node=node)
249 modnode = node.root() 262 modnode = node.root()
250 importedmodnode = self.get_imported_module(modnode, node, basename) 263 importedmodnode = self.get_imported_module(modnode, node, basename)
251 if importedmodnode is None: 264 if importedmodnode is None:
252 return 265 return
253 self._check_relative_import(modnode, node, importedmodnode, basename) 266 self._check_relative_import(modnode, node, importedmodnode, basename)
254 self._check_deprecated_module(node, basename) 267 self._check_deprecated_module(node, basename)
255 for name, _ in node.names: 268 for name, _ in node.names:
256 if name == '*': 269 if name != '*':
257 self.add_message('W0401', args=basename, node=node) 270 self._add_imported_module(node, '%s.%s' % (importedmodnode.name, name))
258 continue 271 self._check_reimport(node, name, basename, node.level)
259 self._add_imported_module(node, '%s.%s' % (importedmodnode.name, nam e))
260 self._check_reimport(node, name, basename, node.level)
261 272
262 def get_imported_module(self, modnode, importnode, modname): 273 def get_imported_module(self, modnode, importnode, modname):
263 try: 274 try:
264 return importnode.do_import_module(modname) 275 return importnode.do_import_module(modname)
265 except astng.InferenceError, ex: 276 except astroid.InferenceError, ex:
266 if str(ex) != modname: 277 if str(ex) != modname:
267 args = '%r (%s)' % (modname, ex) 278 args = '%r (%s)' % (modname, ex)
268 else: 279 else:
269 args = repr(modname) 280 args = repr(modname)
270 self.add_message("F0401", args=args, node=importnode) 281 self.add_message("import-error", args=args, node=importnode)
271 282
272 def _check_relative_import(self, modnode, importnode, importedmodnode, 283 def _check_relative_import(self, modnode, importnode, importedmodnode,
273 importedasname): 284 importedasname):
274 """check relative import. node is either an Import or From node, modname 285 """check relative import. node is either an Import or From node, modname
275 the imported module name. 286 the imported module name.
276 """ 287 """
277 if 'W0403' not in self.active_msgs: 288 if not self.linter.is_message_enabled('relative-import'):
278 return 289 return
279 if importedmodnode.file is None: 290 if importedmodnode.file is None:
280 return False # built-in module 291 return False # built-in module
281 if modnode is importedmodnode: 292 if modnode is importedmodnode:
282 return False # module importing itself 293 return False # module importing itself
283 if modnode.absolute_import_activated() or getattr(importnode, 'level', N one): 294 if modnode.absolute_import_activated() or getattr(importnode, 'level', N one):
284 return False 295 return False
285 if importedmodnode.name != importedasname: 296 if importedmodnode.name != importedasname:
286 # this must be a relative import... 297 # this must be a relative import...
287 self.add_message('W0403', args=(importedasname, importedmodnode.name ), 298 self.add_message('relative-import', args=(importedasname, importedmo dnode.name),
288 node=importnode) 299 node=importnode)
289 300
290 def _add_imported_module(self, node, importedmodname): 301 def _add_imported_module(self, node, importedmodname):
291 """notify an imported module, used to analyze dependencies""" 302 """notify an imported module, used to analyze dependencies"""
303 try:
304 importedmodname = get_module_part(importedmodname)
305 except ImportError:
306 pass
292 context_name = node.root().name 307 context_name = node.root().name
293 if context_name == importedmodname: 308 if context_name == importedmodname:
294 # module importing itself ! 309 # module importing itself !
295 self.add_message('W0406', node=node) 310 self.add_message('import-self', node=node)
296 elif not is_standard_module(importedmodname): 311 elif not is_standard_module(importedmodname):
297 # handle dependencies 312 # handle dependencies
298 importedmodnames = self.stats['dependencies'].setdefault( 313 importedmodnames = self.stats['dependencies'].setdefault(
299 importedmodname, set()) 314 importedmodname, set())
300 if not context_name in importedmodnames: 315 if not context_name in importedmodnames:
301 importedmodnames.add(context_name) 316 importedmodnames.add(context_name)
302 if is_standard_module( importedmodname, (self.package_dir(),) ): 317 # update import graph
303 # update import graph 318 mgraph = self.import_graph.setdefault(context_name, set())
304 mgraph = self.import_graph.setdefault(context_name, set()) 319 if not importedmodname in mgraph:
305 if not importedmodname in mgraph: 320 mgraph.add(importedmodname)
306 mgraph.add(importedmodname)
307 321
308 def _check_deprecated_module(self, node, mod_path): 322 def _check_deprecated_module(self, node, mod_path):
309 """check if the module is deprecated""" 323 """check if the module is deprecated"""
310 for mod_name in self.config.deprecated_modules: 324 for mod_name in self.config.deprecated_modules:
311 if mod_path == mod_name or mod_path.startswith(mod_name + '.'): 325 if mod_path == mod_name or mod_path.startswith(mod_name + '.'):
312 self.add_message('W0402', node=node, args=mod_path) 326 self.add_message('deprecated-module', node=node, args=mod_path)
313 327
314 def _check_reimport(self, node, name, basename=None, level=0): 328 def _check_reimport(self, node, name, basename=None, level=None):
315 """check if the import is necessary (i.e. not already done)""" 329 """check if the import is necessary (i.e. not already done)"""
316 if 'W0404' not in self.active_msgs: 330 if not self.linter.is_message_enabled('reimported'):
317 return 331 return
318 frame = node.frame() 332 frame = node.frame()
319 root = node.root() 333 root = node.root()
320 contexts = [(frame, level)] 334 contexts = [(frame, level)]
321 if root is not frame: 335 if root is not frame:
322 contexts.append((root, 0)) 336 contexts.append((root, None))
323 for context, level in contexts: 337 for context, level in contexts:
324 first = get_first_import(node, context, name, basename, level) 338 first = get_first_import(node, context, name, basename, level)
325 if first is not None: 339 if first is not None:
326 self.add_message('W0404', node=node, 340 self.add_message('reimported', node=node,
327 args=(name, first.fromlineno)) 341 args=(name, first.fromlineno))
328 342
329 343
330 def report_external_dependencies(self, sect, _, dummy): 344 def report_external_dependencies(self, sect, _, dummy):
331 """return a verbatim layout for displaying dependencies""" 345 """return a verbatim layout for displaying dependencies"""
332 dep_info = make_tree_defs(self._external_dependencies_info().items()) 346 dep_info = make_tree_defs(self._external_dependencies_info().iteritems() )
333 if not dep_info: 347 if not dep_info:
334 raise EmptyReport() 348 raise EmptyReport()
335 tree_str = repr_tree_defs(dep_info) 349 tree_str = repr_tree_defs(dep_info)
336 sect.append(VerbatimText(tree_str)) 350 sect.append(VerbatimText(tree_str))
337 351
338 def report_dependencies_graph(self, sect, _, dummy): 352 def report_dependencies_graph(self, sect, _, dummy):
339 """write dependencies as a dot (graphviz) file""" 353 """write dependencies as a dot (graphviz) file"""
340 dep_info = self.stats['dependencies'] 354 dep_info = self.stats['dependencies']
341 if not dep_info or not (self.config.import_graph 355 if not dep_info or not (self.config.import_graph
342 or self.config.ext_import_graph 356 or self.config.ext_import_graph
343 or self.config.int_import_graph): 357 or self.config.int_import_graph):
344 raise EmptyReport() 358 raise EmptyReport()
345 filename = self.config.import_graph 359 filename = self.config.import_graph
346 if filename: 360 if filename:
347 make_graph(filename, dep_info, sect, '') 361 make_graph(filename, dep_info, sect, '')
348 filename = self.config.ext_import_graph 362 filename = self.config.ext_import_graph
349 if filename: 363 if filename:
350 make_graph(filename, self._external_dependencies_info(), 364 make_graph(filename, self._external_dependencies_info(),
351 sect, 'external ') 365 sect, 'external ')
352 filename = self.config.int_import_graph 366 filename = self.config.int_import_graph
353 if filename: 367 if filename:
354 make_graph(filename, self._internal_dependencies_info(), 368 make_graph(filename, self._internal_dependencies_info(),
355 sect, 'internal ') 369 sect, 'internal ')
356 370
357 def _external_dependencies_info(self): 371 def _external_dependencies_info(self):
358 """return cached external dependencies information or build and 372 """return cached external dependencies information or build and
359 cache them 373 cache them
360 """ 374 """
361 if self.__ext_dep_info is None: 375 if self.__ext_dep_info is None:
362 self.__ext_dep_info = filter_dependencies_info( 376 package = self.linter.current_name
363 self.stats['dependencies'], self.package_dir(), 'external') 377 self.__ext_dep_info = result = {}
378 for importee, importers in self.stats['dependencies'].iteritems():
379 if not importee.startswith(package):
380 result[importee] = importers
364 return self.__ext_dep_info 381 return self.__ext_dep_info
365 382
366 def _internal_dependencies_info(self): 383 def _internal_dependencies_info(self):
367 """return cached internal dependencies information or build and 384 """return cached internal dependencies information or build and
368 cache them 385 cache them
369 """ 386 """
370 if self.__int_dep_info is None: 387 if self.__int_dep_info is None:
371 self.__int_dep_info = filter_dependencies_info( 388 package = self.linter.current_name
372 self.stats['dependencies'], self.package_dir(), 'internal') 389 self.__int_dep_info = result = {}
390 for importee, importers in self.stats['dependencies'].iteritems():
391 if importee.startswith(package):
392 result[importee] = importers
373 return self.__int_dep_info 393 return self.__int_dep_info
374 394
375 395
376 def register(linter): 396 def register(linter):
377 """required method to auto register this checker """ 397 """required method to auto register this checker """
378 linter.register_checker(ImportsChecker(linter)) 398 linter.register_checker(ImportsChecker(linter))
OLDNEW
« no previous file with comments | « third_party/pylint/checkers/format.py ('k') | third_party/pylint/checkers/logging.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698