itom 2.2.1
K:/git-itom/sources/itom/Qitom/python/pythonEngine.h
00001 /* ********************************************************************
00002     itom software
00003     URL: http://www.uni-stuttgart.de/ito
00004     Copyright (C) 2016, Institut fuer Technische Optik (ITO),
00005     Universitaet Stuttgart, Germany
00006 
00007     This file is part of itom.
00008   
00009     itom is free software; you can redistribute it and/or modify it
00010     under the terms of the GNU Library General Public Licence as published by
00011     the Free Software Foundation; either version 2 of the Licence, or (at
00012     your option) any later version.
00013 
00014     itom is distributed in the hope that it will be useful, but
00015     WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library
00017     General Public Licence for more details.
00018 
00019     You should have received a copy of the GNU Library General Public License
00020     along with itom. If not, see <http://www.gnu.org/licenses/>.
00021 *********************************************************************** */
00022 
00023 #ifndef PYTHONENGINE_H
00024 #define PYTHONENGINE_H
00025 
00026 /*if you add any include to this file you will DIE an immediate, horrible, painful death*/
00027 
00028 #include <string>
00029 #include <exception>
00030 //#ifndef Q_MOC_RUN
00031 //    #define PY_ARRAY_UNIQUE_SYMBOL itom_ARRAY_API
00032 //    #define NO_IMPORT_ARRAY
00033 //#endif
00034 
00035 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION //see comment in pythonNpDataObject.cpp
00036 
00037 #ifndef Q_MOC_RUN
00038     //python
00039     // see http://vtk.org/gitweb?p=VTK.git;a=commitdiff;h=7f3f750596a105d48ea84ebfe1b1c4ca03e0bab3
00040     #if (defined _DEBUG) && (defined WIN32)
00041         #undef _DEBUG
00042         #if (defined linux) | (defined CMAKE)
00043             #include "Python.h"
00044             #include "node.h"
00045             #include "numpy/arrayobject.h"
00046         #elif (defined __APPLE__) | (defined CMAKE)
00047             #include "Python.h"
00048             #include "node.h"
00049             #include "numpy/arrayobject.h"
00050         #else
00051             #include "Python.h"
00052             #include "node.h"
00053             #include "../Lib/site-packages/numpy/core/include/numpy/arrayobject.h" //for numpy arrays
00054         #endif
00055         #define _DEBUG
00056     #else
00057     #ifdef linux
00058         #include "Python.h"
00059         #include "node.h"
00060         #include "numpy/arrayobject.h"
00061     #elif (defined __APPLE__)
00062         #include "Python.h"
00063         #include "node.h"
00064         #include "numpy/arrayobject.h"
00065     #else
00066         #include "Python.h"
00067         #include "node.h"
00068         #include "../Lib/site-packages/numpy/core/include/numpy/arrayobject.h" //for numpy arrays
00069     #endif
00070     #endif
00071 #endif // Q_MOC_RUN
00072 
00073 /* includes */
00074 
00075 #include "pythonNpDataObject.h"
00076 #include "pythonItom.h"
00077 #include "pythonProxy.h"
00078 #include "pythonStream.h"
00079 
00080 #include "../models/breakPointModel.h"
00081 #include "../../common/sharedStructuresQt.h"
00082 #include "../../common/addInInterface.h"
00083 #include "../global.h"
00084 
00085 #include "pythonWorkspace.h"
00086 
00087 #include <qstringlist.h>
00088 #include <qqueue.h>
00089 #include <qset.h>
00090 #include <qpointer.h>
00091 #include <qatomic.h>
00092 
00093 
00094 /* definition and macros */
00095 
00096 /* global variables (avoid) */
00097 
00098 /* content */
00099 
00100 class QDesktopWidget;
00101 class QTimer;
00102 
00103 namespace ito
00104 {
00105 
00106 class FuncWeakRef
00107 {
00108 public:
00109     FuncWeakRef();
00110     FuncWeakRef(PythonProxy::PyProxy *proxyObject, PyObject *argTuple = NULL);
00111     FuncWeakRef(const FuncWeakRef &rhs);
00112     ~FuncWeakRef();
00113     FuncWeakRef& operator =(FuncWeakRef rhs);
00114 
00115     PythonProxy::PyProxy* getProxyObject() const { return m_proxyObject; } //borrowed reference
00116     PyObject* getArguments() const { return m_argument; } //borrowed reference
00117     bool isValid() const { return (m_proxyObject != NULL); }
00118 
00119     void setHandle(const size_t &handle);
00120     size_t getHandle() const { return m_handle; }
00121 private:
00122     PythonProxy::PyProxy *m_proxyObject;
00123     PyObject *m_argument;
00124     size_t m_handle;
00125 };
00126 
00127 
00128 class PythonEngine : public QObject
00129 {
00130     Q_OBJECT
00131 
00132 public:
00133     PythonEngine();                                 //constructor
00134     ~PythonEngine();                                //destructor
00135 
00136     Q_INVOKABLE void pythonSetup(ito::RetVal *retValue);               //setup
00137     Q_INVOKABLE ito::RetVal scanAndRunAutostartFolder(QString currentDirAfterScan = QString() );
00138     Q_INVOKABLE ito::RetVal pythonShutdown(ItomSharedSemaphore *aimWait = NULL);            //shutdown
00139     Q_INVOKABLE ito::RetVal stringEncodingChanged();
00140 
00141     inline ito::BreakPointModel *getBreakPointModel() const { return bpModel; }
00142     inline bool isPythonBusy() const                { return pythonState != ito::pyStateIdle; }
00143     inline bool isPythonDebugging() const           { return (pythonState == ito::pyStateDebuggingWaitingButBusy || pythonState == ito::pyStateDebugging || pythonState == ito::pyStateDebuggingWaiting); }
00144     inline bool isPythonDebuggingAndWaiting() const { return pythonState == ito::pyStateDebuggingWaiting; }
00145     inline bool execInternalCodeByDebugger() const  { return m_executeInternalPythonCodeInDebugMode; }
00146     inline void setExecInternalCodeByDebugger(bool value) { m_executeInternalPythonCodeInDebugMode = value; }
00147     ito::RetVal checkForPyExceptions();
00148     void printPythonErrorWithoutTraceback();
00149     void pythonDebugFunction(PyObject *callable, PyObject *argTuple, bool gilExternal = false);
00150     void pythonRunFunction(PyObject *callable, PyObject *argTuple, bool gilExternal = false);    
00151     inline PyObject *getGlobalDictionary()  const { return globalDictionary;  }  
00152     inline bool pySyntaxCheckAvailable() const { return (m_pyModSyntaxCheck != NULL); }
00153     QList<int> parseAndSplitCommandInMainComponents(const char *str, QByteArray &encoding) const; //can be directly called from different thread
00154     QString getPythonExecutable() const { return m_pythonExecutable; }
00155     Qt::HANDLE getPythonThreadId() const { return m_pythonThreadId; }
00156 
00157     static bool isInterruptQueued();
00158     static const PythonEngine *getInstance();
00159 protected:
00160     //RetVal syntaxCheck(char* pythonFileName);       // syntaxCheck for file with filename pythonFileName
00161     ito::RetVal runPyFile(const QString &pythonFileName);         // run file pythonFileName
00162     ito::RetVal debugFile(const QString &pythonFileName);         // debug file pythonFileName
00163     ito::RetVal runString(const QString &command);          // run string command
00164     ito::RetVal debugString(const QString &command);        // debug string command
00165     ito::RetVal debugFunction(PyObject *callable, PyObject *argTuple, bool gilExternal = false);
00166     ito::RetVal runFunction(PyObject *callable, PyObject *argTuple, bool gilExternal = false);
00167 
00168     ito::RetVal modifyTracebackDepth(int NrOfLevelsToPopAtFront = -1, bool showTraceback = true);
00169 
00170     PyObject* setPyErrFromException(const std::exception &exc);
00171 
00172 #if QT_VERSION >= 0x050000
00173     void connectNotify(const QMetaMethod &signal);
00174 #else
00175     void connectNotify(const char* signal);
00176 #endif
00177 
00178 private:
00179     static PythonEngine *getInstanceInternal();
00180 
00181     inline PyObject *getLocalDictionary() { return localDictionary; } 
00183     PyObject *getPyObjectByFullName(bool globalNotLocal, const QStringList &fullNameSplittedByDelimiter, QString *validVariableName = NULL); //Python GIL must be locked when calling this function!
00184     PyObject *getPyObjectByFullName(bool globalNotLocal, const QString &fullName, QString *validVariableName = NULL); //Python GIL must be locked when calling this function!
00185 
00186     void setGlobalDictionary(PyObject* mainDict = NULL);
00187     void setLocalDictionary(PyObject* localDict);
00188 
00189     void emitPythonDictionary(bool emitGlobal, bool emitLocal, PyObject* globalDict, PyObject* localDict);
00190 
00191     ito::RetVal pickleDictionary(PyObject *dict, const QString &filename);
00192     ito::RetVal unpickleDictionary(PyObject *destinationDict, const QString &filename, bool overwrite);
00193 
00194     //methods for maintaining python functionality
00195     ito::RetVal addMethodToModule(PyMethodDef* def);
00196     ito::RetVal delMethodFromModule(const char* ml_name);
00197     ito::RetVal pythonAddBuiltinMethods();
00198 
00199     //methods for debugging
00200     void enqueueDbgCmd(ito::tPythonDbgCmd dbgCmd);
00201     ito::tPythonDbgCmd dequeueDbgCmd();
00202     bool DbgCommandsAvailable();
00203     void clearDbgCmdLoop();
00204 
00205     ito::RetVal pythonStateTransition(tPythonTransitions transition);
00206 
00207     //methods for breakpoint
00208     ito::RetVal pythonAddBreakpoint(const QString &filename, const int lineno, const bool enabled, const bool temporary, const QString &condition, const int ignoreCount, int &pyBpNumber);
00209     ito::RetVal pythonEditBreakpoint(const int pyBpNumber, const QString &filename, const int lineno, const bool enabled, const bool temporary, const QString &condition, const int ignoreCount);
00210     ito::RetVal pythonDeleteBreakpoint(const int pyBpNumber);
00211 
00212     ito::RetVal autoReloaderCheck();
00213 
00214     static int queuedInterrupt(void *state); 
00215 
00216     PyObject* getAndCheckIdentifier(const QString &identifier, ito::RetVal &retval) const;
00217     
00218 
00219     //member variables
00220     bool m_started;
00221     //QString m_itomMemberClasses;
00222 
00223     //PyGILState_STATE threadState;
00224 
00225     QMutex dbgCmdMutex;
00226     QMutex pythonStateChangeMutex;
00227     QMutex dictChangeMutex;
00228     QDesktopWidget *m_pDesktopWidget;
00229     QQueue<ito::tPythonDbgCmd> debugCommandQueue;
00230     ito::tPythonDbgCmd debugCommand;
00231     
00232     ito::tPythonState pythonState;
00233     
00234     ito::BreakPointModel *bpModel;
00235 
00236     PyObject* mainModule;          
00237     PyObject* mainDictionary;      
00238     PyObject* localDictionary;     
00239     PyObject* globalDictionary;    
00240     PyObject *itomDbgModule;       
00241     PyObject *itomDbgInstance;     
00242     PyObject *itomModule;          
00243     PyObject *itomFunctions;       
00244     PyObject *m_pyModGC;
00245     PyObject *m_pyModSyntaxCheck;
00246     //PyObject *itomReturnException; //!< if this exception is thrown, the execution of the main application is stopped
00247 
00248     Qt::HANDLE m_pythonThreadId;
00249 
00250     PyObject *dictUnicode;
00251 
00252     QSet<ito::PyWorkspaceContainer*> m_mainWorkspaceContainer;
00253     QSet<ito::PyWorkspaceContainer*> m_localWorkspaceContainer;
00254     QHash<size_t, FuncWeakRef> m_pyFuncWeakRefHashes; 
00255     size_t m_pyFuncWeakRefAutoInc;
00256 
00257     QString m_pythonExecutable; 
00258 
00259     bool m_executeInternalPythonCodeInDebugMode; 
00260     PyMethodDef* PythonAdditionalModuleITOM;
00261 
00262     // decides if itom is automatically included in every source file before it is handed to the syntax checker
00263     bool m_includeItomImportBeforeSyntaxCheck;
00264     QString m_includeItomImportString; 
00265 
00266     wchar_t *m_pUserDefinedPythonHome;
00267 
00268     struct AutoReload
00269     {
00270         PyObject *modAutoReload;
00271         PyObject *classAutoReload;
00272         bool enabled;
00273         bool checkFileExec;
00274         bool checkStringExec;
00275         bool checkFctExec;
00276     };
00277 
00278     AutoReload m_autoReload;
00279 
00281     static PyMethodDef PyMethodItomDbg[];
00282     static PyModuleDef PyModuleItomDbg;
00283     static PyObject* PyInitItomDbg(void);
00284     static PyObject* PyDbgCommandLoop(PyObject *pSelf, PyObject *pArgs);
00285 
00286     //helper methods
00287     //static PyObject* checkForTimeoutHelper(ItomSharedSemaphore* semaphore, int timeout, PyObject *retValueOk);
00288 
00289     //other static members
00290     static QMutex instatiated;
00291     static QMutex instancePtrProtection;
00292     static QString fctHashPrefix;
00293 
00294     static PythonEngine* instance;
00295 
00296     QAtomicInt m_interruptCounter; //protects that a python interrupt can only be placed if there is no interrupt event queued yet.
00297 
00298     // friend class
00299     friend class ito::PythonItom;
00300         friend class ito::PyStream;
00301 
00302 signals:
00303     void pythonDebugPositionChanged(QString filename, int lineNo);
00304     void pythonStateChanged(tPythonTransitions pyTransition);
00305     void pythonModifyLocalDict(PyObject* localDict, ItomSharedSemaphore* semaphore);
00306     void pythonModifyGlobalDict(PyObject* globalDict, ItomSharedSemaphore* semaphore);
00307     void pythonCurrentDirChanged();
00308     void updateCallStack(QStringList filenames, IntList lines, QStringList methods);
00309     void deleteCallStack();
00310 
00311     void pythonSetCursor(const Qt::CursorShape cursor);
00312     void pythonResetCursor();
00313     void pythonAutoReloadChanged(bool enabled, bool checkFile, bool checkCmd, bool checkFct);
00314     void clearCommandLine();
00315     void startInputCommandLine(QSharedPointer<QByteArray> buffer, ItomSharedSemaphore *semaphore);
00316 
00317 public slots:
00318     void pythonRunString(QString cmd);
00319     void pythonDebugString(QString cmd);
00320     void pythonExecStringFromCommandLine(QString cmd);
00321     void pythonRunFile(QString filename);
00322     void pythonDebugFile(QString filename);
00323     void pythonRunStringOrFunction(QString cmdOrFctHash);
00324     void pythonDebugStringOrFunction(QString cmdOrFctHash);
00325     void pythonInterruptExecution();
00326     void pythonDebugCommand(tPythonDbgCmd cmd);
00327 
00328     void setAutoReloader(bool enabled, bool checkFile, bool checkCmd, bool checkFct);
00329 
00330     // Settings are neccesary for automatic itom inclusion and syntax check
00331     void readSettings();
00332     void propertiesChanged();
00333 
00334     void pythonSyntaxCheck(const QString &code, QPointer<QObject> sender);
00335 
00336     void pythonGenericSlot(PyObject* callable, PyObject *argumentTuple);
00337 
00339     void breakPointAdded(BreakPointItem bp, int row);
00340     void breakPointDeleted(QString filename, int lineNo, int pyBpNumber);
00341     void breakPointChanged(BreakPointItem oldBp, BreakPointItem newBp);
00342     ito::RetVal setupBreakPointDebugConnections();
00343     ito::RetVal shutdownBreakPointDebugConnections();
00344 
00345     bool renameVariable(bool globalNotLocal, const QString &oldFullItemName, QString newKey, ItomSharedSemaphore *semaphore = NULL);
00346     bool deleteVariable(bool globalNotLocal, const QStringList &fullItemNames, ItomSharedSemaphore *semaphore = NULL);
00347     ito::RetVal pickleVariables(bool globalNotLocal, QString filename, QStringList varNames, ItomSharedSemaphore *semaphore = NULL);
00348     ito::RetVal pickleSingleParam(QString filename, QSharedPointer<ito::Param> value, const QString &valueName, ItomSharedSemaphore *semaphore = NULL);
00349     ito::RetVal unpickleVariables(bool globalNotLocal, QString filename, QString packedVarName, ItomSharedSemaphore *semaphore = NULL);
00350     ito::RetVal saveMatlabVariables(bool globalNotLocal, QString filename, QStringList varNames, ItomSharedSemaphore *semaphore = NULL);
00351     ito::RetVal saveMatlabSingleParam(QString filename, QSharedPointer<ito::Param> value, const QString &valueName, ItomSharedSemaphore *semaphore = NULL);
00352     ito::RetVal loadMatlabVariables(bool globalNotLocal, QString filename, QString packedVarName, ItomSharedSemaphore *semaphore = NULL);
00353     ito::RetVal registerAddInInstance(QString varname, ito::AddInBase *instance, ItomSharedSemaphore *semaphore = NULL);
00354     ito::RetVal getSysModules(QSharedPointer<QStringList> modNames, QSharedPointer<QStringList> modFilenames, QSharedPointer<IntList> modTypes, ItomSharedSemaphore *semaphore = NULL);
00355     ito::RetVal reloadSysModules(QSharedPointer<QStringList> modNames, ItomSharedSemaphore *semaphore = NULL);
00356 
00357     void registerWorkspaceContainer(PyWorkspaceContainer *container, bool registerNotUnregister, bool globalNotLocal);
00358     void workspaceGetChildNode(PyWorkspaceContainer *container, QString fullNameParentItem);
00359     void workspaceGetValueInformation(PyWorkspaceContainer *container, const QString &fullItemName, QSharedPointer<QString> extendedValue, ItomSharedSemaphore *semaphore = NULL);
00360 
00361     ito::RetVal checkVarnamesInWorkspace(bool globalNotLocal, const QStringList &names, QSharedPointer<IntList> existing, ItomSharedSemaphore *semaphore = NULL); 
00362     ito::RetVal putParamsToWorkspace(bool globalNotLocal, const QStringList &names, const QVector<SharedParamBasePointer > &values, ItomSharedSemaphore *semaphore = NULL);
00363     ito::RetVal getVarnamesListInWorkspace(bool globalNotLocal, const QString &find, QSharedPointer<QStringList> varnameList, ItomSharedSemaphore *semaphore /*= NULL*/);
00364     ito::RetVal getParamsFromWorkspace(bool globalNotLocal, const QStringList &names, QVector<int> paramBaseTypes, QSharedPointer<SharedParamBasePointerVector > values, ItomSharedSemaphore *semaphore = NULL);
00365 
00366 private slots:
00367 
00368 };
00369 
00370 } //end namespace ito
00371 
00372 
00373 #endif
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Properties Friends