itom 2.0.0
|
00001 /* ******************************************************************** 00002 itom software 00003 URL: http://www.uni-stuttgart.de/ito 00004 Copyright (C) 2013, 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 00079 #include "../models/breakPointModel.h" 00080 #include "../../common/sharedStructuresQt.h" 00081 #include "../../common/addInInterface.h" 00082 00083 #include "pythonWorkspace.h" 00084 00085 #include <qstringlist.h> 00086 #include <qqueue.h> 00087 #include <qset.h> 00088 #include <qpointer.h> 00089 #include <qatomic.h> 00090 00091 00092 /* definition and macros */ 00093 00094 /* global variables (avoid) */ 00095 00096 /* content */ 00097 00098 class QDesktopWidget; 00099 class QTimer; 00100 00101 namespace ito 00102 { 00103 00104 class FuncWeakRef 00105 { 00106 public: 00107 FuncWeakRef(); 00108 FuncWeakRef(PythonProxy::PyProxy *proxyObject, PyObject *argTuple = NULL); 00109 FuncWeakRef(const FuncWeakRef &rhs); 00110 ~FuncWeakRef(); 00111 FuncWeakRef& operator =(FuncWeakRef rhs); 00112 00113 PythonProxy::PyProxy* getProxyObject() const { return m_proxyObject; } //borrowed reference 00114 PyObject* getArguments() const { return m_argument; } //borrowed reference 00115 bool isValid() const { return (m_proxyObject != NULL); } 00116 00117 void setHandle(const size_t &handle); 00118 size_t getHandle() const { return m_handle; } 00119 private: 00120 PythonProxy::PyProxy *m_proxyObject; 00121 PyObject *m_argument; 00122 size_t m_handle; 00123 }; 00124 00125 00126 class PythonEngine : public QObject 00127 { 00128 Q_OBJECT 00129 00130 public: 00131 PythonEngine(); //constructor 00132 ~PythonEngine(); //destructor 00133 00134 Q_INVOKABLE void pythonSetup(ito::RetVal *retValue); //setup 00135 Q_INVOKABLE ito::RetVal scanAndRunAutostartFolder(QString currentDirAfterScan = QString() ); 00136 Q_INVOKABLE ito::RetVal pythonShutdown(ItomSharedSemaphore *aimWait = NULL); //shutdown 00137 Q_INVOKABLE ito::RetVal stringEncodingChanged(); 00138 00139 inline ito::BreakPointModel *getBreakPointModel() const { return bpModel; } 00140 inline bool isPythonBusy() const { return pythonState != ito::pyStateIdle; } 00141 inline bool isPythonDebugging() const { return (pythonState == ito::pyStateDebuggingWaitingButBusy || pythonState == ito::pyStateDebugging || pythonState == ito::pyStateDebuggingWaiting); } 00142 inline bool isPythonDebuggingAndWaiting() const { return pythonState == ito::pyStateDebuggingWaiting; } 00143 inline bool execInternalCodeByDebugger() const { return m_executeInternalPythonCodeInDebugMode; } 00144 inline void setExecInternalCodeByDebugger(bool value) { m_executeInternalPythonCodeInDebugMode = value; } 00145 ito::RetVal checkForPyExceptions(); 00146 void printPythonErrorWithoutTraceback(); 00147 void pythonDebugFunction(PyObject *callable, PyObject *argTuple); 00148 void pythonRunFunction(PyObject *callable, PyObject *argTuple); 00149 inline PyObject *getGlobalDictionary() const { return globalDictionary; } 00150 inline bool pySyntaxCheckAvailable() const { return (m_pyModSyntaxCheck != NULL); } 00151 QList<int> parseAndSplitCommandInMainComponents(const char *str, QByteArray &encoding) const; //can be directly called from different thread 00152 QString getPythonExecutable() const { return m_pythonExecutable; } 00153 Qt::HANDLE getPythonThreadId() const { return m_pythonThreadId; } 00154 00155 static bool isInterruptQueued(); 00156 static const PythonEngine *getInstance(); 00157 00158 protected: 00159 //RetVal syntaxCheck(char* pythonFileName); // syntaxCheck for file with filename pythonFileName 00160 ito::RetVal runPyFile(const QString &pythonFileName); // run file pythonFileName 00161 ito::RetVal debugFile(const QString &pythonFileName); // debug file pythonFileName 00162 ito::RetVal runString(const QString &command); // run string command 00163 ito::RetVal debugString(const QString &command); // debug string command 00164 ito::RetVal debugFunction(PyObject *callable, PyObject *argTuple); 00165 ito::RetVal runFunction(PyObject *callable, PyObject *argTuple); 00166 00167 ito::RetVal modifyTracebackDepth(int NrOfLevelsToPopAtFront = -1, bool showTraceback = true); 00168 00169 PyObject* setPyErrFromException(const std::exception &exc); 00170 00171 #if QT_VERSION >= 0x050000 00172 void connectNotify(const QMetaMethod &signal); 00173 #else 00174 void connectNotify(const char* signal); 00175 #endif 00176 00177 private: 00178 static PythonEngine *getInstanceInternal(); 00179 00180 inline PyObject *getLocalDictionary() { return localDictionary; } 00182 PyObject *getPyObjectByFullName(bool globalNotLocal, const QStringList &fullName); 00183 00184 void setGlobalDictionary(PyObject* mainDict = NULL); 00185 void setLocalDictionary(PyObject* localDict); 00186 00187 void emitPythonDictionary(bool emitGlobal, bool emitLocal, PyObject* globalDict, PyObject* localDict); 00188 00189 ito::RetVal pickleDictionary(PyObject *dict, const QString &filename); 00190 ito::RetVal unpickleDictionary(PyObject *destinationDict, const QString &filename, bool overwrite); 00191 00192 //methods for maintaining python functionality 00193 ito::RetVal addMethodToModule(PyMethodDef* def); 00194 ito::RetVal delMethodFromModule(const char* ml_name); 00195 ito::RetVal pythonAddBuiltinMethods(); 00196 00197 //methods for debugging 00198 void enqueueDbgCmd(ito::tPythonDbgCmd dbgCmd); 00199 ito::tPythonDbgCmd dequeueDbgCmd(); 00200 bool DbgCommandsAvailable(); 00201 void clearDbgCmdLoop(); 00202 00203 ito::RetVal pythonStateTransition(tPythonTransitions transition); 00204 00205 //methods for breakpoint 00206 ito::RetVal pythonAddBreakpoint(const QString &filename, const int lineno, const bool enabled, const bool temporary, const QString &condition, const int ignoreCount, int &pyBpNumber); 00207 ito::RetVal pythonEditBreakpoint(const int pyBpNumber, const QString &filename, const int lineno, const bool enabled, const bool temporary, const QString &condition, const int ignoreCount); 00208 ito::RetVal pythonDeleteBreakpoint(const int pyBpNumber); 00209 00210 ito::RetVal autoReloaderCheck(); 00211 00212 static int queuedInterrupt(void *state); 00213 00214 PyObject* getAndCheckIdentifier(const QString &identifier, ito::RetVal &retval) const; 00215 00216 00217 //member variables 00218 bool m_started; 00219 //QString m_itomMemberClasses; 00220 00221 //PyGILState_STATE threadState; 00222 00223 QMutex dbgCmdMutex; 00224 QMutex pythonStateChangeMutex; 00225 QMutex dictChangeMutex; 00226 QDesktopWidget *m_pDesktopWidget; 00227 QQueue<ito::tPythonDbgCmd> debugCommandQueue; 00228 ito::tPythonDbgCmd debugCommand; 00229 00230 ito::tPythonState pythonState; 00231 00232 ito::BreakPointModel *bpModel; 00233 00234 PyObject* mainModule; 00235 PyObject* mainDictionary; 00236 PyObject* localDictionary; 00237 PyObject* globalDictionary; 00238 PyObject *itomDbgModule; 00239 PyObject *itomDbgInstance; 00240 PyObject *itomModule; 00241 PyObject *itomFunctions; 00242 PyObject *m_pyModGC; 00243 PyObject *m_pyModSyntaxCheck; 00244 //PyObject *itomReturnException; //!< if this exception is thrown, the execution of the main application is stopped 00245 00246 Qt::HANDLE m_pythonThreadId; 00247 00248 PyObject *dictUnicode; 00249 00250 QSet<ito::PyWorkspaceContainer*> m_mainWorkspaceContainer; 00251 QSet<ito::PyWorkspaceContainer*> m_localWorkspaceContainer; 00252 QHash<size_t, FuncWeakRef> m_pyFuncWeakRefHashes; 00253 size_t m_pyFuncWeakRefAutoInc; 00254 00255 QString m_pythonExecutable; 00256 00257 bool m_executeInternalPythonCodeInDebugMode; 00258 PyMethodDef* PythonAdditionalModuleITOM; 00259 00260 // decides if itom is automatically included in every source file before it is handed to the syntax checker 00261 bool m_includeItom; 00262 00263 struct AutoReload 00264 { 00265 PyObject *modAutoReload; 00266 PyObject *classAutoReload; 00267 bool enabled; 00268 bool checkFileExec; 00269 bool checkStringExec; 00270 bool checkFctExec; 00271 }; 00272 00273 AutoReload m_autoReload; 00274 00276 static PyMethodDef PyMethodItomDbg[]; 00277 static PyModuleDef PyModuleItomDbg; 00278 static PyObject* PyInitItomDbg(void); 00279 static PyObject* PyDbgCommandLoop(PyObject *pSelf, PyObject *pArgs); 00280 00281 //helper methods 00282 //static PyObject* checkForTimeoutHelper(ItomSharedSemaphore* semaphore, int timeout, PyObject *retValueOk); 00283 00284 //other static members 00285 static QMutex instatiated; 00286 static QMutex instancePtrProtection; 00287 static QString fctHashPrefix; 00288 00289 static PythonEngine* instance; 00290 00291 QAtomicInt m_interruptCounter; //protects that a python interrupt can only be placed if there is no interrupt event queued yet. 00292 00293 // friend class 00294 friend class ito::PythonItom; 00295 00296 signals: 00297 void pythonDebugPositionChanged(QString filename, int lineNo); 00298 void pythonStateChanged(tPythonTransitions pyTransition); 00299 void pythonModifyLocalDict(PyObject* localDict, ItomSharedSemaphore* semaphore); 00300 void pythonModifyGlobalDict(PyObject* globalDict, ItomSharedSemaphore* semaphore); 00301 void pythonCurrentDirChanged(); 00302 void updateCallStack(QStringList filenames, IntList lines, QStringList methods); 00303 void deleteCallStack(); 00304 00305 void pythonSetCursor(const Qt::CursorShape cursor); 00306 void pythonResetCursor(); 00307 void pythonAutoReloadChanged(bool enabled, bool checkFile, bool checkCmd, bool checkFct); 00308 void clearCommandLine(); 00309 00310 public slots: 00311 void pythonRunString(QString cmd); 00312 void pythonDebugString(QString cmd); 00313 void pythonExecStringFromCommandLine(QString cmd); 00314 void pythonRunFile(QString filename); 00315 void pythonDebugFile(QString filename); 00316 void pythonRunStringOrFunction(QString cmdOrFctHash); 00317 void pythonDebugStringOrFunction(QString cmdOrFctHash); 00318 void pythonInterruptExecution(); 00319 void pythonDebugCommand(tPythonDbgCmd cmd); 00320 00321 void setAutoReloader(bool enabled, bool checkFile, bool checkCmd, bool checkFct); 00322 00323 // Settings are neccesary for automatic itom inclusion and syntax check 00324 void readSettings(); 00325 void propertiesChanged(); 00326 00327 void pythonSyntaxCheck(const QString &code, QPointer<QObject> sender); 00328 00329 void pythonGenericSlot(PyObject* callable, PyObject *argumentTuple); 00330 00332 void breakPointAdded(BreakPointItem bp, int row); 00333 void breakPointDeleted(QString filename, int lineNo, int pyBpNumber); 00334 void breakPointChanged(BreakPointItem oldBp, BreakPointItem newBp); 00335 ito::RetVal setupBreakPointDebugConnections(); 00336 ito::RetVal shutdownBreakPointDebugConnections(); 00337 00338 bool renameVariable(bool globalNotLocal, QString oldKey, QString newKey, ItomSharedSemaphore *semaphore = NULL); 00339 bool deleteVariable(bool globalNotLocal, QStringList keys, ItomSharedSemaphore *semaphore = NULL); 00340 ito::RetVal pickleVariables(bool globalNotLocal, QString filename, QStringList varNames, ItomSharedSemaphore *semaphore = NULL); 00341 ito::RetVal unpickleVariables(bool globalNotLocal, QString filename, ItomSharedSemaphore *semaphore = NULL); 00342 ito::RetVal saveMatlabVariables(bool globalNotLocal, QString filename, QStringList varNames, ItomSharedSemaphore *semaphore = NULL); 00343 ito::RetVal loadMatlabVariables(bool globalNotLocal, QString filename, ItomSharedSemaphore *semaphore = NULL); 00344 ito::RetVal registerAddInInstance(QString varname, ito::AddInBase *instance, ItomSharedSemaphore *semaphore = NULL); 00345 ito::RetVal getSysModules(QSharedPointer<QStringList> modNames, QSharedPointer<QStringList> modFilenames, QSharedPointer<IntList> modTypes, ItomSharedSemaphore *semaphore = NULL); 00346 ito::RetVal reloadSysModules(QSharedPointer<QStringList> modNames, ItomSharedSemaphore *semaphore = NULL); 00347 00348 void registerWorkspaceContainer(PyWorkspaceContainer *container, bool registerNotUnregister, bool globalNotLocal); 00349 void workspaceGetChildNode(PyWorkspaceContainer *container, QString fullNameParentItem); 00350 void workspaceGetValueInformation(PyWorkspaceContainer *container, QString fullItemName, QSharedPointer<QString> extendedValue, ItomSharedSemaphore *semaphore = NULL); 00351 00352 ito::RetVal putParamsToWorkspace(bool globalNotLocal, const QStringList &names, const QVector<SharedParamBasePointer > &values, ItomSharedSemaphore *semaphore = NULL); 00353 ito::RetVal getParamsFromWorkspace(bool globalNotLocal, const QStringList &names, QVector<int> paramBaseTypes, QSharedPointer<SharedParamBasePointerVector > values, ItomSharedSemaphore *semaphore = NULL); 00354 00355 private slots: 00356 00357 }; 00358 00359 } //end namespace ito 00360 00361 00362 #endif