17 Class implementing a checker for import statements. |
17 Class implementing a checker for import statements. |
18 """ |
18 """ |
19 |
19 |
20 Codes = [ |
20 Codes = [ |
21 ## Local imports |
21 ## Local imports |
22 "I101", |
22 "I-101", |
23 "I102", |
23 "I-102", |
24 "I103", |
24 "I-103", |
25 ## Various other import related |
25 ## Various other import related |
26 "I901", |
26 "I-901", |
27 "I902", |
27 "I-902", |
28 "I903", |
28 "I-903", |
29 "I904", |
29 "I-904", |
30 ] |
30 ] |
31 |
31 |
32 def __init__(self, source, filename, tree, select, ignore, expected, repeat, args): |
32 def __init__(self, source, filename, tree, select, ignore, expected, repeat, args): |
33 """ |
33 """ |
34 Constructor |
34 Constructor |
64 |
64 |
65 # collection of detected errors |
65 # collection of detected errors |
66 self.errors = [] |
66 self.errors = [] |
67 |
67 |
68 checkersWithCodes = [ |
68 checkersWithCodes = [ |
69 (self.__checkLocalImports, ("I101", "I102", "I103")), |
69 (self.__checkLocalImports, ("I-101", "I-102", "I-103")), |
70 (self.__tidyImports, ("I901", "I902", "I903", "I904")), |
70 (self.__tidyImports, ("I-901", "I-902", "I-903", "I-904")), |
71 ] |
71 ] |
72 |
72 |
73 self.__checkers = [] |
73 self.__checkers = [] |
74 for checker, codes in checkersWithCodes: |
74 for checker, codes in checkersWithCodes: |
75 if any(not (code and self.__ignoreCode(code)) for code in codes): |
75 if any(not (code and self.__ignoreCode(code)) for code in codes): |
195 |
195 |
196 # Sort the structured patterns so we match the specifc ones first. |
196 # Sort the structured patterns so we match the specifc ones first. |
197 self.__bannedStructuredPatterns.sort(key=lambda x: len(x[0]), reverse=True) |
197 self.__bannedStructuredPatterns.sort(key=lambda x: len(x[0]), reverse=True) |
198 |
198 |
199 ruleMethods = [] |
199 ruleMethods = [] |
200 if not self.__ignoreCode("I901"): |
200 if not self.__ignoreCode("I-901"): |
201 ruleMethods.append(self.__checkUnnecessaryAlias) |
201 ruleMethods.append(self.__checkUnnecessaryAlias) |
202 if not self.__ignoreCode("I902") and bool(self.__bannedModules): |
202 if not self.__ignoreCode("I-902") and bool(self.__bannedModules): |
203 ruleMethods.append(self.__checkBannedImport) |
203 ruleMethods.append(self.__checkBannedImport) |
204 if ( |
204 if ( |
205 not self.__ignoreCode("I903") and self.__banRelativeImports == "parents" |
205 not self.__ignoreCode("I-903") and self.__banRelativeImports == "parents" |
206 ) or (not self.__ignoreCode("I904") and self.__banRelativeImports == "true"): |
206 ) or (not self.__ignoreCode("I-904") and self.__banRelativeImports == "true"): |
207 ruleMethods.append(self.__checkBannedRelativeImports) |
207 ruleMethods.append(self.__checkBannedRelativeImports) |
208 |
208 |
209 for node in ast.walk(self.__tree): |
209 for node in ast.walk(self.__tree): |
210 for method in ruleMethods: |
210 for method in ruleMethods: |
211 method(node) |
211 method(node) |
249 if fromName: |
249 if fromName: |
250 rewritten = f"from {fromName} import {importedName}" |
250 rewritten = f"from {fromName} import {importedName}" |
251 else: |
251 else: |
252 rewritten = f"import {importedName}" |
252 rewritten = f"import {importedName}" |
253 |
253 |
254 self.__error(node.lineno - 1, node.col_offset, "I901", rewritten) |
254 self.__error(node.lineno - 1, node.col_offset, "I-901", rewritten) |
255 |
255 |
256 elif isinstance(node, ast.ImportFrom): |
256 elif isinstance(node, ast.ImportFrom): |
257 for alias in node.names: |
257 for alias in node.names: |
258 if alias.name == alias.asname: |
258 if alias.name == alias.asname: |
259 rewritten = f"from {node.module} import {alias.name}" |
259 rewritten = f"from {node.module} import {alias.name}" |
260 |
260 |
261 self.__error(node.lineno - 1, node.col_offset, "I901", rewritten) |
261 self.__error(node.lineno - 1, node.col_offset, "I-901", rewritten) |
262 |
262 |
263 def __isModuleBanned(self, moduleName): |
263 def __isModuleBanned(self, moduleName): |
264 """ |
264 """ |
265 Private method to check, if the given module name banned. |
265 Private method to check, if the given module name banned. |
266 |
266 |
324 # Do not show an error for this line if we already showed |
324 # Do not show an error for this line if we already showed |
325 # a more specific error. |
325 # a more specific error. |
326 continue |
326 continue |
327 else: |
327 else: |
328 warned.add(moduleName) |
328 warned.add(moduleName) |
329 self.__error(node.lineno - 1, node.col_offset, "I902", moduleName) |
329 self.__error(node.lineno - 1, node.col_offset, "I-902", moduleName) |
330 |
330 |
331 def __checkBannedRelativeImports(self, node): |
331 def __checkBannedRelativeImports(self, node): |
332 """ |
332 """ |
333 Private method to check if relative imports are banned. |
333 Private method to check if relative imports are banned. |
334 |
334 |