20 """ |
20 """ |
21 Codes = [ |
21 Codes = [ |
22 "M101", "M102", |
22 "M101", "M102", |
23 "M111", "M112", |
23 "M111", "M112", |
24 "M121", |
24 "M121", |
|
25 "M131", "M132", |
|
26 |
|
27 "M191", "M192", "M193", "M194", |
|
28 "M195", "M196", "M197", "M198", |
25 |
29 |
26 "M601", |
30 "M601", |
27 "M611", "M612", "M613", |
31 "M611", "M612", "M613", |
28 "M621", "M622", "M623", "M624", "M625", |
32 "M621", "M622", "M623", "M624", "M625", |
29 "M631", "M632", |
33 "M631", "M632", |
69 |
79 |
70 self.__blindExceptRegex = re.compile( |
80 self.__blindExceptRegex = re.compile( |
71 r'(\bexcept:)') # __IGNORE_WARNING__ |
81 r'(\bexcept:)') # __IGNORE_WARNING__ |
72 self.__pep3101FormatRegex = re.compile( |
82 self.__pep3101FormatRegex = re.compile( |
73 r'^(?:[^\'"]*[\'"][^\'"]*[\'"])*\s*%|^\s*%') |
83 r'^(?:[^\'"]*[\'"][^\'"]*[\'"])*\s*%|^\s*%') |
|
84 |
|
85 if sys.version_info >= (3, 0): |
|
86 import builtins |
|
87 self.__builtins = [b for b in dir(builtins) |
|
88 if b not in self.BuiltinsWhiteList] |
|
89 else: |
|
90 import __builtin__ |
|
91 self.__builtins = [b for b in dir(__builtin__) |
|
92 if b not in self.BuiltinsWhiteList] |
74 |
93 |
75 # statistics counters |
94 # statistics counters |
76 self.counters = {} |
95 self.counters = {} |
77 |
96 |
78 # collection of detected errors |
97 # collection of detected errors |
80 |
99 |
81 checkersWithCodes = [ |
100 checkersWithCodes = [ |
82 (self.__checkCoding, ("M101", "M102")), |
101 (self.__checkCoding, ("M101", "M102")), |
83 (self.__checkCopyright, ("M111", "M112")), |
102 (self.__checkCopyright, ("M111", "M112")), |
84 (self.__checkBlindExcept, ("M121",)), |
103 (self.__checkBlindExcept, ("M121",)), |
|
104 (self.__checkBuiltins, ("M131", "M132")), |
|
105 (self.__checkComprehensions, ("M191", "M192", "M193", "M194", |
|
106 "M195", "M196", "M197", "M198")), |
85 (self.__checkPep3101, ("M601",)), |
107 (self.__checkPep3101, ("M601",)), |
86 (self.__checkFormatString, ("M611", "M612", "M613", |
108 (self.__checkFormatString, ("M611", "M612", "M613", |
87 "M621", "M622", "M623", "M624", "M625", |
109 "M621", "M622", "M623", "M624", "M625", |
88 "M631", "M632")), |
110 "M631", "M632")), |
89 (self.__checkFuture, ("M701", "M702")), |
111 (self.__checkFuture, ("M701", "M702")), |
475 if parsedSpec[1] is not None) |
497 if parsedSpec[1] is not None) |
476 except ValueError: |
498 except ValueError: |
477 return set(), False, False |
499 return set(), False, False |
478 else: |
500 else: |
479 return fields, implicit, explicit |
501 return fields, implicit, explicit |
|
502 |
|
503 def __checkBuiltins(self): |
|
504 """ |
|
505 Private method to check, if built-ins are shadowed. |
|
506 """ |
|
507 for node in ast.walk(self.__tree): |
|
508 if isinstance(node, ast.Assign): |
|
509 # assign statement |
|
510 for element in node.targets: |
|
511 if isinstance(element, ast.Name) and \ |
|
512 element.id in self.__builtins: |
|
513 self.__error(element.lineno - 1, element.col_offset, |
|
514 "M131", element.id) |
|
515 elif isinstance(node, ast.FunctionDef): |
|
516 if sys.version_info >= (3, 0): |
|
517 for arg in node.args.args: |
|
518 if isinstance(arg, ast.arg) and \ |
|
519 arg.arg in self.__builtins: |
|
520 self.__error(arg.lineno - 1, arg.col_offset, |
|
521 "M132", arg.arg) |
|
522 else: |
|
523 for arg in node.args.args: |
|
524 if isinstance(arg, ast.Name) and \ |
|
525 arg.id in self.__builtins: |
|
526 self.__error(arg.lineno - 1, arg.col_offset, |
|
527 "M132", arg.id) |
|
528 |
|
529 def __checkComprehensions(self): |
|
530 """ |
|
531 Private method to check some comprehension related things. |
|
532 """ |
|
533 for node in ast.walk(self.__tree): |
|
534 if (isinstance(node, ast.Call) and |
|
535 len(node.args) == 1 and |
|
536 isinstance(node.func, ast.Name)): |
|
537 if (isinstance(node.args[0], ast.GeneratorExp) and |
|
538 node.func.id in ('list', 'set', 'dict')): |
|
539 errorCode = { |
|
540 "list": "M191", |
|
541 "set": "M192", |
|
542 "dict": "M193", |
|
543 }[node.func.id] |
|
544 self.__error(node.lineno - 1, node.col_offset, errorCode) |
|
545 |
|
546 elif (isinstance(node.args[0], ast.ListComp) and |
|
547 node.func.id in ('set', 'dict')): |
|
548 errorCode = { |
|
549 'set': 'M194', |
|
550 'dict': 'M195', |
|
551 }[node.func.id] |
|
552 self.__error(node.lineno - 1, node.col_offset, errorCode) |
|
553 |
|
554 elif (isinstance(node.args[0], ast.List) and |
|
555 node.func.id in ('set', 'dict')): |
|
556 errorCode = { |
|
557 'set': 'M196', |
|
558 'dict': 'M197', |
|
559 }[node.func.id] |
|
560 self.__error(node.lineno - 1, node.col_offset, errorCode) |
|
561 |
|
562 elif (isinstance(node.args[0], ast.ListComp) and |
|
563 node.func.id in ('all', 'any', 'frozenset', 'max', 'min', |
|
564 'sorted', 'sum', 'tuple',)): |
|
565 self.__error(node.lineno - 1, node.col_offset, "M198", |
|
566 node.func.id) |
480 |
567 |
481 |
568 |
482 class TextVisitor(ast.NodeVisitor): |
569 class TextVisitor(ast.NodeVisitor): |
483 """ |
570 """ |
484 Class implementing a node visitor for bytes and str instances. |
571 Class implementing a node visitor for bytes and str instances. |