Crash reporting in Python - python

Is there a crash reporting framework that can be used for pure Python Tkinter applications? Ideally, it should work cross-platform.
Practically speaking, this is more of 'exception reporting' since the Python interpreter itself hardly crashes.
Here's a sample crash reporter:

Rather than polluting your code with try..except everywhere, you should just implement your own except hook by setting sys.excepthook. Here is an example:
import sys
import traceback
def install_excepthook():
def my_excepthook(exctype, value, tb):
s = ''.join(traceback.format_exception(exctype, value, tb))
dialog = ErrorReportDialog(None, s)
dialog.exec_()
sys.excepthook = my_excepthook
Call install_exception() when your application starts.
ErrorReportDialog is a Qt dialog I've made. traceback.format_exception() will format argument passed to the except hook in the same way it does in Python's interpreter.
EDIT: I forgot to mention a little gotcha with that. It doesn't work with threads (well, at least it didn't last time I checked). For code running in another thread, you will need to wrap it in a try..except block.

Stick try excepts everywhere your application can crash (I/O, networking etc.). Whenever an except is called, call a function that will kill the old window, spawn a new tkinter notification window, or a custom one with your error message.
Do a root.after to the new window and send your error report (urllib).
Put a restart button if you wish.
There is no crash reporting framework - as tkinter is not that type of GUI. It's pretty much a wrapper for simple command line apps.
Go pyqt/gtk or wxpython if you want the features seen in the screen-shot above. But I'm pretty sure that where ever you go, you'll have to write your own reporter.

Related

debugging a wxPython application under PyCharm leads to termination on every unhandled exception

Under wxPython when an unhandled exception arises in the main loop the traceback is printed and the exception is ignored.
Not so when debugging under PyCharm. Then the unhandled exception leads to termination of the process.
Also, this is new behavior as previous versions of PyCharm did not behave this way.
Take the following test code:
import wx
import wx.lib.sized_controls as sc
def Raise(evt=None):
raise Exception('error')
app = wx.App()
frame = sc.SizedFrame(None,-1,'hello')
p = frame.GetContentsPane()
b = wx.Button(p,-1,'press')
frame.Bind(wx.EVT_BUTTON,Raise,b)
frame.Show()
app.MainLoop()
Pressing the button when running this normally results in an exception printed and ignored.
When running this under PyCharm debug mode the process terminates.
Is there a way to change this behavior?
Windows10, Python3.6, wxPython 4.0.4, PyCharm 2019.3
Like most Python debuggers, PyCharm installs its own exception handler as sys.excepthook, so whenever there is different behavior between normal runs and debugger runs that is the place to start looking. For example, if you look at the list of Breakpoints for your project you'll also see options for breaking on exceptions. That stuff is implemented in the new excepthoot function. If all else fails, you can look at the pydev code that PyCharm uses for launching and communicating with the debuggee, and see what it's doing in it's excepthook-related code, which may give some clues about how to work around this issue.
I'm not using it as much anymore so I may be misremembering, but I seem to recall that there was an option somewhere in PyCharm for stopping on or ignoring unhandled exceptions, or perhaps for ignoring exceptions raised from specific locations, but I'm not seeing either of them now.
OTOH, catching exceptions before the end of an event handler or other callback function is always a good idea.

PyGObject (Glade) Window Never Showing (Multithreaded)

I've been fighting for three hours now to get this process multithreaded, so that I can display a progress box. I finally got it working, insomuch as the process completes as expected, and all the functions call, including the ones to update the progress indicator on the window.
However, the window never actually displays. This is a PyGObject interface designed in Glade. I am not having fun.
def runCompile(obj):
compileWindow = builder.get_object("compilingWindow")
compileWindow.show_all()
pool = ThreadPool(processes=1)
async_result = pool.apply_async(compileStrings, ())
output = async_result.get()
#output = compileStrings() #THIS IS OLD
compileWindow.hide()
return output
As I mentioned, everything works well, except for the fact that the window doesn't appear. Even if I eliminate the compileWindow.hide() command, the window never shows until the process is done. In fact, the whole stupid program freezes until the process is done.
I'm at the end of my rope. Help?
(By the way, the "recommended" processes of using generators doesn't work, as I HAVE to have a return from the "long process".)
I'm not a pyGobject expert and i don't really understand your code. I think that you should post more. Why are you calling the builder in a function? you can call it at the init of the GUI?
Anyways.. It seems that you are having the common multithread problems..
are you using at the startup GObject.threads_init() and Gdk.threads_init() ?
Then, if you want to show a window from a thread you need to use Gdk.threads_enter() and Gdk.threads_leave().
here is an useful doc
I changed the overall flow of my project, so that may affect it. However, it is imperative that Gtk be given a chance to go through its own main loop, by way of...
if Gtk.events_pending():
Gtk.main_iteration()
In this instance, I only want to call it once, to ensure the program doesn't hang.
(The entire program source code can be found on SourceForge. The function in question is on line 372 as of this posting, in function compileModel().

How to kill a pure console application in PySide/PyQt?

I am attempting to convert code from Summerfield's article on (old-style) PyQt Signals/Slots to new-style PySide code. One example is a pure console application, which I have never worked with before. Unfortunately, when I try to run it multiple times, I am told that the previous application is still running.
It is a simple app: it basically lets you set a number, and reports back if the number is new:
from PySide import QtCore
import sys
class TaxRate(QtCore.QObject):
rateChangedSig=QtCore.Signal(float)
def __init__(self):
QtCore.QObject.__init__(self)
self.rate = 17.5
def getRate(self):
return self.rate
def setRate(self, newRate):
if newRate != self.rate:
self.rate = newRate
self.rateChangedSig.emit(self.rate) #was self.emit(SIGNAL("rateChanged"), self.rate)
#QtCore.Slot() #technically not really needed
def rateChangedSlot(value):
print("Tax rate changed to {0:.2f} %".format(value))
if __name__=="__main__":
qtApp = QtCore.QCoreApplication(sys.argv) #origional had QtGui.QApplication, but there is no GUI
vat = TaxRate()
vat.rateChangedSig.connect(rateChangedSlot) #was vat.connect(vat, SIGNAL("rateChanged"), rateChanged)
vat.setRate(8.5) # A change will occur (new rate is different)
qtApp.quit()
sys.exit(qtApp.exec_())
Overall, it works as expected, except the final two lines do not kill the process. When I try to run the program twice, the second time my IDE (Spyder) always tells me that it is already running in a separate process. If I try running it from the command line, the window just hangs.
Strangely, when I comment out the last two lines I do not get this warning. This is the opposite of what I expect (based on previous experience with PySide GUI applications and the documentation for quit()).
Following the Closing a window example at Zetcode, I tried replacing qtApp.quit() with qtApp.instance().quit(), which yielded the same non-killing result.
So, how do I kill this thing?
One idea is that I shouldn't have even started it in the first place (as suggested here). Even though it is a pure console app, Summerfield's original program initializes with app=QtGui.QApplication(sys.argv), and it does not contain the last two lines. Things run fine, multiple times. However, isn't there a concern that each run would create a new process, so his program seems to be effectively multiplying processes without warning? (Note in practice I don't think this is happening on my system, so the answer seems to be 'No' for reasons I don't understand).
What is the correct way to control/initialize/kill a console app using PySide?
(This is ignoring the question, for the time being, why one would ever use PySide for a pure console application in Python as has been pointed out previously. But if anyone were to be interested in answering that separate question, I could start a separate question for it).
Potentially relevant post:
Pyside applications not closing properly
The problem is because you call QCoreApplication.quit() before you call QCoreApplication.exec_(). The call to quit is not queued up in the event loop, it happens immediately. The call to QCoreApplication.exec_() starts the event loop which only ends when a call to QCoreApplication.exit() (or QCoreApplication.quit()) is made while the event loop is running.
This is somewhat explained in the Qt documentation of QCoreApplication but it is very easy to miss.
I imagine you don't really need to call exec_() as you aren't using any events in your current code (most events are to do with window/mouse/keyboard though you might conceivably use some in the future like those generated by QTimer). It really depends what you want to do with the program in the future.
If you don't call exec_(), then your script will exit as you would normally expect any Python script to do (the only blocking function in your code is the call to exec_(), remove that and nothing keeps it running.)

Python curses - getting error texts in nice way

I am developing ncurses app in python. But everytime, when my second thread (or anything else) throw exception, or print som text, it mess my window.
Is there any option, how to catch this text and handle it properly, without ruining my awesome ncurses program design? :)
Thank you
First and foremost, catch all appropriate exceptions at the entry to your threads' call stacks. In all likelyhood, the slave threads should catch it in order to relay the exception (via Queue, e.g.) to the display, or perhaps a log.
Alternatively, you can suppress the printout of the default exception handler (though your question focuses on this aspect, it's almost certainly not what you want):
import sys
sys.stdout.close()
sys.stderr.close()

GUI not updated from another thread when using PyGtk

I am using PyGTK to build a GUI application. I want to update the textview widget from another thread but the widget is not getting updated everytime i try an update. What should i do to get a reliable GUI updating?
GTK+ is not thread-safe, so you should not simply call GUI update methods from other threads. glib.idle_add (or gobject.idle_add in older PyGTK versions) can be used for this purpose.
Instead of writing:
label.set_text("foo")
you would write:
glib.idle_add(label.set_text, "foo")
which causes the function call to be queued in GTK+.
If you need to run multiple statements, it's often easier to wrap them in a function:
def idle():
label1.set_text("foo")
label2.set_text("bar")
glib.idle_add(idle)
Make sure that the function passed to idle_add does not return True; otherwise it will be queued again.
Edit: As Daniel pointed out, you need to call gtk.gdk.threads_init() anywhere in your program first.
As stated in the previous answers, GTK is not "thread safe," but it is "thread-aware" - see this page on Threads: https://developer.gnome.org/gdk2/stable/gdk2-Threads.html
In order to modify GTK widgets from another thread you have to use GTK's locking. Call gtk.threads_init() immediately after importing the gtk module, and then you can update like so:
gtk.threads_enter()
# make changes...
gtk.threads_leave()
Note that the above will not work on Windows (see the link above). On Windows you must use gobject.idle_add() as explained above, though don't forget to put gobject.threads_init() directly after importing gobject in your code! The idle_add() function will execute the update itself in the main thread (the thread running gtk.main()).
the same may be achieved using gobject.idle_add method whose syntax is same as above,you have to import the module gobject
What Johannes said is correct, however since GTK is a wrapper for the glib and gobject things, you would actually want to use gtk.idle_add(). No need for the unnecessary imports.

Categories