eric7/Plugins/CheckerPlugins/CodeStyleChecker/Imports/ImportsChecker.py

branch
eric7
changeset 8808
033fa34447d0
parent 8802
129a973fc33e
child 8811
9ff6b1b5f601
equal deleted inserted replaced
8807:f4486646a233 8808:033fa34447d0
20 ## Local imports 20 ## Local imports
21 "I101", "I102", "I103", 21 "I101", "I102", "I103",
22 22
23 ## Imports order 23 ## Imports order
24 "I201", "I202", "I203", "I204", 24 "I201", "I202", "I203", "I204",
25
26 ## Various other import related
27 "I901", "I902", "I903", "I904",
25 ] 28 ]
26 29
27 def __init__(self, source, filename, tree, select, ignore, expected, 30 def __init__(self, source, filename, tree, select, ignore, expected,
28 repeat, args): 31 repeat, args):
29 """ 32 """
61 # collection of detected errors 64 # collection of detected errors
62 self.errors = [] 65 self.errors = []
63 66
64 checkersWithCodes = [ 67 checkersWithCodes = [
65 (self.__checkLocalImports, ("I101", "I102", "I103")), 68 (self.__checkLocalImports, ("I101", "I102", "I103")),
66 (self.__checkImportOrder, ("I201", "I202", "I203", "I204")) 69 (self.__checkImportOrder, ("I201", "I202", "I203", "I204")),
70 (self.__tidyImports, ("I901", "I902", "I903", "I904")),
67 ] 71 ]
68 72
69 self.__checkers = [] 73 self.__checkers = []
70 for checker, codes in checkersWithCodes: 74 for checker, codes in checkersWithCodes:
71 if any(not (code and self.__ignoreCode(code)) 75 if any(not (code and self.__ignoreCode(code))
319 expectedList = sorted(actualList) 323 expectedList = sorted(actualList)
320 if expectedList != actualList: 324 if expectedList != actualList:
321 return (node, "I204", ", ".join(expectedList)) 325 return (node, "I204", ", ".join(expectedList))
322 326
323 return None 327 return None
328
329 #######################################################################
330 ## Tidy imports
331 ##
332 ## adapted from: flake8-tidy-imports v4.5.0
333 #######################################################################
334
335 def __tidyImports(self):
336 """
337 Private method to check various other import related topics.
338 """
339 self.__bannedModules = self.__args.get("BannedModules", [])
340 self.__banRelativeImports = self.__args.get("BanRelativeImports", "")
341
342 ruleMethods = []
343 if not self.__ignoreCode("I901"):
344 ruleMethods.append(self.__checkUnnecessaryAlias)
345 if (
346 not self.__ignoreCode("I902")
347 and bool(self.__bannedModules)
348 ):
349 ruleMethods.append(self.__checkBannedImport)
350 if (
351 (not self.__ignoreCode("I903") and
352 self.__banRelativeImports == "parents") or
353 (not self.__ignoreCode("I904") and
354 self.__banRelativeImports == "true")
355 ):
356 ruleMethods.append(self.__checkBannedRelativeImports)
357
358 for node in ast.walk(self.__tree):
359 for method in ruleMethods:
360 method(node)
361
362 def __checkUnnecessaryAlias(self, node):
363 """
364 Private method to check unnecessary import aliases.
365
366 @param node reference to the node to be checked
367 @type ast.AST
368 """
369 if isinstance(node, ast.Import):
370 for alias in node.names:
371 if "." not in alias.name:
372 fromName = None
373 importedName = alias.name
374 else:
375 fromName, importedName = alias.name.rsplit(".", 1)
376
377 if importedName == alias.asname:
378 if fromName:
379 rewritten = "from {0} import {1}".format(
380 fromName, importedName)
381 else:
382 rewritten = "import {0}".format(importedName)
383
384 self.__error(node.lineno - 1, node.col_offset, "I901",
385 rewritten)
386
387 elif isinstance(node, ast.ImportFrom):
388 for alias in node.names:
389 if alias.name == alias.asname:
390 rewritten = "from {0} import {1}".format(
391 node.module, alias.name)
392
393 self.__error(node.lineno - 1, node.col_offset, "I901",
394 rewritten)
395
396 def __checkBannedImport(self, node):
397 """
398 Private method to check import of banned modules.
399
400 @param node reference to the node to be checked
401 @type ast.AST
402 """
403 if not bool(self.__bannedModules):
404 return
405
406 if isinstance(node, ast.Import):
407 moduleNames = [alias.name for alias in node.names]
408 elif isinstance(node, ast.ImportFrom):
409 nodeModule = node.module or ""
410 moduleNames = [nodeModule]
411 for alias in node.names:
412 moduleNames.append("{0}.{1}".format(nodeModule, alias.name))
413 else:
414 return
415
416 # Sort from most to least specific paths.
417 moduleNames.sort(key=len, reverse=True)
418
419 warned = set()
420
421 for moduleName in moduleNames:
422 if moduleName in self.__bannedModules:
423 if any(mod.startswith(moduleName) for mod in warned):
424 # Do not show an error for this line if we already showed
425 # a more specific error.
426 continue
427 else:
428 warned.add(moduleName)
429 self.__error(node.lineno - 1, node.col_offset, "I902",
430 moduleName)
431
432 def __checkBannedRelativeImports(self, node):
433 """
434 Private method to check if relative imports are banned.
435
436 @param node reference to the node to be checked
437 @type ast.AST
438 """
439 if not self.__banRelativeImports:
440 return
441
442 elif self.__banRelativeImports == "parents":
443 minNodeLevel = 1
444 msgCode = "I903"
445 else:
446 minNodeLevel = 0
447 msgCode = "I904"
448
449 if (
450 self.__banRelativeImports and
451 isinstance(node, ast.ImportFrom) and
452 node.level > minNodeLevel
453 ):
454 self.__error(node.lineno - 1, node.col_offset, msgCode)

eric ide

mercurial