I need to collect all possible things a given function explicitly raises using the raise keyword for a source analyzer tool I am working on. For example: from some.package import CustomError class NewException(Exception):... def something(i): if i == 2: raise RuntimeError("This is a runtime error") else: raise CustomError("This is a custom error") try: something() except ValueError: raise except Exception as e: raise NewException(e) from e In the case of this function I would like to get a set of {<class RuntimeError>, <class some.package.CustomError>, <class ValueError>, <class [function_path].NewException>}. My current (and unfinished) solution is using the ast and inspect module to parse the function's source code into an AST and collect the exceptions there but I am stuck with detecting custom exceptions as the program crashes while evaluating them. import inspect import ast def _analyze_function(function: Callable[..., Any]): exceptions: set[type[BaseException]] = set() abstract_syntax_tree = ast.parse(inspect.getsource(function), mode="exec") for node in ast.walk(abstract_syntax_tree): if not isinstance(node, ast.Raise): continue if node.exc is None: print("No exception specified") continue match type(node.exc): case ast.Call: call_result = type(eval(ast.unparse(node.exc))) if not issubclass(call_result, BaseException): continue exceptions.add(call_result) case _: pass A problem with this approach is that there is external code execution which could lead to malicious code being evaluated. Continue reading...