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

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

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