Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(872)

Side by Side Diff: third_party/pylint/pylint/checkers/exceptions.py

Issue 1920403002: [content/test/gpu] Run pylint check of gpu tests in unittest instead of PRESUBMIT (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update path to LICENSE.txt of logilab/README.chromium Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE).
2 # http://www.logilab.fr/ -- mailto:contact@logilab.fr
3 # This program is free software; you can redistribute it and/or modify it under
4 # the terms of the GNU General Public License as published by the Free Software
5 # Foundation; either version 2 of the License, or (at your option) any later
6 # version.
7 #
8 # This program is distributed in the hope that it will be useful, but WITHOUT
9 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU General Public License along with
13 # this program; if not, write to the Free Software Foundation, Inc.,
14 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 """exceptions handling (raising, catching, exceptions classes) checker
16 """
17 import sys
18
19 import astroid
20 from astroid import YES, Instance, unpack_infer, List, Tuple
21 from logilab.common.compat import builtins
22
23 from pylint.checkers import BaseChecker
24 from pylint.checkers.utils import (
25 is_empty,
26 is_raising,
27 check_messages,
28 inherit_from_std_ex,
29 EXCEPTIONS_MODULE,
30 has_known_bases,
31 safe_infer)
32 from pylint.interfaces import IAstroidChecker, INFERENCE, INFERENCE_FAILURE
33
34
35 def _annotated_unpack_infer(stmt, context=None):
36 """
37 Recursively generate nodes inferred by the given statement.
38 If the inferred value is a list or a tuple, recurse on the elements.
39 Returns an iterator which yields tuples in the format
40 ('original node', 'infered node').
41 """
42 if isinstance(stmt, (List, Tuple)):
43 for elt in stmt.elts:
44 inferred = safe_infer(elt)
45 if inferred and inferred is not YES:
46 yield elt, inferred
47 return
48 for infered in stmt.infer(context):
49 if infered is YES:
50 continue
51 yield stmt, infered
52
53
54 PY3K = sys.version_info >= (3, 0)
55 OVERGENERAL_EXCEPTIONS = ('Exception',)
56 BUILTINS_NAME = builtins.__name__
57 MSGS = {
58 'E0701': ('Bad except clauses order (%s)',
59 'bad-except-order',
60 'Used when except clauses are not in the correct order (from the '
61 'more specific to the more generic). If you don\'t fix the order, '
62 'some exceptions may not be catched by the most specific handler.' ),
63 'E0702': ('Raising %s while only classes or instances are allowed',
64 'raising-bad-type',
65 'Used when something which is neither a class, an instance or a \
66 string is raised (i.e. a `TypeError` will be raised).'),
67 'E0703': ('Exception context set to something which is not an '
68 'exception, nor None',
69 'bad-exception-context',
70 'Used when using the syntax "raise ... from ...", '
71 'where the exception context is not an exception, '
72 'nor None.',
73 {'minversion': (3, 0)}),
74 'E0710': ('Raising a new style class which doesn\'t inherit from BaseExcepti on',
75 'raising-non-exception',
76 'Used when a new style class which doesn\'t inherit from \
77 BaseException is raised.'),
78 'E0711': ('NotImplemented raised - should raise NotImplementedError',
79 'notimplemented-raised',
80 'Used when NotImplemented is raised instead of \
81 NotImplementedError'),
82 'E0712': ('Catching an exception which doesn\'t inherit from BaseException: %s',
83 'catching-non-exception',
84 'Used when a class which doesn\'t inherit from \
85 BaseException is used as an exception in an except clause.'),
86 'W0702': ('No exception type(s) specified',
87 'bare-except',
88 'Used when an except clause doesn\'t specify exceptions type to \
89 catch.'),
90 'W0703': ('Catching too general exception %s',
91 'broad-except',
92 'Used when an except catches a too general exception, \
93 possibly burying unrelated errors.'),
94 'W0704': ('Except doesn\'t do anything',
95 'pointless-except',
96 'Used when an except clause does nothing but "pass" and there is\
97 no "else" clause.'),
98 'W0710': ('Exception doesn\'t inherit from standard "Exception" class',
99 'nonstandard-exception',
100 'Used when a custom exception class is raised but doesn\'t \
101 inherit from the builtin "Exception" class.',
102 {'maxversion': (3, 0)}),
103 'W0711': ('Exception to catch is the result of a binary "%s" operation',
104 'binary-op-exception',
105 'Used when the exception to catch is of the form \
106 "except A or B:". If intending to catch multiple, \
107 rewrite as "except (A, B):"'),
108 }
109
110
111 class ExceptionsChecker(BaseChecker):
112 """checks for
113 * excepts without exception filter
114 * type of raise argument : string, Exceptions, other values
115 """
116
117 __implements__ = IAstroidChecker
118
119 name = 'exceptions'
120 msgs = MSGS
121 priority = -4
122 options = (('overgeneral-exceptions',
123 {'default' : OVERGENERAL_EXCEPTIONS,
124 'type' :'csv', 'metavar' : '<comma-separated class names>',
125 'help' : 'Exceptions that will emit a warning '
126 'when being caught. Defaults to "%s"' % (
127 ', '.join(OVERGENERAL_EXCEPTIONS),)}
128 ),
129 )
130
131 @check_messages('nonstandard-exception',
132 'raising-bad-type', 'raising-non-exception',
133 'notimplemented-raised', 'bad-exception-context')
134 def visit_raise(self, node):
135 """visit raise possibly inferring value"""
136 # ignore empty raise
137 if node.exc is None:
138 return
139 if PY3K and node.cause:
140 self._check_bad_exception_context(node)
141
142 expr = node.exc
143 if self._check_raise_value(node, expr):
144 return
145 else:
146 try:
147 value = next(unpack_infer(expr))
148 except astroid.InferenceError:
149 return
150 self._check_raise_value(node, value)
151
152 def _check_bad_exception_context(self, node):
153 """Verify that the exception context is properly set.
154
155 An exception context can be only `None` or an exception.
156 """
157 cause = safe_infer(node.cause)
158 if cause in (YES, None):
159 return
160 if isinstance(cause, astroid.Const):
161 if cause.value is not None:
162 self.add_message('bad-exception-context',
163 node=node)
164 elif (not isinstance(cause, astroid.Class) and
165 not inherit_from_std_ex(cause)):
166 self.add_message('bad-exception-context',
167 node=node)
168
169 def _check_raise_value(self, node, expr):
170 """check for bad values, string exception and class inheritance
171 """
172 value_found = True
173 if isinstance(expr, astroid.Const):
174 value = expr.value
175 if not isinstance(value, str):
176 # raising-string will be emitted from python3 porting checker.
177 self.add_message('raising-bad-type', node=node,
178 args=value.__class__.__name__)
179 elif ((isinstance(expr, astroid.Name) and
180 expr.name in ('None', 'True', 'False')) or
181 isinstance(expr, (astroid.List, astroid.Dict, astroid.Tuple,
182 astroid.Module, astroid.Function))):
183 emit = True
184 if not PY3K and isinstance(expr, astroid.Tuple):
185 # On Python 2, using the following is not an error:
186 # raise (ZeroDivisionError, None)
187 # raise (ZeroDivisionError, )
188 # What's left to do is to check that the first
189 # argument is indeed an exception.
190 # Verifying the other arguments is not
191 # the scope of this check.
192 first = expr.elts[0]
193 inferred = safe_infer(first)
194 if isinstance(inferred, Instance):
195 # pylint: disable=protected-access
196 inferred = inferred._proxied
197 if (inferred is YES or
198 isinstance(inferred, astroid.Class)
199 and inherit_from_std_ex(inferred)):
200 emit = False
201 if emit:
202 self.add_message('raising-bad-type',
203 node=node,
204 args=expr.name)
205 elif ((isinstance(expr, astroid.Name) and expr.name == 'NotImplemented')
206 or (isinstance(expr, astroid.CallFunc) and
207 isinstance(expr.func, astroid.Name) and
208 expr.func.name == 'NotImplemented')):
209 self.add_message('notimplemented-raised', node=node)
210 elif isinstance(expr, (Instance, astroid.Class)):
211 if isinstance(expr, Instance):
212 # pylint: disable=protected-access
213 expr = expr._proxied
214 if (isinstance(expr, astroid.Class) and
215 not inherit_from_std_ex(expr)):
216 if expr.newstyle:
217 self.add_message('raising-non-exception', node=node)
218 else:
219 if has_known_bases(expr):
220 confidence = INFERENCE
221 else:
222 confidence = INFERENCE_FAILURE
223 self.add_message(
224 'nonstandard-exception', node=node,
225 confidence=confidence)
226 else:
227 value_found = False
228 else:
229 value_found = False
230 return value_found
231
232 def _check_catching_non_exception(self, handler, exc, part):
233 if isinstance(exc, astroid.Tuple):
234 # Check if it is a tuple of exceptions.
235 inferred = [safe_infer(elt) for elt in exc.elts]
236 if any(node is astroid.YES for node in inferred):
237 # Don't emit if we don't know every component.
238 return
239 if all(node and inherit_from_std_ex(node)
240 for node in inferred):
241 return
242
243 if not isinstance(exc, astroid.Class):
244 # Don't emit the warning if the infered stmt
245 # is None, but the exception handler is something else,
246 # maybe it was redefined.
247 if (isinstance(exc, astroid.Const) and
248 exc.value is None):
249 if ((isinstance(handler.type, astroid.Const) and
250 handler.type.value is None) or
251 handler.type.parent_of(exc)):
252 # If the exception handler catches None or
253 # the exception component, which is None, is
254 # defined by the entire exception handler, then
255 # emit a warning.
256 self.add_message('catching-non-exception',
257 node=handler.type,
258 args=(part.as_string(), ))
259 else:
260 self.add_message('catching-non-exception',
261 node=handler.type,
262 args=(part.as_string(), ))
263 return
264 if (not inherit_from_std_ex(exc) and
265 exc.root().name != BUILTINS_NAME):
266 if has_known_bases(exc):
267 self.add_message('catching-non-exception',
268 node=handler.type,
269 args=(exc.name, ))
270
271 @check_messages('bare-except', 'broad-except', 'pointless-except',
272 'binary-op-exception', 'bad-except-order',
273 'catching-non-exception')
274 def visit_tryexcept(self, node):
275 """check for empty except"""
276 exceptions_classes = []
277 nb_handlers = len(node.handlers)
278 for index, handler in enumerate(node.handlers):
279 # single except doing nothing but "pass" without else clause
280 if is_empty(handler.body) and not node.orelse:
281 self.add_message('pointless-except',
282 node=handler.type or handler.body[0])
283 if handler.type is None:
284 if not is_raising(handler.body):
285 self.add_message('bare-except', node=handler)
286 # check if a "except:" is followed by some other
287 # except
288 if index < (nb_handlers - 1):
289 msg = 'empty except clause should always appear last'
290 self.add_message('bad-except-order', node=node, args=msg)
291
292 elif isinstance(handler.type, astroid.BoolOp):
293 self.add_message('binary-op-exception',
294 node=handler, args=handler.type.op)
295 else:
296 try:
297 excs = list(_annotated_unpack_infer(handler.type))
298 except astroid.InferenceError:
299 continue
300 for part, exc in excs:
301 if exc is YES:
302 continue
303 if (isinstance(exc, astroid.Instance)
304 and inherit_from_std_ex(exc)):
305 # pylint: disable=protected-access
306 exc = exc._proxied
307
308 self._check_catching_non_exception(handler, exc, part)
309
310 if not isinstance(exc, astroid.Class):
311 continue
312
313 exc_ancestors = [anc for anc in exc.ancestors()
314 if isinstance(anc, astroid.Class)]
315 for previous_exc in exceptions_classes:
316 if previous_exc in exc_ancestors:
317 msg = '%s is an ancestor class of %s' % (
318 previous_exc.name, exc.name)
319 self.add_message('bad-except-order',
320 node=handler.type, args=msg)
321 if (exc.name in self.config.overgeneral_exceptions
322 and exc.root().name == EXCEPTIONS_MODULE
323 and not is_raising(handler.body)):
324 self.add_message('broad-except',
325 args=exc.name, node=handler.type)
326
327 exceptions_classes += [exc for _, exc in excs]
328
329
330 def register(linter):
331 """required method to auto register this checker"""
332 linter.register_checker(ExceptionsChecker(linter))
OLDNEW
« no previous file with comments | « third_party/pylint/pylint/checkers/design_analysis.py ('k') | third_party/pylint/pylint/checkers/format.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698