Terminating a wxPython app cleanly - python

I'm working on a wxPython app which has multiple frames and a serial connection. I need to be able to exit the app cleanly, closing the serial connection as the app terminates.
What is the best way to do this? Should this be handled by a subclass of wxApp?
Thanks,
Josh

Not totally sure what you're having trouble with here, but I'll take a shot in the dark and assume this is a program organization/design question.
There may be better ways that I'm unfamiliar with, but this is what I'd try to do: create a "parent" object (doesn't have to have any particular type) that keeps references to the multiple frames. When one of the frames receives the exit event from a menu or what have you, it calls self.parent.broadcast_quit(), which sends a quit event to each of the frames it holds references to.
This way of doing it kind of expresses a view-controller separation, where the frames are part of the view and the parent object is a tell-me-when-to-shut-down controller -- the parent can nicely encapsulate the connection teardown as well, since it can stay informed on which frames have shut down and when. You can keep details on how to tear down the view in the frames themselves, and then can send an "I'm finished" message back to the controller during their teardown, triggering some final teardown on the parent side.
See the docs for wx.PostEvent and Custom Event Classes. (Events are a nice normalized way of expressing cross-window messages in a non-blocking GUI.)

I usually use my close button's event handler to close connections and what-not before closing the frame. If you want to catch the upper right "x" button, then you'll need to bind to EVT_CLOSE. Unfortunately, when you do that, you need to call your frame's Destroy() method rather than its Close() method or you'll end up in an infinite loop.

Related

Update QThread from GUI Widgets

I've seen this question asked in reverse a bunch of times - how to update the GUI from a subclassed QThread - but I actually want to do it in reverse. I have an application which displays the feed from a camera continuously and indefinitely, and the camera runs in a separate thread. I have the camera feed displayed in the GUI using signals from the QThread. The camera controls are in the main GUI window, and I want to be able to send those updates to an already-running camera thread. What would be the best way to do that? Thanks.
If you're using the default QThread::run() implementation which runs an event loop, then you can create a slot on the class and invoke it as a QueuedConnection (which should occur automatically).
Otherwise, you'll need to use standard thread synchronisation primitives, such as QMutex to safely access the same data from both threads.

Stopping function processing externally

I have a huge problem. I am working in a Web Python Project, where, after click in a button, a specific controller is called and then another function, present in a python module, is called as well, as shown in my code below. However , I need a second button that stops the process of the stream function controller.
import analyser
def stream():
analyser.get_texts()
response.flash = "Analysis Done."
return ""
I've been searching a lot how to stop a process by an external event (something similar to interruption), but the solutions that I've got, all of them, were about how to stop python script using sys.exit() ou programatically by a return statement, for example. None of these solutions actually work for me.
I want that the user be able to stop that function whenever he wants, once that my function analyser.get_texts() remains processing all the time.
So, my question is how can I stop the execution of stream function, through a button click on my view? Thanks.
If I understand you correctly, then your analyser doesn't provide its own way to terminate an ongoing calculation. You will therefore need to wrap it into something that allows you to terminate the analyser without its "consent".
The right approach for that depends on how bad terminating the analyser in that way is: does it leave resources in a bad state?
Depending on that, you have multiple options:
Run your analysis in a separate process. These can be cleanly killed from the outside. Note that it's usually not a good idea to forcefully stop a thread, so use processes instead.
Use some kind of asynchronous task management that lets you create and stop tasks (e.g. Celery).

How does Python's Twisted Reactor work?

Recently, I've been diving into the Twisted docs. From what I gathered, the basis of Twisted's functionality is the result of it's event loop called the "Reactor". The reactor listens for certain events and dispatches them to registered callback functions that have been designed to handle these events. In the book, there is some pseudo code describing what the Reactor does but I'm having trouble understanding it, it just doesn't make any sense to me.
while True:
timeout = time_until_next_timed_event()
events = wait_for_events(timeout)
events += timed_events_until(now())
for event in events:
event.process()
What does this mean?
In case it's not obvious, It's called the reactor because it reacts to
things. The loop is how it reacts.
One line at a time:
while True:
It's not actually while True; it's more like while not loop.stopped. You can call reactor.stop() to stop the loop, and (after performing some shut-down logic) the loop will in fact exit. But it is portrayed in the example as while True because when you're writing a long-lived program (as you often are with Twisted) it's best to assume that your program will either crash or run forever, and that "cleanly exiting" is not really an option.
timeout = time_until_next_timed_event()
If we were to expand this calculation a bit, it might make more sense:
def time_until_next_timed_event():
now = time.time()
timed_events.sort(key=lambda event: event.desired_time)
soonest_event = timed_events[0]
return soonest_event.desired_time - now
timed_events is the list of events scheduled with reactor.callLater; i.e. the functions that the application has asked for Twisted to run at a particular time.
events = wait_for_events(timeout)
This line here is the "magic" part of Twisted. I can't expand wait_for_events in a general way, because its implementation depends on exactly how the operating system makes the desired events available. And, given that operating systems are complex and tricky beasts, I can't expand on it in a specific way while keeping it simple enough for an answer to your question.
What this function is intended to mean is, ask the operating system, or a Python wrapper around it, to block, until one or more of the objects previously registered with it - at a minimum, stuff like listening ports and established connections, but also possibly things like buttons that might get clicked on - is "ready for work". The work might be reading some bytes out of a socket when they arrive from the network. The work might be writing bytes to the network when a buffer empties out sufficiently to do so. It might be accepting a new connection or disposing of a closed one. Each of these possible events are functions that the reactor might call on your objects: dataReceived, buildProtocol, resumeProducing, etc, that you will learn about if you go through the full Twisted tutorial.
Once we've got our list of hypothetical "event" objects, each of which has an imaginary "process" method (the exact names of the methods are different in the reactor just due to accidents of history), we then go back to dealing with time:
events += timed_events_until(now())
First, this is assuming events is simply a list of an abstract Event class, which has a process method that each specific type of event needs to fill out.
At this point, the loop has "woken up", because wait_for_events, stopped blocking. However, we don't know how many timed events we might need to execute based on how long it was "asleep" for. We might have slept for the full timeout if nothign was going on, but if lots of connections were active we might have slept for effectively no time at all. So we check the current time ("now()"), and we add to the list of events we need to process, every timed event with a desired_time that is at, or before, the present time.
Finally,
for event in events:
event.process()
This just means that Twisted goes through the list of things that it has to do and does them. In reality of course it handles exceptions around each event, and the concrete implementation of the reactor often just calls straight into an event handler rather than creating an Event-like object to record the work that needs to be done first, but conceptually this is just what happens. event.process here might mean calling socket.recv() and then yourProtocol.dataReceived with the result, for example.
I hope this expanded explanation helps you get your head around it. If you'd like to learn more about Twisted by working on it, I'd encourage you to join the mailing list, hop on to the IRC channel, #twisted to talk about applications or #twisted-dev to work on Twisted itself, both on Freenode.
I will try to elaborate:
The program yields control and go to sleep on wait for events.
I suppose the most interesting part here is event.
Event is:
on external demand (receiving network packet, click on a keyboard, timer, different program call) the program receives control (in some other thread or
in special routine). Somehow the sleep in wait_for_events becomes interrupted and wait_for_events returns.
On that occurrence of control the event handler stores information of that event into some data structure, events, which later is used for doing something about that events (event->process).
There can happen not only one, but many events in the time between entering and exiting of wait_for_events, all of them must be processed.
The event->process() procedure is custom and should usually call the interesting part - user's twisted code.

Is it possible for Python threads to cause their parent/main process to execute code?

Background: I've written a simple RUMPS/PyObjC app that at various points makes HTTP requests and pops system alert dialogs. Most of the HTTP requests are threaded to avoid blocking the main execution.
Query: In PyObjC you're not supposed to create alert dialogs in background threads (only the main process is safe to do this) so I was wondering if there was a sensible pattern I could use to allow child threads to communicate back to their parent to notify it that an alert dialog should be created.
As an example:
Main program has a popAlert() method defined, which call PyObjC functions to create alert dialog.
Main program launches a thread that executes an HTTP request and wants to pop an alert when done.
Child thread, when HTTP request completes, somehow calls back to the main process to trigger popAlert().
At the moment I have the child thread creating the alert dialog which apparently isn't safe in PyObjC.
I'm fairly new to threading/multiprocessing and the inter-thread communication examples I've seen so far seem to mostly involve child threads receiving messages from a queue-like mechanism, with the parent optionally blocking until the queue is empty. I haven't yet seen anything that indicates if it's possible to have the parent respond to a message from a child thread in the way I describe.
If doing this requires re-architecting, that's fine too – I'm not wedded to any particular multiprocessing approach.
Any advice would be much appreciated. Please let me know if I can provide more detail. Many thanks for reading.
Take a look at pyobjc_performSelectorOnMainThread. It might be what you need. Here's a contrived usage example:
class MyClass (NSObject):
def divideByZero_(self, arg):
return arg/0
def doit(self):
try:
result = self.performSelectorOnMainThread_withObject_(
'divideByZero:', 55)
print result
except:
print "Division failed"
You can find it being used in a more concretely in this PyObjC example app. Check out WSTConnectionWindowControllerClass.py in particular.
You can also use a queue to transfer messages from children to parent. The problem here is, that you need a message loop in the main thread, that reads the message queue regularly to display the messages.

QObject (QPlainTextEdit) & Multithreading issues

Im currently trying to learn Networking with Python asyncore and pyqt4.
I coded a small server, which basically listens on some port, and resends all messages it recieves to the sender.
Since both qts QApplication.exec_() and asyncore.loop() are functions which never return i could not start them both in one thread, so i stared asyncore.loop() in a seperate daemon thread.
Whenever my server class (derived from asyncore.dispatcher) establishes or drops a connection, or sends/recieves a message, it calls methods of my window class (derived from QtGui.QMainWindow), which displays the information in a QPlainTextEdit.
But the text is not visible, unless you mark the text with the mouse.
Python console displays following error msg:
QObject::connect: Cannot queue arguments of type 'QTextBlock'
(Make sure 'QTextBlock' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
I read on some forum, that this may be caused by calling qt-functions from another Thread, and that using signals & slots instead of plain function calling may fix the issue, but i have tried signals aswell, and i still get this error.
So, (if that is really the cause of my problems) whats the correct way to call methods of an qt object from another thread ?
EDIT More Info:
the asyncore.loop() call is located in the child thread, well its not really blocking, but only during the runtime of asyncore.loop() my Server class (asyncore.dispatcher) can do networking.
So, during the runtime of asyncore.loop() the methods of my Server class ARE called by asyncore.loop() (=child thread), and in these i
tried to emit signals to the window class running in the main thread
EDIT: Seems like i got it working now, i had some errors in my code, everything works as intended with signals now.
EDIT: small example: http://paste2.org/p/635612 (dead link)
It appears you're trying to access QtGui classes from a thread other than the main thread. Like in some other GUI toolkits (e.g. Java Swing), that's not allowed. From the Threads and QObjects web page:
Although QObject is reentrant, the GUI
classes, notably QWidget and all its
subclasses, are not reentrant. They
can only be used from the main thread.
A solution is to use signals and slots for communication between the main thread (where the GUI objects live) and your secondary thread(s). Basically, you emit signals in one thread that get delivered to the QObjects via the other thread. The page I linked to above has a good discussion of this. Actually, the whole section on Thread Support in Qt is a good read.
One potential issue you could run into is that, normally, to get full signals and slots support working across threads, you need to start an event loop in the child thread using QThread::exec() (or the PyQt equivalent) so that signals can be delivered to slots in the QObjects that live there. In your case, it sounds like you're making a blocking call to asyncore.loop(), which will prevent you from doing this. But, if you only need to emit signals in one direction (from the child thread to widgets in the main thread), I don't think you'll have a problem.

Categories

Resources