eric6/Plugins/CheckerPlugins/CodeStyleChecker/MiscellaneousChecker.py

changeset 7289
6f4761a73f5f
parent 7256
4ef3b78ebb4e
child 7360
9190402e4505
equal deleted inserted replaced
7288:1242c374623b 7289:6f4761a73f5f
12 import re 12 import re
13 import itertools 13 import itertools
14 from string import Formatter 14 from string import Formatter
15 from collections import defaultdict 15 from collections import defaultdict
16 import tokenize 16 import tokenize
17
18 import AstUtilities
17 19
18 20
19 def composeCallPath(node): 21 def composeCallPath(node):
20 """ 22 """
21 Generator function to assemble the call path of a given node. 23 Generator function to assemble the call path of a given node.
465 for node in ast.walk(self.__tree): 467 for node in ast.walk(self.__tree):
466 if (isinstance(node, ast.ImportFrom) and 468 if (isinstance(node, ast.ImportFrom) and
467 node.module == '__future__'): 469 node.module == '__future__'):
468 imports |= {name.name for name in node.names} 470 imports |= {name.name for name in node.names}
469 elif isinstance(node, ast.Expr): 471 elif isinstance(node, ast.Expr):
470 if not isinstance(node.value, ast.Str): 472 if not AstUtilities.isString(node.value):
471 hasCode = True 473 hasCode = True
472 break 474 break
473 elif not isinstance(node, (ast.Module, ast.Str)): 475 elif not (
476 AstUtilities.isString(node) or
477 isinstance(node, ast.Module)
478 ):
474 hasCode = True 479 hasCode = True
475 break 480 break
476 481
477 if isinstance(node, ast.Module) or not hasCode: 482 if isinstance(node, ast.Module) or not hasCode:
478 return 483 return
877 882
878 @param node reference to the AST node 883 @param node reference to the AST node
879 @return flag indicating to check the node 884 @return flag indicating to check the node
880 @rtype bool 885 @rtype bool
881 """ 886 """
882 if not all(isinstance(key, ast.Str) for key in node.keys): 887 if not all(AstUtilities.isString(key) for key in node.keys):
883 return False 888 return False
884 889
885 if ( 890 if (
886 "__IGNORE_WARNING__" in self.__source[node.lineno - 1] or 891 "__IGNORE_WARNING__" in self.__source[node.lineno - 1] or
887 "__IGNORE_WARNING_M201__" in self.__source[node.lineno - 1] 892 "__IGNORE_WARNING_M201__" in self.__source[node.lineno - 1]
1006 """ 1011 """
1007 if not hasattr(node, 'is_docstring'): 1012 if not hasattr(node, 'is_docstring'):
1008 node.is_docstring = False 1013 node.is_docstring = False
1009 self.nodes.append(node) 1014 self.nodes.append(node)
1010 1015
1011 def __isBaseString(self, node):
1012 """
1013 Private method to determine, if a node is a base string node.
1014
1015 @param node reference to the node to check
1016 @type ast.AST
1017 @return flag indicating a base string
1018 @rtype bool
1019 """
1020 typ = (ast.Str,)
1021 if sys.version_info[0] > 2:
1022 typ += (ast.Bytes,)
1023 return isinstance(node, typ)
1024
1025 def visit_Str(self, node): 1016 def visit_Str(self, node):
1026 """ 1017 """
1027 Public method to record a string node. 1018 Public method to record a string node.
1028 1019
1029 @param node reference to the string node 1020 @param node reference to the string node
1037 1028
1038 @param node reference to the bytes node 1029 @param node reference to the bytes node
1039 @type ast.Bytes 1030 @type ast.Bytes
1040 """ 1031 """
1041 self.__addNode(node) 1032 self.__addNode(node)
1033
1034 def visit_Constant(self, node):
1035 """
1036 Public method to handle constant nodes.
1037
1038 @param node reference to the bytes node
1039 @type ast.Constant
1040 """
1041 if sys.version_info >= (3, 8, 0):
1042 if AstUtilities.isBaseString(node):
1043 self.__addNode(node)
1044 else:
1045 super(TextVisitor, self).generic_visit(node)
1046 else:
1047 super(TextVisitor, self).generic_visit(node)
1042 1048
1043 def __visitDefinition(self, node): 1049 def __visitDefinition(self, node):
1044 """ 1050 """
1045 Private method handling class and function definitions. 1051 Private method handling class and function definitions.
1046 1052
1063 marks that as a docstring. 1069 marks that as a docstring.
1064 1070
1065 @param node reference to the node to traverse 1071 @param node reference to the node to traverse
1066 @type ast.AST 1072 @type ast.AST
1067 """ 1073 """
1068 if (node.body and isinstance(node.body[0], ast.Expr) and 1074 if (
1069 self.__isBaseString(node.body[0].value)): 1075 node.body and
1076 isinstance(node.body[0], ast.Expr) and
1077 AstUtilities.isBaseString(node.body[0].value)
1078 ):
1070 node.body[0].value.is_docstring = True 1079 node.body[0].value.is_docstring = True
1071 1080
1072 for subnode in node.body: 1081 for subnode in node.body:
1073 self.visit(subnode) 1082 self.visit(subnode)
1074 1083
1116 Public method to handle a function call. 1125 Public method to handle a function call.
1117 1126
1118 @param node reference to the node to handle 1127 @param node reference to the node to handle
1119 @type ast.Call 1128 @type ast.Call
1120 """ 1129 """
1121 if (isinstance(node.func, ast.Attribute) and 1130 if (
1122 node.func.attr == 'format'): 1131 isinstance(node.func, ast.Attribute) and
1123 if self.__isBaseString(node.func.value): 1132 node.func.attr == 'format'
1133 ):
1134 if AstUtilities.isBaseString(node.func.value):
1124 self.calls[node.func.value] = (node, False) 1135 self.calls[node.func.value] = (node, False)
1125 elif (isinstance(node.func.value, ast.Name) and 1136 elif (
1126 node.func.value.id == 'str' and node.args and 1137 isinstance(node.func.value, ast.Name) and
1127 self.__isBaseString(node.args[0])): 1138 node.func.value.id == 'str' and
1139 node.args and
1140 AstUtilities.isBaseString(node.args[0])
1141 ):
1128 self.calls[node.args[0]] = (node, True) 1142 self.calls[node.args[0]] = (node, True)
1129 super(TextVisitor, self).generic_visit(node) 1143 super(TextVisitor, self).generic_visit(node)
1130 1144
1131 1145
1132 class LoggingVisitor(ast.NodeVisitor): 1146 class LoggingVisitor(ast.NodeVisitor):
1404 ): 1418 ):
1405 self.violations.append((node, "M511")) 1419 self.violations.append((node, "M511"))
1406 if ( 1420 if (
1407 node.func.id == "getattr" and 1421 node.func.id == "getattr" and
1408 len(node.args) == 2 and 1422 len(node.args) == 2 and
1409 isinstance(node.args[1], ast.Str) 1423 AstUtilities.isString(node.args[1])
1410 ): 1424 ):
1411 self.violations.append((node, "M512")) 1425 self.violations.append((node, "M512"))
1412 elif ( 1426 elif (
1413 node.func.id == "setattr" and 1427 node.func.id == "setattr" and
1414 len(node.args) == 3 and 1428 len(node.args) == 3 and
1415 isinstance(node.args[1], ast.Str) 1429 AstUtilities.isString(node.args[1])
1416 ): 1430 ):
1417 self.violations.append((node, "M513")) 1431 self.violations.append((node, "M513"))
1418 except (AttributeError, IndexError): 1432 except (AttributeError, IndexError):
1419 pass 1433 pass
1420 1434
1485 1499
1486 @param node reference to the node to be processed 1500 @param node reference to the node to be processed
1487 @type ast.Assert 1501 @type ast.Assert
1488 """ 1502 """
1489 if ( 1503 if (
1490 isinstance(node.test, ast.NameConstant) and 1504 AstUtilities.isNameConstant(node.test) and
1491 node.test.value is False 1505 AstUtilities.getValue(node.test) is False
1492 ): 1506 ):
1493 self.violations.append((node, "M503")) 1507 self.violations.append((node, "M503"))
1494 1508
1495 self.generic_visit(node) 1509 self.generic_visit(node)
1496 1510
1516 @type ast.Call 1530 @type ast.Call
1517 """ 1531 """
1518 if node.func.attr not in ("lstrip", "rstrip", "strip"): 1532 if node.func.attr not in ("lstrip", "rstrip", "strip"):
1519 return # method name doesn't match 1533 return # method name doesn't match
1520 1534
1521 if len(node.args) != 1 or not isinstance(node.args[0], ast.Str): 1535 if len(node.args) != 1 or not AstUtilities.isString(node.args[0]):
1522 return # used arguments don't match the builtin strip 1536 return # used arguments don't match the builtin strip
1523 1537
1524 s = node.args[0].s 1538 s = AstUtilities.getValue(node.args[0])
1525 if len(s) == 1: 1539 if len(s) == 1:
1526 return # stripping just one character 1540 return # stripping just one character
1527 1541
1528 if len(s) == len(set(s)): 1542 if len(s) == len(set(s)):
1529 return # no characters appear more than once 1543 return # no characters appear more than once
1762 1776
1763 @param node reference to the node to check 1777 @param node reference to the node to check
1764 @type ast.AST 1778 @type ast.AST
1765 @return flag indicating the node contains a None value 1779 @return flag indicating the node contains a None value
1766 """ 1780 """
1767 try: 1781 if sys.version_info[0] > 2:
1768 return isinstance(node, ast.NameConstant) and node.value is None 1782 return (
1769 except AttributeError: 1783 AstUtilities.isNameConstant(node) and
1770 # try Py2 1784 AstUtilities.getValue(node) is None
1785 )
1786 else:
1771 return isinstance(node, ast.Name) and node.id == "None" 1787 return isinstance(node, ast.Name) and node.id == "None"
1772 1788
1773 def __resultExists(self): 1789 def __resultExists(self):
1774 """ 1790 """
1775 Private method to check the existance of a return result. 1791 Private method to check the existance of a return result.
1951 1967
1952 if isDateTimeClass: 1968 if isDateTimeClass:
1953 if node.func.attr == 'datetime': 1969 if node.func.attr == 'datetime':
1954 # datetime.datetime(2000, 1, 1, 0, 0, 0, 0, 1970 # datetime.datetime(2000, 1, 1, 0, 0, 0, 0,
1955 # datetime.timezone.utc) 1971 # datetime.timezone.utc)
1956 isCase1 = (len(node.args) >= 8 and 1972 isCase1 = (
1957 not (isinstance(node.args[7], ast.NameConstant) and 1973 len(node.args) >= 8 and
1958 node.args[7].value is None)) 1974 not (
1975 AstUtilities.isNameConstant(node.args[7]) and
1976 AstUtilities.getValue(node.args[7]) is None
1977 )
1978 )
1959 1979
1960 # datetime.datetime(2000, 1, 1, tzinfo=datetime.timezone.utc) 1980 # datetime.datetime(2000, 1, 1, tzinfo=datetime.timezone.utc)
1961 tzinfoKeyword = self.__getFromKeywords(node.keywords, 'tzinfo') 1981 tzinfoKeyword = self.__getFromKeywords(node.keywords, 'tzinfo')
1962 isCase2 = (tzinfoKeyword is not None and 1982 isCase2 = (
1963 not (isinstance(tzinfoKeyword.value, 1983 tzinfoKeyword is not None and
1964 ast.NameConstant) and 1984 not (
1965 tzinfoKeyword.value.value is None)) 1985 AstUtilities.isNameConstant(tzinfoKeyword.value) and
1986 AstUtilities.getValue(tzinfoKeyword.value) is None
1987 )
1988 )
1966 1989
1967 if not (isCase1 or isCase2): 1990 if not (isCase1 or isCase2):
1968 self.violations.append((node, "M301")) 1991 self.violations.append((node, "M301"))
1969 1992
1970 elif node.func.attr == 'time': 1993 elif node.func.attr == 'time':
1971 # time(12, 10, 45, 0, datetime.timezone.utc) 1994 # time(12, 10, 45, 0, datetime.timezone.utc)
1972 isCase1 = (len(node.args) >= 5 and 1995 isCase1 = (
1973 not (isinstance(node.args[4], ast.NameConstant) and 1996 len(node.args) >= 5 and
1974 node.args[4].value is None)) 1997 not (
1998 AstUtilities.isNameConstant(node.args[4]) and
1999 AstUtilities.getValue(node.args[4]) is None
2000 )
2001 )
1975 2002
1976 # datetime.time(12, 10, 45, tzinfo=datetime.timezone.utc) 2003 # datetime.time(12, 10, 45, tzinfo=datetime.timezone.utc)
1977 tzinfoKeyword = self.__getFromKeywords(node.keywords, 'tzinfo') 2004 tzinfoKeyword = self.__getFromKeywords(node.keywords, 'tzinfo')
1978 isCase2 = (tzinfoKeyword is not None and 2005 isCase2 = (
1979 not (isinstance(tzinfoKeyword.value, 2006 tzinfoKeyword is not None and
1980 ast.NameConstant) and 2007 not (
1981 tzinfoKeyword.value.value is None)) 2008 AstUtilities.isNameConstant(tzinfoKeyword.value) and
2009 AstUtilities.getValue(tzinfoKeyword.value) is None
2010 )
2011 )
1982 2012
1983 if not (isCase1 or isCase2): 2013 if not (isCase1 or isCase2):
1984 self.violations.append((node, "M321")) 2014 self.violations.append((node, "M321"))
1985 2015
1986 elif node.func.attr == 'date': 2016 elif node.func.attr == 'date':
1996 elif node.func.attr == 'utcfromtimestamp': 2026 elif node.func.attr == 'utcfromtimestamp':
1997 self.violations.append((node, "M304")) 2027 self.violations.append((node, "M304"))
1998 2028
1999 elif node.func.attr in 'now': 2029 elif node.func.attr in 'now':
2000 # datetime.now(UTC) 2030 # datetime.now(UTC)
2001 isCase1 = (len(node.args) == 1 and 2031 isCase1 = (
2002 len(node.keywords) == 0 and 2032 len(node.args) == 1 and
2003 not (isinstance(node.args[0], ast.NameConstant) and 2033 len(node.keywords) == 0 and
2004 node.args[0].value is None)) 2034 not (
2035 AstUtilities.isNameConstant(node.args[0]) and
2036 AstUtilities.getValue(node.args[0]) is None
2037 )
2038 )
2005 2039
2006 # datetime.now(tz=UTC) 2040 # datetime.now(tz=UTC)
2007 tzKeyword = self.__getFromKeywords(node.keywords, 'tz') 2041 tzKeyword = self.__getFromKeywords(node.keywords, 'tz')
2008 isCase2 = (tzKeyword is not None and 2042 isCase2 = (
2009 not (isinstance(tzKeyword.value, 2043 tzKeyword is not None and
2010 ast.NameConstant) and 2044 not (
2011 tzKeyword.value.value is None)) 2045 AstUtilities.isNameConstant(tzKeyword.value) and
2046 AstUtilities.getValue(tzKeyword.value) is None
2047 )
2048 )
2012 2049
2013 if not (isCase1 or isCase2): 2050 if not (isCase1 or isCase2):
2014 self.violations.append((node, "M305")) 2051 self.violations.append((node, "M305"))
2015 2052
2016 elif node.func.attr == 'fromtimestamp': 2053 elif node.func.attr == 'fromtimestamp':
2017 # datetime.fromtimestamp(1234, UTC) 2054 # datetime.fromtimestamp(1234, UTC)
2018 isCase1 = (len(node.args) == 2 and 2055 isCase1 = (
2019 len(node.keywords) == 0 and 2056 len(node.args) == 2 and
2020 not (isinstance(node.args[1], ast.NameConstant) and 2057 len(node.keywords) == 0 and
2021 node.args[1].value is None)) 2058 not (
2059 AstUtilities.isNameConstant(node.args[1]) and
2060 AstUtilities.getValue(node.args[1]) is None
2061 )
2062 )
2022 2063
2023 # datetime.fromtimestamp(1234, tz=UTC) 2064 # datetime.fromtimestamp(1234, tz=UTC)
2024 tzKeyword = self.__getFromKeywords(node.keywords, 'tz') 2065 tzKeyword = self.__getFromKeywords(node.keywords, 'tz')
2025 isCase2 = (tzKeyword is not None and 2066 isCase2 = (
2026 not (isinstance(tzKeyword.value, 2067 tzKeyword is not None and
2027 ast.NameConstant) and 2068 not (
2028 tzKeyword.value.value is None)) 2069 AstUtilities.isNameConstant(tzKeyword.value) and
2070 AstUtilities.getValue(tzKeyword.value) is None
2071 )
2072 )
2029 2073
2030 if not (isCase1 or isCase2): 2074 if not (isCase1 or isCase2):
2031 self.violations.append((node, "M306")) 2075 self.violations.append((node, "M306"))
2032 2076
2033 elif node.func.attr == 'strptime': 2077 elif node.func.attr == 'strptime':
2040 elif not isinstance(pparent, ast.Call): 2084 elif not isinstance(pparent, ast.Call):
2041 isCase1 = False 2085 isCase1 = False
2042 else: 2086 else:
2043 tzinfoKeyword = self.__getFromKeywords(pparent.keywords, 2087 tzinfoKeyword = self.__getFromKeywords(pparent.keywords,
2044 'tzinfo') 2088 'tzinfo')
2045 isCase1 = (tzinfoKeyword is not None and 2089 isCase1 = (
2046 not (isinstance(tzinfoKeyword.value, 2090 tzinfoKeyword is not None and
2047 ast.NameConstant) and 2091 not (
2048 tzinfoKeyword.value.value is None)) 2092 AstUtilities.isNameConstant(
2093 tzinfoKeyword.value) and
2094 AstUtilities.getValue(tzinfoKeyword.value) is None
2095 )
2096 )
2049 2097
2050 if not isCase1: 2098 if not isCase1:
2051 self.violations.append((node, "M307")) 2099 self.violations.append((node, "M307"))
2052 2100
2053 elif node.func.attr == 'fromordinal': 2101 elif node.func.attr == 'fromordinal':
2151 """ 2199 """
2152 return ( 2200 return (
2153 self.__isSys("version", node.value) and 2201 self.__isSys("version", node.value) and
2154 isinstance(node.slice, ast.Slice) and 2202 isinstance(node.slice, ast.Slice) and
2155 node.slice.lower is None and 2203 node.slice.lower is None and
2156 isinstance(node.slice.upper, ast.Num) and 2204 AstUtilities.isNumber(node.slice.upper) and
2157 node.slice.upper.n == n and 2205 AstUtilities.getValue(node.slice.upper) == n and
2158 node.slice.step is None 2206 node.slice.step is None
2159 ) 2207 )
2160 2208
2161 def visit_Subscript(self, node): 2209 def visit_Subscript(self, node):
2162 """ 2210 """
2170 elif self.__isSysVersionUpperSlice(node, 3): 2218 elif self.__isSysVersionUpperSlice(node, 3):
2171 self.violations.append((node.value, "M401")) 2219 self.violations.append((node.value, "M401"))
2172 elif ( 2220 elif (
2173 self.__isSys('version', node.value) and 2221 self.__isSys('version', node.value) and
2174 isinstance(node.slice, ast.Index) and 2222 isinstance(node.slice, ast.Index) and
2175 isinstance(node.slice.value, ast.Num) and 2223 AstUtilities.isNumber(node.slice.value) and
2176 node.slice.value.n == 2 2224 AstUtilities.getValue(node.slice.value) == 2
2177 ): 2225 ):
2178 self.violations.append((node.value, "M402")) 2226 self.violations.append((node.value, "M402"))
2179 elif ( 2227 elif (
2180 self.__isSys('version', node.value) and 2228 self.__isSys('version', node.value) and
2181 isinstance(node.slice, ast.Index) and 2229 isinstance(node.slice, ast.Index) and
2182 isinstance(node.slice.value, ast.Num) and 2230 AstUtilities.isNumber(node.slice.value) and
2183 node.slice.value.n == 0 2231 AstUtilities.getValue(node.slice.value) == 0
2184 ): 2232 ):
2185 self.violations.append((node.value, "M421")) 2233 self.violations.append((node.value, "M421"))
2186 2234
2187 self.generic_visit(node) 2235 self.generic_visit(node)
2188 2236
2195 """ 2243 """
2196 if ( 2244 if (
2197 isinstance(node.left, ast.Subscript) and 2245 isinstance(node.left, ast.Subscript) and
2198 self.__isSys('version_info', node.left.value) and 2246 self.__isSys('version_info', node.left.value) and
2199 isinstance(node.left.slice, ast.Index) and 2247 isinstance(node.left.slice, ast.Index) and
2200 isinstance(node.left.slice.value, ast.Num) and 2248 AstUtilities.isNumber(node.left.slice.value) and
2201 node.left.slice.value.n == 0 and 2249 AstUtilities.getValue(node.left.slice.value) == 0 and
2202 len(node.ops) == 1 and 2250 len(node.ops) == 1 and
2203 isinstance(node.ops[0], ast.Eq) and 2251 isinstance(node.ops[0], ast.Eq) and
2204 isinstance(node.comparators[0], ast.Num) and 2252 AstUtilities.isNumber(node.comparators[0]) and
2205 node.comparators[0].n == 3 2253 AstUtilities.getValue(node.comparators[0]) == 3
2206 ): 2254 ):
2207 self.violations.append((node.left, "M411")) 2255 self.violations.append((node.left, "M411"))
2208 elif ( 2256 elif (
2209 self.__isSys('version', node.left) and 2257 self.__isSys('version', node.left) and
2210 len(node.ops) == 1 and 2258 len(node.ops) == 1 and
2211 isinstance(node.ops[0], (ast.Lt, ast.LtE, ast.Gt, ast.GtE)) and 2259 isinstance(node.ops[0], (ast.Lt, ast.LtE, ast.Gt, ast.GtE)) and
2212 isinstance(node.comparators[0], ast.Str) 2260 AstUtilities.isString(node.comparators[0])
2213 ): 2261 ):
2214 if len(node.comparators[0].s) == 1: 2262 if len(AstUtilities.getValue(node.comparators[0])) == 1:
2215 errorCode = "M422" 2263 errorCode = "M422"
2216 else: 2264 else:
2217 errorCode = "M403" 2265 errorCode = "M403"
2218 self.violations.append((node.left, errorCode)) 2266 self.violations.append((node.left, errorCode))
2219 elif ( 2267 elif (
2220 isinstance(node.left, ast.Subscript) and 2268 isinstance(node.left, ast.Subscript) and
2221 self.__isSys('version_info', node.left.value) and 2269 self.__isSys('version_info', node.left.value) and
2222 isinstance(node.left.slice, ast.Index) and 2270 isinstance(node.left.slice, ast.Index) and
2223 isinstance(node.left.slice.value, ast.Num) and 2271 AstUtilities.isNumber(node.left.slice.value) and
2224 node.left.slice.value.n == 1 and 2272 AstUtilities.getValue(node.left.slice.value) == 1 and
2225 len(node.ops) == 1 and 2273 len(node.ops) == 1 and
2226 isinstance(node.ops[0], (ast.Lt, ast.LtE, ast.Gt, ast.GtE)) and 2274 isinstance(node.ops[0], (ast.Lt, ast.LtE, ast.Gt, ast.GtE)) and
2227 isinstance(node.comparators[0], ast.Num) 2275 AstUtilities.isNumber(node.comparators[0])
2228 ): 2276 ):
2229 self.violations.append((node, "M413")) 2277 self.violations.append((node, "M413"))
2230 elif ( 2278 elif (
2231 isinstance(node.left, ast.Attribute) and 2279 isinstance(node.left, ast.Attribute) and
2232 self.__isSys('version_info', node.left.value) and 2280 self.__isSys('version_info', node.left.value) and
2233 node.left.attr == 'minor' and 2281 node.left.attr == 'minor' and
2234 len(node.ops) == 1 and 2282 len(node.ops) == 1 and
2235 isinstance(node.ops[0], (ast.Lt, ast.LtE, ast.Gt, ast.GtE)) and 2283 isinstance(node.ops[0], (ast.Lt, ast.LtE, ast.Gt, ast.GtE)) and
2236 isinstance(node.comparators[0], ast.Num) 2284 AstUtilities.isNumber(node.comparators[0])
2237 ): 2285 ):
2238 self.violations.append((node, "M414")) 2286 self.violations.append((node, "M414"))
2239 2287
2240 self.generic_visit(node) 2288 self.generic_visit(node)
2241 2289

eric ide

mercurial