92 self.__currentClass in {"pydantic_model", "dataclass"} |
92 self.__currentClass in {"pydantic_model", "dataclass"} |
93 and isinstance(node.value, ast.Call) |
93 and isinstance(node.value, ast.Call) |
94 and isFunction(node.value, "Field") |
94 and isFunction(node.value, "Field") |
95 and len(node.value.args) >= 1 |
95 and len(node.value.args) >= 1 |
96 ): |
96 ): |
97 self.__error(node.lineno - 1, node.col_offset, "PYD001") |
97 self.__error(node, "PYD-001") |
98 |
98 |
99 def __checkForPyd002(self, node): |
99 def __checkForPyd002(self, node): |
100 """ |
100 """ |
101 Private method to check non-annotated attribute inside Pydantic model. |
101 Private method to check non-annotated attribute inside Pydantic model. |
102 |
102 |
111 if isinstance(assign.targets[0], ast.Name) |
111 if isinstance(assign.targets[0], ast.Name) |
112 if not assign.targets[0].id.startswith("_") |
112 if not assign.targets[0].id.startswith("_") |
113 if assign.targets[0].id != "model_config" |
113 if assign.targets[0].id != "model_config" |
114 ] |
114 ] |
115 for assignment in invalidAssignments: |
115 for assignment in invalidAssignments: |
116 self.__error(assignment.lineno - 1, assignment.col_offset, "PYD002") |
116 self.__error(assignment, "PYD-002") |
117 |
117 |
118 def __checkForPyd003(self, node): |
118 def __checkForPyd003(self, node): |
119 """ |
119 """ |
120 Private method to check unecessary Field call to specify a default value. |
120 Private method to check unecessary Field call to specify a default value. |
121 |
121 |
127 and isinstance(node.value, ast.Call) |
127 and isinstance(node.value, ast.Call) |
128 and isFunction(node.value, "Field") |
128 and isFunction(node.value, "Field") |
129 and len(node.value.keywords) == 1 |
129 and len(node.value.keywords) == 1 |
130 and node.value.keywords[0].arg == "default" |
130 and node.value.keywords[0].arg == "default" |
131 ): |
131 ): |
132 self.__error(node.lineno - 1, node.col_offset, "PYD003") |
132 self.__error(node, "PYD-003") |
133 |
133 |
134 def __checkForPyd004(self, node): |
134 def __checkForPyd004(self, node): |
135 """ |
135 """ |
136 Private method to check for a default argument specified in annotated. |
136 Private method to check for a default argument specified in annotated. |
137 |
137 |
153 and any(k.arg == "default" for k in elt.keywords) |
153 and any(k.arg == "default" for k in elt.keywords) |
154 ), |
154 ), |
155 None, |
155 None, |
156 ) |
156 ) |
157 if fieldCall is not None: |
157 if fieldCall is not None: |
158 self.__error(node.lineno - 1, node.col_offset, "PYD004") |
158 self.__error(node, "PYD-004") |
159 |
159 |
160 def __checkForPyd005(self, node): |
160 def __checkForPyd005(self, node): |
161 """ |
161 """ |
162 Private method to check for a field name overriding the annotation. |
162 Private method to check for a field name overriding the annotation. |
163 |
163 |
171 if isinstance(stmt, ast.AnnAssign) and isinstance( |
171 if isinstance(stmt, ast.AnnAssign) and isinstance( |
172 stmt.target, ast.Name |
172 stmt.target, ast.Name |
173 ): |
173 ): |
174 previousTargets.add(stmt.target.id) |
174 previousTargets.add(stmt.target.id) |
175 if previousTargets & extractAnnotations(stmt.annotation): |
175 if previousTargets & extractAnnotations(stmt.annotation): |
176 self.__error(stmt.lineno - 1, stmt.col_offset, "PYD005") |
176 self.__error(stmt, "PYD-005") |
177 |
177 |
178 def __checkForPyd006(self, node): |
178 def __checkForPyd006(self, node): |
179 """ |
179 """ |
180 Private method to check for duplicate field names. |
180 Private method to check for duplicate field names. |
181 |
181 |
188 for stmt in node.body: |
188 for stmt in node.body: |
189 if isinstance(stmt, ast.AnnAssign) and isinstance( |
189 if isinstance(stmt, ast.AnnAssign) and isinstance( |
190 stmt.target, ast.Name |
190 stmt.target, ast.Name |
191 ): |
191 ): |
192 if stmt.target.id in previousTargets: |
192 if stmt.target.id in previousTargets: |
193 self.__error(stmt.lineno - 1, stmt.col_offset, "PYD006") |
193 self.__error(stmt, "PYD-006") |
194 |
194 |
195 previousTargets.add(stmt.target.id) |
195 previousTargets.add(stmt.target.id) |
196 |
196 |
197 def __checkForPyd010(self, node: ast.ClassDef) -> None: |
197 def __checkForPyd010(self, node: ast.ClassDef) -> None: |
198 """ |
198 """ |
207 isinstance(stmt, ast.AnnAssign) |
207 isinstance(stmt, ast.AnnAssign) |
208 and isinstance(stmt.target, ast.Name) |
208 and isinstance(stmt.target, ast.Name) |
209 and stmt.target.id == "__pydantic_config__" |
209 and stmt.target.id == "__pydantic_config__" |
210 ): |
210 ): |
211 ##~ __pydantic_config__: ... = ... |
211 ##~ __pydantic_config__: ... = ... |
212 self.__error(stmt.lineno - 1, stmt.col_offset, "PYD010") |
212 self.__error(stmt, "PYD-010") |
213 |
213 |
214 if isinstance(stmt, ast.Assign) and any( |
214 if isinstance(stmt, ast.Assign) and any( |
215 t.id == "__pydantic_config__" |
215 t.id == "__pydantic_config__" |
216 for t in stmt.targets |
216 for t in stmt.targets |
217 if isinstance(t, ast.Name) |
217 if isinstance(t, ast.Name) |
218 ): |
218 ): |
219 ##~ __pydantic_config__ = ... |
219 ##~ __pydantic_config__ = ... |
220 self.__error(stmt.lineno - 1, stmt.col_offset, "PYD010") |
220 self.__error(stmt, "PYD-010") |
221 |
221 |
222 def visit_ClassDef(self, node: ast.ClassDef) -> None: |
222 def visit_ClassDef(self, node: ast.ClassDef) -> None: |
223 """ |
223 """ |
224 Public method to process class definitions. |
224 Public method to process class definitions. |
225 |
225 |
226 @param node reference to the node to be processed. |
226 @param node reference to the node to be processed. |
227 @type ast.ClassDef |
227 @type ast.ClassDef |
228 """ |
228 """ |
229 self.__enterClass(node) |
229 self.__enterClass(node) |
230 |
230 |
231 # TODO: implement these methods |
|
232 self.__checkForPyd002(node) |
231 self.__checkForPyd002(node) |
233 self.__checkForPyd005(node) |
232 self.__checkForPyd005(node) |
234 self.__checkForPyd006(node) |
233 self.__checkForPyd006(node) |
235 self.__checkForPyd010(node) |
234 self.__checkForPyd010(node) |
236 |
235 |