2012-01-25 32 views
19

Bir işleve uygulamak için bir dekoratör yazıyorum. Herhangi bir özel durumu yakalamalı ve özgün istisna mesajına göre özel bir istisna oluşturmalıdır. (Bunun sebebi, perdelerin web hizmeti tarafından atılan istisnayı ayrıştıran ve onu yansıtmak için bir Python istisnası geliştiren genel bir WebFault istisnası atar.)Python: İstisna dekoratör. Stacktrace nasıl korunur

Ancak, sarıcıdaki özel özel durumu kaldırdığımda, StackTrace'in orijinal WebFault istisnasını yükselten fonksiyona işaret etmesini isteyin. Şimdiye kadar sahip olduğum şey doğru istisnayı yükseltir (mesajı dinamik olarak ayrıştırır ve istisna sınıfını başlatır). Sorumu: WebTracker istisnasını yükselten orijinal işlevi işaret edecek şekilde stacktrace'i nasıl koruyabilirim?

Python 2.x
from functools import wraps 

def try_except(fn): 
     def wrapped(*args, **kwargs): 
      try: 
       fn(*args, **kwargs) 
      except Exception, e: 
       parser = exceptions.ExceptionParser() 
       raised_exception = parser.get_raised_exception_class_name(e) 
       exception = getattr(exceptions, raised_exception) 
       raise exception(parser.get_message(e)) 
     return wraps(fn)(wrapped) 
+1

Eğer 'traceback' modül baktınız mı:

Ben unittests çıktı basılmış orijinal iz korumak için dekoratör vücutta inşa aşağıdaki kullanılan? http://docs.python.org/library/traceback.html – stderr

+0

Bir dekoratörde sarıldığında [functools.wrap] (https://docs.python.org/2/library/functools.html) –

+0

olası yinelemesini kullanın. ["İç istisna" (iz bırakarak) Python'da?) (Http://stackoverflow.com/questions/1350671/inner-exception-with-traceback-in-python) –

cevap

37

, raise bir az bilinen özelliği sadece birden fazla argüman ile kullanılabilir olmasıdır: raise üç argüman formu istisna tipini, istisna örneğini alır ve geri iz. Özel durum türünü, özel durum örneğini ve geri kalanını döndüren (rastgele olmayan) sys.exc_info() ile traceback'e ulaşabilirsiniz.

(bu istisna tipini ve iki ayrı bağımsız değişkenler olarak istisna örneğini davranır nedeni istisna sınıfları önce günlerden bir eserdir.) Böylece

:

Python 3
import sys 

class MyError(Exception): 
    pass 

def try_except(fn): 
    def wrapped(*args, **kwargs): 
     try: 
      return fn(*args, **kwargs) 
     except Exception, e: 
      et, ei, tb = sys.exc_info() 
      raise MyError, MyError(e), tb 
    return wrapped 

def bottom(): 
    1/0 

@try_except 
def middle(): 
    bottom() 

def top(): 
    middle() 

>>> top() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "tmp.py", line 24, in top 
    middle() 
    File "tmp.py", line 10, in wrapped 
    return fn(*args, **kwargs) 
    File "tmp.py", line 21, in middle 
    bottom() 
    File "tmp.py", line 17, in bottom 
    1/0 
__main__.MyError: integer division or modulo by zero 

, bu değişti biraz. Orada, tracebacks yerine istisna örneğine bağlı ve onlar bir with_traceback yöntemi sahiptirler: Öte yandan Python 3 günü

raise MyError(e).with_traceback(tb) 

da istisna birçok durumda daha mantıklı, zincirleme vardır; O kullanmak için, sadece kullanırsınız: Ben özel dekoratörler ile dekore edilmiş testlerle bu sorunla karşı karşıya ettik

raise MyError(e) from e 
+0

Harika, teşekkürler! Bu iş yaptı. Tek sorun, dekoratörün deklarasyonunu dekore edilen işlevle aynı dosyaya taşımak zorunda olduğumdu, aksi halde sys.exc_info() geri döndü (Hiçbiri, Hiçbiri, Hiçbiri) - bunun neden olabileceğine dair herhangi bir fikir var mıydı? – igniteflow

+0

Bu ... mantıklı değil. sys.exc_info() arayanın tanımlandığı yeri umursamıyor. Halen ele alınan istisnayı döndürür. Ayrı bir dosyada sahip olduğunuz dekoratörün doğru şeyi yapmadığı anlaşılıyor, ama gerçek kodu görmeden söylemek zor. –

4

.

try: 
    result = func(self, *args, **kwargs) 
except Exception: 
    exc_type, exc_instance, exc_traceback = sys.exc_info() 
    formatted_traceback = ''.join(traceback.format_tb(
     exc_traceback)) 
    message = '\n{0}\n{1}:\n{2}'.format(
     formatted_traceback, 
     exc_type.__name__, 
     exc_instance.message 
    ) 
    raise exc_type(message) 
+0

Evet ama dekoratörün argümanları nelerdir? –

+0

Sadece yukarıdaki kodla arasındaki farkın 'traceback.format_tb' olduğunu belirtmek yeterli. Teşekkürler. – Ehvince

İlgili konular