13 from functools import lru_cache |
13 from functools import lru_cache |
14 |
14 |
15 import AstUtilities |
15 import AstUtilities |
16 |
16 |
17 from .AnnotationsEnums import AnnotationType, ClassDecoratorType, FunctionType |
17 from .AnnotationsEnums import AnnotationType, ClassDecoratorType, FunctionType |
|
18 from .AnnotationsCheckerDefaults import AnnotationsCheckerDefaultArgs |
18 |
19 |
19 |
20 |
20 class AnnotationsChecker: |
21 class AnnotationsChecker: |
21 """ |
22 """ |
22 Class implementing a checker for function type annotations. |
23 Class implementing a checker for function type annotations. |
87 ), |
88 ), |
88 (self.__checkAnnotationsCoverage, ("A881",)), |
89 (self.__checkAnnotationsCoverage, ("A881",)), |
89 (self.__checkAnnotationComplexity, ("A891", "A892")), |
90 (self.__checkAnnotationComplexity, ("A891", "A892")), |
90 ] |
91 ] |
91 |
92 |
92 # TODO: the parameters to CodeStyleCheckerDialog |
|
93 self.__defaultArgs = { |
|
94 # Annotations |
|
95 "SuppressNoneReturning": False, |
|
96 "SuppressDummyArgs": False, |
|
97 "AllowUntypedDefs": False, |
|
98 "AllowUntypedNested": False, |
|
99 "MypyInitReturn": False, |
|
100 "DispatchDecorators": [ |
|
101 "singledispatch", |
|
102 "singledispatchmethod", |
|
103 ], |
|
104 "OverloadDecorators": ["overload"], |
|
105 |
|
106 # Annotation Coverage |
|
107 "MinimumCoverage": 75, # % of type annotation coverage |
|
108 |
|
109 # Annotation Complexity |
|
110 "MaximumComplexity": 3, |
|
111 "MaximumLength": 7, |
|
112 } |
|
113 |
|
114 self.__checkers = [] |
93 self.__checkers = [] |
115 for checker, codes in checkersWithCodes: |
94 for checker, codes in checkersWithCodes: |
116 if any(not (code and self.__ignoreCode(code)) |
95 if any(not (code and self.__ignoreCode(code)) |
117 for code in codes): |
96 for code in codes): |
118 self.__checkers.append(checker) |
97 self.__checkers.append(checker) |
191 """ |
170 """ |
192 Private method to check for function annotation issues. |
171 Private method to check for function annotation issues. |
193 """ |
172 """ |
194 suppressNoneReturning = self.__args.get( |
173 suppressNoneReturning = self.__args.get( |
195 "SuppressNoneReturning", |
174 "SuppressNoneReturning", |
196 self.__defaultArgs["SuppressNoneReturning"]) |
175 AnnotationsCheckerDefaultArgs["SuppressNoneReturning"]) |
197 suppressDummyArgs = self.__args.get( |
176 suppressDummyArgs = self.__args.get( |
198 "SuppressDummyArgs", |
177 "SuppressDummyArgs", |
199 self.__defaultArgs["SuppressDummyArgs"]) |
178 AnnotationsCheckerDefaultArgs["SuppressDummyArgs"]) |
200 allowUntypedDefs = self.__args.get( |
179 allowUntypedDefs = self.__args.get( |
201 "AllowUntypedDefs", |
180 "AllowUntypedDefs", |
202 self.__defaultArgs["AllowUntypedDefs"]) |
181 AnnotationsCheckerDefaultArgs["AllowUntypedDefs"]) |
203 allowUntypedNested = self.__args.get( |
182 allowUntypedNested = self.__args.get( |
204 "AllowUntypedNested", |
183 "AllowUntypedNested", |
205 self.__defaultArgs["AllowUntypedNested"]) |
184 AnnotationsCheckerDefaultArgs["AllowUntypedNested"]) |
206 mypyInitReturn = self.__args.get( |
185 mypyInitReturn = self.__args.get( |
207 "MypyInitReturn", |
186 "MypyInitReturn", |
208 self.__defaultArgs["MypyInitReturn"]) |
187 AnnotationsCheckerDefaultArgs["MypyInitReturn"]) |
209 |
188 |
210 # Store decorator lists as sets for easier lookup |
189 # Store decorator lists as sets for easier lookup |
211 dispatchDecorators = set(self.__args.get( |
190 dispatchDecorators = set(self.__args.get( |
212 "DispatchDecorators", |
191 "DispatchDecorators", |
213 self.__defaultArgs["DispatchDecorators"])) |
192 AnnotationsCheckerDefaultArgs["DispatchDecorators"])) |
214 overloadDecorators = set(self.__args.get( |
193 overloadDecorators = set(self.__args.get( |
215 "OverloadDecorators", |
194 "OverloadDecorators", |
216 self.__defaultArgs["OverloadDecorators"])) |
195 AnnotationsCheckerDefaultArgs["OverloadDecorators"])) |
217 |
196 |
218 from .AnnotationsFunctionVisitor import FunctionVisitor |
197 from .AnnotationsFunctionVisitor import FunctionVisitor |
219 visitor = FunctionVisitor(self.__source) |
198 visitor = FunctionVisitor(self.__source) |
220 visitor.visit(self.__tree) |
199 visitor.visit(self.__tree) |
221 |
200 |
230 if ( |
209 if ( |
231 function.isDynamicallyTyped() and |
210 function.isDynamicallyTyped() and |
232 (allowUntypedDefs or |
211 (allowUntypedDefs or |
233 (function.isNested and allowUntypedNested)) |
212 (function.isNested and allowUntypedNested)) |
234 ): |
213 ): |
235 # Skip yielding errors from dynamically typed functions |
214 # Skip recording errors from dynamically typed functions |
236 # or nested functions |
215 # or nested functions |
237 continue |
216 continue |
238 |
217 |
239 # Skip yielding errors for configured dispatch functions, such as |
218 # Skip recording errors for configured dispatch functions, such as |
240 # (by default) `functools.singledispatch` and |
219 # (by default) `functools.singledispatch` and |
241 # `functools.singledispatchmethod` |
220 # `functools.singledispatchmethod` |
242 if function.hasDecorator(dispatchDecorators): |
221 if function.hasDecorator(dispatchDecorators): |
243 continue |
222 continue |
244 |
223 |
422 def __checkAnnotationsCoverage(self): |
401 def __checkAnnotationsCoverage(self): |
423 """ |
402 """ |
424 Private method to check for function annotation coverage. |
403 Private method to check for function annotation coverage. |
425 """ |
404 """ |
426 minAnnotationsCoverage = self.__args.get( |
405 minAnnotationsCoverage = self.__args.get( |
427 "MinimumCoverage", self.__defaultArgs["MinimumCoverage"]) |
406 "MinimumCoverage", AnnotationsCheckerDefaultArgs["MinimumCoverage"]) |
428 if minAnnotationsCoverage == 0: |
407 if minAnnotationsCoverage == 0: |
429 # 0 means it is switched off |
408 # 0 means it is switched off |
430 return |
409 return |
431 |
410 |
432 functionDefs = [ |
411 functionDefs = [ |
477 def __checkAnnotationComplexity(self): |
456 def __checkAnnotationComplexity(self): |
478 """ |
457 """ |
479 Private method to check the type annotation complexity. |
458 Private method to check the type annotation complexity. |
480 """ |
459 """ |
481 maxAnnotationComplexity = self.__args.get( |
460 maxAnnotationComplexity = self.__args.get( |
482 "MaximumComplexity", self.__defaultArgs["MaximumComplexity"]) |
461 "MaximumComplexity", AnnotationsCheckerDefaultArgs["MaximumComplexity"]) |
483 # TODO: include 'MaximumLength' in CodeStyleCheckerDialog |
462 # TODO: include 'MaximumLength' in CodeStyleCheckerDialog |
484 maxAnnotationLength = self.__args.get( |
463 maxAnnotationLength = self.__args.get( |
485 "MaximumLength", self.__defaultArgs["MaximumLength"]) |
464 "MaximumLength", AnnotationsCheckerDefaultArgs["MaximumLength"]) |
486 typeAnnotations = [] |
465 typeAnnotations = [] |
487 |
466 |
488 functionDefs = [ |
467 functionDefs = [ |
489 f for f in ast.walk(self.__tree) |
468 f for f in ast.walk(self.__tree) |
490 if isinstance(f, (ast.AsyncFunctionDef, ast.FunctionDef)) |
469 if isinstance(f, (ast.AsyncFunctionDef, ast.FunctionDef)) |