Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Catching control-C

14 views
Skip to first unread message

Michael Mossey

unread,
Jul 6, 2009, 5:37:53 PM7/6/09
to
What is required in a python program to make sure it catches a control-
c on the command-line? Do some i/o? The OS here is Linux.

Thanks,
Mike

Chris Rebert

unread,
Jul 6, 2009, 5:44:20 PM7/6/09
to Michael Mossey, pytho...@python.org
On Mon, Jul 6, 2009 at 2:37 PM, Michael Mossey<michae...@gmail.com> wrote:
> What is required in a python program to make sure it catches a control-
> c on the command-line? Do some i/o? The OS here is Linux.

try:
#code that reads input
except KeyboardInterrupt:
#Ctrl-C was pressed

Cheers,
Chris
--
http://blog.rebertia.com

Philip Semanchuk

unread,
Jul 6, 2009, 5:47:57 PM7/6/09
to Python-list (General)

You can use a try/except to catch a KeyboardInterrupt exception, or
you can trap it using the signal module:
http://docs.python.org/library/signal.html

You want to trap SIGINT.


HTH
Philip

Michael Mossey

unread,
Jul 6, 2009, 6:02:26 PM7/6/09
to

Thanks to both of you. However, my question is also about whether I
need to be doing i/o or some similar operation for my program to
notice in any shape or form that Control-C has been pressed. In the
past, I've written Python programs that go about their business
ignoring Ctrl-C. Other programs respond to it immediately by exiting.
I think the difference is that the latter programs are doing i/o. But
I want to understand better what the "secret" is to responding to a
ctrl-C in any shape or form.

For example, does trapping SIGINT always work, regardless of what my
process is doing?

Thanks,
Mike

Philip Semanchuk

unread,
Jul 6, 2009, 6:16:06 PM7/6/09
to Python-list (General)

Hi Mike,
Sorry, I don't know the Python internals well enough to answer your
question.

Good luck
Philip

Ben Charrow

unread,
Jul 6, 2009, 6:38:12 PM7/6/09
to Michael Mossey, pytho...@python.org
Michael Mossey wrote:
> On Jul 6, 2:47 pm, Philip Semanchuk <phi...@semanchuk.com> wrote:
>> On Jul 6, 2009, at 5:37 PM, Michael Mossey wrote:
>>
>>> What is required in a python program to make sure it catches a control-
>>> c on the command-line? Do some i/o? The OS here is Linux.
>> You can use a try/except to catch a KeyboardInterrupt exception, or you
>> can trap it using the signal
>> module:http://docs.python.org/library/signal.html
>>
>> You want to trap SIGINT.
>>
>> HTH Philip
>
> Thanks to both of you. However, my question is also about whether I need to
> be doing i/o or some similar operation for my program to notice in any shape
> or form that Control-C has been pressed.

You don't need to be doing I/O in order to raise a KeyboardIneterrupt. For
example, the following program should use up a lot of your CPU until you
hit Ctrl-C.

>>> while True:
... pass
...
^CTraceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyboardInterrupt

> In the past, I've written Python programs that go about their business
> ignoring Ctrl-C.

Can you be more specific? Can you share the relevant sections of these
programs? Were these programs multi-threaded?

> But I want to understand better what the "secret" is to responding to a
> ctrl-C in any shape or form.

Strictly speaking, I don't think you can always respond to a Ctrl-C in any
shape or form. Quoting from the signal module:

Although Python signal handlers are called asynchronously as far as the Python
user is concerned, they can only occur between the "atomic" instructions of the
Python interpreter. This means that signals arriving during long calculations
implemented purely in C (such as regular expression matches on large bodies of
text) may be delayed for an arbitrary amount of time.

HTH,
Ben

Piet van Oostrum

unread,
Jul 6, 2009, 7:05:44 PM7/6/09
to
>>>>> Philip Semanchuk <phi...@semanchuk.com> (PS) wrote:

>PS> On Jul 6, 2009, at 5:37 PM, Michael Mossey wrote:

>>> What is required in a python program to make sure it catches a control-
>>> c on the command-line? Do some i/o? The OS here is Linux.

>PS> You can use a try/except to catch a KeyboardInterrupt exception, or you
>PS> can trap it using the signal module:
>PS> http://docs.python.org/library/signal.html

>PS> You want to trap SIGINT.

And make sure threads don't mess up the signal handling.
--
Piet van Oostrum <pi...@cs.uu.nl>
URL: http://pietvanoostrum.com [PGP 8DAE142BE17999C4]
Private email: pi...@vanoostrum.org

Steven D'Aprano

unread,
Jul 7, 2009, 1:07:08 AM7/7/09
to
On Mon, 06 Jul 2009 15:02:26 -0700, Michael Mossey wrote:

> On Jul 6, 2:47 pm, Philip Semanchuk <phi...@semanchuk.com> wrote:
>> On Jul 6, 2009, at 5:37 PM, Michael Mossey wrote:
>>
>> > What is required in a python program to make sure it catches a
>> > control-
>> > c on the command-line? Do some i/o? The OS here is Linux.
>>
>> You can use a try/except to catch a KeyboardInterrupt exception, or you
>> can trap it using the signal
>> module:http://docs.python.org/library/signal.html
>>
>> You want to trap SIGINT.
>>
>> HTH
>> Philip
>
> Thanks to both of you. However, my question is also about whether I need
> to be doing i/o or some similar operation for my program to notice in
> any shape or form that Control-C has been pressed. In the past, I've
> written Python programs that go about their business ignoring Ctrl-C.

I bet that somewhere in your code you have something like:


for x in really_big_list:
try:
long_running_process(x)
except:
continue


If that's what you're doing, stop! The correct way is:


for x in really_big_list:
try:
long_running_process(x)
except Exception:
# Let KeyboardInterrupt and SystemExit through.
continue


or even:

for x in really_big_list:
try:
long_running_process(x)
except (KeyboardInterrupt, SystemExit):
print "User requested exit... shutting down now"
cleanup()
raise
except Exception:
continue

--
Steven

Simon Forman

unread,
Jul 7, 2009, 10:22:48 AM7/7/09
to

Try some experiments. ;]

Nick Craig-Wood

unread,
Jul 8, 2009, 6:30:01 AM7/8/09
to

Note that it is a relatively recent change (in python 2.5) which made
KeyboardInterrupt not a child of Exception

ncw@dogger:~$ python2.4
Python 2.4.6 (#2, Feb 17 2009, 20:01:48)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
Loaded customisations from '/home/ncw/.pystartup'
>>> isinstance(KeyboardInterrupt(), Exception)
True
>>>

ncw@dogger:~$ python2.5
Python 2.5.4 (r254:67916, Feb 17 2009, 20:16:45)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
Loaded customisations from '/home/ncw/.pystartup'
>>> isinstance(KeyboardInterrupt(), Exception)
False
>>>

> for x in really_big_list:
> try:
> long_running_process(x)
> except (KeyboardInterrupt, SystemExit):
> print "User requested exit... shutting down now"
> cleanup()
> raise
> except Exception:
> continue

That is the backwards compatible way

--
Nick Craig-Wood <ni...@craig-wood.com> -- http://www.craig-wood.com/nick

Lie Ryan

unread,
Jul 9, 2009, 9:20:19 AM7/9/09
to

Are you asking: "when would the python interpreter process
KeyboardInterrupt?"

In a multi threaded python program (where KeyboardInterrupt doesn't
always work), only the main thread can process KeyboardInterrupt; thus
the main thread must regain control before the interrupt is raised.
Normally, python will context switch (i.e. thread switch) every 100
interpreter "ticks", but when the interpreter received a SIGINT, the
interpreter will try to context switch as fast as it can (every tick) to
allow the main thread to regain control. So the answer is in
multithreaded python program: "when the main thread regains control"

In single threaded python program, the currently running thread is
always the main thread (which can handle KeyboardInterrupt). I believe
SIGINT is checked at every ticks. But SIGINT cannot interrupt atomic
operations (i.e. it cannot interrupt long operations that takes a single
tick).

An example, where python have difficulties processing KeyboardInterrupt:
>>> print 'foo'*10000000
...foofoofoo...
because printing a string is an atomic operation

I believe a tick in python is equivalent to a single bytecode, but
please correct me if I'm wrong.

Miles Kaufmann

unread,
Jul 9, 2009, 7:28:11 PM7/9/09
to pytho...@python.org
On Jul 9, 2009, at 9:20 AM, Lie Ryan wrote:

> Michael Mossey wrote:
>> I want to understand better what the "secret" is to responding to a
>> ctrl-C in any shape or form.
>

> Are you asking: "when would the python interpreter process
> KeyboardInterrupt?"

> ...


> In single threaded python program, the currently running thread is
> always the main thread (which can handle KeyboardInterrupt). I believe
> SIGINT is checked at every ticks. But SIGINT cannot interrupt atomic
> operations (i.e. it cannot interrupt long operations that takes a
> single
> tick).

Some otherwise atomic single-bytecode operations (like large integer
arithmetic) do manual checks for whether signals were raised (though
that won't help at all if the operation isn't on the main thread).

> I believe a tick in python is equivalent to a single bytecode, but
> please correct me if I'm wrong.

Not all opcodes qualify as a tick. In general, those opcodes that
cause control to remain in the eval loop (and not make calls to other
Python or C functions) don't qualify as ticks (but there are
exceptions, e.g. so that while True: pass is interruptible). In
Python/ceval.c: PyEval_EvalFrameEx(), those opcodes that don't end in
goto fast_next_opcode are ticks.

Please correct me if _I'm_ wrong! :)
-Miles

MCIPERF

unread,
Jul 15, 2009, 2:40:32 PM7/15/09
to

You don't need to do I/O.

This works:

try:
process_forever()
except KeyboardInterrupt:
save critical stuff
write nice messages

I often wrap a large computational task like this, with the idea that
the exception can let me exit safely, in my case by writing restart
parameters and printing a summary pf progress to date.

Gerry

0 new messages