45 @param repeat flag indicating to report each occurrence of a code |
46 @param repeat flag indicating to report each occurrence of a code |
46 @type bool |
47 @type bool |
47 @param args dictionary of arguments for the various checks |
48 @param args dictionary of arguments for the various checks |
48 @type dict |
49 @type dict |
49 """ |
50 """ |
50 self.__select = tuple(x for x in select if x.startswith(AsyncChecker.Prefix)) |
51 super().__init__( |
51 self.__ignore = tuple(x for x in ignore if x.startswith(AsyncChecker.Prefix)) |
52 AsyncChecker.Category, |
52 self.__expected = expected[:] |
53 source, |
53 self.__repeat = repeat |
54 filename, |
54 self.__filename = filename |
55 tree, |
55 self.__source = source[:] |
56 select, |
56 self.__tree = copy.deepcopy(tree) |
57 ignore, |
57 self.__args = args |
58 expected, |
58 |
59 repeat, |
59 # statistics counters |
60 args, |
60 self.counters = {} |
61 ) |
61 |
|
62 # collection of detected errors |
|
63 self.errors = [] |
|
64 |
62 |
65 checkersWithCodes = [ |
63 checkersWithCodes = [ |
66 ( |
64 ( |
67 self.__checkSyncUses, |
65 self.__checkSyncUses, |
68 ("ASY100", "ASY101", "ASY102", "ASY103", "ASY104", "ASY105"), |
66 ("ASY-100", "ASY-101", "ASY-102", "ASY-103", "ASY-104", "ASY-105"), |
69 ), |
67 ), |
70 ] |
68 ] |
71 |
69 self._initializeCheckers(checkersWithCodes) |
72 self.__checkers = [] |
|
73 for checker, codes in checkersWithCodes: |
|
74 if any(not (code and self.__ignoreCode(code)) for code in codes): |
|
75 self.__checkers.append(checker) |
|
76 |
|
77 def __ignoreCode(self, code): |
|
78 """ |
|
79 Private method to check if the message code should be ignored. |
|
80 |
|
81 @param code message code to check for |
|
82 @type str |
|
83 @return flag indicating to ignore the given code |
|
84 @rtype bool |
|
85 """ |
|
86 return code in self.__ignore or ( |
|
87 code.startswith(self.__ignore) and not code.startswith(self.__select) |
|
88 ) |
|
89 |
|
90 def __error(self, lineNumber, offset, code, *args): |
|
91 """ |
|
92 Private method to record an issue. |
|
93 |
|
94 @param lineNumber line number of the issue |
|
95 @type int |
|
96 @param offset position within line of the issue |
|
97 @type int |
|
98 @param code message code |
|
99 @type str |
|
100 @param args arguments for the message |
|
101 @type list |
|
102 """ |
|
103 if self.__ignoreCode(code): |
|
104 return |
|
105 |
|
106 if code in self.counters: |
|
107 self.counters[code] += 1 |
|
108 else: |
|
109 self.counters[code] = 1 |
|
110 |
|
111 # Don't care about expected codes |
|
112 if code in self.__expected: |
|
113 return |
|
114 |
|
115 if code and (self.counters[code] == 1 or self.__repeat): |
|
116 # record the issue with one based line number |
|
117 self.errors.append( |
|
118 { |
|
119 "file": self.__filename, |
|
120 "line": lineNumber + 1, |
|
121 "offset": offset, |
|
122 "code": code, |
|
123 "args": args, |
|
124 } |
|
125 ) |
|
126 |
|
127 def run(self): |
|
128 """ |
|
129 Public method to check the given source against miscellaneous |
|
130 conditions. |
|
131 """ |
|
132 if not self.__filename: |
|
133 # don't do anything, if essential data is missing |
|
134 return |
|
135 |
|
136 if not self.__checkers: |
|
137 # don't do anything, if no codes were selected |
|
138 return |
|
139 |
|
140 for check in self.__checkers: |
|
141 check() |
|
142 |
70 |
143 def __checkSyncUses(self): |
71 def __checkSyncUses(self): |
144 """ |
72 """ |
145 Private method to check for use of synchroneous functions in async methods. |
73 Private method to check for use of synchroneous functions in async methods. |
146 """ |
74 """ |
147 from .AsyncVisitor import AsyncVisitor |
75 from .AsyncVisitor import AsyncVisitor |
148 |
76 |
149 visitor = AsyncVisitor(self.__args, self) |
77 visitor = AsyncVisitor(self.args, self) |
150 visitor.visit(copy.deepcopy(self.__tree)) |
78 visitor.visit(copy.deepcopy(self.tree)) |
151 for violation in visitor.violations: |
79 for violation in visitor.violations: |
152 if not self.__ignoreCode(violation[1]): |
80 self.addErrorFromNode(violation[0], violation[1]) |
153 node = violation[0] |
|
154 reason = violation[1] |
|
155 self.__error(node.lineno - 1, node.col_offset, reason) |
|