Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #32035 > unrolled thread

resume execution after catching with an excepthook?

Started byandrea crotti <andrea.crotti.0@gmail.com>
First post2012-10-24 13:51 +0100
Last post2012-10-26 03:02 +1100
Articles 8 — 5 participants

Back to article view | Back to comp.lang.python


Contents

  resume execution after catching with an excepthook? andrea crotti <andrea.crotti.0@gmail.com> - 2012-10-24 13:51 +0100
    Re: resume execution after catching with an excepthook? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-10-25 01:15 +0000
      Re: resume execution after catching with an excepthook? andrea crotti <andrea.crotti.0@gmail.com> - 2012-10-25 15:27 +0100
      Re: resume execution after catching with an excepthook? Chris Angelico <rosuav@gmail.com> - 2012-10-26 01:51 +1100
        Re: resume execution after catching with an excepthook? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-10-25 15:40 +0000
      RE: resume execution after catching with an excepthook? "Prasad, Ramit" <ramit.prasad@jpmorgan.com> - 2012-10-25 20:59 +0000
    Re: resume execution after catching with an excepthook? Hans Mulder <hansmu@xs4all.nl> - 2012-10-25 17:31 +0200
      Re: resume execution after catching with an excepthook? Chris Angelico <rosuav@gmail.com> - 2012-10-26 03:02 +1100

#32035 — resume execution after catching with an excepthook?

Fromandrea crotti <andrea.crotti.0@gmail.com>
Date2012-10-24 13:51 +0100
Subjectresume execution after catching with an excepthook?
Message-ID<mailman.2758.1351083094.27098.python-list@python.org>
So I would like to be able to ask for confirmation when I receive a C-c,
and continue if the answer is "N/n".

I'm already using an exception handler set with sys.excepthook, but I
can't make it work with the confirm_exit, because it's going to quit in
any case..

A possible solution would be to do a global "try/except
KeyboardInterrupt", but since I already have an excepthook I wanted to
use this.  Any way to make it continue where it was running after the
exception is handled?


def confirm_exit():
    while True:
        q = raw_input("This will quit the program, are you sure? [y/N]")
        if q in ('y', 'Y'):
            sys.exit(0)
        elif q in ('n', 'N'):
            print("Continuing execution")
            # just go back to normal execution, is it possible??
            break


def _exception_handler(etype, value, tb):
    if etype == KeyboardInterrupt:
        confirm_exit()
    else:
        sys.exit(1)


def set_exception_handler():
    sys.excepthook = _exception_handler

[toc] | [next] | [standalone]


#32083

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2012-10-25 01:15 +0000
Message-ID<5088929e$0$29978$c3e8da3$5496439d@news.astraweb.com>
In reply to#32035
On Wed, 24 Oct 2012 13:51:30 +0100, andrea crotti wrote:

> So I would like to be able to ask for confirmation when I receive a C-c,
> and continue if the answer is "N/n".

I don't think there is any way to do this directly.

Without a try...except block, execution will cease after an exception is 
caught, even when using sys.excepthook. I don't believe that there is any 
way to jump back to the line of code that just failed (and why would you, 
it will just fail again) or the next line (which will likely fail because 
the previous line failed).

I think the only way you can do this is to write your own execution loop:

while True:
    try:
        run(next_command())
    except KeyboardInterrupt:
        if confirm_quit():
            break


Of course you need to make run() atomic, or use transactions that can be 
reverted or backed out of. How plausible this is depends on what you are 
trying to do -- Python's Ctrl-C is not really designed to be ignored.

Perhaps a better approach would be to treat Ctrl-C as an unconditional 
exit, and periodically poll the keyboard for another key press to use as 
a conditional exit. Here's a snippet of platform-specific code to get a 
key press:

http://code.activestate.com/recipes/577977

Note however that it blocks if there is no key press waiting.

I suspect that you may need a proper event loop, as provided by GUI 
frameworks, or curses.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#32129

Fromandrea crotti <andrea.crotti.0@gmail.com>
Date2012-10-25 15:27 +0100
Message-ID<mailman.2844.1351175253.27098.python-list@python.org>
In reply to#32083
2012/10/25 Steven D'Aprano <steve+comp.lang.python@pearwood.info>:
> On Wed, 24 Oct 2012 13:51:30 +0100, andrea crotti wrote:
>
>> So I would like to be able to ask for confirmation when I receive a C-c,
>> and continue if the answer is "N/n".
>
> I don't think there is any way to do this directly.
>
> Without a try...except block, execution will cease after an exception is
> caught, even when using sys.excepthook. I don't believe that there is any
> way to jump back to the line of code that just failed (and why would you,
> it will just fail again) or the next line (which will likely fail because
> the previous line failed).
>
> I think the only way you can do this is to write your own execution loop:
>
> while True:
>     try:
>         run(next_command())
>     except KeyboardInterrupt:
>         if confirm_quit():
>             break
>
>
> Of course you need to make run() atomic, or use transactions that can be
> reverted or backed out of. How plausible this is depends on what you are
> trying to do -- Python's Ctrl-C is not really designed to be ignored.
>
> Perhaps a better approach would be to treat Ctrl-C as an unconditional
> exit, and periodically poll the keyboard for another key press to use as
> a conditional exit. Here's a snippet of platform-specific code to get a
> key press:
>
> http://code.activestate.com/recipes/577977
>
> Note however that it blocks if there is no key press waiting.
>
> I suspect that you may need a proper event loop, as provided by GUI
> frameworks, or curses.
>
>
>
> --
> Steven
> --
> http://mail.python.org/mailman/listinfo/python-list



Ok thanks, but here the point is not to resume something that is going
to fail again, just to avoid accidental kill of processes that take a
long time.  Probably needed only by me in debugging mode, but anyway I
can do the simple try/except then, thanks..

[toc] | [prev] | [next] | [standalone]


#32130

FromChris Angelico <rosuav@gmail.com>
Date2012-10-26 01:51 +1100
Message-ID<mailman.2845.1351176706.27098.python-list@python.org>
In reply to#32083
On Thu, Oct 25, 2012 at 12:15 PM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> I don't believe that there is any
> way to jump back to the line of code that just failed (and why would you,
> it will just fail again)

There are several reasons to retry something after an exception,
mainly if some external state gets changed. Virtual memory is usually
implemented using traps, so the OS handles an interrupt by paging
something in from the disk, then retrying the "failing" instruction.
The old-favorite "Abort, retry, ignore[, fail]?" prompt from DOS has
the same notion; you tried to save a file onto a write-protected
floppy disk, an exception is thrown, you handle the exception by
getting the user to unprotect or change disks, and you resume where
you left off. CPU-level interrupts always have a return address for
that exact reason.

Handling Ctrl-C in this way makes a lot of sense. Give the user the
option to try to abort, but then to optionally change his/her mind and
keep going. Or possibly have a third option: break out of the current
operation and go back to some primary loop (throw the exception and
let it be caught at the main loop).

Arguably the problem here is that KeyboardInterrupt is an exception.
Perhaps a more classic signal handling structure should be used: when
signal received, call function. That function then has the power to
raise an exception, which will propagate through whatever code is
currently executing. This sort of thing would have all the usual
dangers of signal handlers, though; you have NO IDEA what state the
program's in, so you have to be ubercareful of what globals you use or
change.

ChrisA

[toc] | [prev] | [next] | [standalone]


#32136

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2012-10-25 15:40 +0000
Message-ID<50895d7b$0$29978$c3e8da3$5496439d@news.astraweb.com>
In reply to#32130
On Fri, 26 Oct 2012 01:51:43 +1100, Chris Angelico wrote:

> On Thu, Oct 25, 2012 at 12:15 PM, Steven D'Aprano
> <steve+comp.lang.python@pearwood.info> wrote:
>> I don't believe that there is any
>> way to jump back to the line of code that just failed (and why would
>> you, it will just fail again)
> 
> There are several reasons to retry something after an exception, 

I'm sure there are, but you're taking my point out of context. 

Andrea described his problem as *continuing*, not *re-trying*. I 
understand that re-trying operations is useful:

while True:
    try:
        some_operation()
    except SomeException:
        if not retry():
            break  # or raise an exception, or return


but I wouldn't describe that as "continuing", as Andrea did. I understand 
that as:

try:
    operation(1)
    operation(2)
    operation(3)
    operation(4)
    # and so forth...
except SomeException:
    if retry():
        # Magically jump back to the operation that was
        # active when the exception occurred.
        magic_happens_here()


If you could guarantee that each operation(N) was atomic ("all or 
nothing" -- it either succeeds, or has no effect) then such a feature 
would be useful. But as far as I know, you can't jump back into a try 
block from the except block, and even if you could, what's to stop the 
operation from failing again and again and again?
        
In Andrea's case, the failure he is worried about is "oops, I hit Ctrl-C 
when I actually wanted to not hit Ctrl-C", so presumably the failure 
wouldn't reoccur if you could jump backwards. But in any case, I can see 
no obvious way to make it work.

The python debugger pdb has a "jump" command that allows you to step 
backwards and re-execute code under certain conditions, so perhaps it is 
not quite impossible.

(I'm tempted to reply that the actual solution to this problem of 
accidentally hitting Ctrl-C is "well don't do that then".)



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#32164

From"Prasad, Ramit" <ramit.prasad@jpmorgan.com>
Date2012-10-25 20:59 +0000
Message-ID<mailman.2866.1351198768.27098.python-list@python.org>
In reply to#32083
andrea crotti wrote:
> 2012/10/25 Steven D'Aprano <steve+comp.lang.python@pearwood.info>:
> > On Wed, 24 Oct 2012 13:51:30 +0100, andrea crotti wrote:
> >
[snip]
> > Without a try...except block, execution will cease after an exception is
> > caught, even when using sys.excepthook. I don't believe that there is any
> > way to jump back to the line of code that just failed (and why would you,
> > it will just fail again) or the next line (which will likely fail because
> > the previous line failed).
> >
> > I think the only way you can do this is to write your own execution loop:
> >
> > while True:
> >     try:
> >         run(next_command())
> >     except KeyboardInterrupt:
> >         if confirm_quit():
> >             break
> >
> >
> > Of course you need to make run() atomic, or use transactions that can be
> > reverted or backed out of. How plausible this is depends on what you are
> > trying to do -- Python's Ctrl-C is not really designed to be ignored.
> >
> > Perhaps a better approach would be to treat Ctrl-C as an unconditional
> > exit, and periodically poll the keyboard for another key press to use as
> > a conditional exit. Here's a snippet of platform-specific code to get a
> > key press:
> >
> > http://code.activestate.com/recipes/577977
> >
> > Note however that it blocks if there is no key press waiting.
> >
> > I suspect that you may need a proper event loop, as provided by GUI
> > frameworks, or curses.
> >
> 
> Ok thanks, but here the point is not to resume something that is going
> to fail again, just to avoid accidental kill of processes that take a
> long time.  Probably needed only by me in debugging mode, but anyway I
> can do the simple try/except then, thanks..

On the other hand, if you store state externally (pickle?) maybe 
you can just restart at the last "check point". That way even if
the program dies you can recover on the next run.

Ramit Prasad


This email is confidential and subject to important disclaimers and
conditions including on offers for the purchase or sale of
securities, accuracy and completeness of information, viruses,
confidentiality, legal privilege, and legal entity disclaimers,
available at http://www.jpmorgan.com/pages/disclosures/email.  

[toc] | [prev] | [next] | [standalone]


#32134

FromHans Mulder <hansmu@xs4all.nl>
Date2012-10-25 17:31 +0200
Message-ID<50895b4f$0$6931$e4fe514c@news2.news.xs4all.nl>
In reply to#32035
On 24/10/12 14:51:30, andrea crotti wrote:
> So I would like to be able to ask for confirmation when I receive a C-c,
> and continue if the answer is "N/n".
> 
> I'm already using an exception handler set with sys.excepthook, but I
> can't make it work with the confirm_exit, because it's going to quit in
> any case..
> 
> A possible solution would be to do a global "try/except
> KeyboardInterrupt", but since I already have an excepthook I wanted to
> use this.  Any way to make it continue where it was running after the
> exception is handled?
> 
> 
> def confirm_exit():
>     while True:
>         q = raw_input("This will quit the program, are you sure? [y/N]")
>         if q in ('y', 'Y'):
>             sys.exit(0)
>         elif q in ('n', 'N'):
>             print("Continuing execution")
>             # just go back to normal execution, is it possible??
>             break
> 
> 
> def _exception_handler(etype, value, tb):
>     if etype == KeyboardInterrupt:
>         confirm_exit()
>     else:
>         sys.exit(1)
> 
> 
> def set_exception_handler():
>     sys.excepthook = _exception_handler

I think the trick is to not use an except hook, but trap the
interrupt on a lower level.

This seems to work; I'm not sure how robust it is:

import signal

def handler(signum, frame):
    while True:
        q = raw_input("This will quit the program, are you sure? [y/N]")
        if q[:1] in "yY":
            raise KeyboardInterrupt
        elif q[:1] in "nN":
            print("Continuing execution")
            # just go back to normal execution
            return

signal.signal(signal.SIGINT, handler)


If you're debugging this on a Unix platform, it may help to know
that you can also kill a process with control-\

Hope this helps,

-- HansM

[toc] | [prev] | [next] | [standalone]


#32138

FromChris Angelico <rosuav@gmail.com>
Date2012-10-26 03:02 +1100
Message-ID<mailman.2850.1351180934.27098.python-list@python.org>
In reply to#32134
On Fri, Oct 26, 2012 at 2:31 AM, Hans Mulder <hansmu@xs4all.nl> wrote:
> This seems to work; I'm not sure how robust it is:
>
> import signal
>
> def handler(signum, frame):
>     while True:
>         q = raw_input("This will quit the program, are you sure? [y/N]")
>         if q[:1] in "yY":
>             raise KeyboardInterrupt
>         elif q[:1] in "nN":
>             print("Continuing execution")
>             # just go back to normal execution
>             return
>
> signal.signal(signal.SIGINT, handler)
>

Yes, that's what I was talking about. You do have to be fairly careful
what you do (for instance, what should happen if the user hits Ctrl-C
during handler()? Default is that it'll raise KeyboardInterrupt
unconditionally), but you have perfect flexibility.

ChrisA

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web