Open linwaytin opened 5 years ago
Did you figure out what caused this? I'm just using Python to plot things with Matplotlib and I noticed that when I closed the window, I got the same error. I suspect it is some update in the QT library? It has only started happening after I updated. Thanks!
I have no idea but I do think it's related to the graphical backend. Did you have the error in running the script or in the REPL environment?
I can reproduce the problem. It's not a "crash", just an exception. You can reproduce it interactively with:
using PyPlot
matplotlib."interactive"(false)
plot([2,4], [3,8])
show()
which throws the error after closing the window. Interestingly, if you call the plot
and show
functions a second time in the same session, there is no error.
The exception is triggered by this line in the qt5 backend, and I can reproduce it as follows:
using PyCall
signal = pyimport("signal")
old_signal = pycall(signal."getsignal", PyObject, signal."SIGINT")
pycall(signal."signal", PyObject, signal."SIGINT", old_signal)
The problem seems to be that old_signal
is PyObject None
, probably because no signal handler has been set for embedded Python usage, but None
is not accepted as an argument to signal.signal
. (This seems like a bug in Python? signal
should accept the return value of getsignal
…)
Meanwhile, we can probably work around it by setting the handler to SIG_DFL
, e.g. doing this before plotting eliminates the exception:
let signal = PyPlot.PyCall.pyimport("signal")
signal."signal"(signal."SIGINT", signal."SIG_DFL")
end
but I'm not sure if that's the correct behavior in general… the interaction of Python signal handling with Julia signal handling is a little murky.
Basically, the problem is that Julia installs its own SIGINT
handler, and the Python signals module doesn't know how to save/restore signal handlers when that happens. The following stand-alone embedded Python code in C reproduces the same TypeError: signal handler must be ...
problem:
#include <Python.h>
#include <signal.h>
#include <stdio.h>
void myhandler(int sig) { printf("got signal %d\n", sig); }
int main(void)
{
signal(SIGINT, myhandler);
Py_InitializeEx(0);
PyRun_SimpleString("import signal\n"
"old_signal = signal.getsignal(signal.SIGINT)\n"
"signal.signal(signal.SIGINT, old_signal)\n"
"print(old_signal)\n");
Py_Finalize();
return 0;
}
This will make it difficult to use PyCall with any module that tries to muck with the signal handlers.
Several things that could be done here:
CPython should arguably support this better — if old_signal
is None
, then signal.signal(signal.SIGINT, None)
shouldn't throw an error if the handler is not being changed, and signal.signal(signal.SIGINT, signal.SIG_DFL)
shouldn't change the signal handler. Filed https://bugs.python.org/issue39438
CPython should document that if getsignal
returns None
, then you probably shouldn't try to change the signal handler because there is no way to restore the old handler.
Matplotlib should not attempt to change the signal handler if getsignal
returns None
. (submitted PR: matplotlib/matplotlib#16311)
As a temporary workaround, we could monkey-patch Matplotlib to avoid changing the signal handler in the qt5 backend.
Should be fixed in matplotlib 3.1.3 (the next release).
The script is like this:
and then I run the script in a terminal. It shows a window displaying the plot. Everything is fine until the window is closed.
The error message is the following:
My julia version is 1.2.0.