itom 2.2.1
|
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