cdo-bindings icon indicating copy to clipboard operation
cdo-bindings copied to clipboard

Process using cdo cannot be ctrl-C'd

Open nikola-rados opened this issue 4 years ago • 6 comments

Running a process with a Cdo() interface instantiated in a python module does not allow for a ctrl-C exit. This is likely a problem with the signal handling. It looks like the issue may be here, where some cleanup occurs but the signal is ignored (using signal.raise may solve the issue).

nikola-rados avatar Mar 02 '20 23:03 nikola-rados

hi! I didn't get a notification, sorry. Could you use ctrl-D? it works for me.

Try2Code avatar May 04 '20 13:05 Try2Code

Hello! Sorry I must have missed your notification as well. No, crtl-D doesn't work. Here is what the terminal output looks like when I try to crtl-C:

^Ccaught signal <cdo.Cdo object at 0x7f9c262dde10> 2 <frame object at 0x2307e88

nikola-rados avatar May 28 '20 22:05 nikola-rados

I work on a new cdo.py release 2.0 with a new interface. Will take of this for 2.0 then.

thx for your patience

Try2Code avatar Aug 10 '20 11:08 Try2Code

No problem! Thank you for addressing the issue.

nikola-rados avatar Aug 10 '20 15:08 nikola-rados

Think I duplicated this issue in #43. Also here's a possible workaround (although I can't test it -- seems the current master branch does not work right now). Inside Cdo.__init__ I replace the signal definitions with this:

        # handling different exits from interactive sessions {{{
        # python3 has threading.main_thread(), but python2 doesn't
        import functools
        if sys.version_info[0] == 2 \
                or threading.current_thread() is threading.main_thread():
            sigint_default = signal.getsignal(signal.SIGINT)
            sigterm_default = signal.getsignal(signal.SIGTERM)
            sigsegv_default = signal.getsignal(signal.SIGSEGV)
            sigint = functools.partial(self.__catch__, default=sigint_default)
            sigterm = functools.partial(self.__catch__, default=sigterm_default)
            sigsegv = functools.partial(self.__catch__, default=sigsegv_default)
            signal.signal(signal.SIGINT,  sigint)
            signal.signal(signal.SIGTERM, sigterm)
            signal.signal(signal.SIGSEGV, sigsegv)

and then replace Cdo.__catch__ with the following lines that throw the default handler after removing tempfiles:

    def __catch__(self, signum, frame, default=None):
        self.tempStore.__del__()
        if callable(default):
            default()
        else:
            print("caught signal", self, signum, frame)

lukelbd avatar Apr 23 '22 22:04 lukelbd

Ok while I couldn't test the above solution on the master branch, here's a simple workaround that succeeds with the latest stable version. I just call cdo = _init_cdo() instead of cdo = Cdo() in the python script or interactive session:

import signal
import threading
from cdo import Cdo
def _cdo_handler(cdo, handler):
    def _handle_signal(*args, **kwargs):
        cdo.tempStore.__del__()
        handler(*args, **kwargs)
    return _handle_signal
def _init_cdo():
    sigint = signal.getsignal(signal.SIGINT)
    sigterm = signal.getsignal(signal.SIGTERM)
    sigsegv = signal.getsignal(signal.SIGSEGV)
    cdo = Cdo()
    signal.signal(signal.SIGINT, _cdo_handler(cdo, sigint))
    signal.signal(signal.SIGTERM, _cdo_handler(cdo, sigterm))
    signal.signal(signal.SIGSEGV, _cdo_handler(cdo, sigsegv))
    return cdo

lukelbd avatar Apr 25 '22 01:04 lukelbd

Think this issue can be closed (see #44 merge)

lukelbd avatar Jun 09 '23 19:06 lukelbd