[PyScripter] Please let me interrupt you

963 views
Skip to first unread message

PyScripter

unread,
Mar 9, 2012, 8:05:01 PM3/9/12
to pyscr...@googlegroups.com

The standard way of interrupting a long running script in a Python shell is to press Ctrl+C which signals a keyboard interrupt and the interpreter raises a KeyboardInterrupt exception.  I was trying for a while to find a way to raise a KeyboardInterrupt execption at the remote python engine without much success.  The way IDLE handles this, is by running a separate thread in the server, which waits for such a signal to arrive from IDLE and then uses the interrupt_main function of the threading module.  I thought that having a separate thread just for this purpose would slow down the execution of scripts and the PyScripter solution of reinitializing the engine was good enough.

Resently, a user has posted an issue about this at PyScripter’s bug tracker and I had another look at the problem.  So I found a solution using Windows API and avoiding run overheads,  For the benefit of Windows hackers I show the code below:

function CtrlHandler( fdwCtrlType : dword): LongBool; stdcall;
begin
  Result := True;
end;

AttachConsole := GetProcAddress (GetModuleHandle ('kernel32.dll'), 'AttachConsole');
if Assigned(AttachConsole) then
try
  OSCheck(AttachConsole(fRemotePython.ServerProcess.ProcessInfo.dwProcessId));
  OSCheck(SetConsoleCtrlHandler(@CtrlHandler, True));
  try
    OSCheck(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0));
    Sleep(100);
  finally
    OSCheck(SetConsoleCtrlHandler(@CtrlHandler, False));
    OSCheck(FreeConsole);
  end;
except
end;

Note that the CtrlHandler is needed to avoid killing PyScripter itself.  It took me a while to work out this piece of code since, I could not find such code sample (only pieces of the puzzle) in the Internet.  The only solution I found involved injecting code into the server process.

So starting from the forthcoming version 2.5, the Abort command will result in a KeyboardInterrupt exeption in script is run or debugged.  So there is no need to reinitialize the engine to stop a script.  After the script stops you can enter the Post-Mortem mode to see what the script was doing when it received the Keyboard interrupt.

I could have added a shortcut Ctrl+C to the interpreter for raising a Keyboard interrupt, but the Ctrl-C shortcut in GUI applications is associated with the copy command.  So the Abort command will achieve the same thing as pressing Ctrl+C in Python Shell.  When a scrip is stopped at a breakpoint, the Abort command will work as before.



--
Ανάρτηση Από τον/την PyScripter στο PyScripter τη 3/09/2012 05:05:00 μμ

dusans

unread,
Mar 10, 2012, 11:03:09 AM3/10/12
to pyscr...@googlegroups.com
Nice :) this is very very usefull

Chris Zeh

unread,
Mar 19, 2012, 12:04:04 PM3/19/12
to PyScripter
I tried to test out this new feature, perhaps I'm using it wrong, but
it seems broken:

I try clicking the Abort Debugging button while running the following
script:
>>> for x in range(0,100):
... sleep(1)
...

And I get the following error:

Traceback (most recent call last):
File "<string>", line 73, in execInThread
File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\netref.py",
line 196, in __call__
File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\netref.py",
line 71, in syncreq
File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core
\protocol.py", line 431, in sync_request
File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core
\protocol.py", line 379, in serve
File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core
\protocol.py", line 337, in _recv
File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core
\channel.py", line 50, in recv
File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\stream.py",
line 166, in read
EOFError: [Errno 10054] An existing connection was forcibly closed by
the remote host

I'm forced to reinitialize the remote host at this point to continue.

This happens both for the script running from the interpreter, or as a
file started with CTRL+F9.

Thanks,
Chris

Kiriakos Vlahos

unread,
Mar 19, 2012, 12:52:32 PM3/19/12
to pyscr...@googlegroups.com
Oops.  Abort should only be available when you run or debug a script and not when you issue a command in the interpreter.  Please file an Issue at the bug trucker about this.  Or better ask for Abort to work in the interpreter as well.which would be a good idea.

To see how it works try the same example by running the same code in an editor script.

Thanks

Kiriakos


--
You received this message because you are subscribed to the Google Groups "PyScripter" group.
To post to this group, send email to pyscr...@googlegroups.com.
To unsubscribe from this group, send email to pyscripter+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/pyscripter?hl=en.


PyScripter

unread,
Mar 19, 2012, 1:16:33 PM3/19/12
to pyscr...@googlegroups.com
Actually I tried it in the interpreter and it works OK.


>>> for x in range(0,100):
...     sleep(1)
...
Traceback (most recent call last):
  File "<interactive input>", line 2, in <module>
KeyboardInterrupt
>>>

Can you try it again.  Can anyone else try it to see if it works.


On Monday, March 19, 2012 6:52:32 PM UTC+2, PyScripter wrote:
Oops.  Abort should only be available when you run or debug a script and not when you issue a command in the interpreter.  Please file an Issue at the bug trucker about this.  Or better ask for Abort to work in the interpreter as well.which would be a good idea.

To see how it works try the same example by running the same code in an editor script.

Thanks

Kiriakos

Chris Zeh

unread,
Mar 19, 2012, 9:54:57 PM3/19/12
to PyScripter
I tested again on my work laptop and the issue is still present.

The problem is also present on my home PC, Win7 same Python Version
(2.7.1) and same PyScripter.

I have a personal laptop, WinXP SP3 again running the same versions of
Python and PyScripter and I do not have the issue. I get the Keyboard
Interrupt just as you've described above.

My home laptop and PC show differences in behavior on Issue 543 as
well. I'm not sure what could be causing these differences.

Anyone else experience a similar problem?

Chris Zeh

unread,
Mar 20, 2012, 1:15:24 PM3/20/12
to PyScripter
I've attached the dump of the PyScripter - application error that is
thrown when I have this problem

It has more information than the Python error I pasted above. Perhaps
this is useful.
http://pastebin.com/AqdMMR1H

Chris Zeh

unread,
Mar 20, 2012, 1:53:01 PM3/20/12
to PyScripter
I also noticed that when I have the Remote Interpreter (Wx) is
running, (yet sitting idle), looking at my Task Manager I see a
python.exe process taking exactly 25% of my CPU resources.

One interesting thing I noticed, which may be insignificant, is that
my colleague who is running 2.4.1, only has a pythonw.exe process and
not a python.exe process. Tonight when I get home I'll check my laptop
where this feature works to see if there are any differences.

Chris Zeh

unread,
Mar 20, 2012, 9:09:24 PM3/20/12
to PyScripter
Sorry for the continuous stream of messages. My home PC's do not have
this 25% CPU usage issue. Might be time for a full re-install it seems.

PyScripter

unread,
Mar 20, 2012, 9:45:36 PM3/20/12
to pyscr...@googlegroups.com
The Keyboard interrupt feature when you press Abort, may not be 100% full proof.  Sometimes it kills the remote engine, which was the case you experienced.  In those circumstances just reinitialize the remote engine and should be able to carry on working.

PyScripter

unread,
Mar 20, 2012, 9:54:48 PM3/20/12
to pyscr...@googlegroups.com
The remote python engine does some checking for new messages from the client, so I would expect to see some workload.  Here it is about 12 % for Remote wx, but it is about 10% without PyScripter running.   Regarding the remote python process, it has been changed from pythonw.exe to python.exe in version 2.5 to support raising the KeyboardInterrupt.
Reply all
Reply to author
Forward
0 new messages