62 self.__blindExceptRegex = re.compile( |
61 self.__blindExceptRegex = re.compile( |
63 r'(except:)') # __IGNORE_WARNING__ |
62 r'(except:)') # __IGNORE_WARNING__ |
64 self.__pep3101FormatRegex = re.compile( |
63 self.__pep3101FormatRegex = re.compile( |
65 r'^(?:[^\'"]*[\'"][^\'"]*[\'"])*\s*%|^\s*%') |
64 r'^(?:[^\'"]*[\'"][^\'"]*[\'"])*\s*%|^\s*%') |
66 |
65 |
67 self.__availableFutureImports = { |
|
68 # future import: (code missing, code present) |
|
69 'division': ("M701", "M721"), |
|
70 'absolute_import': ("M702", "M722"), |
|
71 'with_statement': ("M703", "M723"), |
|
72 'print_function': ("M704", "M724"), |
|
73 'unicode_literals': ("M705", "M725"), |
|
74 'generator_stop': ("M706", "M726"), |
|
75 } |
|
76 |
|
77 # statistics counters |
66 # statistics counters |
78 self.counters = {} |
67 self.counters = {} |
79 |
68 |
80 # collection of detected errors |
69 # collection of detected errors |
81 self.errors = [] |
70 self.errors = [] |
86 (self.__checkCopyright, ("M111", "M112")), |
75 (self.__checkCopyright, ("M111", "M112")), |
87 (self.__checkBlindExcept, ("M121",)), |
76 (self.__checkBlindExcept, ("M121",)), |
88 (self.__checkPep3101, ("M131",)), |
77 (self.__checkPep3101, ("M131",)), |
89 (self.__checkPrintStatements, ("M801",)), |
78 (self.__checkPrintStatements, ("M801",)), |
90 (self.__checkTuple, ("M811", )), |
79 (self.__checkTuple, ("M811", )), |
91 (self.__checkFuture, ("M701", "M702", "M703", "M704", "M705", |
80 (self.__checkFuture, ("M701", "M702")), |
92 "M706", "M721", "M722", "M723", "M724", |
|
93 "M725", "M726")), |
|
94 ] |
81 ] |
95 |
82 |
96 self.__defaultArgs = { |
83 self.__defaultArgs = { |
97 "CodingChecker": 'latin-1, utf-8', |
84 "CodingChecker": 'latin-1, utf-8', |
98 "CopyrightChecker": { |
85 "CopyrightChecker": { |
294 |
281 |
295 def __checkFuture(self): |
282 def __checkFuture(self): |
296 """ |
283 """ |
297 Private method to check the __future__ imports. |
284 Private method to check the __future__ imports. |
298 """ |
285 """ |
299 visitor = FutureImportVisitor() |
286 expectedImports = set( |
300 visitor.visit(self.__tree) |
287 [i.strip() |
301 if not visitor.hasCode: |
288 for i in self.__args.get("FutureChecker", "").split(",") |
302 return |
289 if bool(i.strip())]) |
303 |
290 if len(expectedImports) == 0: |
304 present = set() |
291 # nothing to check for; disabling the check |
305 for importNode in visitor.futureImports: |
292 return |
306 for alias in importNode.names: |
293 |
307 if alias.name not in self.__availableFutureImports: |
294 imports = set() |
308 # unknown code |
295 node = None |
309 continue |
296 |
310 self.__error(importNode.lineno - 1, 0, |
297 for node in ast.walk(self.__tree): |
311 self.__availableFutureImports[alias.name][1]) |
298 if (isinstance(node, ast.ImportFrom) and |
312 present.add(alias.name) |
299 node.module == '__future__'): |
313 for name in self.__availableFutureImports: |
300 imports |= set(name.name for name in node.names) |
314 if name not in present: |
301 elif isinstance(node, ast.Expr): |
315 self.__error(0, 0, |
302 if not isinstance(node.value, ast.Str): |
316 self.__availableFutureImports[name][0]) |
303 break |
317 |
304 elif not isinstance(node, ast.Module): |
318 |
305 break |
319 class FutureImportVisitor(ast.NodeVisitor): |
306 |
320 """ |
307 if isinstance(node, ast.Module): |
321 Class implementing a node visitor to look for __future__ imports. |
308 return |
322 """ |
309 |
323 def __init__(self): |
310 if not (imports >= expectedImports): |
324 """ |
311 if imports: |
325 Constructor |
312 self.__error(node.lineno - 1, node.col_offset, "M701", |
326 """ |
313 ", ".join(expectedImports), ", ".join(imports)) |
327 super(FutureImportVisitor, self).__init__() |
314 else: |
328 self.futureImports = [] |
315 self.__error(node.lineno - 1, node.col_offset, "M702", |
329 self.__hasCode = False |
316 ", ".join(expectedImports)) |
330 |
|
331 def visit_ImportFrom(self, node): |
|
332 """ |
|
333 Public method to analyze an 'from ... import ...' node. |
|
334 |
|
335 @param node reference to the ImportFrom node |
|
336 @type ast.AST |
|
337 """ |
|
338 if node.module == '__future__': |
|
339 self.futureImports += [node] |
|
340 |
|
341 def visit_Expr(self, node): |
|
342 """ |
|
343 Public method to analyze an expression node. |
|
344 |
|
345 @param node reference to the expression node |
|
346 @type ast.AST |
|
347 """ |
|
348 if not isinstance(node.value, ast.Str) or node.value.col_offset != 0: |
|
349 self.__hasCode = True |
|
350 |
|
351 def generic_visit(self, node): |
|
352 """ |
|
353 Public method to analyze any other node. |
|
354 |
|
355 @param node reference to the node |
|
356 @type ast.AST |
|
357 """ |
|
358 if not isinstance(node, ast.Module): |
|
359 self.__hasCode = True |
|
360 super(FutureImportVisitor, self).generic_visit(node) |
|
361 |
|
362 @property |
|
363 def hasCode(self): |
|
364 """ |
|
365 Public method to check for the presence of some code. |
|
366 """ |
|
367 return self.__hasCode or self.futureImports |
|