Как перечислить все исключения, которые функция могла бы повысить в Python 3?

Есть ли программный способ получить список всех исключений, которые могла бы повысить функция?

Я знаю, например, что os.makedirs(path[, mode]) может поднять PermissionError (и, возможно, другие), но в документации упоминается только OSError . (Это всего лишь пример – может быть, даже плохой, меня это особенно не интересует – больше в проблеме вообще).

Существует ли программный способ найти все возможные исключения, если они не документированы / плохо документированы? Это может быть особенно полезно в сторонних библиотеках и библиотеках, которые не поставляются с исходным кодом Python.

Решение, представленное в « Python: как я могу узнать, какие исключения могут быть выбраны из вызова метода », не работает в Python 3; нет compiler .

2 Solutions collect form web for “Как перечислить все исключения, которые функция могла бы повысить в Python 3?”

Вы не можете получить достоверные результаты для некоторых (если не большинства) функций. Некоторые примеры:

  • функции, выполняющие произвольный код (например, exec(')(rorrEeulaV esiar'[::-1]) вызывает ValueError )

  • функции, которые не написаны на Python

  • функции, вызывающие другие функции, которые могут распространять ошибки вызывающего

  • функции, восстанавливающие активные исключения в блоке except: block

К сожалению, этот список неполный.

Например, os.makedirs написано на Python, и вы можете увидеть его источник:

 ... try: mkdir(name, mode) except OSError as e: if not exist_ok or e.errno != errno.EEXIST or not path.isdir(name): raise 

Bare raise re-raises последнее активное исключение ( OSError или один из его подклассов). Вот иерархия классов для OSError :

 +-- OSError | +-- BlockingIOError | +-- ChildProcessError | +-- ConnectionError | | +-- BrokenPipeError | | +-- ConnectionAbortedError | | +-- ConnectionRefusedError | | +-- ConnectionResetError | +-- FileExistsError | +-- FileNotFoundError | +-- InterruptedError | +-- IsADirectoryError | +-- NotADirectoryError | +-- PermissionError | +-- ProcessLookupError | +-- TimeoutError 

Чтобы получить точные типы исключений, вам нужно будет посмотреть в mkdir , функции, которые он вызывает, функции, вызываемые этими функциями и т. Д.

Таким образом, получение возможных исключений без выполнения функции очень сложно, и вы действительно не должны этого делать.


Однако для простых случаев, таких как

 raise Exception # without arguments raise Exception('abc') # with arguments 

комбинация функциональности модуля ast и inspect.getclosurevars (чтобы получить классы исключений, введенные в Python 3.3), могут дать довольно точные результаты:

 from inspect import getclosurevars, getsource from collections import ChainMap from textwrap import dedent import ast, os class MyException(Exception): pass def g(): raise Exception class A(): def method(): raise OSError def f(x): int() A.method() os.makedirs() g() raise MyException raise ValueError('argument') def get_exceptions(func, ids=set()): try: vars = ChainMap(*getclosurevars(func)[:3]) source = dedent(getsource(func)) except TypeError: return class _visitor(ast.NodeTransformer): def __init__(self): self.nodes = [] self.other = [] def visit_Raise(self, n): self.nodes.append(n.exc) def visit_Expr(self, n): if not isinstance(n.value, ast.Call): return c, ob = n.value.func, None if isinstance(c, ast.Attribute): parts = [] while getattr(c, 'value', None): parts.append(c.attr) c = c.value if c.id in vars: ob = vars[c.id] for name in reversed(parts): ob = getattr(ob, name) elif isinstance(c, ast.Name): if c.id in vars: ob = vars[c.id] if ob is not None and id(ob) not in ids: self.other.append(ob) ids.add(id(ob)) v = _visitor() v.visit(ast.parse(source)) for n in v.nodes: if isinstance(n, (ast.Call, ast.Name)): name = n.id if isinstance(n, ast.Name) else n.func.id if name in vars: yield vars[name] for o in v.other: yield from get_exceptions(o) for e in get_exceptions(f): print(e) 

печать

 <class '__main__.MyException'> <class 'ValueError'> <class 'OSError'> <class 'Exception'> 

Имейте в виду, что этот код работает только для функций, написанных на Python.

Обнаружение исключения в не встроенном исходном коде:

Как сказано в теме Python: как я могу узнать, какие исключения могут быть выбраны из вызова метода , вы можете получить абстрактное дерево синтаксиса и искать дополнительные исключения.

 import ast def find_raise(body): raises = [] for ast_ in body: if isinstance(ast_, ast.Raise): raises.append(ast_) if hasattr(ast_, 'body'): raises += find_raise(ast_.body) return list(set(raises)) test = ''' def f(arg): raise OSError(arg) ''' raises = find_raise(ast.parse(test).body) print [i.type.func.id for i in raises] # print ['OSError'] 

Этот метод работает для каждого фрагмента кода, который вы написали.


Обнаружение исключения во встроенных методах

Вы не можете разобрать встроенную функцию, например os.makedirs .

Две альтернативы:

  • Вы можете посмотреть тесты, включенные в ваш дистрибутив python ( например, cpython )
  • и если ваш целевой метод предлагает исходный код python, вы можете проанализировать его, как раньше (код будет в /usr/lib/python3/*.py)

Для всех собственных методов С, вы застряли в документации и должны доверять ей. Когда os.makedirs говорит, что возвращает только OSError , это правда, поскольку исключения PermissionError и FileExistError являются подклассами OSError .

Чтобы найти Ошибки программно для встроенного, вы можете использовать этот пример:

 >>> import re >>> re.findall(r'\w+Error', open.__doc__) ['IOError', 'FileExistsError', 'ValueError'] >>> re.findall(r'\w+Error', os.makedirs.__doc__) ['OSError'] 

Он ловит все исключения с именем, заканчивающимся на «Ошибка», его можно расширить, чтобы найти все стандартные исключения.

Interesting Posts

Как избежать «Значение пытается установить на копии среза из DataFrame»?

Вычислять хеш только данных основного изображения (исключая метаданные) для изображения

Python! = Операция против "не"

Использование python для записи определенных строк из одного файла в другой файл

pyinstaller, spec file, ImportError: Нет модуля с именем 'blah'

многопроцессорность Слушатели и клиенты между python и pypy

Nodejs crypto vs python hashlib

Изменение размера изображения с сохранением пропорций И ​​создание портретных и ландшафтных изображений одинакового размера?

Пожалуйста, обсудите, что и зачем использовать портлеты

Python OpenCV: обратный вызов мыши для рисования прямоугольника

Matplotlib: ширина линии добавляется к длине строки

Очистить все виджеты в макете в pyqt

Почему разные методы одного и того же объекта имеют один и тот же идентификатор?

Pygame Позиция изображения

Группирование сообщений по временным интервалам

Python - лучший язык программирования в мире.