171 @type ast.ImportFrom |
171 @type ast.ImportFrom |
172 """ |
172 """ |
173 if node.module == "logging": |
173 if node.module == "logging": |
174 for alias in node.names: |
174 for alias in node.names: |
175 if alias.name == "WARN": |
175 if alias.name == "WARN": |
176 if sys.version_info >= (3, 10): |
176 self.__error( |
177 lineno = alias.lineno |
177 alias if sys.version_info >= (3, 10) else node, "L-109" |
178 colOffset = alias.col_offset |
178 ) |
179 else: |
|
180 lineno = node.lineno |
|
181 colOffset = node.col_offset |
|
182 self.__error(lineno - 1, colOffset, "L-109") |
|
183 if not alias.asname: |
179 if not alias.asname: |
184 self.__fromImports[alias.name] = node.module |
180 self.__fromImports[alias.name] = node.module |
185 |
181 |
186 self.generic_visit(node) |
182 self.generic_visit(node) |
187 |
183 |
196 self.__loggingName |
192 self.__loggingName |
197 and isinstance(node.value, ast.Name) |
193 and isinstance(node.value, ast.Name) |
198 and node.value.id == self.__loggingName |
194 and node.value.id == self.__loggingName |
199 and node.attr == "WARN" |
195 and node.attr == "WARN" |
200 ): |
196 ): |
201 self.__error(node.lineno - 1, node.col_offset, "L-109") |
197 self.__error(node, "L-109") |
202 |
198 |
203 self.generic_visit(node) |
199 self.generic_visit(node) |
204 |
200 |
205 def visit_Call(self, node): |
201 def visit_Call(self, node): |
206 """ |
202 """ |
221 isinstance(node.func, ast.Name) |
217 isinstance(node.func, ast.Name) |
222 and node.func.id == "Logger" |
218 and node.func.id == "Logger" |
223 and self.__fromImports.get("Logger") == "logging" |
219 and self.__fromImports.get("Logger") == "logging" |
224 ) |
220 ) |
225 ) and not self.__atModuleLevel(): |
221 ) and not self.__atModuleLevel(): |
226 self.__error(node.lineno - 1, node.col_offset, "L-101") |
222 self.__error(node, "L-101") |
227 |
223 |
228 if ( |
224 if ( |
229 isinstance(node.func, ast.Attribute) |
225 isinstance(node.func, ast.Attribute) |
230 and node.func.attr in _LoggerMethods |
226 and node.func.attr in _LoggerMethods |
231 and isinstance(node.func.value, ast.Name) |
227 and isinstance(node.func.value, ast.Name) |
234 ) or ( |
230 ) or ( |
235 isinstance(node.func, ast.Name) |
231 isinstance(node.func, ast.Name) |
236 and node.func.id in _LoggerMethods |
232 and node.func.id in _LoggerMethods |
237 and self.__fromImports.get(node.func.id) == "logging" |
233 and self.__fromImports.get(node.func.id) == "logging" |
238 ): |
234 ): |
239 self.__error(node.lineno - 1, node.col_offset, "L-115") |
235 self.__error(node, "L-115") |
240 |
236 |
241 if ( |
237 if ( |
242 self.__loggingName |
238 self.__loggingName |
243 and isinstance(node.func, ast.Attribute) |
239 and isinstance(node.func, ast.Attribute) |
244 and node.func.attr == "getLogger" |
240 and node.func.attr == "getLogger" |
261 if ( |
257 if ( |
262 node.args |
258 node.args |
263 and isinstance(node.args[0], ast.Name) |
259 and isinstance(node.args[0], ast.Name) |
264 and node.args[0].id in self.GetLoggerNames |
260 and node.args[0].id in self.GetLoggerNames |
265 ): |
261 ): |
266 self.__error(node.args[0].lineno - 1, node.args[0].col_offset, "L-102") |
262 self.__error(node.args[0], "L-102") |
267 |
263 |
268 if ( |
264 if ( |
269 isinstance(node.func, ast.Attribute) |
265 isinstance(node.func, ast.Attribute) |
270 and node.func.attr in _LoggerMethods |
266 and node.func.attr in _LoggerMethods |
271 and isinstance(node.func.value, ast.Name) |
267 and isinstance(node.func.value, ast.Name) |
275 ): |
271 ): |
276 excHandler = self.__currentExceptHandler() |
272 excHandler = self.__currentExceptHandler() |
277 |
273 |
278 # L108 |
274 # L108 |
279 if node.func.attr == "warn": |
275 if node.func.attr == "warn": |
280 self.__error(node.lineno - 1, node.col_offset, "L-108") |
276 self.__error(node, "L-108") |
281 |
277 |
282 # L103 |
278 # L103 |
283 extraKeys = [] |
279 extraKeys = [] |
284 if any((extraNode := kw).arg == "extra" for kw in node.keywords): |
280 if any((extraNode := kw).arg == "extra" for kw in node.keywords): |
285 if isinstance(extraNode.value, ast.Dict): |
281 if isinstance(extraNode.value, ast.Dict): |
299 if k.arg is not None |
295 if k.arg is not None |
300 ] |
296 ] |
301 |
297 |
302 for key, keyNode in extraKeys: |
298 for key, keyNode in extraKeys: |
303 if key in _LogrecordAttributes: |
299 if key in _LogrecordAttributes: |
304 self.__error( |
300 self.__error(keyNode, "L-103", repr(key)) |
305 keyNode.lineno - 1, keyNode.col_offset, "L-103", repr(key) |
|
306 ) |
|
307 |
301 |
308 if node.func.attr == "exception": |
302 if node.func.attr == "exception": |
309 # L104 |
303 # L104 |
310 if not excHandler: |
304 if not excHandler: |
311 self.__error(node.lineno - 1, node.col_offset, "L-104") |
305 self.__error(node, "L-104") |
312 |
306 |
313 if any((excInfo := kw).arg == "exc_info" for kw in node.keywords): |
307 if any((excInfo := kw).arg == "exc_info" for kw in node.keywords): |
314 # L106 |
308 # L106 |
315 if ( |
309 if ( |
316 isinstance(excInfo.value, ast.Constant) and excInfo.value.value |
310 isinstance(excInfo.value, ast.Constant) and excInfo.value.value |
317 ) or ( |
311 ) or ( |
318 excHandler |
312 excHandler |
319 and isinstance(excInfo.value, ast.Name) |
313 and isinstance(excInfo.value, ast.Name) |
320 and excInfo.value.id == excHandler.name |
314 and excInfo.value.id == excHandler.name |
321 ): |
315 ): |
322 self.__error(excInfo.lineno - 1, excInfo.col_offset, "L-106") |
316 self.__error(excInfo, "L-106") |
323 |
317 |
324 # L107 |
318 # L107 |
325 elif ( |
319 elif ( |
326 isinstance(excInfo.value, ast.Constant) |
320 isinstance(excInfo.value, ast.Constant) |
327 and not excInfo.value.value |
321 and not excInfo.value.value |
328 ): |
322 ): |
329 self.__error(excInfo.lineno - 1, excInfo.col_offset, "L-107") |
323 self.__error(excInfo, "L-107") |
330 |
324 |
331 # L105 |
325 # L105 |
332 elif node.func.attr == "error" and excHandler is not None: |
326 elif node.func.attr == "error" and excHandler is not None: |
333 rewritable = False |
327 rewritable = False |
334 if any((excInfo := kw).arg == "exc_info" for kw in node.keywords): |
328 if any((excInfo := kw).arg == "exc_info" for kw in node.keywords): |
341 rewritable = True |
335 rewritable = True |
342 else: |
336 else: |
343 rewritable = True |
337 rewritable = True |
344 |
338 |
345 if rewritable: |
339 if rewritable: |
346 self.__error(node.lineno - 1, node.col_offset, "L-105") |
340 self.__error(node, "L-105") |
347 |
341 |
348 # L114 |
342 # L114 |
349 elif ( |
343 elif ( |
350 excHandler is None |
344 excHandler is None |
351 and any((excInfo := kw).arg == "exc_info" for kw in node.keywords) |
345 and any((excInfo := kw).arg == "exc_info" for kw in node.keywords) |
352 and isinstance(excInfo.value, ast.Constant) |
346 and isinstance(excInfo.value, ast.Constant) |
353 and excInfo.value.value |
347 and excInfo.value.value |
354 ): |
348 ): |
355 self.__error(excInfo.lineno - 1, excInfo.col_offset, "L-114") |
349 self.__error(excInfo, "L-114") |
356 |
350 |
357 # L110 |
351 # L110 |
358 if ( |
352 if ( |
359 node.func.attr == "exception" |
353 node.func.attr == "exception" |
360 and len(node.args) >= 1 |
354 and len(node.args) >= 1 |
361 and isinstance(node.args[0], ast.Name) |
355 and isinstance(node.args[0], ast.Name) |
362 and excHandler is not None |
356 and excHandler is not None |
363 and node.args[0].id == excHandler.name |
357 and node.args[0].id == excHandler.name |
364 ): |
358 ): |
365 self.__error(node.args[0].lineno - 1, node.args[0].col_offset, "L-110") |
359 self.__error(node.args[0], "L-110") |
366 |
360 |
367 msgArgKwarg = False |
361 msgArgKwarg = False |
368 if node.func.attr == "log" and len(node.args) >= 2: |
362 if node.func.attr == "log" and len(node.args) >= 2: |
369 msgArg = node.args[1] |
363 msgArg = node.args[1] |
370 elif node.func.attr != "log" and len(node.args) >= 1: |
364 elif node.func.attr != "log" and len(node.args) >= 1: |
376 except IndexError: |
370 except IndexError: |
377 msgArg = None |
371 msgArg = None |
378 |
372 |
379 # L111 |
373 # L111 |
380 if isinstance(msgArg, ast.JoinedStr): |
374 if isinstance(msgArg, ast.JoinedStr): |
381 self.__error(msgArg.lineno - 1, msgArg.col_offset, "L-111a") |
375 self.__error(msgArg, "L-111a") |
382 elif ( |
376 elif ( |
383 isinstance(msgArg, ast.Call) |
377 isinstance(msgArg, ast.Call) |
384 and isinstance(msgArg.func, ast.Attribute) |
378 and isinstance(msgArg.func, ast.Attribute) |
385 and isinstance(msgArg.func.value, ast.Constant) |
379 and isinstance(msgArg.func.value, ast.Constant) |
386 and isinstance(msgArg.func.value.value, str) |
380 and isinstance(msgArg.func.value.value, str) |
387 and msgArg.func.attr == "format" |
381 and msgArg.func.attr == "format" |
388 ): |
382 ): |
389 self.__error(msgArg.lineno - 1, msgArg.col_offset, "L-111b") |
383 self.__error(msgArg, "L-111b") |
390 elif ( |
384 elif ( |
391 isinstance(msgArg, ast.BinOp) |
385 isinstance(msgArg, ast.BinOp) |
392 and isinstance(msgArg.op, ast.Mod) |
386 and isinstance(msgArg.op, ast.Mod) |
393 and isinstance(msgArg.left, ast.Constant) |
387 and isinstance(msgArg.left, ast.Constant) |
394 and isinstance(msgArg.left.value, str) |
388 and isinstance(msgArg.left.value, str) |
395 ): |
389 ): |
396 self.__error(msgArg.lineno - 1, msgArg.col_offset, "L-111c") |
390 self.__error(msgArg, "L-111c") |
397 elif isinstance(msgArg, ast.BinOp) and self.__isAddChainWithNonStr(msgArg): |
391 elif isinstance(msgArg, ast.BinOp) and self.__isAddChainWithNonStr(msgArg): |
398 self.__error(msgArg.lineno - 1, msgArg.col_offset, "L-111d") |
392 self.__error(msgArg, "L-111d") |
399 |
393 |
400 # L112 |
394 # L112 |
401 if ( |
395 if ( |
402 msgArg is not None |
396 msgArg is not None |
403 and not msgArgKwarg |
397 and not msgArgKwarg |
439 ) |
433 ) |
440 ): |
434 ): |
441 # L113 |
435 # L113 |
442 given = {cast(ast.Constant, k).value for k in dictNode.keys} |
436 given = {cast(ast.Constant, k).value for k in dictNode.keys} |
443 if missing := modnames - given: |
437 if missing := modnames - given: |
444 self.__error( |
438 # missing keys |
445 msgArg.lineno - 1, |
439 self.__error(msgArg, "L-113a", ", ".join([repr(k) for k in missing])) |
446 msgArg.col_offset, |
|
447 "L-113a", # missing keys |
|
448 ", ".join([repr(k) for k in missing]), |
|
449 ) |
|
450 |
440 |
451 if missing := given - modnames: |
441 if missing := given - modnames: |
452 self.__error( |
442 # unreferenced keys |
453 msgArg.lineno - 1, |
443 self.__error(msgArg, "L-113b", ", ".join([repr(k) for k in missing])) |
454 msgArg.col_offset, |
|
455 "L-113b", # unreferenced keys |
|
456 ", ".join([repr(k) for k in missing]), |
|
457 ) |
|
458 |
444 |
459 return |
445 return |
460 |
446 |
461 # L112 |
447 # L112 |
462 modposCount = sum( |
448 modposCount = sum( |
465 if m["spec"] != "%" |
451 if m["spec"] != "%" |
466 ) |
452 ) |
467 argCount = len(node.args) - 1 - (node.func.attr == "log") |
453 argCount = len(node.args) - 1 - (node.func.attr == "log") |
468 |
454 |
469 if modposCount > 0 and modposCount != argCount: |
455 if modposCount > 0 and modposCount != argCount: |
470 self.__error( |
456 self.__error(msgArg, "L-112", modposCount, "'%'", argCount) # noqa: M-601 |
471 msgArg.lineno - 1, |
|
472 msgArg.col_offset, |
|
473 "L-112", |
|
474 modposCount, |
|
475 "'%'", # noqa: M-601 |
|
476 argCount, |
|
477 ) |
|
478 return |
457 return |
479 |
458 |
480 def __atModuleLevel(self): |
459 def __atModuleLevel(self): |
481 """ |
460 """ |
482 Private method to check, if we are on the module level. |
461 Private method to check, if we are on the module level. |