def _check_catching_non_exception(self, handler, exc, part): if isinstance(exc, astroid.Tuple): # Check if it is a tuple of exceptions. inferred = [safe_infer(elt) for elt in exc.elts] if any(node is astroid.YES for node in inferred): # Don't emit if we don't know every component. return if all(node and inherit_from_std_ex(node) for node in inferred): return if not isinstance(exc, astroid.Class): # Don't emit the warning if the infered stmt # is None, but the exception handler is something else, # maybe it was redefined. if (isinstance(exc, astroid.Const) and exc.value is None): if ((isinstance(handler.type, astroid.Const) and handler.type.value is None) or handler.type.parent_of(exc)): # If the exception handler catches None or # the exception component, which is None, is # defined by the entire exception handler, then # emit a warning. self.add_message('catching-non-exception', node=handler.type, args=(part.as_string(), )) else: self.add_message('catching-non-exception', node=handler.type, args=(part.as_string(), )) return if (not inherit_from_std_ex(exc) and exc.root().name != BUILTINS_NAME): if has_known_bases(exc): self.add_message('catching-non-exception', node=handler.type, args=(exc.name, ))
def _check_catching_non_exception(self, handler, exc, part): if isinstance(exc, astroid.Tuple): # Check if it is a tuple of exceptions. inferred = [safe_infer(elt) for elt in exc.elts] if any(node is astroid.YES for node in inferred): # Don't emit if we don't know every component. return if all(node and inherit_from_std_ex(node) for node in inferred): return if not isinstance(exc, astroid.ClassDef): # Don't emit the warning if the infered stmt # is None, but the exception handler is something else, # maybe it was redefined. if isinstance(exc, astroid.Const) and exc.value is None: if (isinstance(handler.type, astroid.Const) and handler.type.value is None) or handler.type.parent_of( exc ): # If the exception handler catches None or # the exception component, which is None, is # defined by the entire exception handler, then # emit a warning. self.add_message("catching-non-exception", node=handler.type, args=(part.as_string(),)) else: self.add_message("catching-non-exception", node=handler.type, args=(part.as_string(),)) return if not inherit_from_std_ex(exc) and exc.name not in self.builtin_exceptions: if has_known_bases(exc): self.add_message("catching-non-exception", node=handler.type, args=(exc.name,))
def _check_raise_value(self, node, expr): """check for bad values, string exception and class inheritance """ value_found = True if isinstance(expr, astroid.Const): value = expr.value if not isinstance(value, str): # raising-string will be emitted from python3 porting checker. self.add_message('raising-bad-type', node=node, args=value.__class__.__name__) elif ((isinstance(expr, astroid.Name) and expr.name in ('None', 'True', 'False')) or isinstance(expr, (astroid.List, astroid.Dict, astroid.Tuple, astroid.Module, astroid.FunctionDef))): emit = True if not PY3K and isinstance(expr, astroid.Tuple) and expr.elts: # On Python 2, using the following is not an error: # raise (ZeroDivisionError, None) # raise (ZeroDivisionError, ) # What's left to do is to check that the first # argument is indeed an exception. # Verifying the other arguments is not # the scope of this check. first = expr.elts[0] inferred = safe_infer(first) if isinstance(inferred, astroid.Instance): # pylint: disable=protected-access inferred = inferred._proxied if (inferred is astroid.YES or isinstance(inferred, astroid.ClassDef) and inherit_from_std_ex(inferred)): emit = False if emit: self.add_message('raising-bad-type', node=node, args=expr.name) elif ((isinstance(expr, astroid.Name) and expr.name == 'NotImplemented') or (isinstance(expr, astroid.Call) and isinstance(expr.func, astroid.Name) and expr.func.name == 'NotImplemented')): self.add_message('notimplemented-raised', node=node) elif isinstance(expr, (astroid.Instance, astroid.ClassDef)): if isinstance(expr, astroid.Instance): # pylint: disable=protected-access expr = expr._proxied if (isinstance(expr, astroid.ClassDef) and not inherit_from_std_ex(expr) and has_known_bases(expr)): if expr.newstyle: self.add_message('raising-non-exception', node=node) else: self.add_message('nonstandard-exception', node=node) else: value_found = False else: value_found = False return value_found
def _check_raise_value(self, node, expr): """check for bad values, string exception and class inheritance """ value_found = True if isinstance(expr, astroid.Const): value = expr.value if not isinstance(value, str): # raising-string will be emitted from python3 porting checker. self.add_message('raising-bad-type', node=node, args=value.__class__.__name__) elif ((isinstance(expr, astroid.Name) and expr.name in ('None', 'True', 'False')) or isinstance(expr, (astroid.List, astroid.Dict, astroid.Tuple, astroid.Module, astroid.FunctionDef))): emit = True if not PY3K and isinstance(expr, astroid.Tuple) and expr.elts: # On Python 2, using the following is not an error: # raise (ZeroDivisionError, None) # raise (ZeroDivisionError, ) # What's left to do is to check that the first # argument is indeed an exception. # Verifying the other arguments is not # the scope of this check. first = expr.elts[0] inferred = safe_infer(first) if isinstance(inferred, astroid.Instance): # pylint: disable=protected-access inferred = inferred._proxied if (inferred is astroid.YES or isinstance(inferred, astroid.ClassDef) and inherit_from_std_ex(inferred)): emit = False if emit: self.add_message('raising-bad-type', node=node, args=expr.name) elif ( (isinstance(expr, astroid.Name) and expr.name == 'NotImplemented') or (isinstance(expr, astroid.Call) and isinstance(expr.func, astroid.Name) and expr.func.name == 'NotImplemented')): self.add_message('notimplemented-raised', node=node) elif isinstance(expr, (astroid.Instance, astroid.ClassDef)): if isinstance(expr, astroid.Instance): # pylint: disable=protected-access expr = expr._proxied if (isinstance(expr, astroid.ClassDef) and not inherit_from_std_ex(expr) and has_known_bases(expr)): if expr.newstyle: self.add_message('raising-non-exception', node=node) else: self.add_message('nonstandard-exception', node=node) else: value_found = False else: value_found = False return value_found
def visit_classdef(self, node: nodes.ClassDef) -> None: # TODO (Typing): This function can be called from visit_instance # with the return type of instance._proxied (not typed right now) if not utils.inherit_from_std_ex(node) and utils.has_known_bases(node): if node.newstyle: self._checker.add_message("raising-non-exception", node=self._node)
def visit_classdef(self, cls): if (not utils.inherit_from_std_ex(cls) and utils.has_known_bases(cls)): if cls.newstyle: self._checker.add_message('raising-non-exception', node=self._node) else: self._checker.add_message('nonstandard-exception', node=self._node)
def visit_tryexcept(self, node): """check for empty except""" exceptions_classes = [] nb_handlers = len(node.handlers) for index, handler in enumerate(node.handlers): if handler.type is None: if not is_raising(handler.body): self.add_message('bare-except', node=handler) # check if a "except:" is followed by some other # except if index < (nb_handlers - 1): msg = 'empty except clause should always appear last' self.add_message('bad-except-order', node=node, args=msg) elif isinstance(handler.type, astroid.BoolOp): self.add_message('binary-op-exception', node=handler, args=handler.type.op) else: try: excs = list(_annotated_unpack_infer(handler.type)) except astroid.InferenceError: continue for part, exc in excs: if exc is astroid.YES: continue if (isinstance(exc, astroid.Instance) and inherit_from_std_ex(exc)): # pylint: disable=protected-access exc = exc._proxied self._check_catching_non_exception(handler, exc, part) if not isinstance(exc, astroid.ClassDef): continue exc_ancestors = [ anc for anc in exc.ancestors() if isinstance(anc, astroid.ClassDef) ] for previous_exc in exceptions_classes: if previous_exc in exc_ancestors: msg = '%s is an ancestor class of %s' % ( previous_exc.name, exc.name) self.add_message('bad-except-order', node=handler.type, args=msg) if (exc.name in self.config.overgeneral_exceptions and exc.root().name == EXCEPTIONS_MODULE and not is_raising(handler.body)): self.add_message('broad-except', args=exc.name, node=handler.type) if exc in exceptions_classes: self.add_message('duplicate-except', args=exc.name, node=handler.type) exceptions_classes += [exc for _, exc in excs]
def visit_raise(self, node): """visit raise possibly inferring value""" # ignore empty raise if node.exc is None: return if PY3K and node.cause: try: cause = next(node.cause.infer()) except astroid.InferenceError: pass else: if cause is YES: return if isinstance(cause, astroid.Const): if cause.value is not None: self.add_message('bad-exception-context', node=node) elif (not isinstance(cause, astroid.Class) and not inherit_from_std_ex(cause)): self.add_message('bad-exception-context', node=node) expr = node.exc if self._check_raise_value(node, expr): return else: try: value = next(unpack_infer(expr)) except astroid.InferenceError: return self._check_raise_value(node, value)
def _check_catching_non_exception(self, handler, exc, part): if isinstance(exc, nodes.Tuple): # Check if it is a tuple of exceptions. inferred = [utils.safe_infer(elt) for elt in exc.elts] if any(node is astroid.Uninferable for node in inferred): # Don't emit if we don't know every component. return if all( node and (utils.inherit_from_std_ex(node) or not utils.has_known_bases(node)) for node in inferred ): return if not isinstance(exc, nodes.ClassDef): # Don't emit the warning if the inferred stmt # is None, but the exception handler is something else, # maybe it was redefined. if isinstance(exc, nodes.Const) and exc.value is None: if ( isinstance(handler.type, nodes.Const) and handler.type.value is None ) or handler.type.parent_of(exc): # If the exception handler catches None or # the exception component, which is None, is # defined by the entire exception handler, then # emit a warning. self.add_message( "catching-non-exception", node=handler.type, args=(part.as_string(),), ) else: self.add_message( "catching-non-exception", node=handler.type, args=(part.as_string(),), ) return if ( not utils.inherit_from_std_ex(exc) and exc.name not in self._builtin_exceptions ): if utils.has_known_bases(exc): self.add_message( "catching-non-exception", node=handler.type, args=(exc.name,) )
def visit_tryexcept(self, node): """check for empty except""" self._check_try_except_raise(node) exceptions_classes = [] nb_handlers = len(node.handlers) for index, handler in enumerate(node.handlers): if handler.type is None: if not utils.is_raising(handler.body): self.add_message('bare-except', node=handler) # check if an "except:" is followed by some other # except if index < (nb_handlers - 1): msg = 'empty except clause should always appear last' self.add_message('bad-except-order', node=node, args=msg) elif isinstance(handler.type, astroid.BoolOp): self.add_message('binary-op-exception', node=handler, args=handler.type.op) else: try: excs = list(_annotated_unpack_infer(handler.type)) except astroid.InferenceError: continue for part, exc in excs: if exc is astroid.Uninferable: continue if (isinstance(exc, astroid.Instance) and utils.inherit_from_std_ex(exc)): # pylint: disable=protected-access exc = exc._proxied self._check_catching_non_exception(handler, exc, part) if not isinstance(exc, astroid.ClassDef): continue exc_ancestors = [anc for anc in exc.ancestors() if isinstance(anc, astroid.ClassDef)] for previous_exc in exceptions_classes: if previous_exc in exc_ancestors: msg = '%s is an ancestor class of %s' % ( previous_exc.name, exc.name) self.add_message('bad-except-order', node=handler.type, args=msg) if (exc.name in self.config.overgeneral_exceptions and exc.root().name == utils.EXCEPTIONS_MODULE and not utils.is_raising(handler.body)): self.add_message('broad-except', args=exc.name, node=handler.type) if exc in exceptions_classes: self.add_message('duplicate-except', args=exc.name, node=handler.type) exceptions_classes += [exc for _, exc in excs]
def visit_subscript(self, node): """ Look for indexing exceptions. """ try: for infered in node.value.infer(): if not isinstance(infered, astroid.Instance): continue if utils.inherit_from_std_ex(infered): self.add_message('indexing-exception', node=node) except astroid.InferenceError: return
def possible_exc_types(node: nodes.NodeNG) -> set[nodes.ClassDef]: """Gets all the possible raised exception types for the given raise node. .. note:: Caught exception types are ignored. :param node: The raise node to find exception types for. :returns: A list of exception types possibly raised by :param:`node`. """ exceptions = [] if isinstance(node.exc, nodes.Name): inferred = utils.safe_infer(node.exc) if inferred: exceptions = [inferred] elif node.exc is None: handler = node.parent while handler and not isinstance(handler, nodes.ExceptHandler): handler = handler.parent if handler and handler.type: try: for exception in astroid.unpack_infer(handler.type): if exception is not astroid.Uninferable: exceptions.append(exception) except astroid.InferenceError: pass else: target = _get_raise_target(node) if isinstance(target, nodes.ClassDef): exceptions = [target] elif isinstance(target, nodes.FunctionDef): for ret in target.nodes_of_class(nodes.Return): if ret.value is None: continue if ret.frame(future=True) != target: # return from inner function - ignore it continue val = utils.safe_infer(ret.value) if val and utils.inherit_from_std_ex(val): if isinstance(val, nodes.ClassDef): exceptions.append(val) elif isinstance(val, astroid.Instance): exceptions.append(val.getattr("__class__")[0]) try: return { exc for exc in exceptions if not utils.node_ignores_exception(node, exc.name) } except astroid.InferenceError: return set()
def test_inherit_from_std_ex_recursive_definition(): node = astroid.extract_node(""" import datetime class First(datetime.datetime): pass class Second(datetime.datetime): #@ pass datetime.datetime = First datetime.datetime = Second """) assert not utils.inherit_from_std_ex(node)
def visit_attribute(self, node): """ Look for accessing message on exceptions. """ try: for infered in node.expr.infer(): if not isinstance(infered, astroid.Instance): continue if utils.inherit_from_std_ex(infered): if node.attrname == 'message': self.add_message('exception-message-attribute', node=node) except astroid.InferenceError: return
def possible_exc_types(node): """ Gets all of the possible raised exception types for the given raise node. .. note:: Caught exception types are ignored. :param node: The raise node to find exception types for. :type node: astroid.node_classes.NodeNG :returns: A list of exception types possibly raised by :param:`node`. :rtype: set(str) """ excs = [] if isinstance(node.exc, astroid.Name): inferred = utils.safe_infer(node.exc) if inferred: excs = [inferred.name] elif (isinstance(node.exc, astroid.Call) and isinstance(node.exc.func, astroid.Name)): target = utils.safe_infer(node.exc.func) if isinstance(target, astroid.ClassDef): excs = [target.name] elif isinstance(target, astroid.FunctionDef): for ret in target.nodes_of_class(astroid.Return): if ret.frame() != target: # return from inner function - ignore it continue val = utils.safe_infer(ret.value) if (val and isinstance(val, (astroid.Instance, astroid.ClassDef)) and utils.inherit_from_std_ex(val)): excs.append(val.name) elif node.exc is None: handler = node.parent while handler and not isinstance(handler, astroid.ExceptHandler): handler = handler.parent if handler and handler.type: inferred_excs = astroid.unpack_infer(handler.type) excs = (exc.name for exc in inferred_excs if exc is not astroid.Uninferable) try: return { exc for exc in excs if not utils.node_ignores_exception(node, exc) } except astroid.InferenceError: return set()
def visit_attribute(self, node): """ Look for accessing message on exceptions. """ try: for inferred in node.expr.infer(): if (isinstance(inferred, astroid.Instance) and utils.inherit_from_std_ex(inferred)): if node.attrname == 'message': self.add_message('exception-message-attribute', node=node) if isinstance(inferred, astroid.Module): self._warn_if_deprecated(node, inferred.name, {node.attrname}) except astroid.InferenceError: return
def visit_tryexcept(self, node: nodes.TryExcept) -> None: """check for empty except""" for handler in node.handlers: if handler.type is None: continue if isinstance(handler.type, astroid.BoolOp): continue try: excs = list(_annotated_unpack_infer(handler.type)) except astroid.InferenceError: continue handled_in_clause: List[Tuple[Any, Any]] = [] for part, exc in excs: if exc is astroid.Uninferable: continue if isinstance( exc, astroid.Instance) and utils.inherit_from_std_ex(exc): # pylint: disable=protected-access exc = exc._proxied if not isinstance(exc, astroid.ClassDef): continue exc_ancestors = [ anc for anc in exc.ancestors() if isinstance(anc, astroid.ClassDef) ] for prev_part, prev_exc in handled_in_clause: prev_exc_ancestors = [ anc for anc in prev_exc.ancestors() if isinstance(anc, astroid.ClassDef) ] if exc == prev_exc: self.add_message( "overlapping-except", node=handler.type, args= f"{prev_part.as_string()} and {part.as_string()} are the same", ) elif prev_exc in exc_ancestors or exc in prev_exc_ancestors: ancestor = part if exc in prev_exc_ancestors else prev_part descendant = part if prev_exc in exc_ancestors else prev_part self.add_message( "overlapping-except", node=handler.type, args= f"{ancestor.as_string()} is an ancestor class of {descendant.as_string()}", ) handled_in_clause += [(part, exc)]
def _check_bad_exception_context(self, node): """Verify that the exception context is properly set. An exception context can be only `None` or an exception. """ cause = safe_infer(node.cause) if cause in (astroid.YES, None): return if isinstance(cause, astroid.Const): if cause.value is not None: self.add_message("bad-exception-context", node=node) elif not isinstance(cause, astroid.ClassDef) and not inherit_from_std_ex(cause): self.add_message("bad-exception-context", node=node)
def visit_tryexcept(self, node): """check for empty except""" for handler in node.handlers: if handler.type is None: continue if isinstance(handler.type, astroid.BoolOp): continue try: excs = list(_annotated_unpack_infer(handler.type)) except astroid.InferenceError: continue handled_in_clause = [] for part, exc in excs: if exc is astroid.Uninferable: continue if isinstance(exc, astroid.Instance) and utils.inherit_from_std_ex(exc): # pylint: disable=protected-access exc = exc._proxied if not isinstance(exc, astroid.ClassDef): continue exc_ancestors = [ anc for anc in exc.ancestors() if isinstance(anc, astroid.ClassDef) ] for prev_part, prev_exc in handled_in_clause: prev_exc_ancestors = [ anc for anc in prev_exc.ancestors() if isinstance(anc, astroid.ClassDef) ] if exc == prev_exc: self.add_message( "overlapping-except", node=handler.type, args="%s and %s are the same" % (prev_part.as_string(), part.as_string()), ) elif prev_exc in exc_ancestors or exc in prev_exc_ancestors: ancestor = part if exc in prev_exc_ancestors else prev_part descendant = part if prev_exc in exc_ancestors else prev_part self.add_message( "overlapping-except", node=handler.type, args="%s is an ancestor class of %s" % (ancestor.as_string(), descendant.as_string()), ) handled_in_clause += [(part, exc)]
def possible_exc_types(node): """ Gets all of the possible raised exception types for the given raise node. .. note:: Caught exception types are ignored. :param node: The raise node to find exception types for. :type node: astroid.node_classes.NodeNG :returns: A list of exception types possibly raised by :param:`node`. :rtype: list(str) """ excs = [] if isinstance(node.exc, astroid.Name): inferred = safe_infer(node.exc) if inferred: excs = [inferred.name] elif (isinstance(node.exc, astroid.Call) and isinstance(node.exc.func, astroid.Name)): target = safe_infer(node.exc.func) if isinstance(target, astroid.ClassDef): excs = [target.name] elif isinstance(target, astroid.FunctionDef): for ret in target.nodes_of_class(astroid.Return): if ret.frame() != target: # return from inner function - ignore it continue val = safe_infer(ret.value) if (val and isinstance(val, (astroid.Instance, astroid.ClassDef)) and inherit_from_std_ex(val)): excs.append(val.name) elif node.exc is None: handler = node.parent while handler and not isinstance(handler, astroid.ExceptHandler): handler = handler.parent if handler and handler.type: inferred_excs = astroid.unpack_infer(handler.type) excs = (exc.name for exc in inferred_excs if exc is not astroid.Uninferable) try: return set(exc for exc in excs if not node_ignores_exception(node, exc)) except astroid.InferenceError: return ()
def visit_tryexcept(self, node): """check for empty except""" for handler in node.handlers: if handler.type is None: continue if isinstance(handler.type, astroid.BoolOp): continue try: excs = list(_annotated_unpack_infer(handler.type)) except astroid.InferenceError: continue handled_in_clause = [] for part, exc in excs: if exc is astroid.YES: continue if (isinstance(exc, astroid.Instance) and utils.inherit_from_std_ex(exc)): # pylint: disable=protected-access exc = exc._proxied if not isinstance(exc, astroid.ClassDef): continue exc_ancestors = [ anc for anc in exc.ancestors() if isinstance(anc, astroid.ClassDef) ] for prev_part, prev_exc in handled_in_clause: prev_exc_ancestors = [ anc for anc in prev_exc.ancestors() if isinstance(anc, astroid.ClassDef) ] if exc == prev_exc: self.add_message( 'overlapping-except', node=handler.type, args='%s and %s are the same' % (prev_part.as_string(), part.as_string())) elif (prev_exc in exc_ancestors or exc in prev_exc_ancestors): ancestor = part if exc in prev_exc_ancestors else prev_part descendant = part if prev_exc in exc_ancestors else prev_part self.add_message( 'overlapping-except', node=handler.type, args='%s is an ancestor class of %s' % (ancestor.as_string(), descendant.as_string())) handled_in_clause += [(part, exc)]
def _check_bad_exception_context(self, node): """Verify that the exception context is properly set. An exception context can be only `None` or an exception. """ cause = safe_infer(node.cause) if cause in (YES, None): return if isinstance(cause, astroid.Const): if cause.value is not None: self.add_message('bad-exception-context', node=node) elif (not isinstance(cause, astroid.Class) and not inherit_from_std_ex(cause)): self.add_message('bad-exception-context', node=node)
def _check_bad_exception_context(self, node: astroid.Raise) -> None: """Verify that the exception context is properly set. An exception context can be only `None` or an exception. """ cause = utils.safe_infer(node.cause) if cause in (astroid.Uninferable, None): return if isinstance(cause, astroid.Const): if cause.value is not None: self.add_message("bad-exception-context", node=node) elif not isinstance( cause, astroid.ClassDef) and not utils.inherit_from_std_ex(cause): self.add_message("bad-exception-context", node=node)
def visit_attribute(self, node): """Look for accessing message on exceptions. """ message = 'message' try: for inferred in node.expr.infer(): if (isinstance(inferred, astroid.Instance) and utils.inherit_from_std_ex(inferred)): if node.attrname == message: # Exceptions with .message clearly defined are an exception if message in inferred.instance_attrs: continue self.add_message('exception-message-attribute', node=node) if isinstance(inferred, astroid.Module): self._warn_if_deprecated(node, inferred.name, {node.attrname}, report_on_modules=False) except astroid.InferenceError: return
def _check_raise_value(self, node, expr): """check for bad values, string exception and class inheritance """ value_found = True if isinstance(expr, astroid.Const): value = expr.value if isinstance(value, str): self.add_message('raising-string', node=node) else: self.add_message('raising-bad-type', node=node, args=value.__class__.__name__) elif (isinstance(expr, astroid.Name) and \ expr.name in ('None', 'True', 'False')) or \ isinstance(expr, (astroid.List, astroid.Dict, astroid.Tuple, astroid.Module, astroid.Function)): self.add_message('raising-bad-type', node=node, args=expr.name) elif ( (isinstance(expr, astroid.Name) and expr.name == 'NotImplemented') or (isinstance(expr, astroid.CallFunc) and isinstance(expr.func, astroid.Name) and expr.func.name == 'NotImplemented')): self.add_message('notimplemented-raised', node=node) elif isinstance(expr, astroid.BinOp) and expr.op == '%': self.add_message('raising-string', node=node) elif isinstance(expr, (Instance, astroid.Class)): if isinstance(expr, Instance): expr = expr._proxied if (isinstance(expr, astroid.Class) and not inherit_from_std_ex(expr) and expr.root().name != BUILTINS_NAME): if expr.newstyle: self.add_message('raising-non-exception', node=node) else: self.add_message( 'nonstandard-exception', node=node, confidence=INFERENCE if has_known_bases(expr) else INFERENCE_FAILURE) else: value_found = False else: value_found = False return value_found
def _check_raise_value(self, node, expr): """check for bad values, string exception and class inheritance """ value_found = True if isinstance(expr, astroid.Const): value = expr.value if isinstance(value, str): # raising-string will be emitted from python3 porting checker. pass else: self.add_message('raising-bad-type', node=node, args=value.__class__.__name__) elif (isinstance(expr, astroid.Name) and \ expr.name in ('None', 'True', 'False')) or \ isinstance(expr, (astroid.List, astroid.Dict, astroid.Tuple, astroid.Module, astroid.Function)): self.add_message('raising-bad-type', node=node, args=expr.name) elif ((isinstance(expr, astroid.Name) and expr.name == 'NotImplemented') or (isinstance(expr, astroid.CallFunc) and isinstance(expr.func, astroid.Name) and expr.func.name == 'NotImplemented')): self.add_message('notimplemented-raised', node=node) elif isinstance(expr, (Instance, astroid.Class)): if isinstance(expr, Instance): expr = expr._proxied if (isinstance(expr, astroid.Class) and not inherit_from_std_ex(expr) and expr.root().name != BUILTINS_NAME): if expr.newstyle: self.add_message('raising-non-exception', node=node) else: self.add_message( 'nonstandard-exception', node=node, confidence=INFERENCE if has_known_bases(expr) else INFERENCE_FAILURE) else: value_found = False else: value_found = False return value_found
def visit_classdef(self, node: nodes.ClassDef) -> None: if not utils.inherit_from_std_ex(node) and utils.has_known_bases(node): if node.newstyle: self._checker.add_message("raising-non-exception", node=self._node)
def visit_classdef(self, cls): if not utils.inherit_from_std_ex(cls) and utils.has_known_bases(cls): if cls.newstyle: self._checker.add_message("raising-non-exception", node=self._node)
def visit_tryexcept(self, node): """check for empty except""" exceptions_classes = [] nb_handlers = len(node.handlers) for index, handler in enumerate(node.handlers): # `raise` as the first operator inside the except handler if utils.is_raising([handler.body[0]]): # flags when there is a bare raise if handler.body[0].exc is None: self.add_message('try-except-raise', node=handler) else: # not a bare raise raise_type = None if isinstance(handler.body[0].exc, astroid.Call): raise_type = handler.body[0].exc.func # flags only when the exception types of the handler # and the raise statement match b/c we're raising the same # type of exception that we're trying to handle. Example: # # except ValueError: # raise ValueError('some user friendly message') if (isinstance(handler.type, astroid.Name) and isinstance(raise_type, astroid.Name) and raise_type.name == handler.type.name): self.add_message('try-except-raise', node=handler) if handler.type is None: if not utils.is_raising(handler.body): self.add_message('bare-except', node=handler) # check if an "except:" is followed by some other # except if index < (nb_handlers - 1): msg = 'empty except clause should always appear last' self.add_message('bad-except-order', node=node, args=msg) elif isinstance(handler.type, astroid.BoolOp): self.add_message('binary-op-exception', node=handler, args=handler.type.op) else: try: excs = list(_annotated_unpack_infer(handler.type)) except astroid.InferenceError: continue for part, exc in excs: if exc is astroid.Uninferable: continue if (isinstance(exc, astroid.Instance) and utils.inherit_from_std_ex(exc)): # pylint: disable=protected-access exc = exc._proxied self._check_catching_non_exception(handler, exc, part) if not isinstance(exc, astroid.ClassDef): continue exc_ancestors = [anc for anc in exc.ancestors() if isinstance(anc, astroid.ClassDef)] for previous_exc in exceptions_classes: if previous_exc in exc_ancestors: msg = '%s is an ancestor class of %s' % ( previous_exc.name, exc.name) self.add_message('bad-except-order', node=handler.type, args=msg) if (exc.name in self.config.overgeneral_exceptions and exc.root().name == utils.EXCEPTIONS_MODULE and not utils.is_raising(handler.body)): self.add_message('broad-except', args=exc.name, node=handler.type) if exc in exceptions_classes: self.add_message('duplicate-except', args=exc.name, node=handler.type) exceptions_classes += [exc for _, exc in excs]
def visit_tryexcept(self, node: nodes.TryExcept) -> None: """Check for empty except.""" self._check_try_except_raise(node) exceptions_classes: list[Any] = [] nb_handlers = len(node.handlers) for index, handler in enumerate(node.handlers): if handler.type is None: if not _is_raising(handler.body): self.add_message("bare-except", node=handler) # check if an "except:" is followed by some other # except if index < (nb_handlers - 1): msg = "empty except clause should always appear last" self.add_message("bad-except-order", node=node, args=msg) elif isinstance(handler.type, nodes.BoolOp): self.add_message("binary-op-exception", node=handler, args=handler.type.op) else: try: exceptions = list(_annotated_unpack_infer(handler.type)) except astroid.InferenceError: continue for part, exception in exceptions: if exception is astroid.Uninferable: continue if isinstance(exception, astroid.Instance ) and utils.inherit_from_std_ex(exception): exception = exception._proxied self._check_catching_non_exception(handler, exception, part) if not isinstance(exception, nodes.ClassDef): continue exc_ancestors = [ anc for anc in exception.ancestors() if isinstance(anc, nodes.ClassDef) ] for previous_exc in exceptions_classes: if previous_exc in exc_ancestors: msg = f"{previous_exc.name} is an ancestor class of {exception.name}" self.add_message("bad-except-order", node=handler.type, args=msg) if (exception.name in self.linter.config.overgeneral_exceptions and exception.root().name == utils.EXCEPTIONS_MODULE and not _is_raising(handler.body)): self.add_message("broad-except", args=exception.name, node=handler.type) if exception in exceptions_classes: self.add_message("duplicate-except", args=exception.name, node=handler.type) exceptions_classes += [exc for _, exc in exceptions]
def visit_tryexcept(self, node): """check for empty except""" exceptions_classes = [] nb_handlers = len(node.handlers) for index, handler in enumerate(node.handlers): # single except doing nothing but "pass" without else clause if is_empty(handler.body) and not node.orelse: self.add_message('pointless-except', node=handler.type or handler.body[0]) if handler.type is None: if not is_raising(handler.body): self.add_message('bare-except', node=handler) # check if a "except:" is followed by some other # except if index < (nb_handlers - 1): msg = 'empty except clause should always appear last' self.add_message('bad-except-order', node=node, args=msg) elif isinstance(handler.type, astroid.BoolOp): self.add_message('binary-op-exception', node=handler, args=handler.type.op) else: try: excs = list(_annotated_unpack_infer(handler.type)) except astroid.InferenceError: continue for part, exc in excs: if exc is YES: continue if isinstance(exc, astroid.Instance) and inherit_from_std_ex(exc): exc = exc._proxied if not isinstance(exc, astroid.Class): # Don't emit the warning if the infered stmt # is None, but the exception handler is something else, # maybe it was redefined. if (isinstance(exc, astroid.Const) and exc.value is None): if ((isinstance(handler.type, astroid.Const) and handler.type.value is None) or handler.type.parent_of(exc)): # If the exception handler catches None or # the exception component, which is None, is # defined by the entire exception handler, then # emit a warning. self.add_message('catching-non-exception', node=handler.type, args=(part.as_string(), )) else: self.add_message('catching-non-exception', node=handler.type, args=(part.as_string(), )) continue exc_ancestors = [anc for anc in exc.ancestors() if isinstance(anc, astroid.Class)] for previous_exc in exceptions_classes: if previous_exc in exc_ancestors: msg = '%s is an ancestor class of %s' % ( previous_exc.name, exc.name) self.add_message('bad-except-order', node=handler.type, args=msg) if (exc.name in self.config.overgeneral_exceptions and exc.root().name == EXCEPTIONS_MODULE and not is_raising(handler.body)): self.add_message('broad-except', args=exc.name, node=handler.type) if (not inherit_from_std_ex(exc) and exc.root().name != BUILTINS_NAME): if has_known_bases(exc): self.add_message('catching-non-exception', node=handler.type, args=(exc.name, )) exceptions_classes += [exc for _, exc in excs]
def visit_tryexcept(self, node): """check for empty except""" exceptions_classes = [] nb_handlers = len(node.handlers) for index, handler in enumerate(node.handlers): # `raise` as the first operator inside the except handler if utils.is_raising([handler.body[0]]): # flags when there is a bare raise if handler.body[0].exc is None: self.add_message('try-except-raise', node=handler) else: # not a bare raise raise_type = None if isinstance(handler.body[0].exc, astroid.Call): raise_type = handler.body[0].exc.func # flags only when the exception types of the handler # and the raise statement match b/c we're raising the same # type of exception that we're trying to handle. Example: # # except ValueError: # raise ValueError('some user friendly message') if (isinstance(handler.type, astroid.Name) and isinstance(raise_type, astroid.Name) and raise_type.name == handler.type.name): self.add_message('try-except-raise', node=handler) if handler.type is None: if not utils.is_raising(handler.body): self.add_message('bare-except', node=handler) # check if an "except:" is followed by some other # except if index < (nb_handlers - 1): msg = 'empty except clause should always appear last' self.add_message('bad-except-order', node=node, args=msg) elif isinstance(handler.type, astroid.BoolOp): self.add_message('binary-op-exception', node=handler, args=handler.type.op) else: try: excs = list(_annotated_unpack_infer(handler.type)) except astroid.InferenceError: continue for part, exc in excs: if exc is astroid.YES: continue if (isinstance(exc, astroid.Instance) and utils.inherit_from_std_ex(exc)): # pylint: disable=protected-access exc = exc._proxied self._check_catching_non_exception(handler, exc, part) if not isinstance(exc, astroid.ClassDef): continue exc_ancestors = [ anc for anc in exc.ancestors() if isinstance(anc, astroid.ClassDef) ] for previous_exc in exceptions_classes: if previous_exc in exc_ancestors: msg = '%s is an ancestor class of %s' % ( previous_exc.name, exc.name) self.add_message('bad-except-order', node=handler.type, args=msg) if (exc.name in self.config.overgeneral_exceptions and exc.root().name == utils.EXCEPTIONS_MODULE and not utils.is_raising(handler.body)): self.add_message('broad-except', args=exc.name, node=handler.type) if exc in exceptions_classes: self.add_message('duplicate-except', args=exc.name, node=handler.type) exceptions_classes += [exc for _, exc in excs]