16 |
16 |
17 class LocalImportVisitor(ast.NodeVisitor): |
17 class LocalImportVisitor(ast.NodeVisitor): |
18 """ |
18 """ |
19 Class implementing a node visitor for checking local import statements. |
19 Class implementing a node visitor for checking local import statements. |
20 """ |
20 """ |
|
21 |
21 def __init__(self, args, checker): |
22 def __init__(self, args, checker): |
22 """ |
23 """ |
23 Constructor |
24 Constructor |
24 |
25 |
25 @param args dictionary containing the checker arguments |
26 @param args dictionary containing the checker arguments |
26 @type dict |
27 @type dict |
27 @param checker reference to the checker |
28 @param checker reference to the checker |
28 @type ImportsChecker |
29 @type ImportsChecker |
29 """ |
30 """ |
30 self.__appImportNames = args.get("ApplicationPackageNames", []) |
31 self.__appImportNames = args.get("ApplicationPackageNames", []) |
31 self.__checker = checker |
32 self.__checker = checker |
32 |
33 |
33 self.violations = [] |
34 self.violations = [] |
34 |
35 |
35 def visit(self, node): |
36 def visit(self, node): |
36 """ |
37 """ |
37 Public method to traverse the tree of an AST node. |
38 Public method to traverse the tree of an AST node. |
38 |
39 |
39 @param node AST node to parse |
40 @param node AST node to parse |
40 @type ast.AST |
41 @type ast.AST |
41 """ |
42 """ |
42 previous = None |
43 previous = None |
43 isLocal = ( |
44 isLocal = isinstance(node, ast.FunctionDef) or getattr(node, "is_local", False) |
44 isinstance(node, ast.FunctionDef) or |
|
45 getattr(node, 'is_local', False) |
|
46 ) |
|
47 for child in ast.iter_child_nodes(node): |
45 for child in ast.iter_child_nodes(node): |
48 child.parent = node |
46 child.parent = node |
49 child.previous = previous |
47 child.previous = previous |
50 child.is_local = isLocal |
48 child.is_local = isLocal |
51 previous = child |
49 previous = child |
52 |
50 |
53 super().visit(node) |
51 super().visit(node) |
54 |
52 |
55 def visit_FunctionDef(self, node): |
53 def visit_FunctionDef(self, node): |
56 """ |
54 """ |
57 Public method to handle a function definition. |
55 Public method to handle a function definition. |
58 |
56 |
59 @param node reference to the node to be processed |
57 @param node reference to the node to be processed |
60 @type ast.FunctionDef |
58 @type ast.FunctionDef |
61 """ |
59 """ |
62 children = list(ast.iter_child_nodes(node)) |
60 children = list(ast.iter_child_nodes(node)) |
63 if len(children) > 1: |
61 if len(children) > 1: |
64 firstStatement = children[1] |
62 firstStatement = children[1] |
65 |
63 |
66 if isinstance(firstStatement, ast.Expr): |
64 if isinstance(firstStatement, ast.Expr): |
67 value = getattr(firstStatement, 'value', None) |
65 value = getattr(firstStatement, "value", None) |
68 if isinstance(value, ast.Constant): |
66 if isinstance(value, ast.Constant): |
69 firstStatement.is_doc_str = True |
67 firstStatement.is_doc_str = True |
70 |
68 |
71 self.generic_visit(node) |
69 self.generic_visit(node) |
72 |
70 |
73 def visit_Import(self, node): |
71 def visit_Import(self, node): |
74 """ |
72 """ |
75 Public method to handle an import statement. |
73 Public method to handle an import statement. |
76 |
74 |
77 @param node reference to the node to be processed |
75 @param node reference to the node to be processed |
78 @type ast.Import |
76 @type ast.Import |
79 """ |
77 """ |
80 if not getattr(node, 'is_local', False): |
78 if not getattr(node, "is_local", False): |
81 self.generic_visit(node) |
79 self.generic_visit(node) |
82 return |
80 return |
83 |
81 |
84 for name in node.names: |
82 for name in node.names: |
85 self.__assertExternalModule(node, name.name or '') |
83 self.__assertExternalModule(node, name.name or "") |
86 |
84 |
87 self.__visitImportNode(node) |
85 self.__visitImportNode(node) |
88 |
86 |
89 def visit_ImportFrom(self, node): |
87 def visit_ImportFrom(self, node): |
90 """ |
88 """ |
91 Public method to handle an import from statement. |
89 Public method to handle an import from statement. |
92 |
90 |
93 @param node reference to the node to be processed |
91 @param node reference to the node to be processed |
94 @type ast.ImportFrom |
92 @type ast.ImportFrom |
95 """ |
93 """ |
96 if not getattr(node, 'is_local', False): |
94 if not getattr(node, "is_local", False): |
97 self.generic_visit(node) |
95 self.generic_visit(node) |
98 return |
96 return |
99 |
97 |
100 self.__assertExternalModule(node, node.module or '') |
98 self.__assertExternalModule(node, node.module or "") |
101 |
99 |
102 self.__visitImportNode(node) |
100 self.__visitImportNode(node) |
103 |
101 |
104 def __visitImportNode(self, node): |
102 def __visitImportNode(self, node): |
105 """ |
103 """ |
106 Private method to handle an import or import from statement. |
104 Private method to handle an import or import from statement. |
107 |
105 |
108 @param node reference to the node to be processed |
106 @param node reference to the node to be processed |
109 @type ast.Import or ast.ImportFrom |
107 @type ast.Import or ast.ImportFrom |
110 """ |
108 """ |
111 parent = getattr(node, 'parent', None) |
109 parent = getattr(node, "parent", None) |
112 if isinstance(parent, ast.Module): |
110 if isinstance(parent, ast.Module): |
113 self.generic_visit(node) |
111 self.generic_visit(node) |
114 return |
112 return |
115 |
113 |
116 previous = getattr(node, 'previous', None) |
114 previous = getattr(node, "previous", None) |
117 |
115 |
118 isAllowedPrevious = ( |
116 isAllowedPrevious = ( |
119 (isinstance(previous, ast.Expr) and |
117 isinstance(previous, ast.Expr) and getattr(previous, "is_doc_str", False) |
120 getattr(previous, 'is_doc_str', False)) or |
118 ) or isinstance(previous, (ast.Import, ast.ImportFrom, ast.arguments)) |
121 isinstance(previous, (ast.Import, ast.ImportFrom, ast.arguments)) |
119 |
122 ) |
|
123 |
|
124 if not isinstance(parent, ast.FunctionDef) or not isAllowedPrevious: |
120 if not isinstance(parent, ast.FunctionDef) or not isAllowedPrevious: |
125 self.violations.append((node, "I101")) |
121 self.violations.append((node, "I101")) |
126 |
122 |
127 self.generic_visit(node) |
123 self.generic_visit(node) |
128 |
124 |
129 def __assertExternalModule(self, node, module): |
125 def __assertExternalModule(self, node, module): |
130 """ |
126 """ |
131 Private method to assert the given node. |
127 Private method to assert the given node. |
132 |
128 |
133 @param node reference to the node to be processed |
129 @param node reference to the node to be processed |
134 @type ast.stmt |
130 @type ast.stmt |
135 @param module name of the module |
131 @param module name of the module |
136 @type str |
132 @type str |
137 """ |
133 """ |
138 parent = getattr(node, 'parent', None) |
134 parent = getattr(node, "parent", None) |
139 if isinstance(parent, ast.Module): |
135 if isinstance(parent, ast.Module): |
140 return |
136 return |
141 |
137 |
142 modulePrefix = module + '.' |
138 modulePrefix = module + "." |
143 |
139 |
144 if ( |
140 if getattr(node, "level", 0) != 0 or any( |
145 getattr(node, 'level', 0) != 0 or |
141 modulePrefix.startswith(appModule + ".") |
146 any(modulePrefix.startswith(appModule + '.') |
142 for appModule in self.__appImportNames |
147 for appModule in self.__appImportNames) |
|
148 ): |
143 ): |
149 return |
144 return |
150 |
145 |
151 if module.split('.')[0] not in self.__checker.getStandardModules(): |
146 if module.split(".")[0] not in self.__checker.getStandardModules(): |
152 self.violations.append((node, "I102")) |
147 self.violations.append((node, "I102")) |
153 else: |
148 else: |
154 self.violations.append((node, "I103")) |
149 self.violations.append((node, "I103")) |