resume execution after catching with an excepthook?

Discussion in 'Python' started by andrea crotti, Oct 24, 2012.

  1. 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
    andrea crotti, Oct 24, 2012
    #1
    1. Advertising

  2. 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
    Steven D'Aprano, Oct 25, 2012
    #2
    1. Advertising

  3. 2012/10/25 Steven D'Aprano <>:
    > 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..
    andrea crotti, Oct 25, 2012
    #3
  4. On Thu, Oct 25, 2012 at 12:15 PM, Steven D'Aprano
    <> 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
    Chris Angelico, Oct 25, 2012
    #4
  5. andrea crotti

    Hans Mulder Guest

    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
    Hans Mulder, Oct 25, 2012
    #5
  6. On Fri, 26 Oct 2012 01:51:43 +1100, Chris Angelico wrote:

    > On Thu, Oct 25, 2012 at 12:15 PM, Steven D'Aprano
    > <> 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
    Steven D'Aprano, Oct 25, 2012
    #6
  7. On Fri, Oct 26, 2012 at 2:31 AM, Hans Mulder <> 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
    Chris Angelico, Oct 25, 2012
    #7
  8. andrea crotti wrote:

    > 2012/10/25 Steven D'Aprano <>:

    > > 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 thepurchase 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.
    Prasad, Ramit, Oct 25, 2012
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alex
    Replies:
    0
    Views:
    311
  2. Tony
    Replies:
    4
    Views:
    1,043
    vegetablevn
    Sep 27, 2010
  3. Miki Tebeka

    Freeze and Resume execution

    Miki Tebeka, May 20, 2004, in forum: Python
    Replies:
    8
    Views:
    412
    Miki Tebeka
    May 24, 2004
  4. Hari Sekhon

    catching syntax errors via excepthook?

    Hari Sekhon, Jul 3, 2006, in forum: Python
    Replies:
    1
    Views:
    411
    Alex Martelli
    Jul 3, 2006
  5. Stephen Lead
    Replies:
    3
    Views:
    245
    Aldric Giacomoni
    Oct 14, 2009
Loading...

Share This Page