2016-07-24 4 views
1

Ich bin am irren, versuchen, etwas ähnliches IPython/Jupyter Notebooks zu bauen. Ich schreibe meine Anwendung in QT5, so viel davon hängt mit dem "Einbetten" von Python in einer nativen Anwendung zusammen.Embedded Python stürzt beim Import von Matplotlib.pyplot

Ich habe herausgefunden, wie man Python einbetten kann und wie man Skripte ausführen kann, die vom Benutzer eingegeben werden. Ich möchte in der Lage sein, Plotbibliotheken (wie Matplotlib) zu verwenden und ihre Ausgabe in meiner Anwendung anzuzeigen. (Tatsächlich scheint das, was ich zu tun versuche, sehr ähnlich dem zu sein, was in this question beschrieben ist).

Wenn ich jedoch versuche, die Plot-Bibliothek mit import matplotlib.pyplot zu importieren, meine Anwendung segfaults (Ich habe versucht zu debuggen, aber der Absturz ist nicht in meinem Code, so kann ich nichts vernünftiges daraus bekommen).

Der Code, den ich verwende, um das eingebettete Python zu initialisieren und willkürliche Skripts auszuführen, wird am Ende dieser Frage angezeigt.

Ich kann andere Bibliotheken (wie sys oder numpy) in Ordnung importieren. Ich kann matplotlib in Ordnung importieren. Aber wenn ich versuche, matplotlib.pyplot zu importieren, segfaults.

Hat jemand irgendwelche Vorschläge?

EDIT: Ich habe festgestellt, dass die Ursache (aus irgendeinem Grund) bei mir mit QT liegt. Wenn ich eine einfache C oder C++ Programm kompilieren, die matplotlib importiert, hat es nicht segfault ...

Mein Code:

#include "pythoninteractor.h" 

#include <QString> 
#include <Python.h> 
#include <string> 
#include <QList> 

PythonInteractor::PythonInteractor() 
{ 
    this->pyOutput_redir = 
"import sys\n\ 
class CatchOutErr:\n\ 
    def __init__(self):\n\ 
     self.value = ''\n\ 
    def write(self, txt):\n\ 
     self.value += txt\n\ 
catchOutErr = CatchOutErr()\n\ 
sys.stdout = catchOutErr\n\ 
sys.stderr = catchOutErr\n\ 
"; //this is python code to redirect stdouts/stderr 


    QString paths[] = {"", 
         "/home/tcpie/anaconda3/lib/python35.zip", 
         "/home/tcpie/anaconda3/lib/python3.5", 
         "/home/tcpie/anaconda3/lib/python3.5/plat-linux", 
         "/home/tcpie/anaconda3/lib/python3.5/lib-dynload", 
         "/home/tcpie/anaconda3/lib/python3.5/site-packages",}; 

    Py_SetProgramName(L"qt-notepad-tut"); 
    Py_Initialize(); 

    PyObject *pModule = PyImport_AddModule("__main__"); //create main module 
    PyRun_SimpleString(this->pyOutput_redir.toStdString().c_str()); //invoke code to redirect 

    PyObject *sys_path; 
    PyObject *path; 

    sys_path = PySys_GetObject("path"); 
    if (sys_path == NULL) 
     return; 

    PySequence_DelSlice(sys_path, 0, PySequence_Length(sys_path)); 
    for (size_t i = 0; i < sizeof(paths)/sizeof(QString); i++) { 
     path = PyUnicode_FromString(paths[i].toStdString().c_str()); 

     if (path == NULL) 
      continue; 

     if (PyList_Append(sys_path, path) < 0) 
      continue; 
    } 
} 

QString PythonInteractor::run_script(QString script) 
{ 
    QString ret = ""; 
    PyObject *pModule = PyImport_AddModule("__main__"); 
    PyRun_SimpleString(script.toStdString().c_str()); 
    PyErr_Print(); //make python print any errors 

    PyObject *catcher = PyObject_GetAttrString(pModule,"catchOutErr"); //get our catchOutErr created above 

    if (catcher == NULL) { 
     Py_Finalize(); 
     return ret; 
    } 

    PyObject *output = PyObject_GetAttrString(catcher,"value"); //get the stdout and stderr from our catchOutErr object 

    if (output == NULL) { 
     return ret; 
    } 

    ret = QString(PyUnicode_AsUTF8(output)); 
    return ret; 
} 
+0

Warum versuchen Sie, Python einzubetten? – user4759923

+0

Ich möchte sehen, ob ich etwas ähnliches zu IPython-Notebooks machen kann, aber in einer nativen Anwendung. – tcpie

+0

Ich bezweifle, dass das Sinn macht (Qt ist sehr gut) – user4759923

Antwort

2

Der Grund dieser Absturz erwies sich als ein Konflikt zwischen QT-Versionen zu sein .

Zunächst kann das Problem mit dem folgenden minimalen Code reproduziert werden. Das Auskommentieren der Zeile "Q_OBJECT" in main.h verhindert in allen Fällen den Absturz.

Datei main.h:

#ifndef MAIN_H 
#define MAIN_H 

#include <QMainWindow> 

class test : public QMainWindow 
{ 
    Q_OBJECT // Commenting out this line prevents the crash 
}; 

#endif // MAIN_H 

Datei main.cpp:

#include <Python.h> 
#include "main.h" 

int main() 
{ 
    Py_Initialize(); 
    PyRun_SimpleString("import matplotlib.pyplot as plt");  
    PyRun_SimpleString("print('If we are here, we did not crash')"); 

    Py_Finalize(); 
    return 0; 
} 

ich Python3 durch Anaconda leite. Allerdings hatte ich QT5 über meinen Paket-Manager installiert (in meinem Fall: apt-get auf Ubuntu). Ich vermute, das Problem liegt in der Installation meiner Anaconda-Installation unter Verwendung einer anderen QT5-Version als derjenigen, die ich über meinen Paket-Manager installiert hatte.

Die Lösung ist einfach: Die Installation von Matplotlib über meinen Paket-Manager behebt das Problem! (auf meinem Ubuntu-System: sudo apt-get install python3-matplotlib)