Comment capturer toutes les exceptions d'une application wxPython?
-
03-07-2019 - |
Question
J'écris une petite application de débogage pour un peu de kit que nous développons et j'aimerais la transmettre à quelques utilisateurs pour voir s'ils peuvent provoquer des plantages. Est-ce que quelqu'un connaît un moyen d'encapsuler efficacement une application wxPython pour intercepter toutes les exceptions non gérées qui provoqueraient le blocage de l'application?
Idéalement, je souhaiterais capturer toutes les sorties (pas seulement les erreurs) et les enregistrer dans un fichier. Toutes les exceptions non gérées doivent se connecter au fichier actuel, puis permettre à l’exception de se transmettre comme à l’habitude (c’est-à-dire que le processus de journalisation doit être transparent).
Je suis sûr que quelqu'un a déjà fait quelque chose dans ce sens auparavant, mais je n'ai pas réussi à trouver quoi que ce soit qui paraisse utile via Google.
La solution
Pour consigner la sortie standard, vous pouvez utiliser un wrapper stdout, tel que celui-ci:
from __future__ import with_statement
class OutWrapper(object):
def __init__(self, realOutput, logFileName):
self._realOutput = realOutput
self._logFileName = logFileName
def _log(self, text):
with open(self._logFileName, 'a') as logFile:
logFile.write(text)
def write(self, text):
self._log(text)
self._realOutput.write(text)
Vous devez ensuite l'initialiser dans votre fichier Python principal (celui qui exécute tout):
import sys
sys.stdout = OutWrapper(sys.stdout, r'c:\temp\log.txt')
En ce qui concerne la journalisation des exceptions, la solution la plus simple consiste à envelopper la méthode MainLoop
de wx.App dans un essai..exception, puis à extraire les informations sur l'exception, à les enregistrer d'une certaine manière, puis relancez l'exception avec raise
, par exemple:
try:
app.MainLoop()
except:
exc_info = sys.exc_info()
saveExcInfo(exc_info) # this method you have to write yourself
raise
Autres conseils
Pour la gestion des exceptions, en supposant que votre fichier journal est ouvert en tant que journal:
import sys
import traceback
def excepthook(type, value, tb):
message = 'Uncaught exception:\n'
message += ''.join(traceback.format_exception(type, value, tb))
log.write(message)
sys.excepthook = excepthook
Vous pouvez utiliser
sys.excepthook
(voir documents Python )
et lui attribuer un objet personnalisé, qui intercepterait toutes les exceptions non détectées plus tôt dans votre code. Vous pouvez ensuite consigner n'importe quel message dans n'importe quel fichier, avec trace, et faire ce que bon vous semble avec l'exception (relancez-le, affichez le message d'erreur et laissez l'utilisateur continuer à utiliser votre application, etc.).
En ce qui concerne la journalisation de stdout - le meilleur moyen pour moi consistait à écrire quelque chose de similaire à OutWrapper de DzinX.
Si vous en êtes au stade du débogage, envisagez de vider vos fichiers journaux après chaque entrée. Cela nuit beaucoup aux performances, mais si vous parvenez à causer une erreur de segmentation dans du code C sous-jacent, vos journaux ne vous induiront pas en erreur.
Il y a différentes manières. Vous pouvez mettre un bloc try..catch dans wxApplication :: OnInit, cependant, cela ne fonctionnerait pas toujours avec Gtk.
Une bonne alternative serait de surcharger Application :: HandleEvent dans votre classe dérivée wxApplication et d'écrire un code comme celui-ci:
void Application::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& event) const
{
try
{
wxAppConsole::HandleEvent(handler, func, event);
}
catch (const std::exception& e)
{
wxMessageBox(std2wx(e.what()), _("Unhandled Error"),
wxOK | wxICON_ERROR, wxGetTopLevelParent(wxGetActiveWindow()));
}
}
C’est un exemple C ++, mais vous pouvez sûrement traduire facilement en Python.