Capturar exceções MainLoop e exibi-las em MessageDialogs
-
03-07-2019 - |
Pergunta
Eu tenho um aplicativo wxPython que depende de um arquivo de configuração externo.Quero fornecer caixas de diálogo de mensagens amigáveis que apareçam se houver algum erro de configuração.Tentei fazer isso funcionar envolvendo minha chamada app.MainLoop() em uma instrução try/except.
O código abaixo funciona para o código init na minha classe de quadro MainWindow, mas não captura nenhuma exceção que ocorra no MainLoop.Como posso capturar essas exceções também?
if __name__ == '__main__':
app = MyApp(0)
try:
MainWindow(None, -1, 'My Cool App')
app.MainLoop()
except ConfigParser.Error, error_message:
messagebox = wx.MessageDialog(None, error_message, 'Configuration Error', wx.OK | wx.ICON_ERROR)
messagebox.ShowModal()
Eu li algumas menções a um método OnExceptionInMainLoop que pode ser substituído na classe wx.App, mas a fonte que li deve estar desatualizada (2004), pois wx.App não parece mais ter um método com esse nome.
EDITAR:
Preciso ser capaz de capturar exceções não tratadas durante meu mainloop para poder tratá-las ainda mais e exibi-las em caixas de diálogo de erro, não passar silenciosamente e não encerrar o aplicativo.
A solução sys.excepthook é de nível muito baixo e não funciona bem com o thread principal wxPython.Enquanto o link para a outra resposta faz a mesma tentativa/exceto envolver o mainloop que não funciona devido, mais uma vez, ao wxPython gerar um thread diferente para o aplicativo/ui.
Solução
Eu codifiquei algo assim para Chandler, onde qualquer exceção não tratada abre uma janela com a pilha e outras informações, e os usuários podem colocar comentários adicionais (o que eles fizeram quando isso aconteceu, etc.) e enviá-los para os desenvolvedores do Chandler.Um pouco como o Mozilla Talkback (hoje em dia eles usam o recurso Breakpad, eu acredito), se você preferir.
Para fazer isso no wxPython, você precisa fornecer o parâmetro de redirecionamento para wx.App.Isso irá aparecer wx.PyOnDemandOutputWindow (você provavelmente desejará substituí-lo para fornecer uma implementação mais bonita).
Os arquivos de origem relevantes no Chandler estão aqui:
- Chandler.py inicia o aplicativo e define o atributo de redirecionamento, bem como tenta capturar e exibir caixas de diálogo de erro caso a inicialização normal do aplicativo falhe
- Aplicativo.py personaliza o objeto do aplicativo, incluindo a configuração de nosso wx.PyOnDemandOutputWindow personalizado
- feedback.py possui a implementação para o wx.PyOnDemandOutputWindow customizado;também precisará de feedback.xrc e feedback_xrc.py
Outras dicas
Não sei se isso funcionará para um aplicativo wxPython, mas no módulo sys você pode sobrescrever o atributo excepthook, que é uma função chamada com 3 argumentos, (type, value, traceback)
, quando uma exceção não detectada é capturada.Você pode instalar sua própria função que lida apenas com as exceções desejadas e chamar a função original para todas as outras.
Consultar: http://docs.python.org/library/sys.html#sys.excepthook
Talvez esse questão pode ser de alguma utilidade, ela tenta capturar todas as exceções.
Postando a solução que funcionou para mim com um problema muito semelhante.
import wx
import sys
import traceback
class Frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None)
panel = wx.Panel(self)
m_close = wx.Button(panel, -1, "Error")
m_close.Bind(wx.EVT_BUTTON, self.OnErr)
def OnErr(self, event):
1/0
def handleGUIException(exc_type, exc_value, exc_traceback):
err_msg = ''.join(traceback.format_exception(exc_type, exc_value, exc_traceback))
err_msg += '\n Your App will now terminate'
# Here collecting traceback and some log files to be sent for debugging.
# But also possible to handle the error and continue working.
dlg = wx.MessageDialog(None, err_msg, 'Termination dialog', wx.OK | wx.ICON_ERROR)
dlg.ShowModal()
dlg.Destroy()
sys.exit()
sys.excepthook = handleGUIException
if __name__ == '__main__':
app = wx.App(redirect=False)
top = Frame()
top.Show()
app.MainLoop()
Usando sys.excepthook
está muito bem para mim.
Acho o seguinte artigo de grande ajuda: wxPython:Capturando exceções de qualquer lugar.