Як у Python, як можна застерегти, ніби вони є винятками?


103

Стороння бібліотека (написана на С), яку я використовую в коді python, видає попередження. Я хочу мати можливість використовувати try exceptсинтаксис, щоб правильно обробляти ці попередження. Чи є спосіб це зробити?


2
Це попередження, лише написані текстові повідомлення, чи не жорсткіше?
— Феніксо

1
Феніксо: Я не знаю точно, здається, справжні попередження
— Борис Горелік

1
Як розпізнати "реальне попередження"? Я думав, що в C ви отримуєте реальне попередження під час компіляції.
— Феніксо

warnings.filterwarningsробить саме те, що ви хочете, я не розумію, у чому полягає ваша проблема?
— Рош Оксиморон

4
@Fenikso, @Rosh Oxymoron ви мали рацію. Моя помилка. warnings.filterwarnigns('error')виконує роботу. Я не можу знайти оригінальну відповідь, яка запропонувала це рішення
— Борис Горелік

Відповіді:


51

Цитувати з посібника пітона ( 27.6.4. Попередження про тестування ):

import warnings

def fxn():
    warnings.warn("deprecated", DeprecationWarning)

with warnings.catch_warnings(record=True) as w:
    # Cause all warnings to always be triggered.
    warnings.simplefilter("always")
    # Trigger a warning.
    fxn()
    # Verify some things
    assert len(w) == 1
    assert issubclass(w[-1].category, DeprecationWarning)
    assert "deprecated" in str(w[-1].message)

6
Ось відповідь, яка розповідає про те, як використовувати try exceptсинтаксис.
— Унапіедра

Це має перевагу перед відповіддю niekas, що якщо fnxщось повертається, ви зберігаєте цей результат (і все ще можете керувати попередженням).
— П'єтро Баттістон

Це не відповідає на питання ОП, яке стосувалося поводження з джгутами, а не їх тестування. Однак відповідь niekas нижче показує, як поводитися з попередженнями.
— Biggsy

Лише зауважте, що вищевказана функція не буде працювати, якщо ваша функція лише періодично повертає попередження, оскільки у випадку, fxn()якщо попередження не повернеться, тоді wбуде порожній список. Якщо wце порожній список (тобто []), а потім запустити код дасть вам наступне повідомлення про помилку: IndexError: list index out of range. Якщо ви просто хочете відформатувати чи перевірити властивості захоплених попереджень, тоді краще використовувати цикл for:for x in w: print(f'{x.category.__name__}: {str(x.message)}')
— Стівен М. Мортімер

130

Для обробки попереджень як помилок просто використовуйте це:

import warnings
warnings.filterwarnings("error")

Після цього ви зможете зафіксувати попередження так само, як і помилки, наприклад, це спрацює:

try:
    some_heavy_calculations()
except RuntimeWarning:
    import ipdb; ipdb.set_trace()

PS Додав цю відповідь, оскільки найкраща відповідь у коментарях містить неправильне написання: filterwarnignsзамість filterwarnings.


8
І якщо ви просто хочете побачити слід стека, перші два рядки - це все, що вам потрібно.
— z0r

5
Це прекрасно. Я просто хотів, щоб мій сценарій припинив виконання, як тільки було видано попередження, щоб я міг надрукувати відповідну інформацію про налагодження та виправити проблему.
— Praveen

1
Вам не потрібен filterwarningsдзвінок, щоб зловити Warnings, принаймні, у python 3. він просто працює.
— naught101

1
Прийнята відповідь не відповідає на питання ОП. Ця відповідь так і є. Це відповідь, яку я шукав, коли мій пошук знайшов це питання.
— Biggsy


15

Ось варіант, який дозволяє зрозуміти, як працювати лише зі своїми спеціальними попередженнями.

import warnings
with warnings.catch_warnings(record=True) as w:
    # Cause all warnings to always be triggered.
    warnings.simplefilter("always")

    # Call some code that triggers a custom warning.
    functionThatRaisesWarning()

    # ignore any non-custom warnings that may be in the list
    w = filter(lambda i: issubclass(i.category, UserWarning), w)

    if len(w):
        # do something with the first warning
        email_admins(w[0].message)

4

У деяких випадках для перетворення попереджень у помилки потрібно використовувати ctypes. Наприклад:

str(b'test')  # no error
import warnings
warnings.simplefilter('error', BytesWarning)
str(b'test')  # still no error
import ctypes
ctypes.c_int.in_dll(ctypes.pythonapi, 'Py_BytesWarningFlag').value = 2
str(b'test')  # this raises an error

Ця відповідь конструктивна лише для того, щоб показати, як помилитися лише в певних типах попередження. Для майже будь-якого великого програмного проекту, якщо ви цього warnings.simplefilter('error')не зробите, ви не отримаєте прослідкування попередження, яке ви бачили в журналах, а натомість отримаєте відслідковування попередньо відфільтрованих попереджень. Використання simplefilter- це також найшвидший спосіб отримати відповідь, якщо у вас є виклик CLI.
— AlanSE
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.