Files
create/src/Base/Interpreter.h
Zheng, Lei 3fcbf71fb5 Base: misc patches
Convenience macros/function (in Interpreter.h)

* FC_PY_GetObject/Callable(), look for callables in a python object,
  which will be used in future patch to improve performance in various
  python observer/features.

* pyCall(WithKeywords)(), helper function to invoke the callable

Matrix4D:

* hasScale(), check if there is any scale in the transformation. If so,
  further check if the scale is uniform or not. This will be used in
  future patch for Part::TopoShape to decide which type of transform to
  apply.

Placement:

* translate/rotate(), new convenience API

Rotation:

* isSame/multiVec(), new convenience API

Polygon2d:

* Intersect(), GetCenter(), new convenience API.

FlagToggler:

* New class for exception safe flag toggling, similar to StateLocker
  but with template (actually, FlagToggler is added earlier by me).

BitsetLocker:

* New class for exception manipulation of a std::bitset variable.
2019-08-17 14:52:08 +02:00

334 lines
11 KiB
C++

/***************************************************************************
* (c) Jürgen Riegel (juergen.riegel@web.de) 2002 *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License (LGPL) *
* as published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* for detail see the LICENCE text file. *
* *
* FreeCAD is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with FreeCAD; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
* *
* Juergen Riegel 2002 *
***************************************************************************/
#ifndef BASE_INTERPRETER_H
#define BASE_INTERPRETER_H
#if defined (_POSIX_C_SOURCE)
# undef _POSIX_C_SOURCE
#endif // (re-)defined in pyconfig.h
#if defined (_XOPEN_SOURCE)
# undef _XOPEN_SOURCE
#endif // (re-)defined in pyconfig.h
#include <Python.h>
#include <CXX/Extensions.hxx>
#ifdef FC_OS_MACOSX
#undef toupper
#undef tolower
#undef isupper
#undef islower
#undef isspace
#undef isalpha
#undef isalnum
#endif
// Std. configurations
#include <string>
#include <map>
#include "Exception.h"
/** Helper macro to obtain callable from an object
*
* @param _pyobj: PyObject pointer
* @param _name: the callable string name
* @param _var: the callable variable to be assigned
*
* See FeaturePythonImp::init() for example usage
*/
#define FC_PY_GetCallable(_pyobj,_name,_var) \
do {\
_var = Py::Object();\
if(PyObject_HasAttrString(_pyobj, _name)) {\
Py::Object _obj(PyObject_GetAttrString (_pyobj, _name), true);\
if(_obj.isCallable())\
_var = _obj;\
}\
}while(0)
/** Helper macro to obtain attribute from an object
*
* @param _pyobj: PyObject pointer
* @param _name: the attribute string name
* @param _var: the attribute variable to be assigned
*
* See FeaturePythonImp::init() for example usage
*/
#define FC_PY_GetObject(_pyobj,_name,_var) \
do {\
_var = Py::Object();\
if(PyObject_HasAttrString(_pyobj, _name))\
_var = Py::asObject(PyObject_GetAttrString (_pyobj, _name));\
}while(0)
namespace Base {
using std::string;
using std::vector;
class BaseExport PyException : public Exception
{
public:
/// constructor does the whole job
PyException(void);
PyException(const Py::Object &obj);
~PyException() throw();
void raiseException();
/// this method determines if the original exception
/// can be reconstructed or not, if yes throws the reconstructed version
/// if not, throws a generic PyException.
static void ThrowException(void);
/// this function returns the stack trace
const std::string &getStackTrace(void) const {return _stackTrace;}
const std::string &getErrorType(void) const {return _errorType;}
virtual PyObject *getPyExceptionType(void) const override {return _exceptionType;}
void ReportException (void) const;
protected:
std::string _stackTrace;
std::string _errorType;
PyObject *_exceptionType;
};
inline Py::Object pyCall(PyObject *callable, PyObject *args=0) {
PyObject *result = PyObject_CallObject(callable, args);
if(!result)
Base::PyException::ThrowException();
return Py::asObject(result);
}
inline Py::Object pyCallWithKeywords(PyObject *callable, PyObject *args, PyObject *kwds=0) {
PyObject *result = PyObject_Call(callable, args, kwds);
if(!result)
Base::PyException::ThrowException();
return Py::asObject(result);
}
/**
* The SystemExitException is thrown if the Python-internal PyExc_SystemExit exception
* was thrown.
* @author Werner Mayer
*/
class BaseExport SystemExitException : public Exception
{
public:
SystemExitException(void);
SystemExitException(const SystemExitException &inst);
virtual ~SystemExitException() throw() {}
long getExitCode(void) const { return _exitCode;}
protected:
long _exitCode;
};
/** If the application starts we release immediately the global interpreter lock
* (GIL) once the Python interpreter is initialized, i.e. no thread -- including
* the main thread doesn't hold the GIL. Thus, every thread must instantiate an
* object of PyGILStateLocker if it needs to access protected areas in Python or
* areas where the lock is needed. It's best to create the instance on the stack,
* not on the heap.
*/
class BaseExport PyGILStateLocker
{
public:
PyGILStateLocker()
{
gstate = PyGILState_Ensure();
}
~PyGILStateLocker()
{
PyGILState_Release(gstate);
}
private:
PyGILState_STATE gstate;
};
/**
* If a thread holds the global interpreter lock (GIL) but runs a long operation
* in C where it doesn't need to hold the GIL it can release it temporarily. Or
* if the thread has to run code in the main thread where Python code may be
* executed it must release the GIL to avoid a deadlock. In either case the thread
* must hold the GIL when instantiating an object of PyGILStateRelease.
* As PyGILStateLocker it's best to create an instance of PyGILStateRelease on the
* stack.
*/
class BaseExport PyGILStateRelease
{
public:
PyGILStateRelease()
{
// release the global interpreter lock
state = PyEval_SaveThread();
}
~PyGILStateRelease()
{
// grab the global interpreter lock again
PyEval_RestoreThread(state);
}
private:
PyThreadState* state;
};
/** The Interpreter class
* This class manage the python interpreter and hold a lot
* helper functions for handling python stuff
*/
class BaseExport InterpreterSingleton
{
public:
InterpreterSingleton();
~InterpreterSingleton();
/** @name execution methods
*/
//@{
/// Run a statement on the python interpreter and gives back a string with the representation of the result.
std::string runString(const char *psCmd);
/// Run a statement on the python interpreter and return back the result object.
Py::Object runStringObject(const char *sCmd);
/// Run a statement on the python interpreter and gives back a string with the representation of the result.
void runInteractiveString(const char *psCmd);
/// Run file (script) on the python interpreter
void runFile(const char*pxFileName, bool local);
/// Run a statement with arguments on the python interpreter
void runStringArg(const char * psCom,...);
/// runs a python object method with no return value and no arguments
void runMethodVoid(PyObject *pobject, const char *method);
/// runs a python object method which returns a arbitrary object
PyObject* runMethodObject(PyObject *pobject, const char *method);
/// runs a python method with arbitrary params
void runMethod(PyObject *pobject, const char *method,
const char *resfmt=0, void *cresult=0,
const char *argfmt="()", ... );
//@}
/** @name Module handling
*/
//@{
/* Loads a module
*/
bool loadModule(const char* psModName);
/// Add an additional python path
void addPythonPath(const char* Path);
static void addType(PyTypeObject* Type,PyObject* Module, const char * Name);
//@}
/** @name Cleanup
*/
//@{
/** Register a cleanup function to be called by finalize(). The cleanup function will be called with no
* arguments and should return no value. At most 32 cleanup functions can be registered. When the registration
* is successful 0 is returned; on failure -1 is returned. The cleanup function registered last is called
* first. Each cleanup function will be called at most once. Since Python's internal finalization will have
* completed before the cleanup function, no Python APIs should be called by \a func.
*/
int cleanup(void (*func)(void));
/** This calls the registered cleanup functions. @see cleanup() for more details. */
void finalize();
/// This shuts down the application.
void systemExit();
//@}
/** @name startup and singletons
*/
//@{
/// init the interpreter and returns the module search path
const char* init(int argc,char *argv[]);
int runCommandLine(const char *prompt);
void replaceStdOutput();
static InterpreterSingleton &Instance(void);
static void Destruct(void);
//@}
/** @name external wrapper libs
* here we can access external dynamically loaded wrapper libs
* done e.g. by SWIG or SIP
*/
//@{
/// generate a SWIG object
PyObject* createSWIGPointerObj(const char* Modole, const char* TypeName, void* Pointer, int own);
bool convertSWIGPointerObj(const char* Module, const char* TypeName, PyObject* obj, void** ptr, int flags);
void cleanupSWIG(const char* TypeName);
//@}
/** @name methods for debugging facility
*/
//@{
/// sets the file name which should be debugged
void dbgObserveFile(const char* sFileName="");
/// sets a break point to a special line number in the current file
void dbgSetBreakPoint(unsigned int uiLineNumber);
/// unsets a break point to a special line number in the current file
void dbgUnsetBreakPoint(unsigned int uiLineNumber);
/// One step further
void dbgStep(void);
//@}
/** @name static helper functions
*/
//@{
/// replaces all char with escapes for usage in python console
static const std::string strToPython(const char* Str);
static const std::string strToPython(const std::string &Str){return strToPython(Str.c_str());}
//@}
PyObject *getValue(const char *key, const char *result_var);
protected:
// singleton
static InterpreterSingleton *_pcSingelton;
private:
std::string _cDebugFileName;
PyThreadState* _global;
};
/** Access to the InterpreterSingleton object
* This method is used to gain access to the one and only instance of
* the InterpreterSingleton class.
*/
inline InterpreterSingleton &Interpreter(void)
{
return InterpreterSingleton::Instance();
}
} //namespace Base
#endif // BASE_INTERPRETER_H