I'm using py.shell.Shell within a larger application.
Is there a way to interrupt long running code?
Keyboard events are obviously not handled by wxPython while the code is
running in the shell.
If I'm doing a Ctrl-C in the console window, the application is
terminated...
I've tried to place a try/except KeyboardInterrupt around some places
where the interpreter is called, but with no effect.
Something like PythonWin's "Break into running code" would be nice.
(If you don't know this: PythonWin is creating an icon in the system
tray which offers this menu item. When you select this, it will send
a KeyboardInterrupt to the code that is running in PythonWin's
interactive window.)
Regards,
Dietmar
On Nov 14, 2009, at 5:58 AM, Dietmar Schwertberger wrote:
>
> Hi!
>
> I'm using py.shell.Shell within a larger application.
>
> Is there a way to interrupt long running code?
> Keyboard events are obviously not handled by wxPython while the code
> is
> running in the shell.
> If I'm doing a Ctrl-C in the console window, the application is
> terminated...
> I've tried to place a try/except KeyboardInterrupt around some places
> where the interpreter is called, but with no effect.
This is because it runs in the same instance of python and the same
thread that your application is running in. So while code is running
in the shell it is blocking your applications so no key events will be
processed durning that time. To fix this py.shell would need to
execute its code in a python shell that is running in a separate
process and relay that back to the ui portion of the shell that is
running in your process.
Cody
If I have a standard console script, it's no problem.
E.g. this one will run an infinite loop until I hit Ctrl-C and then
continues with the raw_input:
import code
int = code.InteractiveInterpreter(locals=None)
try:
source = "while True:print '.',\n"
int.runsource(source)
except KeyboardInterrupt:
print "Interrupted"
raw_input()
But if I try the same with py shell by inserting a try/except in the
following code and do a Ctrl-C in the console window, I can't catch
the interrupt:
...\Lib\site-packages\wx-2.8-msw-unicode\wx\py\interpreter.py
class Interpreter(InteractiveInterpreter):
def runsource(self, source):
"""Compile and run source code in the interpreter."""
stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
sys.stdin, sys.stdout, sys.stderr = \
self.stdin, self.stdout, self.stderr
try:
more = InteractiveInterpreter.runsource(self, source)
except KeyboardInterrupt:
print "KeyboardInterrupt"
Regards,
Dietmar
On Nov 14, 2009, at 10:10 AM, Dietmar Schwertberger wrote:
>>
> Thanks. Yes, I know about event handling and a separate process would
> not help if the shell should be able to control the application.
> A separate thread would also not be too nice as the shell then could
> not
> call any code that manipulates the GUI.
> Therefore I tried with the console window as this will receive the
> KeyboardInterrupt. It should somehow be possible that the
> KeyboardInterrupt interrupts the running code and but is handled in
> the interpreter before it propagates to the wx main loop. But by
> placing
> try/except at some obvious places I could not achieve this.
>
> If I have a standard console script, it's no problem.
> E.g. this one will run an infinite loop until I hit Ctrl-C and then
> continues with the raw_input:
>
> import code
> int = code.InteractiveInterpreter(locals=None)
> try:
> source = "while True:print '.',\n"
> int.runsource(source)
> except KeyboardInterrupt:
> print "Interrupted"
>
> raw_input()
There is a major difference here. When your in the console and run
'python myscript.py' that forks of a separate child process from the
console itself. So when you hit ctrl+c in the console it sends a
signal to the child python process that is running your script which
will then cause the KeyboardInterupt to be raised.
As mentioned py.shell is running in the same process as your main
application. So if you are running an infinite loop in the shell it
will be blocking the execution of any other code in your application.
Hitting Ctrl+C here will cause a wx KeyEvent to be generated but since
the mainloop is being blocked by the code in the shell the key events
will and cannot be processed until the code being run by the shell has
returned control to the main loop.
Cody
Regards,
Dietmar
(*) Or, I'm starting the script from a console window.
Result is the same as with double-clicking the .py file.
No. It is being caught by a signal handler set up by the native UI
library which is then causing a termination of the app. Python is not
able to catch it in this case.
> In the wxWidgets documentation there are methods like
> wxApp::OnUnhandledException. But from what I see, these are not
> available in wxPython.
And it's not for Python exceptions anyway.
--
Robin Dunn
Software Craftsman
http://wxPython.org
The default signal handler is default_int_handler:
>>> import signal
>>> signal.getsignal(signal.SIGINT)
<built-in function default_int_handler>
It's also possible to ignore the signal:
signal.signal(signal.SIGINT, signal.SIG_IGN)
So, it seems that setting the handler to default_int_handler before the
shell will execute any code could do the job. The rest of the time it
can remain at SIG_IGN.
The app can then only be terminated regularly by the GUI code or
alternatively by closing the console window.
Regards,
Dietmar
The code in _core.py:
class App(wx.PyApp):
[...]
def __init__(self, redirect=_defRedirect, filename=None,
useBestVisual=False, clearSigInt=True):
[...]
if clearSigInt:
try:
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
except:
pass