mirror of https://github.com/KLayout/klayout.git
WIP: some refactoring of pya to reduce dependency on GSI for bridge applications.
This commit is contained in:
parent
d938bb999b
commit
7f2e740dd4
|
|
@ -20,16 +20,18 @@
|
|||
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief This header provides the definitions for embedding support
|
||||
*/
|
||||
|
||||
#ifndef _HDR_pya
|
||||
#define _HDR_pya
|
||||
|
||||
#include "pyaRefs.h"
|
||||
#include "pyaCommon.h"
|
||||
|
||||
#include "gsi.h"
|
||||
#include "gsiInterpreter.h"
|
||||
#include "tlScriptError.h"
|
||||
#include "pyaCommon.h"
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
|
@ -68,42 +70,6 @@ namespace pya
|
|||
throw; \
|
||||
}
|
||||
|
||||
/**
|
||||
* Two helper macros that translate C++ exceptions into Python errors
|
||||
*/
|
||||
|
||||
#define PYA_TRY \
|
||||
{ \
|
||||
try {
|
||||
|
||||
#define PYA_CATCH(where) \
|
||||
} catch (tl::ExitException &ex) { \
|
||||
PyErr_SetObject (PyExc_SystemExit, PyLong_FromLong (ex.status ())); \
|
||||
} catch (std::exception &ex) { \
|
||||
std::string msg = std::string(ex.what ()) + tl::to_string (QObject::tr (" in ")) + (where); \
|
||||
PyErr_SetString (PyExc_RuntimeError, msg.c_str ()); \
|
||||
} catch (tl::Exception &ex) { \
|
||||
std::string msg; \
|
||||
msg = ex.msg () + tl::to_string (QObject::tr (" in ")) + (where); \
|
||||
PyErr_SetString (PyExc_RuntimeError, msg.c_str ()); \
|
||||
} catch (...) { \
|
||||
std::string msg = tl::to_string (QObject::tr ("Unspecific exception in ")) + (where); \
|
||||
PyErr_SetString (PyExc_RuntimeError, msg.c_str ()); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PYA_CATCH_ANYWHERE \
|
||||
} catch (tl::ExitException &ex) { \
|
||||
PyErr_SetObject (PyExc_SystemExit, PyLong_FromLong (ex.status ())); \
|
||||
} catch (std::exception &ex) { \
|
||||
PyErr_SetString (PyExc_RuntimeError, ex.what ()); \
|
||||
} catch (tl::Exception &ex) { \
|
||||
PyErr_SetString (PyExc_RuntimeError, ex.msg ().c_str ()); \
|
||||
} catch (...) { \
|
||||
PyErr_SetString (PyExc_RuntimeError, tl::to_string (QObject::tr ("Unspecific exception in ")).c_str ()); \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A class encapsulating a python exception
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@ SOURCES = \
|
|||
pyaObject.cc \
|
||||
pyaRefs.cc \
|
||||
pyaUtils.cc \
|
||||
pyaModule.cc
|
||||
pyaModule.cc \
|
||||
pyaSignalHandler.cc \
|
||||
pyaStatusChangedListener.cc
|
||||
|
||||
HEADERS += \
|
||||
pya.h \
|
||||
|
|
@ -27,7 +29,9 @@ HEADERS += \
|
|||
pyaObject.h \
|
||||
pyaRefs.h \
|
||||
pyaUtils.h \
|
||||
pyaModule.h
|
||||
pyaModule.h \
|
||||
pyaSignalHandler.h \
|
||||
pyaStatusChangedListener.h
|
||||
|
||||
INCLUDEPATH += $$PYTHONINCLUDE $$TL_INC $$GSI_INC
|
||||
DEPENDPATH += $$PYTHONINCLUDE $$TL_INC $$GSI_INC
|
||||
|
|
|
|||
|
|
@ -24,13 +24,21 @@
|
|||
#include "pyaConvert.h"
|
||||
#include "pyaObject.h"
|
||||
#include "pyaModule.h"
|
||||
#include "pyaStatusChangedListener.h"
|
||||
#include "pyaUtils.h"
|
||||
|
||||
#include "gsiClassBase.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace pya
|
||||
{
|
||||
|
||||
bool is_derived_from (const gsi::ClassBase *cls, const std::type_info &ti)
|
||||
{
|
||||
return cls->is_derived_from (gsi::class_by_typeinfo_no_assert (ti));
|
||||
}
|
||||
|
||||
template <>
|
||||
long python2c_func<long>::operator() (PyObject *rval)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
#include "pyaCommon.h"
|
||||
#include "pyaModule.h"
|
||||
#include "pyaObject.h"
|
||||
#include "gsiClassBase.h"
|
||||
|
||||
#include "tlVariant.h"
|
||||
#include "tlException.h"
|
||||
|
|
@ -39,10 +38,14 @@
|
|||
#include <QString>
|
||||
#include <QByteArray>
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
class ClassBase;
|
||||
class ArgType;
|
||||
|
||||
const ClassBase *class_by_typeinfo_no_assert (const std::type_info &ti);
|
||||
}
|
||||
|
||||
namespace pya
|
||||
|
|
@ -50,6 +53,9 @@ namespace pya
|
|||
|
||||
class PYAObjectBase;
|
||||
|
||||
// Forward declarations to reduce the dependency on gsi
|
||||
PYA_PUBLIC bool is_derived_from (const gsi::ClassBase *cls, const std::type_info &ti);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Conversion of a generic object to a Python object
|
||||
|
||||
|
|
@ -196,7 +202,7 @@ struct test_type_func<T &>
|
|||
{
|
||||
// TODO: we currently don't check for non-constness
|
||||
const gsi::ClassBase *cls_decl = pya::PythonModule::cls_for_type (Py_TYPE (rval));
|
||||
return cls_decl && cls_decl->is_derived_from (gsi::class_by_typeinfo_no_assert (typeid (T)));
|
||||
return cls_decl && is_derived_from (cls_decl, typeid (T));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -338,7 +344,7 @@ template <class T> struct python2c_func<T &>
|
|||
|
||||
const gsi::ClassBase *cls_decl = PythonModule::cls_for_type (Py_TYPE (rval));
|
||||
tl_assert (cls_decl != 0);
|
||||
tl_assert (cls_decl->is_derived_from (gsi::class_by_typeinfo_no_assert (typeid (T))));
|
||||
tl_assert (is_derived_from (cls_decl, typeid (T)));
|
||||
|
||||
PYAObjectBase *p = (PYAObjectBase *) (rval);
|
||||
return *((T *)p->obj ());
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "pyaMarshal.h"
|
||||
#include "pyaObject.h"
|
||||
#include "pyaConvert.h"
|
||||
#include "pyaSignalHandler.h"
|
||||
#include "pya.h"
|
||||
|
||||
namespace pya
|
||||
|
|
|
|||
|
|
@ -24,10 +24,12 @@
|
|||
#include <Python.h>
|
||||
|
||||
#include "pyaModule.h"
|
||||
#include "pya.h"
|
||||
#include "pyaObject.h"
|
||||
#include "pyaConvert.h"
|
||||
#include "pyaHelpers.h"
|
||||
#include "pyaMarshal.h"
|
||||
#include "pyaSignalHandler.h"
|
||||
#include "pyaUtils.h"
|
||||
|
||||
#include <map>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,21 @@
|
|||
#ifndef _HDR_pyaModule
|
||||
#define _HDR_pyaModule
|
||||
|
||||
#include "pya.h"
|
||||
#include <Python.h>
|
||||
|
||||
#include "pyaCommon.h"
|
||||
#include "pyaRefs.h"
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
class ClassBase;
|
||||
class MethodBase;
|
||||
}
|
||||
|
||||
namespace pya
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,91 +25,61 @@
|
|||
#include "pyaMarshal.h"
|
||||
#include "pyaUtils.h"
|
||||
#include "pyaConvert.h"
|
||||
#include "pyaSignalHandler.h"
|
||||
#include "pyaStatusChangedListener.h"
|
||||
#include "pya.h"
|
||||
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiDeclBasic.h"
|
||||
#include "gsiSignals.h"
|
||||
#include "tlObject.h"
|
||||
|
||||
#include "tlLog.h"
|
||||
|
||||
namespace pya
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Implementation of CallbackFunction
|
||||
// Private classes
|
||||
|
||||
CallbackFunction::CallbackFunction (PythonRef pym, const gsi::MethodBase *m)
|
||||
: mp_method (m)
|
||||
/**
|
||||
* @brief An adaptor class for the callback mechanism
|
||||
*/
|
||||
class Callee
|
||||
: public gsi::Callee
|
||||
{
|
||||
// We have a problem here with cyclic references. Bound instances methods can
|
||||
// create reference cycles if their target objects somehow points back to us
|
||||
// (or worse, to some parent of us, i.e. inside a QWidget hierarchy).
|
||||
// A solution is to take a bound instance method apart and store a weak
|
||||
// reference to self plus a real reference to the function.
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for a Callee object pointing the to given Python object
|
||||
*/
|
||||
Callee (PYAObjectBase *obj);
|
||||
|
||||
if (pym && PyMethod_Check (pym.get ()) && PyMethod_Self (pym.get ()) != NULL) {
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~Callee ();
|
||||
|
||||
m_weak_self = PythonRef (PyWeakref_NewRef (PyMethod_Self (pym.get ()), NULL));
|
||||
m_callable = PythonRef (PyMethod_Function (pym.get ()), false /* borrowed ref */);
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
m_class = PythonRef (PyMethod_Class (pym.get ()), false /* borrowed ref */);
|
||||
#endif
|
||||
/**
|
||||
* @brief Adds a callback (given by the CallbackFunction)
|
||||
* This method returns a callback ID which can be used to register the callback
|
||||
* at an GSI object.
|
||||
*/
|
||||
int add_callback (const CallbackFunction &vf);
|
||||
|
||||
} else {
|
||||
m_callable = pym;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Clears all callbacks registered
|
||||
*/
|
||||
void clear_callbacks ();
|
||||
|
||||
const gsi::MethodBase *CallbackFunction::method () const
|
||||
{
|
||||
return mp_method;
|
||||
}
|
||||
/**
|
||||
* @brief Implementation of the Callee interface
|
||||
*/
|
||||
virtual void call (int id, gsi::SerialArgs &args, gsi::SerialArgs &ret) const;
|
||||
|
||||
PythonRef CallbackFunction::callable () const
|
||||
{
|
||||
if (m_callable && m_weak_self) {
|
||||
|
||||
PyObject *self = PyWeakref_GetObject (m_weak_self.get ());
|
||||
if (self == Py_None) {
|
||||
// object expired - no callback possible
|
||||
return PythonRef ();
|
||||
}
|
||||
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
return PythonRef (PyMethod_New (m_callable.get (), self, m_class.get ()));
|
||||
#else
|
||||
return PythonRef (PyMethod_New (m_callable.get (), self));
|
||||
#endif
|
||||
|
||||
} else {
|
||||
return m_callable;
|
||||
}
|
||||
}
|
||||
|
||||
bool CallbackFunction::is_instance_method () const
|
||||
{
|
||||
return m_callable && m_weak_self;
|
||||
}
|
||||
|
||||
PyObject *CallbackFunction::self_ref () const
|
||||
{
|
||||
return PyWeakref_GetObject (m_weak_self.get ());
|
||||
}
|
||||
|
||||
PyObject *CallbackFunction::callable_ref () const
|
||||
{
|
||||
return m_callable.get ();
|
||||
}
|
||||
|
||||
bool CallbackFunction::operator== (const CallbackFunction &other) const
|
||||
{
|
||||
if (is_instance_method () != other.is_instance_method ()) {
|
||||
return false;
|
||||
}
|
||||
if (m_weak_self) {
|
||||
if (self_ref () != other.self_ref ()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return callable_ref () == other.callable_ref ();
|
||||
}
|
||||
private:
|
||||
PYAObjectBase *mp_obj;
|
||||
std::vector<CallbackFunction> m_cbfuncs;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Implementation of Callee
|
||||
|
|
@ -196,135 +166,12 @@ Callee::call (int id, gsi::SerialArgs &args, gsi::SerialArgs &ret) const
|
|||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Implementation of SignalHandler
|
||||
|
||||
SignalHandler::SignalHandler ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
SignalHandler::~SignalHandler ()
|
||||
{
|
||||
clear ();
|
||||
}
|
||||
|
||||
void SignalHandler::call (const gsi::MethodBase *meth, gsi::SerialArgs &args, gsi::SerialArgs &ret) const
|
||||
{
|
||||
PYTHON_BEGIN_EXEC
|
||||
|
||||
tl::Heap heap;
|
||||
|
||||
int args_avail = int (std::distance (meth->begin_arguments (), meth->end_arguments ()));
|
||||
PythonRef argv (PyTuple_New (args_avail));
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); args && a != meth->end_arguments (); ++a) {
|
||||
PyTuple_SetItem (argv.get (), int (a - meth->begin_arguments ()), pop_arg (*a, args, 0, heap).release ());
|
||||
}
|
||||
|
||||
// NOTE: in case one event handler deletes the object, it's safer to first collect the handlers and
|
||||
// then call them.
|
||||
std::vector<PythonRef> callables;
|
||||
callables.reserve (m_cbfuncs.size ());
|
||||
for (std::vector<CallbackFunction>::const_iterator c = m_cbfuncs.begin (); c != m_cbfuncs.end (); ++c) {
|
||||
callables.push_back (c->callable ());
|
||||
}
|
||||
|
||||
PythonRef result;
|
||||
|
||||
for (std::vector<PythonRef>::const_iterator c = callables.begin (); c != callables.end (); ++c) {
|
||||
|
||||
// determine the number of arguments required
|
||||
int arg_count = args_avail;
|
||||
if (args_avail > 0) {
|
||||
|
||||
PythonRef fc (PyObject_GetAttrString (c->get (), "__code__"));
|
||||
if (fc) {
|
||||
PythonRef ac (PyObject_GetAttrString (fc.get (), "co_argcount"));
|
||||
if (ac) {
|
||||
arg_count = python2c<int> (ac.get ());
|
||||
if (PyObject_HasAttrString (c->get (), "__self__")) {
|
||||
arg_count -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// use less arguments if applicable
|
||||
if (arg_count == 0) {
|
||||
result = PythonRef (PyObject_CallObject (c->get (), NULL));
|
||||
} else if (arg_count < args_avail) {
|
||||
PythonRef argv_less (PyTuple_GetSlice (argv.get (), 0, arg_count));
|
||||
result = PythonRef (PyObject_CallObject (c->get (), argv_less.get ()));
|
||||
} else {
|
||||
result = PythonRef (PyObject_CallObject (c->get (), argv.get ()));
|
||||
}
|
||||
|
||||
if (! result) {
|
||||
check_error ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
push_arg (meth->ret_type (), ret, result.get (), heap);
|
||||
|
||||
// a Python callback must not leave temporary objects
|
||||
tl_assert (heap.empty ());
|
||||
|
||||
PYTHON_END_EXEC
|
||||
}
|
||||
|
||||
void SignalHandler::add (PyObject *callable)
|
||||
{
|
||||
remove (callable);
|
||||
m_cbfuncs.push_back (CallbackFunction (PythonPtr (callable), 0));
|
||||
}
|
||||
|
||||
void SignalHandler::remove (PyObject *callable)
|
||||
{
|
||||
// To avoid cyclic references, the CallbackFunction holder is employed. However, the
|
||||
// "true" callable no longer is the original one. Hence, we need to do a strict compare
|
||||
// against the effective one.
|
||||
CallbackFunction cbref (PythonPtr (callable), 0);
|
||||
for (std::vector<CallbackFunction>::iterator c = m_cbfuncs.begin (); c != m_cbfuncs.end (); ++c) {
|
||||
if (*c == cbref) {
|
||||
m_cbfuncs.erase (c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SignalHandler::clear ()
|
||||
{
|
||||
m_cbfuncs.clear ();
|
||||
}
|
||||
|
||||
void SignalHandler::assign (const SignalHandler *other)
|
||||
{
|
||||
m_cbfuncs = other->m_cbfuncs;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Implementation of StatusChangedListener
|
||||
|
||||
StatusChangedListener::StatusChangedListener (PYAObjectBase *pya_object)
|
||||
: mp_pya_object (pya_object)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
StatusChangedListener::object_status_changed (gsi::ObjectBase::StatusEventType type)
|
||||
{
|
||||
mp_pya_object->object_status_changed (type);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Implementation of PYAObjectBase
|
||||
|
||||
PYAObjectBase::PYAObjectBase(const gsi::ClassBase *_cls_decl)
|
||||
: m_listener (this),
|
||||
m_callee (this),
|
||||
: m_listener (new pya::StatusChangedListener (this)),
|
||||
m_callee (new pya::Callee (this)),
|
||||
m_cls_decl (_cls_decl),
|
||||
m_obj (0),
|
||||
m_owned (false),
|
||||
|
|
@ -361,32 +208,24 @@ PYAObjectBase::~PYAObjectBase ()
|
|||
}
|
||||
|
||||
void
|
||||
PYAObjectBase::object_status_changed (gsi::ObjectBase::StatusEventType type)
|
||||
PYAObjectBase::object_destroyed ()
|
||||
{
|
||||
if (type == gsi::ObjectBase::ObjectDestroyed) {
|
||||
// This may happen outside the Python interpreter, so we safeguard ourselves against this.
|
||||
// In this case, we may encounter a memory leak, but there is little we can do
|
||||
// against this and it will happen in the application teardown anyway.
|
||||
if (PythonInterpreter::instance ()) {
|
||||
|
||||
// This may happen outside the Python interpreter, so we safeguard ourselves against this.
|
||||
// In this case, we may encounter a memory leak, but there is little we can do
|
||||
// against this and it will happen in the application teardown anyway.
|
||||
if (PythonInterpreter::instance ()) {
|
||||
bool prev_owner = m_owned;
|
||||
|
||||
bool prev_owner = m_owned;
|
||||
m_destroyed = true; // NOTE: must be set before detach!
|
||||
|
||||
m_destroyed = true; // NOTE: must be set before detach!
|
||||
|
||||
detach ();
|
||||
|
||||
// NOTE: this may delete "this"!
|
||||
if (!prev_owner) {
|
||||
Py_DECREF (this);
|
||||
}
|
||||
detach ();
|
||||
|
||||
// NOTE: this may delete "this"!
|
||||
if (!prev_owner) {
|
||||
Py_DECREF (this);
|
||||
}
|
||||
|
||||
} else if (type == gsi::ObjectBase::ObjectKeep) {
|
||||
keep_internal ();
|
||||
} else if (type == gsi::ObjectBase::ObjectRelease) {
|
||||
release ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -446,7 +285,7 @@ PYAObjectBase::detach ()
|
|||
if (! m_destroyed && cls && cls->is_managed ()) {
|
||||
gsi::ObjectBase *gsi_object = cls->gsi_object (m_obj, false);
|
||||
if (gsi_object) {
|
||||
gsi_object->status_changed_event ().remove (&m_listener, &StatusChangedListener::object_status_changed);
|
||||
gsi_object->status_changed_event ().remove (m_listener.get (), &StatusChangedListener::object_status_changed);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -485,7 +324,7 @@ PYAObjectBase::set (void *obj, bool owned, bool const_ref, bool can_destroy)
|
|||
if (gsi_object->already_kept ()) {
|
||||
keep_internal ();
|
||||
}
|
||||
gsi_object->status_changed_event ().add (&m_listener, &StatusChangedListener::object_status_changed);
|
||||
gsi_object->status_changed_event ().add (m_listener.get (), &StatusChangedListener::object_status_changed);
|
||||
}
|
||||
|
||||
if (!m_owned) {
|
||||
|
|
@ -586,8 +425,8 @@ PYAObjectBase::initialize_callbacks ()
|
|||
const char *nstr = (*m)->primary_name ().c_str ();
|
||||
py_attr = PyObject_GetAttrString ((PyObject *) Py_TYPE (this), nstr);
|
||||
|
||||
int id = m_callee.add_callback (CallbackFunction (py_attr, *m));
|
||||
(*m)->set_callback (m_obj, gsi::Callback (id, &m_callee, (*m)->argsize (), (*m)->retsize ()));
|
||||
int id = m_callee->add_callback (CallbackFunction (py_attr, *m));
|
||||
(*m)->set_callback (m_obj, gsi::Callback (id, m_callee.get (), (*m)->argsize (), (*m)->retsize ()));
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -671,7 +510,7 @@ PYAObjectBase::detach_callbacks ()
|
|||
}
|
||||
}
|
||||
|
||||
m_callee.clear_callbacks ();
|
||||
m_callee->clear_callbacks ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -24,152 +24,28 @@
|
|||
#ifndef _HDR_pyaObject
|
||||
#define _HDR_pyaObject
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiDeclBasic.h"
|
||||
#include "gsiSignals.h"
|
||||
#include "tlObject.h"
|
||||
#include <Python.h>
|
||||
|
||||
#include "pyaRefs.h"
|
||||
#include "pyaCommon.h"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
class ClassBase;
|
||||
class MethodBase;
|
||||
}
|
||||
|
||||
namespace pya
|
||||
{
|
||||
|
||||
class PYAObjectBase;
|
||||
|
||||
/**
|
||||
* @brief A storage object for a function to callback
|
||||
*/
|
||||
struct CallbackFunction
|
||||
{
|
||||
CallbackFunction (PythonRef pym, const gsi::MethodBase *m);
|
||||
|
||||
PythonRef callable () const;
|
||||
const gsi::MethodBase *method () const;
|
||||
bool operator== (const CallbackFunction &other) const;
|
||||
|
||||
private:
|
||||
PythonRef m_callable;
|
||||
PythonRef m_weak_self;
|
||||
PythonRef m_class;
|
||||
const gsi::MethodBase *mp_method;
|
||||
|
||||
PyObject *self_ref () const;
|
||||
PyObject *callable_ref () const;
|
||||
bool is_instance_method () const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An adaptor class for the callback mechanism
|
||||
*/
|
||||
class Callee
|
||||
: public gsi::Callee
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for a Callee object pointing the to given Python object
|
||||
*/
|
||||
Callee (PYAObjectBase *obj);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~Callee ();
|
||||
|
||||
/**
|
||||
* @brief Adds a callback (given by the CallbackFunction)
|
||||
* This method returns a callback ID which can be used to register the callback
|
||||
* at an GSI object.
|
||||
*/
|
||||
int add_callback (const CallbackFunction &vf);
|
||||
|
||||
/**
|
||||
* @brief Clears all callbacks registered
|
||||
*/
|
||||
void clear_callbacks ();
|
||||
|
||||
/**
|
||||
* @brief Implementation of the Callee interface
|
||||
*/
|
||||
virtual void call (int id, gsi::SerialArgs &args, gsi::SerialArgs &ret) const;
|
||||
|
||||
private:
|
||||
PYAObjectBase *mp_obj;
|
||||
std::vector<CallbackFunction> m_cbfuncs;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The signal handler abstraction
|
||||
*
|
||||
* This class implements the signal handler that interfaces to GSI's signal system
|
||||
*/
|
||||
class SignalHandler
|
||||
: public gsi::SignalHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
SignalHandler ();
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~SignalHandler ();
|
||||
|
||||
/**
|
||||
* @brief Implementation of the callback interface
|
||||
*/
|
||||
virtual void call (const gsi::MethodBase *method, gsi::SerialArgs &args, gsi::SerialArgs &ret) const;
|
||||
|
||||
/**
|
||||
* @brief Adds a callable to the list of targets
|
||||
*/
|
||||
void add (PyObject *callable);
|
||||
|
||||
/**
|
||||
* @brief Removes a callable from the list of targets
|
||||
*/
|
||||
void remove (PyObject *callable);
|
||||
|
||||
/**
|
||||
* @brief Clears the list of callables
|
||||
*/
|
||||
void clear ();
|
||||
|
||||
/**
|
||||
* @brief Assign another handler to this
|
||||
*/
|
||||
void assign (const SignalHandler *other);
|
||||
|
||||
private:
|
||||
std::vector<CallbackFunction> m_cbfuncs;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper object to forward status changed events to a Python object
|
||||
* This object is used to connect the events to the Python object. Unfortunately,
|
||||
* PYAObjectBase cannot be derived from tl::Object directly since in that case,
|
||||
* tl::Object will be placed before PyObject in the memory layout.
|
||||
*/
|
||||
class StatusChangedListener
|
||||
: public tl::Object
|
||||
{
|
||||
public:
|
||||
StatusChangedListener (PYAObjectBase *pya_object);
|
||||
|
||||
void object_status_changed (gsi::ObjectBase::StatusEventType type);
|
||||
|
||||
PYAObjectBase *pya_object () const
|
||||
{
|
||||
return mp_pya_object;
|
||||
}
|
||||
|
||||
private:
|
||||
PYAObjectBase *mp_pya_object;
|
||||
};
|
||||
class SignalHandler;
|
||||
class Callee;
|
||||
class StatusChangedListener;
|
||||
|
||||
/**
|
||||
* @brief The Python object representing a GSI object
|
||||
|
|
@ -290,22 +166,6 @@ public:
|
|||
return m_owned;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The callee interface
|
||||
*/
|
||||
Callee &callee ()
|
||||
{
|
||||
return m_callee;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The callee interface (const pointer)
|
||||
*/
|
||||
const Callee &callee () const
|
||||
{
|
||||
return m_callee;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the signal handler for the signal given by "meth"
|
||||
* If a signal handler was already present, the existing object is returned.
|
||||
|
|
@ -326,9 +186,11 @@ private:
|
|||
|
||||
void detach_callbacks ();
|
||||
void initialize_callbacks ();
|
||||
void object_destroyed ();
|
||||
void keep_internal ();
|
||||
|
||||
StatusChangedListener m_listener;
|
||||
Callee m_callee;
|
||||
std::auto_ptr<StatusChangedListener> m_listener;
|
||||
std::auto_ptr<Callee> m_callee;
|
||||
const gsi::ClassBase *m_cls_decl;
|
||||
void *m_obj;
|
||||
bool m_owned : 1;
|
||||
|
|
@ -336,9 +198,6 @@ private:
|
|||
bool m_destroyed : 1;
|
||||
bool m_can_destroy : 1;
|
||||
std::map <const gsi::MethodBase *, pya::SignalHandler> m_signal_table;
|
||||
|
||||
void object_status_changed (gsi::ObjectBase::StatusEventType type);
|
||||
void keep_internal ();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,219 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "pyaSignalHandler.h"
|
||||
#include "pya.h"
|
||||
#include "pyaMarshal.h"
|
||||
#include "pyaConvert.h"
|
||||
#include "pyaUtils.h"
|
||||
|
||||
namespace pya
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Implementation of CallbackFunction
|
||||
|
||||
CallbackFunction::CallbackFunction (PythonRef pym, const gsi::MethodBase *m)
|
||||
: mp_method (m)
|
||||
{
|
||||
// We have a problem here with cyclic references. Bound instances methods can
|
||||
// create reference cycles if their target objects somehow points back to us
|
||||
// (or worse, to some parent of us, i.e. inside a QWidget hierarchy).
|
||||
// A solution is to take a bound instance method apart and store a weak
|
||||
// reference to self plus a real reference to the function.
|
||||
|
||||
if (pym && PyMethod_Check (pym.get ()) && PyMethod_Self (pym.get ()) != NULL) {
|
||||
|
||||
m_weak_self = PythonRef (PyWeakref_NewRef (PyMethod_Self (pym.get ()), NULL));
|
||||
m_callable = PythonRef (PyMethod_Function (pym.get ()), false /* borrowed ref */);
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
m_class = PythonRef (PyMethod_Class (pym.get ()), false /* borrowed ref */);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
m_callable = pym;
|
||||
}
|
||||
}
|
||||
|
||||
const gsi::MethodBase *CallbackFunction::method () const
|
||||
{
|
||||
return mp_method;
|
||||
}
|
||||
|
||||
PythonRef CallbackFunction::callable () const
|
||||
{
|
||||
if (m_callable && m_weak_self) {
|
||||
|
||||
PyObject *self = PyWeakref_GetObject (m_weak_self.get ());
|
||||
if (self == Py_None) {
|
||||
// object expired - no callback possible
|
||||
return PythonRef ();
|
||||
}
|
||||
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
return PythonRef (PyMethod_New (m_callable.get (), self, m_class.get ()));
|
||||
#else
|
||||
return PythonRef (PyMethod_New (m_callable.get (), self));
|
||||
#endif
|
||||
|
||||
} else {
|
||||
return m_callable;
|
||||
}
|
||||
}
|
||||
|
||||
bool CallbackFunction::is_instance_method () const
|
||||
{
|
||||
return m_callable && m_weak_self;
|
||||
}
|
||||
|
||||
PyObject *CallbackFunction::self_ref () const
|
||||
{
|
||||
return PyWeakref_GetObject (m_weak_self.get ());
|
||||
}
|
||||
|
||||
PyObject *CallbackFunction::callable_ref () const
|
||||
{
|
||||
return m_callable.get ();
|
||||
}
|
||||
|
||||
bool CallbackFunction::operator== (const CallbackFunction &other) const
|
||||
{
|
||||
if (is_instance_method () != other.is_instance_method ()) {
|
||||
return false;
|
||||
}
|
||||
if (m_weak_self) {
|
||||
if (self_ref () != other.self_ref ()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return callable_ref () == other.callable_ref ();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Implementation of SignalHandler
|
||||
|
||||
SignalHandler::SignalHandler ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
SignalHandler::~SignalHandler ()
|
||||
{
|
||||
clear ();
|
||||
}
|
||||
|
||||
void SignalHandler::call (const gsi::MethodBase *meth, gsi::SerialArgs &args, gsi::SerialArgs &ret) const
|
||||
{
|
||||
PYTHON_BEGIN_EXEC
|
||||
|
||||
tl::Heap heap;
|
||||
|
||||
int args_avail = int (std::distance (meth->begin_arguments (), meth->end_arguments ()));
|
||||
PythonRef argv (PyTuple_New (args_avail));
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); args && a != meth->end_arguments (); ++a) {
|
||||
PyTuple_SetItem (argv.get (), int (a - meth->begin_arguments ()), pop_arg (*a, args, 0, heap).release ());
|
||||
}
|
||||
|
||||
// NOTE: in case one event handler deletes the object, it's safer to first collect the handlers and
|
||||
// then call them.
|
||||
std::vector<PythonRef> callables;
|
||||
callables.reserve (m_cbfuncs.size ());
|
||||
for (std::vector<CallbackFunction>::const_iterator c = m_cbfuncs.begin (); c != m_cbfuncs.end (); ++c) {
|
||||
callables.push_back (c->callable ());
|
||||
}
|
||||
|
||||
PythonRef result;
|
||||
|
||||
for (std::vector<PythonRef>::const_iterator c = callables.begin (); c != callables.end (); ++c) {
|
||||
|
||||
// determine the number of arguments required
|
||||
int arg_count = args_avail;
|
||||
if (args_avail > 0) {
|
||||
|
||||
PythonRef fc (PyObject_GetAttrString (c->get (), "__code__"));
|
||||
if (fc) {
|
||||
PythonRef ac (PyObject_GetAttrString (fc.get (), "co_argcount"));
|
||||
if (ac) {
|
||||
arg_count = python2c<int> (ac.get ());
|
||||
if (PyObject_HasAttrString (c->get (), "__self__")) {
|
||||
arg_count -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// use less arguments if applicable
|
||||
if (arg_count == 0) {
|
||||
result = PythonRef (PyObject_CallObject (c->get (), NULL));
|
||||
} else if (arg_count < args_avail) {
|
||||
PythonRef argv_less (PyTuple_GetSlice (argv.get (), 0, arg_count));
|
||||
result = PythonRef (PyObject_CallObject (c->get (), argv_less.get ()));
|
||||
} else {
|
||||
result = PythonRef (PyObject_CallObject (c->get (), argv.get ()));
|
||||
}
|
||||
|
||||
if (! result) {
|
||||
check_error ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
push_arg (meth->ret_type (), ret, result.get (), heap);
|
||||
|
||||
// a Python callback must not leave temporary objects
|
||||
tl_assert (heap.empty ());
|
||||
|
||||
PYTHON_END_EXEC
|
||||
}
|
||||
|
||||
void SignalHandler::add (PyObject *callable)
|
||||
{
|
||||
remove (callable);
|
||||
m_cbfuncs.push_back (CallbackFunction (PythonPtr (callable), 0));
|
||||
}
|
||||
|
||||
void SignalHandler::remove (PyObject *callable)
|
||||
{
|
||||
// To avoid cyclic references, the CallbackFunction holder is employed. However, the
|
||||
// "true" callable no longer is the original one. Hence, we need to do a strict compare
|
||||
// against the effective one.
|
||||
CallbackFunction cbref (PythonPtr (callable), 0);
|
||||
for (std::vector<CallbackFunction>::iterator c = m_cbfuncs.begin (); c != m_cbfuncs.end (); ++c) {
|
||||
if (*c == cbref) {
|
||||
m_cbfuncs.erase (c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SignalHandler::clear ()
|
||||
{
|
||||
m_cbfuncs.clear ();
|
||||
}
|
||||
|
||||
void SignalHandler::assign (const SignalHandler *other)
|
||||
{
|
||||
m_cbfuncs = other->m_cbfuncs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _HDR_pyaSignalHandler
|
||||
#define _HDR_pyaSignalHandler
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "pyaRefs.h"
|
||||
|
||||
#include "gsiSignals.h"
|
||||
|
||||
namespace pya
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A storage object for a function to callback
|
||||
*/
|
||||
struct CallbackFunction
|
||||
{
|
||||
CallbackFunction (PythonRef pym, const gsi::MethodBase *m);
|
||||
|
||||
PythonRef callable () const;
|
||||
const gsi::MethodBase *method () const;
|
||||
bool operator== (const CallbackFunction &other) const;
|
||||
|
||||
private:
|
||||
PythonRef m_callable;
|
||||
PythonRef m_weak_self;
|
||||
PythonRef m_class;
|
||||
const gsi::MethodBase *mp_method;
|
||||
|
||||
PyObject *self_ref () const;
|
||||
PyObject *callable_ref () const;
|
||||
bool is_instance_method () const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The signal handler abstraction
|
||||
*
|
||||
* This class implements the signal handler that interfaces to GSI's signal system
|
||||
*/
|
||||
class SignalHandler
|
||||
: public gsi::SignalHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
SignalHandler ();
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~SignalHandler ();
|
||||
|
||||
/**
|
||||
* @brief Implementation of the callback interface
|
||||
*/
|
||||
virtual void call (const gsi::MethodBase *method, gsi::SerialArgs &args, gsi::SerialArgs &ret) const;
|
||||
|
||||
/**
|
||||
* @brief Adds a callable to the list of targets
|
||||
*/
|
||||
void add (PyObject *callable);
|
||||
|
||||
/**
|
||||
* @brief Removes a callable from the list of targets
|
||||
*/
|
||||
void remove (PyObject *callable);
|
||||
|
||||
/**
|
||||
* @brief Clears the list of callables
|
||||
*/
|
||||
void clear ();
|
||||
|
||||
/**
|
||||
* @brief Assign another handler to this
|
||||
*/
|
||||
void assign (const SignalHandler *other);
|
||||
|
||||
private:
|
||||
std::vector<CallbackFunction> m_cbfuncs;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "pyaStatusChangedListener.h"
|
||||
#include "pyaObject.h"
|
||||
|
||||
namespace pya
|
||||
{
|
||||
// --------------------------------------------------------------------------
|
||||
// Implementation of StatusChangedListener
|
||||
|
||||
StatusChangedListener::StatusChangedListener (PYAObjectBase *pya_object)
|
||||
: mp_pya_object (pya_object)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
StatusChangedListener::object_status_changed (gsi::ObjectBase::StatusEventType type)
|
||||
{
|
||||
if (type == gsi::ObjectBase::ObjectDestroyed) {
|
||||
mp_pya_object->object_destroyed ();
|
||||
} else if (type == gsi::ObjectBase::ObjectKeep) {
|
||||
mp_pya_object->keep_internal ();
|
||||
} else if (type == gsi::ObjectBase::ObjectRelease) {
|
||||
mp_pya_object->release ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _HDR_pyaStatusChangedListener
|
||||
#define _HDR_pyaStatusChangedListener
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "pyaRefs.h"
|
||||
|
||||
#include "gsiSignals.h"
|
||||
#include "gsiObject.h"
|
||||
|
||||
namespace pya
|
||||
{
|
||||
|
||||
class PYAObjectBase;
|
||||
|
||||
/**
|
||||
* @brief A helper object to forward status changed events to a Python object
|
||||
* This object is used to connect the events to the Python object. Unfortunately,
|
||||
* PYAObjectBase cannot be derived from tl::Object directly since in that case,
|
||||
* tl::Object will be placed before PyObject in the memory layout.
|
||||
*/
|
||||
class StatusChangedListener
|
||||
: public tl::Object
|
||||
{
|
||||
public:
|
||||
StatusChangedListener (PYAObjectBase *pya_object);
|
||||
|
||||
void object_status_changed (gsi::ObjectBase::StatusEventType type);
|
||||
|
||||
PYAObjectBase *pya_object () const
|
||||
{
|
||||
return mp_pya_object;
|
||||
}
|
||||
|
||||
private:
|
||||
PYAObjectBase *mp_pya_object;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -24,9 +24,47 @@
|
|||
#ifndef _HDR_pyaUtils
|
||||
#define _HDR_pyaUtils
|
||||
|
||||
#include "tlScriptError.h"
|
||||
|
||||
namespace pya
|
||||
{
|
||||
|
||||
/**
|
||||
* Some helper macros that translate C++ exceptions into Python errors
|
||||
*/
|
||||
|
||||
#define PYA_TRY \
|
||||
{ \
|
||||
try {
|
||||
|
||||
#define PYA_CATCH(where) \
|
||||
} catch (tl::ExitException &ex) { \
|
||||
PyErr_SetObject (PyExc_SystemExit, PyLong_FromLong (ex.status ())); \
|
||||
} catch (std::exception &ex) { \
|
||||
std::string msg = std::string(ex.what ()) + tl::to_string (QObject::tr (" in ")) + (where); \
|
||||
PyErr_SetString (PyExc_RuntimeError, msg.c_str ()); \
|
||||
} catch (tl::Exception &ex) { \
|
||||
std::string msg; \
|
||||
msg = ex.msg () + tl::to_string (QObject::tr (" in ")) + (where); \
|
||||
PyErr_SetString (PyExc_RuntimeError, msg.c_str ()); \
|
||||
} catch (...) { \
|
||||
std::string msg = tl::to_string (QObject::tr ("Unspecific exception in ")) + (where); \
|
||||
PyErr_SetString (PyExc_RuntimeError, msg.c_str ()); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PYA_CATCH_ANYWHERE \
|
||||
} catch (tl::ExitException &ex) { \
|
||||
PyErr_SetObject (PyExc_SystemExit, PyLong_FromLong (ex.status ())); \
|
||||
} catch (std::exception &ex) { \
|
||||
PyErr_SetString (PyExc_RuntimeError, ex.what ()); \
|
||||
} catch (tl::Exception &ex) { \
|
||||
PyErr_SetString (PyExc_RuntimeError, ex.msg ().c_str ()); \
|
||||
} catch (...) { \
|
||||
PyErr_SetString (PyExc_RuntimeError, tl::to_string (QObject::tr ("Unspecific exception in ")).c_str ()); \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Turn Python errors into C++ exceptions
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@ QT = core
|
|||
# - GSI (generic scripting interface)
|
||||
# - TL (basic toolkit)
|
||||
# - PYA (Python binding for GSI)
|
||||
INCLUDEPATH += $$PYTHONINCLUDE $$INC/tl/tl $$INC/gsi/gsi $$INC/pya/pya
|
||||
DEPENDPATH += $$PYTHONINCLUDE $$INC/tl/tl $$INC/gsi/gsi $$INC/pya/pya
|
||||
LIBS += $$PYTHONLIBFILE -L$$LIBDIR -lklayout_tl -lklayout_gsi -lklayout_pya
|
||||
INCLUDEPATH += $$PYTHONINCLUDE $$INC/tl/tl $$INC/pya/pya
|
||||
DEPENDPATH += $$PYTHONINCLUDE $$INC/tl/tl $$INC/pya/pya
|
||||
LIBS += $$PYTHONLIBFILE -L$$LIBDIR -lklayout_tl -lklayout_pya
|
||||
|
||||
# Also include DB as this is our sample
|
||||
INCLUDEPATH += $$INC/db/db
|
||||
|
|
|
|||
|
|
@ -31,7 +31,10 @@
|
|||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "pyaModule.h"
|
||||
#include "pyaUtils.h"
|
||||
|
||||
#include "gsi.h"
|
||||
#include "gsiExpression.h"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue