poethepoet
poethepoet copied to clipboard
ValueError: Unsupported signal: 2
For a complicated, multi-threaded application that uses zmq
, I get the following error when I Ctrl-C the application that I started using poe to run the task "poetry run python .\\main.py"
Traceback (most recent call last):
File "C:\Users\dmwyatt\AppData\Local\Programs\Python\Python39\lib\runpy.py", line 197, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:\Users\dmwyatt\AppData\Local\Programs\Python\Python39\lib\runpy.py", line 87, in _run_code
exec(code, run_globals)
File "C:\Users\dmwyatt\AppData\Local\pypoetry\Cache\virtualenvs\win-backup-exclude-MbZQpObE-py3.9\Scripts\poe.exe\__main__.py", line 7, in <module>
File "C:\Users\dmwyatt\AppData\Local\pypoetry\Cache\virtualenvs\win-backup-exclude-MbZQpObE-py3.9\lib\site-packages\poethepoet\__init__.py", line 32, in main
result = app(cli_args=sys.argv[1:])
File "C:\Users\dmwyatt\AppData\Local\pypoetry\Cache\virtualenvs\win-backup-exclude-MbZQpObE-py3.9\lib\site-packages\poethepoet\app.py", line 52, in __call__
return self.run_task() or 0
File "C:\Users\dmwyatt\AppData\Local\pypoetry\Cache\virtualenvs\win-backup-exclude-MbZQpObE-py3.9\lib\site-packages\poethepoet\app.py", line 80, in run_task
return self.task.run(
File "C:\Users\dmwyatt\AppData\Local\pypoetry\Cache\virtualenvs\win-backup-exclude-MbZQpObE-py3.9\lib\site-packages\poethepoet\task\base.py", line 142, in run
return self._handle_run(context, extra_args, env)
File "C:\Users\dmwyatt\AppData\Local\pypoetry\Cache\virtualenvs\win-backup-exclude-MbZQpObE-py3.9\lib\site-packages\poethepoet\task\cmd.py", line 39, in _handle_run
return context.get_executor(env, self.options.get("executor")).execute(cmd)
File "C:\Users\dmwyatt\AppData\Local\pypoetry\Cache\virtualenvs\win-backup-exclude-MbZQpObE-py3.9\lib\site-packages\poethepoet\executor\poetry.py", line 31, in execute
return self._execute_cmd(cmd, input)
File "C:\Users\dmwyatt\AppData\Local\pypoetry\Cache\virtualenvs\win-backup-exclude-MbZQpObE-py3.9\lib\site-packages\poethepoet\executor\poetry.py", line 64, in _execute_cmd
return self._exec_via_subproc(
File "C:\Users\dmwyatt\AppData\Local\pypoetry\Cache\virtualenvs\win-backup-exclude-MbZQpObE-py3.9\lib\site-packages\poethepoet\executor\base.py", line 134, in _exec_via_subproc
proc.communicate(input)
File "C:\Users\dmwyatt\AppData\Local\Programs\Python\Python39\lib\subprocess.py", line 1126, in communicate
self.wait()
File "C:\Users\dmwyatt\AppData\Local\Programs\Python\Python39\lib\subprocess.py", line 1189, in wait
return self._wait(timeout=timeout)
File "C:\Users\dmwyatt\AppData\Local\Programs\Python\Python39\lib\subprocess.py", line 1470, in _wait
result = _winapi.WaitForSingleObject(self._handle,
File "C:\Users\dmwyatt\AppData\Local\pypoetry\Cache\virtualenvs\win-backup-exclude-MbZQpObE-py3.9\lib\site-packages\poethepoet\executor\base.py", line 129, in handle_signal
proc.send_signal(signum)
File "C:\Users\dmwyatt\AppData\Local\Programs\Python\Python39\lib\subprocess.py", line 1545, in send_signal
raise ValueError("Unsupported signal: {}".format(sig))
ValueError: Unsupported signal: 2
Other notes
- Other sorts of tasks like
format = "black ."
run just fine, so it has something to do with how poe is running my application. - If I don't use poe to run my application it exits just fine without a traceback.
- The last things my application does when exiting via a
try...finally
block is terminating thezmq
context and closing several sockets...but removing those actions doesn't solve this traceback popping up. - I can try to come up with a minimal reproduction, but I expect that to be difficult so I wanted to see if anyone had any ideas first.
Hi @dmwyatt, thanks for the feedback.
I made a quick investigation, and it looks like this is an issue with how SIGTERM signals work on windows (i.e. they don't), reference: https://stackoverflow.com/questions/47306805/signal-sigterm-not-received-by-subprocess-on-windows
I don't really know much about windows, and the links from that discussion on stack overflow seem to suggest that it's non-trivial to get this to work properly. So since I don't have a proper windows dev environment to hand, I'll need some help with this one. The relevant code is around here.
Hi, I just got hit with the issue trying to run a "docker compose up" through poe on windows.
It looks like from the send_signal
implementation for windows that there're only a few signals you can send to a subproc:
def send_signal(self, sig):
"""Send a signal to the process."""
# Don't signal a process that we know has already died.
if self.returncode is not None:
return
if sig == signal.SIGTERM:
self.terminate()
elif sig == signal.CTRL_C_EVENT:
os.kill(self.pid, signal.CTRL_C_EVENT)
elif sig == signal.CTRL_BREAK_EVENT:
os.kill(self.pid, signal.CTRL_BREAK_EVENT)
else:
raise ValueError("Unsupported signal: {}".format(sig))
Considering this and the fact that a SIGTERM actually calls terminate()
on the subprocess, I managed to make my use case work by hacking the SIGINT handler handle_signal
into sending a SIGTERM signal instead to the subprocess. My subprocess (docker compose up) and poe are all terminating gracefully.
With a check on the platform first, that could be one way to solve it, though I have no idea if and how it would work on a more general basis.
Actually, it might be better to send a CTRL_C_EVENT than a SIGTERM.
So the code modification could look like this:
# signal pass through
def handle_signal(signum, _frame):
# sigint is not handled on windows
signum = signal.CTRL_C_EVENT if self._is_windows else signum
proc.send_signal(signum)
old_signal_handler = signal.signal(signal.SIGINT, handle_signal)
Hi @JCapul,
Thanks for the investigation. That sounds reasonable. I'll add this to be TODO list for the next release. Or feel free to open a PR for it :)