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

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

Issue 719313003: Revert "pylint: upgrade to 1.3.1" (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Created 6 years, 1 month 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
« no previous file with comments | « third_party/pylint/checkers/design_analysis.py ('k') | third_party/pylint/checkers/format.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE). 1 # Copyright (c) 2003-2007 LOGILAB S.A. (Paris, FRANCE).
2 # http://www.logilab.fr/ -- mailto:contact@logilab.fr 2 # http://www.logilab.fr/ -- mailto:contact@logilab.fr
3 # This program is free software; you can redistribute it and/or modify it under 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 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 5 # Foundation; either version 2 of the License, or (at your option) any later
6 # version. 6 # version.
7 # 7 #
8 # This program is distributed in the hope that it will be useful, but WITHOUT 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 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. 10 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11 # 11 #
12 # You should have received a copy of the GNU General Public License along with 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., 13 # this program; if not, write to the Free Software Foundation, Inc.,
14 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 14 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 """exceptions handling (raising, catching, exceptions classes) checker 15 """exceptions handling (raising, catching, exceptions classes) checker
16 """ 16 """
17 import sys 17 import sys
18 18
19 from logilab.common.compat import builtins 19 from logilab.common.compat import builtins
20 BUILTINS_NAME = builtins.__name__ 20 BUILTINS_NAME = builtins.__name__
21 import astroid 21 from logilab import astng
22 from astroid import YES, Instance, unpack_infer 22 from logilab.astng import YES, Instance, unpack_infer
23 23
24 from pylint.checkers import BaseChecker 24 from pylint.checkers import BaseChecker
25 from pylint.checkers.utils import is_empty, is_raising, check_messages 25 from pylint.checkers.utils import is_empty, is_raising
26 from pylint.interfaces import IAstroidChecker 26 from pylint.interfaces import IASTNGChecker
27 27
28 def infer_bases(klass):
29 """ Fully infer the bases of the klass node.
30 28
31 This doesn't use .ancestors(), because we need
32 the non-inferable nodes (YES nodes),
33 which can't be retrieved from .ancestors()
34 """
35 for base in klass.bases:
36 try:
37 inferit = base.infer().next()
38 except astroid.InferenceError:
39 continue
40 if inferit is YES:
41 yield inferit
42 else:
43 for base in infer_bases(inferit):
44 yield base
45
46 PY3K = sys.version_info >= (3, 0)
47 OVERGENERAL_EXCEPTIONS = ('Exception',) 29 OVERGENERAL_EXCEPTIONS = ('Exception',)
48 30
49 MSGS = { 31 MSGS = {
50 'E0701': ('Bad except clauses order (%s)', 32 'E0701': (
51 'bad-except-order', 33 'Bad except clauses order (%s)',
52 'Used when except clauses are not in the correct order (from the ' 34 'Used when except clauses are not in the correct order (from the \
53 'more specific to the more generic). If you don\'t fix the order, ' 35 more specific to the more generic). If you don\'t fix the order, \
54 'some exceptions may not be catched by the most specific handler.' ), 36 some exceptions may not be catched by the most specific handler.'),
55 'E0702': ('Raising %s while only classes, instances or string are allowed', 37 'E0702': ('Raising %s while only classes, instances or string are allowed',
56 'raising-bad-type',
57 'Used when something which is neither a class, an instance or a \ 38 'Used when something which is neither a class, an instance or a \
58 string is raised (i.e. a `TypeError` will be raised).'), 39 string is raised (i.e. a `TypeError` will be raised).'),
59 'E0703': ('Exception context set to something which is not an '
60 'exception, nor None',
61 'bad-exception-context',
62 'Used when using the syntax "raise ... from ...", '
63 'where the exception context is not an exception, '
64 'nor None.',
65 {'minversion': (3, 0)}),
66 'E0710': ('Raising a new style class which doesn\'t inherit from BaseExcepti on', 40 'E0710': ('Raising a new style class which doesn\'t inherit from BaseExcepti on',
67 'raising-non-exception',
68 'Used when a new style class which doesn\'t inherit from \ 41 'Used when a new style class which doesn\'t inherit from \
69 BaseException is raised.'), 42 BaseException is raised.'),
70 'E0711': ('NotImplemented raised - should raise NotImplementedError', 43 'E0711': ('NotImplemented raised - should raise NotImplementedError',
71 'notimplemented-raised',
72 'Used when NotImplemented is raised instead of \ 44 'Used when NotImplemented is raised instead of \
73 NotImplementedError'), 45 NotImplementedError'),
74 'E0712': ('Catching an exception which doesn\'t inherit from BaseException: %s', 46
75 'catching-non-exception',
76 'Used when a class which doesn\'t inherit from \
77 BaseException is used as an exception in an except clause.'),
78
79 'W0701': ('Raising a string exception', 47 'W0701': ('Raising a string exception',
80 'raising-string',
81 'Used when a string exception is raised.'), 48 'Used when a string exception is raised.'),
82 'W0702': ('No exception type(s) specified', 49 'W0702': ('No exception type(s) specified',
83 'bare-except',
84 'Used when an except clause doesn\'t specify exceptions type to \ 50 'Used when an except clause doesn\'t specify exceptions type to \
85 catch.'), 51 catch.'),
86 'W0703': ('Catching too general exception %s', 52 'W0703': ('Catching too general exception %s',
87 'broad-except',
88 'Used when an except catches a too general exception, \ 53 'Used when an except catches a too general exception, \
89 possibly burying unrelated errors.'), 54 possibly burying unrelated errors.'),
90 'W0704': ('Except doesn\'t do anything', 55 'W0704': ('Except doesn\'t do anything',
91 'pointless-except',
92 'Used when an except clause does nothing but "pass" and there is\ 56 'Used when an except clause does nothing but "pass" and there is\
93 no "else" clause.'), 57 no "else" clause.'),
94 'W0710': ('Exception doesn\'t inherit from standard "Exception" class', 58 'W0710': ('Exception doesn\'t inherit from standard "Exception" class',
95 'nonstandard-exception',
96 'Used when a custom exception class is raised but doesn\'t \ 59 'Used when a custom exception class is raised but doesn\'t \
97 inherit from the builtin "Exception" class.', 60 inherit from the builtin "Exception" class.'),
98 {'maxversion': (3, 0)}),
99 'W0711': ('Exception to catch is the result of a binary "%s" operation',
100 'binary-op-exception',
101 'Used when the exception to catch is of the form \
102 "except A or B:". If intending to catch multiple, \
103 rewrite as "except (A, B):"'),
104 'W0712': ('Implicit unpacking of exceptions is not supported in Python 3',
105 'unpacking-in-except',
106 'Python3 will not allow implicit unpacking of exceptions in except '
107 'clauses. '
108 'See http://www.python.org/dev/peps/pep-3110/',
109 {'maxversion': (3, 0)}),
110 'W0713': ('Indexing exceptions will not work on Python 3',
111 'indexing-exception',
112 'Indexing exceptions will not work on Python 3. Use '
113 '`exception.args[index]` instead.',
114 {'maxversion': (3, 0)}),
115 } 61 }
116 62
117 63
118 if sys.version_info < (3, 0): 64 if sys.version_info < (3, 0):
119 EXCEPTIONS_MODULE = "exceptions" 65 EXCEPTIONS_MODULE = "exceptions"
120 else: 66 else:
121 EXCEPTIONS_MODULE = "builtins" 67 EXCEPTIONS_MODULE = "builtins"
122 68
123 class ExceptionsChecker(BaseChecker): 69 class ExceptionsChecker(BaseChecker):
124 """checks for 70 """checks for
125 * excepts without exception filter 71 * excepts without exception filter
126 * type of raise argument : string, Exceptions, other values 72 * type of raise argument : string, Exceptions, other values
127 """ 73 """
128 74
129 __implements__ = IAstroidChecker 75 __implements__ = IASTNGChecker
130 76
131 name = 'exceptions' 77 name = 'exceptions'
132 msgs = MSGS 78 msgs = MSGS
133 priority = -4 79 priority = -4
134 options = (('overgeneral-exceptions', 80 options = (('overgeneral-exceptions',
135 {'default' : OVERGENERAL_EXCEPTIONS, 81 {'default' : OVERGENERAL_EXCEPTIONS,
136 'type' :'csv', 'metavar' : '<comma-separated class names>', 82 'type' :'csv', 'metavar' : '<comma-separated class names>',
137 'help' : 'Exceptions that will emit a warning ' 83 'help' : 'Exceptions that will emit a warning '
138 'when being caught. Defaults to "%s"' % ( 84 'when being caught. Defaults to "%s"' % (
139 ', '.join(OVERGENERAL_EXCEPTIONS),)} 85 ', '.join(OVERGENERAL_EXCEPTIONS),)}
140 ), 86 ),
141 ) 87 )
142 88
143 @check_messages('raising-string', 'nonstandard-exception', 'raising-bad-type ',
144 'raising-non-exception', 'notimplemented-raised', 'bad-excep tion-context')
145 def visit_raise(self, node): 89 def visit_raise(self, node):
146 """visit raise possibly inferring value""" 90 """visit raise possibly inferring value"""
147 # ignore empty raise 91 # ignore empty raise
148 if node.exc is None: 92 if node.exc is None:
149 return 93 return
150 if PY3K and node.cause:
151 try:
152 cause = node.cause.infer().next()
153 except astroid.InferenceError:
154 pass
155 else:
156 if cause is YES:
157 return
158 if isinstance(cause, astroid.Const):
159 if cause.value is not None:
160 self.add_message('bad-exception-context',
161 node=node)
162 elif (not isinstance(cause, astroid.Class) and
163 not inherit_from_std_ex(cause)):
164 self.add_message('bad-exception-context',
165 node=node)
166 expr = node.exc 94 expr = node.exc
167 if self._check_raise_value(node, expr): 95 if self._check_raise_value(node, expr):
168 return 96 return
169 else: 97 else:
170 try: 98 try:
171 value = unpack_infer(expr).next() 99 value = unpack_infer(expr).next()
172 except astroid.InferenceError: 100 except astng.InferenceError:
173 return 101 return
174 self._check_raise_value(node, value) 102 self._check_raise_value(node, value)
175 103
176 def _check_raise_value(self, node, expr): 104 def _check_raise_value(self, node, expr):
177 """check for bad values, string exception and class inheritance 105 """check for bad values, string exception and class inheritance
178 """ 106 """
179 value_found = True 107 value_found = True
180 if isinstance(expr, astroid.Const): 108 if isinstance(expr, astng.Const):
181 value = expr.value 109 value = expr.value
182 if isinstance(value, str): 110 if isinstance(value, str):
183 self.add_message('raising-string', node=node) 111 self.add_message('W0701', node=node)
184 else: 112 else:
185 self.add_message('raising-bad-type', node=node, 113 self.add_message('E0702', node=node,
186 args=value.__class__.__name__) 114 args=value.__class__.__name__)
187 elif (isinstance(expr, astroid.Name) and \ 115 elif (isinstance(expr, astng.Name) and \
188 expr.name in ('None', 'True', 'False')) or \ 116 expr.name in ('None', 'True', 'False')) or \
189 isinstance(expr, (astroid.List, astroid.Dict, astroid.Tuple, 117 isinstance(expr, (astng.List, astng.Dict, astng.Tuple,
190 astroid.Module, astroid.Function)): 118 astng.Module, astng.Function)):
191 self.add_message('raising-bad-type', node=node, args=expr.name) 119 self.add_message('E0702', node=node, args=expr.name)
192 elif ((isinstance(expr, astroid.Name) and expr.name == 'NotImplemented') 120 elif ( (isinstance(expr, astng.Name) and expr.name == 'NotImplemented')
193 or (isinstance(expr, astroid.CallFunc) and 121 or (isinstance(expr, astng.CallFunc) and
194 isinstance(expr.func, astroid.Name) and 122 isinstance(expr.func, astng.Name) and
195 expr.func.name == 'NotImplemented')): 123 expr.func.name == 'NotImplemented') ):
196 self.add_message('notimplemented-raised', node=node) 124 self.add_message('E0711', node=node)
197 elif isinstance(expr, astroid.BinOp) and expr.op == '%': 125 elif isinstance(expr, astng.BinOp) and expr.op == '%':
198 self.add_message('raising-string', node=node) 126 self.add_message('W0701', node=node)
199 elif isinstance(expr, (Instance, astroid.Class)): 127 elif isinstance(expr, (Instance, astng.Class)):
200 if isinstance(expr, Instance): 128 if isinstance(expr, Instance):
201 expr = expr._proxied 129 expr = expr._proxied
202 if (isinstance(expr, astroid.Class) and 130 if (isinstance(expr, astng.Class) and
203 not inherit_from_std_ex(expr) and 131 not inherit_from_std_ex(expr) and
204 expr.root().name != BUILTINS_NAME): 132 expr.root().name != BUILTINS_NAME):
205 if expr.newstyle: 133 if expr.newstyle:
206 self.add_message('raising-non-exception', node=node) 134 self.add_message('E0710', node=node)
207 else: 135 else:
208 self.add_message('nonstandard-exception', node=node) 136 self.add_message('W0710', node=node)
209 else: 137 else:
210 value_found = False 138 value_found = False
211 else: 139 else:
212 value_found = False 140 value_found = False
213 return value_found 141 return value_found
214 142
215 @check_messages('unpacking-in-except')
216 def visit_excepthandler(self, node):
217 """Visit an except handler block and check for exception unpacking."""
218 if isinstance(node.name, (astroid.Tuple, astroid.List)):
219 self.add_message('unpacking-in-except', node=node)
220 143
221 @check_messages('indexing-exception')
222 def visit_subscript(self, node):
223 """ Look for indexing exceptions. """
224 try:
225 for infered in node.value.infer():
226 if not isinstance(infered, astroid.Instance):
227 continue
228 if inherit_from_std_ex(infered):
229 self.add_message('indexing-exception', node=node)
230 except astroid.InferenceError:
231 return
232
233 @check_messages('bare-except', 'broad-except', 'pointless-except',
234 'binary-op-exception', 'bad-except-order',
235 'catching-non-exception')
236 def visit_tryexcept(self, node): 144 def visit_tryexcept(self, node):
237 """check for empty except""" 145 """check for empty except"""
238 exceptions_classes = [] 146 exceptions_classes = []
239 nb_handlers = len(node.handlers) 147 nb_handlers = len(node.handlers)
240 for index, handler in enumerate(node.handlers): 148 for index, handler in enumerate(node.handlers):
241 # single except doing nothing but "pass" without else clause 149 # single except doing nothing but "pass" without else clause
242 if is_empty(handler.body) and not node.orelse: 150 if nb_handlers == 1 and is_empty(handler.body) and not node.orelse:
243 self.add_message('pointless-except', node=handler.type or handle r.body[0]) 151 self.add_message('W0704', node=handler.type or handler.body[0])
244 if handler.type is None: 152 if handler.type is None:
245 if not is_raising(handler.body): 153 if nb_handlers == 1 and not is_raising(handler.body):
246 self.add_message('bare-except', node=handler) 154 self.add_message('W0702', node=handler)
247 # check if a "except:" is followed by some other 155 # check if a "except:" is followed by some other
248 # except 156 # except
249 if index < (nb_handlers - 1): 157 elif index < (nb_handlers - 1):
250 msg = 'empty except clause should always appear last' 158 msg = 'empty except clause should always appear last'
251 self.add_message('bad-except-order', node=node, args=msg) 159 self.add_message('E0701', node=node, args=msg)
252
253 elif isinstance(handler.type, astroid.BoolOp):
254 self.add_message('binary-op-exception', node=handler, args=handl er.type.op)
255 else: 160 else:
256 try: 161 try:
257 excs = list(unpack_infer(handler.type)) 162 excs = list(unpack_infer(handler.type))
258 except astroid.InferenceError: 163 except astng.InferenceError:
259 continue 164 continue
260 for exc in excs: 165 for exc in excs:
261 # XXX skip other non class nodes 166 # XXX skip other non class nodes
262 if exc is YES or not isinstance(exc, astroid.Class): 167 if exc is YES or not isinstance(exc, astng.Class):
263 continue 168 continue
264 exc_ancestors = [anc for anc in exc.ancestors() 169 exc_ancestors = [anc for anc in exc.ancestors()
265 if isinstance(anc, astroid.Class)] 170 if isinstance(anc, astng.Class)]
266 for previous_exc in exceptions_classes: 171 for previous_exc in exceptions_classes:
267 if previous_exc in exc_ancestors: 172 if previous_exc in exc_ancestors:
268 msg = '%s is an ancestor class of %s' % ( 173 msg = '%s is an ancestor class of %s' % (
269 previous_exc.name, exc.name) 174 previous_exc.name, exc.name)
270 self.add_message('bad-except-order', node=handler.ty pe, args=msg) 175 self.add_message('E0701', node=handler.type, args=ms g)
271 if (exc.name in self.config.overgeneral_exceptions 176 if (exc.name in self.config.overgeneral_exceptions
272 and exc.root().name == EXCEPTIONS_MODULE 177 and exc.root().name == EXCEPTIONS_MODULE
273 and not is_raising(handler.body)): 178 and nb_handlers == 1 and not is_raising(handler.body)):
274 self.add_message('broad-except', args=exc.name, node=han dler.type) 179 self.add_message('W0703', args=exc.name, node=handler.ty pe)
275
276 if (not inherit_from_std_ex(exc) and
277 exc.root().name != BUILTINS_NAME):
278 # try to see if the exception is based on a C based
279 # exception, by infering all the base classes and
280 # looking for inference errors
281 bases = infer_bases(exc)
282 fully_infered = all(inferit is not YES
283 for inferit in bases)
284 if fully_infered:
285 self.add_message('catching-non-exception',
286 node=handler.type,
287 args=(exc.name, ))
288
289 exceptions_classes += excs 180 exceptions_classes += excs
290 181
291 182
292 def inherit_from_std_ex(node): 183 def inherit_from_std_ex(node):
293 """return true if the given class node is subclass of 184 """return true if the given class node is subclass of
294 exceptions.Exception 185 exceptions.Exception
295 """ 186 """
296 if node.name in ('Exception', 'BaseException') \ 187 if node.name in ('Exception', 'BaseException') \
297 and node.root().name == EXCEPTIONS_MODULE: 188 and node.root().name == EXCEPTIONS_MODULE:
298 return True 189 return True
299 for parent in node.ancestors(recurs=False): 190 for parent in node.ancestors(recurs=False):
300 if inherit_from_std_ex(parent): 191 if inherit_from_std_ex(parent):
301 return True 192 return True
302 return False 193 return False
303 194
304 def register(linter): 195 def register(linter):
305 """required method to auto register this checker""" 196 """required method to auto register this checker"""
306 linter.register_checker(ExceptionsChecker(linter)) 197 linter.register_checker(ExceptionsChecker(linter))
OLDNEW
« no previous file with comments | « third_party/pylint/checkers/design_analysis.py ('k') | third_party/pylint/checkers/format.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698