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 |
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 |
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 |
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': |
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 |