У меня есть класс Python, который выдает предупреждение внутри __init__()
.Он также предоставляет метод фабричного класса для открытия и чтения файла:
from warnings import warn
class MyWarning(Warning):
"""Warning issued when an invalid name is found."""
pass
class MyClass:
def __init__(self, names):
# Simplified; actual code is longer
if is_invalid(names):
names = fix_names(names)
warn(f'{names!r} contains invalid element(s)',
MyWarning, stacklevel=2)
self._names = names
@classmethod
def from_file(cls, filename):
with open(filename) as file:
names = extract_names(file)
return cls(names)
stacklevel=2
заставляет предупреждение относиться к вызову MyClass()
, а не к самому оператору warn()
.Это работает, когда пользовательский код напрямую создает экземпляр MyClass.Однако, когда MyClass.from_file()
выдает предупреждение, MyWarning
относится к return cls(names)
, а не к пользовательскому коду, вызывающему from_file()
.
. Как я могу убедиться, что фабричный метод также выдает предупреждение, указывающее навызывающий?Некоторые варианты, которые я рассмотрел:
- Добавьте «скрытый» параметр
_stacklevel
к __init__()
и создайте экземпляр MyClass с _stacklevel=2
внутри from_file()
. - Это очень уродливо и подвергает API внутреннему поведению.
- Добавьте «скрытый» атрибут класса
_stacklevel
и получите доступ к нему внутри __init__()
.Затем временно измените этот атрибут в from_file()
- Добавьте метод
_set_names()
, который проверяет / исправляет имена и при необходимости выдает предупреждение.Затем вызовите этот метод внутри конструктора.Для from_file()
сначала создайте экземпляр MyClass с пустыми аргументами, а затем напрямую вызовите _set_names()
, чтобы MyWarning указывал на вызывающего. - По-прежнему хакерский и эффективно вызывает
_set_names()
дважды, когда вызывается from_file()
.
- Поймать и повторно выдать предупреждение, подобно цепочке исключений.
- Звучит хорошо, но я понятия не имею, как это сделать.
Я прочитал warning
модуль документации , но этопредлагает небольшую помощь по безопасному отлову и повторному выбрасыванию предупреждений.Преобразование предупреждения в исключение с использованием warnings.simplefilter()
приведет к прерыванию MyClass()
и заставит меня вызвать его снова.