Python'da, uyarılar istisnaymış gibi nasıl yakalanır?


105

Python kodumda kullandığım bir üçüncü taraf kitaplığı (C ile yazılmış) uyarılar veriyor. try exceptBu uyarıları düzgün şekilde işlemek için sözdizimini kullanabilmek istiyorum . Bunu yapmanın bir yolu var mı?


2
Bu uyarılar sadece yazılı mesajlar mı stderr?
Fenikso

1
Fenikso: Emin bilmiyorum, gerçek uyarıları gibi görünüyor
Boris Gorelik

1
"Gerçek uyarıyı" nasıl anlarsınız? C'de derleme sırasında gerçek bir uyarı alacağınızı düşündüm.
Fenikso

warnings.filterwarningstam olarak istediğini yapıyor, sorunun ne olduğunu anlamadım?
Rosh Oxymoron

4
@Fenikso, @Rosh Oxymoron haklıydın. Benim hatam. warnings.filterwarnigns('error')işi yapar. Bu çözümü öneren orijinal cevabı bulamıyorum
Boris Görelik

Yanıtlar:


52

Python el kitabından alıntı yapmak için ( 27.6.4. Test Uyarıları ):

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
İşte size try exceptsözdizimini nasıl kullanacağınızı söyleyen bir cevap .
Unapiedra

Bu, niekas'ın cevabına göre bir avantaja sahiptir, eğer bir fnxşey döndürürse, o sonucu tutarsınız (ve yine de uyarıyı yönetebilirsiniz).
Pietro Battiston

Bu, OP'nin solgunlukları test etmekle değil, ele almakla ilgili sorusuna cevap vermiyor. Bununla birlikte, aşağıdaki niekas'ın cevabı uyarıların nasıl ele alınacağını göstermektedir.
Biggsy

Yukarıdaki işlevin yalnızca aralıklı olarak bir uyarı döndürmesi durumunda çalışmayacağına dikkat edin, çünkü fxn()bir uyarı döndürmeyen olayda wboş bir liste olacaktır. Eğer wboş bir liste (yani []), sonra kod çalıştıran size aşağıdaki hatayı verecektir: IndexError: list index out of range. Yakalanan uyarıların özelliklerini sadece biçimlendirmek veya kontrol etmek istiyorsanız, bir döngü kullanmak daha iyidir:for x in w: print(f'{x.category.__name__}: {str(x.message)}')
Steven M. Mortimer

132

Uyarıları hata olarak ele almak için şunu kullanın:

import warnings
warnings.filterwarnings("error")

Bundan sonra, hatalarla aynı uyarıları yakalayabileceksiniz, örneğin bu işe yarayacaktır:

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

Not: Yorumlardaki en iyi yanıt, filterwarnignsyerine yazım hatası içerdiği için bu yanıtı eklendi filterwarnings.


8
Ve sadece bir yığın izi görmek istiyorsanız, ihtiyacınız olan tek şey ilk iki satırdır.
z0r

5
Bu harika. Sadece komut dosyamın uyarı verilir verilmez yürütmeyi durdurmasını istedim, böylece ilgili hata ayıklama bilgilerini yazdırabilir ve sorunu çözebilirim.
Praveen

1
filterwarningsYakalamak için çağrıya ihtiyacınız yok Warnings, en azından python 3'te çalışıyor.
naught101

1
Kabul edilen cevap OP'nin sorusuna cevap vermiyor. Bu cevap yapar. Araştırmam bu soruyu bulduğunda aradığım cevap buydu.
Biggsy

16

İşte yalnızca özel uyarılarınızla nasıl çalışılacağını daha net hale getiren bir varyasyon.

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)

16

Yalnızca komut dosyasının uyarılarda başarısız olmasını istiyorsanız python, -Wargümanla çağırabilirsiniz :

python -W error foobar.py

4

Bazı durumlarda, uyarıları hatalara dönüştürmek için ctype kullanmanız gerekir. Örneğin:

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

Bu cevap, yalnızca belirli uyarı türlerinde nasıl hata yapılacağını göstermek için yapıcıdır. Neredeyse tüm büyük yazılım projeleri için, eğer yaparsanız warnings.simplefilter('error'), günlüklerde gördüğünüz uyarı için geri dönüşü almazsınız, bunun yerine önceden filtrelenmiş uyarılardan izler alırsınız. Kullanmak simplefilter, eğer bazı CLI çağrılarınız varsa cevabınıza ulaşmanın en hızlı yoludur.
AlanSE
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.