[Python] Info su cancellazione traceback

Matteo Boscolo matteo.boscolo a boscolini.eu
Dom 20 Nov 2022 08:33:40 CET


On 19/11/2022 10:47, Marco Giusti wrote:
> On 19.11.2022 08:45, Matteo Boscolo wrote:
>> Buongiorno a tutti,
>>
>> vorrei cancellare il traceback di python e mostrare solo il mio raise,
>> questa cosa mi serve per evitare che lo stack dell'errore venga visto
>> in console.
>>
>> ho provato con questo decoratore
>>
>> def avoid_traceback(message=''):
>>     ''' call a function a number of times '''
>>     def decorate(fn):
>>         @wraps(fn)
>>         def wrapper(*args, **kwargs):
>>             try:
>>                 result = fn(*args, **kwargs)
>>             except Exception as ex:
>>                 if message:
>>                     raise Exception(message)
>>                 raise Exception("Error on method %s" % fn.__name__)
>>             return result
>>         return wrapper
>>     return decorate
>>
>>
>> che funziona, ma il traceback resta attivo, nel senso che se metto
>>
>> traceback.print_exc()
>>
>> mi vedo tutto lo stack dell'errore:
>>
>> Traceback (most recent call last):
>>   File "/media/OneTDisk/workspace/test.py", line 133, in wrapper
>>     result = fn(*args, **kwargs)
>>   File "/media/OneTDisk/workspace/test.py", line 218, in rise
>>     raise Exception("rise")
>> Exception: rise
>>
>>
>> potete provare con questo esempietto qua:
>>
>> class A(object):
>>     def __init__(self):
>>         pass
>>
>>     @avoid_traceback("errore generico")#
>>     def rise1(self):
>>         return self.rise()
>>
>>     @avoid_traceback("errore generico")#
>>     def rise(self):
>>         raise Exception("rise")
>> a=A()
>> a.rise1()
>> traceback.print_exc()
>>
>> ho trovato in rete
>>
>> https://www.programcreek.com/python/example/119512/traceback.clear_frames 
>>
>>
>> ma sembra che non funzioni..
>>
>> qualche idea ?
>
>
> Ciao Matteo,
>
> vorrei premettere che non trovo sia una buona idea nascondere
> informazioni quando si ha a che fare con delle eccezioni, anzi, piu'
> informazioni ci sono e meglio e'. Comunque, usa il costrutto
>
>     raise exception from None
>
> Quando lanci un'eccezione al momento in cui ne stai gia' gestendo
> un'altra, le due eccezioni sono concatenate in due punti: __context__ e
> __cause__. Il primo attributo e' settato automaticamente e per
> sovrascriverlo hai bisogno di un ulteriore blocco try/except. Non farlo,
> perche' per visualizzare il traceback e' usato __suppress_context__.
>
> Se il valore e' False, allora viene visualizzato __cause__ o
> __context__, se il valore e' True, allora la precedente eccezione non e'
> visualizzata. Usando "raise ... from None: ottieni gia' quello
> che desideri: __cause__ e' settato to None e __suppress_context__ e'
> settato to True.
>
> Ecco qualche esempio usando sempre questo codice e usando il decoratore
> "avoid_traceback" solo sul metodo "rise1".
>
>     a = A()
>     try:
>         a.rise1()
>     except Exception as exc:
>         print(f"exc.__cause__: {exc.__cause__}")
>         print(f"exc.__suppress_context__: {exc.__suppress_context__}")
>         print(f"exc.__context__: {exc.__context__}")
>         raise
>     traceback.print_exc()
>
>
> Esempio 1, lasciando il decoratore invariato:
>
>     $ python3 hide_traceback.py
>     exc.__cause__: None
>     exc.__suppress_context__: False
>     exc.__context__: rise
>     Traceback (most recent call last):
>       File "/home/marco/hide_traceback.py", line 11, in wrapper
>         result = fn(*args, **kwargs)
>       File "/home/marco/hide_traceback.py", line 27, in rise1
>         return self.rise()
>       File "/home/marco/hide_traceback.py", line 30, in rise
>         raise Exception("rise")
>     Exception: rise
>
>     During handling of the above exception, another exception occurred:
>
>     Traceback (most recent call last):
>       File "/home/marco/hide_traceback.py", line 35, in <module>
>         a.rise1()
>       File "/home/marco/hide_traceback.py", line 14, in wrapper
>         raise Exception(message)
>     Exception: errore generico
>
> Esempio 2, usando raise ... from None
>
>     $ python3 hide_traceback.py
>     exc.__cause__: None
>     exc.__suppress_context__: True
>     exc.__context__: rise
>     Traceback (most recent call last):
>       File "/home/marco/hide_traceback.py", line 35, in <module>
>         a.rise1()
>       File "/home/marco/hide_traceback.py", line 14, in wrapper
>         raise Exception(message) from None
>     Exception: errore generico
>
> Esempio 3, usando un ulteriore blocco try/catch
>
>
>     ...
>     try:
>         try:
>             result = fn(*args, **kwargs)
>         except Exception as ex:
>             if message:
>                 raise Exception(message) from None
>             raise Exception("Error on method %s" % fn.__name__) from None
>     except Exception as exc:
>         exc.__context__ = None
>         raise exc
>
>     $ python3 hide_traceback.py
>     exc.__cause__: None
>     exc.__suppress_context__: True
>     exc.__context__: None
>     Traceback (most recent call last):
>       File "/home/marco/hide_traceback.py", line 39, in <module>
>         a.rise1()
>       File "/home/marco/hide_traceback.py", line 19, in wrapper
>         raise exc
>       File "/home/marco/hide_traceback.py", line 15, in wrapper
>         raise Exception(message) from None
>     Exception: errore generico
>
Grazie mille Marco per le preziose informazioni.

Questo codice fa parte di un gestore di licenze che meno informazioni da 
meglio e' ...

Saluti,

Matteo



Maggiori informazioni sulla lista Python