Як у 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.