src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Miscellaneous/MiscellaneousChecker.py

branch
eric7
changeset 10356
09c698245a5c
parent 10186
91c3ba0767ad
child 10359
de0420dac60e
equal deleted inserted replaced
10355:f3187412ecf4 10356:09c698245a5c
141 "M530", 141 "M530",
142 "M531", 142 "M531",
143 "M532", 143 "M532",
144 "M533", 144 "M533",
145 "M534", 145 "M534",
146 "M535",
146 ## Bugbear++ 147 ## Bugbear++
147 "M581", 148 "M581",
148 "M582", 149 "M582",
149 ## Format Strings 150 ## Format Strings
150 "M601", 151 "M601",
337 "M530", 338 "M530",
338 "M531", 339 "M531",
339 "M532", 340 "M532",
340 "M533", 341 "M533",
341 "M534", 342 "M534",
343 "M535",
342 "M581", 344 "M581",
343 "M582", 345 "M582",
344 ), 346 ),
345 ), 347 ),
346 (self.__checkPep3101, ("M601",)), 348 (self.__checkPep3101, ("M601",)),
1615 1617
1616 1618
1617 ####################################################################### 1619 #######################################################################
1618 ## BugBearVisitor 1620 ## BugBearVisitor
1619 ## 1621 ##
1620 ## adapted from: flake8-bugbear v23.7.10 1622 ## adapted from: flake8-bugbear v23.11.26
1621 ## 1623 ##
1622 ## Original: Copyright (c) 2016 Łukasz Langa 1624 ## Original: Copyright (c) 2016 Łukasz Langa
1623 ####################################################################### 1625 #######################################################################
1624 1626
1625 BugBearContext = namedtuple("BugBearContext", ["node", "stack"]) 1627 BugBearContext = namedtuple("BugBearContext", ["node", "stack"])
1894 @yield node references as determined by the ast.walk() function 1896 @yield node references as determined by the ast.walk() function
1895 @ytype ast.Node 1897 @ytype ast.Node
1896 """ 1898 """
1897 for node in nodes: 1899 for node in nodes:
1898 yield from ast.walk(node) 1900 yield from ast.walk(node)
1901
1902 def __getNamesFromTuple(self, node):
1903 """
1904 Private method to get the names from an ast.Tuple node.
1905
1906 @param node ast node to be processed
1907 @type ast.Tuple
1908 @yield names
1909 @ytype str
1910 """
1911 for dim in node.elts:
1912 if isinstance(dim, ast.Name):
1913 yield dim.id
1914 elif isinstance(dim, ast.Tuple):
1915 yield from self.__getNamesFromTuple(dim)
1916
1917 def __getDictCompLoopVarNames(self, node):
1918 """
1919 Private method to get the names of comprehension loop variables.
1920
1921 @param node ast node to be processed
1922 @type ast.DictComp
1923 @yield loop variable names
1924 @ytype str
1925 """
1926 for gen in node.generators:
1927 if isinstance(gen.target, ast.Name):
1928 yield gen.target.id
1929 elif isinstance(gen.target, ast.Tuple):
1930 yield from self.__getNamesFromTuple(gen.target)
1899 1931
1900 def visit(self, node): 1932 def visit(self, node):
1901 """ 1933 """
1902 Public method to traverse a given AST node. 1934 Public method to traverse a given AST node.
1903 1935
2022 and self.__isIdentifier(node.args[1]) 2054 and self.__isIdentifier(node.args[1])
2023 and iskeyword(AstUtilities.getValue(node.args[1])) 2055 and iskeyword(AstUtilities.getValue(node.args[1]))
2024 ): 2056 ):
2025 self.violations.append((node, "M510")) 2057 self.violations.append((node, "M510"))
2026 2058
2027 self.__checkForM526(node) 2059 self.__checkForM526(node)
2028 2060
2029 self.__checkForM528(node) 2061 self.__checkForM528(node)
2030 self.__checkForM534(node) 2062 self.__checkForM534(node)
2031 2063
2032 self.generic_visit(node) 2064 self.generic_visit(node)
2127 2159
2128 @param node reference to the node to be processed 2160 @param node reference to the node to be processed
2129 @type ast.DictComp 2161 @type ast.DictComp
2130 """ 2162 """
2131 self.__checkForM523(node) 2163 self.__checkForM523(node)
2164 self.__checkForM535(node)
2132 2165
2133 self.generic_visit(node) 2166 self.generic_visit(node)
2134 2167
2135 def visit_GeneratorExp(self, node): 2168 def visit_GeneratorExp(self, node):
2136 """ 2169 """
2263 """ 2296 """
2264 self.__checkForM505(node) 2297 self.__checkForM505(node)
2265 2298
2266 self.generic_visit(node) 2299 self.generic_visit(node)
2267 2300
2301 def visit_ImportFrom(self, node):
2302 """
2303 Public method to check from imports.
2304
2305 @param node reference to the node to be processed
2306 @type ast.Import
2307 """
2308 self.visit_Import(node)
2309
2268 def visit_Set(self, node): 2310 def visit_Set(self, node):
2269 """ 2311 """
2270 Public method to check a set. 2312 Public method to check a set.
2271 2313
2272 @param node reference to the node to be processed 2314 @param node reference to the node to be processed
2284 @type ast.Call 2326 @type ast.Call
2285 """ 2327 """
2286 if isinstance(node, ast.Import): 2328 if isinstance(node, ast.Import):
2287 for name in node.names: 2329 for name in node.names:
2288 self.__M505Imports.add(name.asname or name.name) 2330 self.__M505Imports.add(name.asname or name.name)
2331 elif isinstance(node, ast.ImportFrom):
2332 for name in node.names:
2333 self.__M505Imports.add(f"{node.module}.{name.name or name.asname}")
2289 elif isinstance(node, ast.Call): 2334 elif isinstance(node, ast.Call):
2290 if node.func.attr not in ("lstrip", "rstrip", "strip"): 2335 if node.func.attr not in ("lstrip", "rstrip", "strip"):
2291 return # method name doesn't match 2336 return # method name doesn't match
2292 2337
2293 if ( 2338 if (
2384 """ 2429 """
2385 item = node.items[0] 2430 item = node.items[0]
2386 itemContext = item.context_expr 2431 itemContext = item.context_expr
2387 if ( 2432 if (
2388 hasattr(itemContext, "func") 2433 hasattr(itemContext, "func")
2389 and isinstance(itemContext.func, ast.Attribute)
2390 and ( 2434 and (
2391 itemContext.func.attr == "assertRaises" 2435 (
2436 isinstance(itemContext.func, ast.Attribute)
2437 and (
2438 itemContext.func.attr == "assertRaises"
2439 or (
2440 itemContext.func.attr == "raises"
2441 and isinstance(itemContext.func.value, ast.Name)
2442 and itemContext.func.value.id == "pytest"
2443 and "match"
2444 not in [kwd.arg for kwd in itemContext.keywords]
2445 )
2446 )
2447 )
2392 or ( 2448 or (
2393 itemContext.func.attr == "raises" 2449 isinstance(itemContext.func, ast.Name)
2394 and isinstance(itemContext.func.value, ast.Name) 2450 and itemContext.func.id == "raises"
2395 and itemContext.func.value.id == "pytest" 2451 and isinstance(itemContext.func.ctx, ast.Load)
2452 and "pytest.raises" in self.__M505Imports
2396 and "match" not in [kwd.arg for kwd in itemContext.keywords] 2453 and "match" not in [kwd.arg for kwd in itemContext.keywords]
2397 ) 2454 )
2398 ) 2455 )
2399 and len(itemContext.args) == 1 2456 and len(itemContext.args) == 1
2400 and isinstance(itemContext.args[0], ast.Name) 2457 and isinstance(itemContext.args[0], ast.Name)
2843 2900
2844 if node.func.attr in ("sub", "subn"): 2901 if node.func.attr in ("sub", "subn"):
2845 check(3, "count") 2902 check(3, "count")
2846 elif node.func.attr == "split": 2903 elif node.func.attr == "split":
2847 check(2, "maxsplit") 2904 check(2, "maxsplit")
2905
2906 def __checkForM535(self, node: ast.DictComp):
2907 """
2908 Private method to check that a static key isn't used in a dict comprehension.
2909
2910 Record a warning if a likely unchanging key is used - either a constant,
2911 or a variable that isn't coming from the generator expression.
2912
2913 @param node reference to the node to be processed
2914 @type ast.DictComp
2915 """
2916 """Check that a static key isn't used in a dict comprehension.
2917
2918 Emit a warning if a likely unchanging key is used - either a constant,
2919 or a variable that isn't coming from the generator expression.
2920 """
2921 if isinstance(node.key, ast.Constant):
2922 self.violations.append((node, "M535", node.key.value))
2923 elif isinstance(node.key, ast.Name):
2924 if node.key.id not in self.__getDictCompLoopVarNames(node):
2925 self.violations.append((node, "M535", node.key.id))
2848 2926
2849 2927
2850 class NameFinder(ast.NodeVisitor): 2928 class NameFinder(ast.NodeVisitor):
2851 """ 2929 """
2852 Class to extract a name out of a tree of nodes. 2930 Class to extract a name out of a tree of nodes.

eric ide

mercurial