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

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

Issue 739393004: Revert "Revert "pylint: upgrade to 1.3.1"" (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools/
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 | Annotate | Revision Log
« 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-2007 LOGILAB S.A. (Paris, FRANCE). 1 # Copyright (c) 2003-2013 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 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 14 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 from logilab import astng 21 import astroid
22 from logilab.astng import YES, Instance, unpack_infer 22 from astroid 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 25 from pylint.checkers.utils import is_empty, is_raising, check_messages
26 from pylint.interfaces import IASTNGChecker 26 from pylint.interfaces import IAstroidChecker
27 27
28 def infer_bases(klass):
29 """ Fully infer the bases of the klass node.
28 30
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)
29 OVERGENERAL_EXCEPTIONS = ('Exception',) 47 OVERGENERAL_EXCEPTIONS = ('Exception',)
30 48
31 MSGS = { 49 MSGS = {
32 'E0701': ( 50 'E0701': ('Bad except clauses order (%s)',
33 'Bad except clauses order (%s)', 51 'bad-except-order',
34 'Used when except clauses are not in the correct order (from the \ 52 'Used when except clauses are not in the correct order (from the '
35 more specific to the more generic). If you don\'t fix the order, \ 53 'more specific to the more generic). If you don\'t fix the order, '
36 some exceptions may not be catched by the most specific handler.'), 54 'some exceptions may not be catched by the most specific handler.' ),
37 'E0702': ('Raising %s while only classes, instances or string are allowed', 55 'E0702': ('Raising %s while only classes, instances or string are allowed',
56 'raising-bad-type',
38 'Used when something which is neither a class, an instance or a \ 57 'Used when something which is neither a class, an instance or a \
39 string is raised (i.e. a `TypeError` will be raised).'), 58 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)}),
40 'E0710': ('Raising a new style class which doesn\'t inherit from BaseExcepti on', 66 'E0710': ('Raising a new style class which doesn\'t inherit from BaseExcepti on',
67 'raising-non-exception',
41 'Used when a new style class which doesn\'t inherit from \ 68 'Used when a new style class which doesn\'t inherit from \
42 BaseException is raised.'), 69 BaseException is raised.'),
43 'E0711': ('NotImplemented raised - should raise NotImplementedError', 70 'E0711': ('NotImplemented raised - should raise NotImplementedError',
71 'notimplemented-raised',
44 'Used when NotImplemented is raised instead of \ 72 'Used when NotImplemented is raised instead of \
45 NotImplementedError'), 73 NotImplementedError'),
46 74 'E0712': ('Catching an exception which doesn\'t inherit from BaseException: %s',
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
47 'W0701': ('Raising a string exception', 79 'W0701': ('Raising a string exception',
80 'raising-string',
48 'Used when a string exception is raised.'), 81 'Used when a string exception is raised.'),
49 'W0702': ('No exception type(s) specified', 82 'W0702': ('No exception type(s) specified',
83 'bare-except',
50 'Used when an except clause doesn\'t specify exceptions type to \ 84 'Used when an except clause doesn\'t specify exceptions type to \
51 catch.'), 85 catch.'),
52 'W0703': ('Catching too general exception %s', 86 'W0703': ('Catching too general exception %s',
87 'broad-except',
53 'Used when an except catches a too general exception, \ 88 'Used when an except catches a too general exception, \
54 possibly burying unrelated errors.'), 89 possibly burying unrelated errors.'),
55 'W0704': ('Except doesn\'t do anything', 90 'W0704': ('Except doesn\'t do anything',
91 'pointless-except',
56 'Used when an except clause does nothing but "pass" and there is\ 92 'Used when an except clause does nothing but "pass" and there is\
57 no "else" clause.'), 93 no "else" clause.'),
58 'W0710': ('Exception doesn\'t inherit from standard "Exception" class', 94 'W0710': ('Exception doesn\'t inherit from standard "Exception" class',
95 'nonstandard-exception',
59 'Used when a custom exception class is raised but doesn\'t \ 96 'Used when a custom exception class is raised but doesn\'t \
60 inherit from the builtin "Exception" class.'), 97 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)}),
61 } 115 }
62 116
63 117
64 if sys.version_info < (3, 0): 118 if sys.version_info < (3, 0):
65 EXCEPTIONS_MODULE = "exceptions" 119 EXCEPTIONS_MODULE = "exceptions"
66 else: 120 else:
67 EXCEPTIONS_MODULE = "builtins" 121 EXCEPTIONS_MODULE = "builtins"
68 122
69 class ExceptionsChecker(BaseChecker): 123 class ExceptionsChecker(BaseChecker):
70 """checks for 124 """checks for
71 * excepts without exception filter 125 * excepts without exception filter
72 * type of raise argument : string, Exceptions, other values 126 * type of raise argument : string, Exceptions, other values
73 """ 127 """
74 128
75 __implements__ = IASTNGChecker 129 __implements__ = IAstroidChecker
76 130
77 name = 'exceptions' 131 name = 'exceptions'
78 msgs = MSGS 132 msgs = MSGS
79 priority = -4 133 priority = -4
80 options = (('overgeneral-exceptions', 134 options = (('overgeneral-exceptions',
81 {'default' : OVERGENERAL_EXCEPTIONS, 135 {'default' : OVERGENERAL_EXCEPTIONS,
82 'type' :'csv', 'metavar' : '<comma-separated class names>', 136 'type' :'csv', 'metavar' : '<comma-separated class names>',
83 'help' : 'Exceptions that will emit a warning ' 137 'help' : 'Exceptions that will emit a warning '
84 'when being caught. Defaults to "%s"' % ( 138 'when being caught. Defaults to "%s"' % (
85 ', '.join(OVERGENERAL_EXCEPTIONS),)} 139 ', '.join(OVERGENERAL_EXCEPTIONS),)}
86 ), 140 ),
87 ) 141 )
88 142
143 @check_messages('raising-string', 'nonstandard-exception', 'raising-bad-type ',
144 'raising-non-exception', 'notimplemented-raised', 'bad-excep tion-context')
89 def visit_raise(self, node): 145 def visit_raise(self, node):
90 """visit raise possibly inferring value""" 146 """visit raise possibly inferring value"""
91 # ignore empty raise 147 # ignore empty raise
92 if node.exc is None: 148 if node.exc is None:
93 return 149 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)
94 expr = node.exc 166 expr = node.exc
95 if self._check_raise_value(node, expr): 167 if self._check_raise_value(node, expr):
96 return 168 return
97 else: 169 else:
98 try: 170 try:
99 value = unpack_infer(expr).next() 171 value = unpack_infer(expr).next()
100 except astng.InferenceError: 172 except astroid.InferenceError:
101 return 173 return
102 self._check_raise_value(node, value) 174 self._check_raise_value(node, value)
103 175
104 def _check_raise_value(self, node, expr): 176 def _check_raise_value(self, node, expr):
105 """check for bad values, string exception and class inheritance 177 """check for bad values, string exception and class inheritance
106 """ 178 """
107 value_found = True 179 value_found = True
108 if isinstance(expr, astng.Const): 180 if isinstance(expr, astroid.Const):
109 value = expr.value 181 value = expr.value
110 if isinstance(value, str): 182 if isinstance(value, str):
111 self.add_message('W0701', node=node) 183 self.add_message('raising-string', node=node)
112 else: 184 else:
113 self.add_message('E0702', node=node, 185 self.add_message('raising-bad-type', node=node,
114 args=value.__class__.__name__) 186 args=value.__class__.__name__)
115 elif (isinstance(expr, astng.Name) and \ 187 elif (isinstance(expr, astroid.Name) and \
116 expr.name in ('None', 'True', 'False')) or \ 188 expr.name in ('None', 'True', 'False')) or \
117 isinstance(expr, (astng.List, astng.Dict, astng.Tuple, 189 isinstance(expr, (astroid.List, astroid.Dict, astroid.Tuple,
118 astng.Module, astng.Function)): 190 astroid.Module, astroid.Function)):
119 self.add_message('E0702', node=node, args=expr.name) 191 self.add_message('raising-bad-type', node=node, args=expr.name)
120 elif ( (isinstance(expr, astng.Name) and expr.name == 'NotImplemented') 192 elif ((isinstance(expr, astroid.Name) and expr.name == 'NotImplemented')
121 or (isinstance(expr, astng.CallFunc) and 193 or (isinstance(expr, astroid.CallFunc) and
122 isinstance(expr.func, astng.Name) and 194 isinstance(expr.func, astroid.Name) and
123 expr.func.name == 'NotImplemented') ): 195 expr.func.name == 'NotImplemented')):
124 self.add_message('E0711', node=node) 196 self.add_message('notimplemented-raised', node=node)
125 elif isinstance(expr, astng.BinOp) and expr.op == '%': 197 elif isinstance(expr, astroid.BinOp) and expr.op == '%':
126 self.add_message('W0701', node=node) 198 self.add_message('raising-string', node=node)
127 elif isinstance(expr, (Instance, astng.Class)): 199 elif isinstance(expr, (Instance, astroid.Class)):
128 if isinstance(expr, Instance): 200 if isinstance(expr, Instance):
129 expr = expr._proxied 201 expr = expr._proxied
130 if (isinstance(expr, astng.Class) and 202 if (isinstance(expr, astroid.Class) and
131 not inherit_from_std_ex(expr) and 203 not inherit_from_std_ex(expr) and
132 expr.root().name != BUILTINS_NAME): 204 expr.root().name != BUILTINS_NAME):
133 if expr.newstyle: 205 if expr.newstyle:
134 self.add_message('E0710', node=node) 206 self.add_message('raising-non-exception', node=node)
135 else: 207 else:
136 self.add_message('W0710', node=node) 208 self.add_message('nonstandard-exception', node=node)
137 else: 209 else:
138 value_found = False 210 value_found = False
139 else: 211 else:
140 value_found = False 212 value_found = False
141 return value_found 213 return value_found
142 214
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)
143 220
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')
144 def visit_tryexcept(self, node): 236 def visit_tryexcept(self, node):
145 """check for empty except""" 237 """check for empty except"""
146 exceptions_classes = [] 238 exceptions_classes = []
147 nb_handlers = len(node.handlers) 239 nb_handlers = len(node.handlers)
148 for index, handler in enumerate(node.handlers): 240 for index, handler in enumerate(node.handlers):
149 # single except doing nothing but "pass" without else clause 241 # single except doing nothing but "pass" without else clause
150 if nb_handlers == 1 and is_empty(handler.body) and not node.orelse: 242 if is_empty(handler.body) and not node.orelse:
151 self.add_message('W0704', node=handler.type or handler.body[0]) 243 self.add_message('pointless-except', node=handler.type or handle r.body[0])
152 if handler.type is None: 244 if handler.type is None:
153 if nb_handlers == 1 and not is_raising(handler.body): 245 if not is_raising(handler.body):
154 self.add_message('W0702', node=handler) 246 self.add_message('bare-except', node=handler)
155 # check if a "except:" is followed by some other 247 # check if a "except:" is followed by some other
156 # except 248 # except
157 elif index < (nb_handlers - 1): 249 if index < (nb_handlers - 1):
158 msg = 'empty except clause should always appear last' 250 msg = 'empty except clause should always appear last'
159 self.add_message('E0701', node=node, args=msg) 251 self.add_message('bad-except-order', 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)
160 else: 255 else:
161 try: 256 try:
162 excs = list(unpack_infer(handler.type)) 257 excs = list(unpack_infer(handler.type))
163 except astng.InferenceError: 258 except astroid.InferenceError:
164 continue 259 continue
165 for exc in excs: 260 for exc in excs:
166 # XXX skip other non class nodes 261 # XXX skip other non class nodes
167 if exc is YES or not isinstance(exc, astng.Class): 262 if exc is YES or not isinstance(exc, astroid.Class):
168 continue 263 continue
169 exc_ancestors = [anc for anc in exc.ancestors() 264 exc_ancestors = [anc for anc in exc.ancestors()
170 if isinstance(anc, astng.Class)] 265 if isinstance(anc, astroid.Class)]
171 for previous_exc in exceptions_classes: 266 for previous_exc in exceptions_classes:
172 if previous_exc in exc_ancestors: 267 if previous_exc in exc_ancestors:
173 msg = '%s is an ancestor class of %s' % ( 268 msg = '%s is an ancestor class of %s' % (
174 previous_exc.name, exc.name) 269 previous_exc.name, exc.name)
175 self.add_message('E0701', node=handler.type, args=ms g) 270 self.add_message('bad-except-order', node=handler.ty pe, args=msg)
176 if (exc.name in self.config.overgeneral_exceptions 271 if (exc.name in self.config.overgeneral_exceptions
177 and exc.root().name == EXCEPTIONS_MODULE 272 and exc.root().name == EXCEPTIONS_MODULE
178 and nb_handlers == 1 and not is_raising(handler.body)): 273 and not is_raising(handler.body)):
179 self.add_message('W0703', args=exc.name, node=handler.ty pe) 274 self.add_message('broad-except', args=exc.name, node=han dler.type)
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
180 exceptions_classes += excs 289 exceptions_classes += excs
181 290
182 291
183 def inherit_from_std_ex(node): 292 def inherit_from_std_ex(node):
184 """return true if the given class node is subclass of 293 """return true if the given class node is subclass of
185 exceptions.Exception 294 exceptions.Exception
186 """ 295 """
187 if node.name in ('Exception', 'BaseException') \ 296 if node.name in ('Exception', 'BaseException') \
188 and node.root().name == EXCEPTIONS_MODULE: 297 and node.root().name == EXCEPTIONS_MODULE:
189 return True 298 return True
190 for parent in node.ancestors(recurs=False): 299 for parent in node.ancestors(recurs=False):
191 if inherit_from_std_ex(parent): 300 if inherit_from_std_ex(parent):
192 return True 301 return True
193 return False 302 return False
194 303
195 def register(linter): 304 def register(linter):
196 """required method to auto register this checker""" 305 """required method to auto register this checker"""
197 linter.register_checker(ExceptionsChecker(linter)) 306 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