eric6/Plugins/CheckerPlugins/CodeStyleChecker/MiscellaneousChecker.py

changeset 7637
c878e8255972
parent 7610
df7025fe26a3
child 7639
422fd05e9c91
equal deleted inserted replaced
7636:61566f35ab22 7637:c878e8255972
149 self.__args = args 149 self.__args = args
150 150
151 self.__pep3101FormatRegex = re.compile( 151 self.__pep3101FormatRegex = re.compile(
152 r'^(?:[^\'"]*[\'"][^\'"]*[\'"])*\s*%|^\s*%') 152 r'^(?:[^\'"]*[\'"][^\'"]*[\'"])*\s*%|^\s*%')
153 153
154 if sys.version_info >= (3, 0): 154 import builtins
155 import builtins 155 self.__builtins = [b for b in dir(builtins)
156 self.__builtins = [b for b in dir(builtins) 156 if b not in self.BuiltinsWhiteList]
157 if b not in self.BuiltinsWhiteList]
158 else:
159 import __builtin__
160 self.__builtins = [b for b in dir(__builtin__)
161 if b not in self.BuiltinsWhiteList]
162 157
163 # statistics counters 158 # statistics counters
164 self.counters = {} 159 self.counters = {}
165 160
166 # collection of detected errors 161 # collection of detected errors
290 285
291 @return generated AST 286 @return generated AST
292 @rtype ast.AST 287 @rtype ast.AST
293 """ 288 """
294 source = "".join(self.__source) 289 source = "".join(self.__source)
295 # Check type for py2: if not str it's unicode
296 if sys.version_info[0] == 2:
297 try:
298 source = source.encode('utf-8')
299 except UnicodeError:
300 pass
301
302 return compile(source, self.__filename, 'exec', ast.PyCF_ONLY_AST) 290 return compile(source, self.__filename, 'exec', ast.PyCF_ONLY_AST)
303 291
304 def run(self): 292 def run(self):
305 """ 293 """
306 Public method to check the given source against miscellaneous 294 Public method to check the given source against miscellaneous
531 519
532 visitor = TextVisitor() 520 visitor = TextVisitor()
533 visitor.visit(self.__tree) 521 visitor.visit(self.__tree)
534 for node in visitor.nodes: 522 for node in visitor.nodes:
535 text = node.s 523 text = node.s
536 if sys.version_info[0] > 2 and isinstance(text, bytes): 524 if isinstance(text, bytes):
537 try: 525 try:
538 text = text.decode(coding) 526 text = text.decode(coding)
539 except UnicodeDecodeError: 527 except UnicodeDecodeError:
540 continue 528 continue
541 fields, implicit, explicit = self.__getFields(text) 529 fields, implicit, explicit = self.__getFields(text)
709 element.col_offset, 697 element.col_offset,
710 "M131", element.id) 698 "M131", element.id)
711 elif any(isinstance(node, functionDef) 699 elif any(isinstance(node, functionDef)
712 for functionDef in functionDefs): 700 for functionDef in functionDefs):
713 # (asynchronous) function definition 701 # (asynchronous) function definition
714 if sys.version_info >= (3, 0): 702 for arg in node.args.args:
715 for arg in node.args.args: 703 if (
716 if ( 704 isinstance(arg, ast.arg) and
717 isinstance(arg, ast.arg) and 705 arg.arg in self.__builtins
718 arg.arg in self.__builtins 706 ):
719 ): 707 self.__error(arg.lineno - 1, arg.col_offset,
720 self.__error(arg.lineno - 1, arg.col_offset, 708 "M132", arg.arg)
721 "M132", arg.arg)
722 else:
723 for arg in node.args.args:
724 if (
725 isinstance(arg, ast.Name) and
726 arg.id in self.__builtins
727 ):
728 self.__error(arg.lineno - 1, arg.col_offset,
729 "M132", arg.id)
730 709
731 def __checkComprehensions(self): 710 def __checkComprehensions(self):
732 """ 711 """
733 Private method to check some comprehension related things. 712 Private method to check some comprehension related things.
734 """ 713 """
960 939
961 def __checkDateTime(self): 940 def __checkDateTime(self):
962 """ 941 """
963 Private method to check use of naive datetime functions. 942 Private method to check use of naive datetime functions.
964 """ 943 """
965 if sys.version_info[0] >= 3: 944 # step 1: generate an augmented node tree containing parent info
966 # this check is only performed for Python 3 945 # for each child node
967 946 tree = self.__generateTree()
968 # step 1: generate an augmented node tree containing parent info 947 for node in ast.walk(tree):
969 # for each child node 948 for childNode in ast.iter_child_nodes(node):
970 tree = self.__generateTree() 949 childNode._dtCheckerParent = node
971 for node in ast.walk(tree): 950
972 for childNode in ast.iter_child_nodes(node): 951 # step 2: perform checks and report issues
973 childNode._dtCheckerParent = node 952 visitor = DateTimeVisitor()
974 953 visitor.visit(tree)
975 # step 2: perform checks and report issues 954 for violation in visitor.violations:
976 visitor = DateTimeVisitor() 955 node = violation[0]
977 visitor.visit(tree) 956 reason = violation[1]
978 for violation in visitor.violations: 957 self.__error(node.lineno - 1, node.col_offset, reason)
979 node = violation[0]
980 reason = violation[1]
981 self.__error(node.lineno - 1, node.col_offset, reason)
982 958
983 def __checkSysVersion(self): 959 def __checkSysVersion(self):
984 """ 960 """
985 Private method to check the use of sys.version and sys.version_info. 961 Private method to check the use of sys.version and sys.version_info.
986 """ 962 """
1382 Public method to handle a function call. 1358 Public method to handle a function call.
1383 1359
1384 @param node reference to the node to be processed 1360 @param node reference to the node to be processed
1385 @type ast.Call 1361 @type ast.Call
1386 """ 1362 """
1387 if sys.version_info >= (3, 0): 1363 validPaths = ("six", "future.utils", "builtins")
1388 validPaths = ("six", "future.utils", "builtins") 1364 methodsDict = {
1389 methodsDict = { 1365 "M521": ("iterkeys", "itervalues", "iteritems", "iterlists"),
1390 "M521": ("iterkeys", "itervalues", "iteritems", "iterlists"), 1366 "M522": ("viewkeys", "viewvalues", "viewitems", "viewlists"),
1391 "M522": ("viewkeys", "viewvalues", "viewitems", "viewlists"), 1367 "M523": ("next",),
1392 "M523": ("next",), 1368 }
1393 }
1394 else:
1395 validPaths = ()
1396 methodsDict = {}
1397 1369
1398 if isinstance(node.func, ast.Attribute): 1370 if isinstance(node.func, ast.Attribute):
1399 for code, methods in methodsDict.items(): 1371 for code, methods in methodsDict.items():
1400 if node.func.attr in methods: 1372 if node.func.attr in methods:
1401 callPath = ".".join(composeCallPath(node.func.value)) 1373 callPath = ".".join(composeCallPath(node.func.value))
1448 @param node reference to the node to be processed 1420 @param node reference to the node to be processed
1449 @type ast.Attribute 1421 @type ast.Attribute
1450 """ 1422 """
1451 callPath = list(composeCallPath(node)) 1423 callPath = list(composeCallPath(node))
1452 1424
1453 if '.'.join(callPath) == 'sys.maxint' and sys.version_info >= (3, 0): 1425 if '.'.join(callPath) == 'sys.maxint':
1454 self.violations.append((node, "M504")) 1426 self.violations.append((node, "M504"))
1455 1427
1456 elif ( 1428 elif (
1457 len(callPath) == 2 and 1429 len(callPath) == 2 and
1458 callPath[1] == 'message' and 1430 callPath[1] == 'message'
1459 sys.version_info >= (2, 6)
1460 ): 1431 ):
1461 name = callPath[0] 1432 name = callPath[0]
1462 for elem in reversed(self.__nodeStack[:-1]): 1433 for elem in reversed(self.__nodeStack[:-1]):
1463 if isinstance(elem, ast.ExceptHandler) and elem.name == name: 1434 if isinstance(elem, ast.ExceptHandler) and elem.name == name:
1464 self.violations.append((node, "M505")) 1435 self.violations.append((node, "M505"))
1473 """ 1444 """
1474 if isinstance(self.__nodeStack[-2], ast.ClassDef): 1445 if isinstance(self.__nodeStack[-2], ast.ClassDef):
1475 # By using 'hasattr' below we're ignoring starred arguments, slices 1446 # By using 'hasattr' below we're ignoring starred arguments, slices
1476 # and tuples for simplicity. 1447 # and tuples for simplicity.
1477 assignTargets = {t.id for t in node.targets if hasattr(t, 'id')} 1448 assignTargets = {t.id for t in node.targets if hasattr(t, 'id')}
1478 if '__metaclass__' in assignTargets and sys.version_info >= (3, 0): 1449 if '__metaclass__' in assignTargets:
1479 self.violations.append((node, "M524")) 1450 self.violations.append((node, "M524"))
1480 1451
1481 elif len(node.targets) == 1: 1452 elif len(node.targets) == 1:
1482 target = node.targets[0] 1453 target = node.targets[0]
1483 if ( 1454 if (
1783 1754
1784 @param node reference to the node to check 1755 @param node reference to the node to check
1785 @type ast.AST 1756 @type ast.AST
1786 @return flag indicating the node contains a None value 1757 @return flag indicating the node contains a None value
1787 """ 1758 """
1788 if sys.version_info[0] > 2: 1759 return (
1789 return ( 1760 AstUtilities.isNameConstant(node) and
1790 AstUtilities.isNameConstant(node) and 1761 AstUtilities.getValue(node) is None
1791 AstUtilities.getValue(node) is None 1762 )
1792 )
1793 else:
1794 return isinstance(node, ast.Name) and node.id == "None"
1795 1763
1796 def __resultExists(self): 1764 def __resultExists(self):
1797 """ 1765 """
1798 Private method to check the existance of a return result. 1766 Private method to check the existance of a return result.
1799 1767
1848 return 1816 return
1849 1817
1850 try: 1818 try:
1851 okNodes = (ast.Return, ast.Raise, ast.While, ast.Try) 1819 okNodes = (ast.Return, ast.Raise, ast.While, ast.Try)
1852 except AttributeError: 1820 except AttributeError:
1853 # Py2
1854 okNodes = (ast.Return, ast.Raise, ast.While) 1821 okNodes = (ast.Return, ast.Raise, ast.While)
1855 if not isinstance(node, okNodes): 1822 if not isinstance(node, okNodes):
1856 self.violations.append((node, "M833")) 1823 self.violations.append((node, "M833"))
1857 1824
1858 def __checkUnnecessaryAssign(self, node): 1825 def __checkUnnecessaryAssign(self, node):

eric ide

mercurial