WIP: some refactoring of pya binding and data keeping. Added more conversion functions for use in external code. Needs testing.

This commit is contained in:
Matthias Koefferlein 2018-06-07 01:05:36 +02:00
parent 17846d12dd
commit eca8697398
13 changed files with 3563 additions and 3349 deletions

View File

@ -130,7 +130,9 @@ ClassBase::add_child_class (const ClassBase *cls)
bool
ClassBase::is_derived_from (const ClassBase *base) const
{
if (base == this) {
if (! base) {
return false;
} else if (base == this) {
return true;
} else if (!mp_base) {
return false;

View File

@ -30,7 +30,7 @@
namespace gsi
{
class GSI_PUBLIC ClassBase;
class ClassBase;
/**
* @brief Implements an object holder

View File

@ -1286,7 +1286,7 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
const gsi::MethodBase::MethodSynonym &syn = i->second.first->begin_synonyms () [i->second.second];
DocumentationParser method_doc (i->second.first);
std::string pydoc = pya::PythonModule::python_doc (i->second.first);
std::string pydoc = pya::PythonInterpreter::python_doc (i->second.first);
os << "<tr>";
if (i->first != prev_title) {

File diff suppressed because it is too large Load Diff

View File

@ -124,92 +124,7 @@ public:
{ }
};
class MethodTable;
/**
* @brief A representative for a Python module
* Instantiate this object to represent a python module.
* If used externally (for a library), call init with the module name.
* Then call make_classes to create the individual classes.
*/
class PYA_PUBLIC PythonModule
{
public:
/**
* @brief Constructor
*/
PythonModule ();
/**
* @brief Destructor
*/
~PythonModule ();
/**
* @brief Initializes the module
* This entry point is for external use where the module has not been created yet
*/
void init (const char *mod_name, const char *description);
/**
* @brief Initializes the module
* This entry point is for internal use where the module is created by the interpreter
*/
void init (const char *mod_name, PyObject *module);
/**
* @brief Creates the classes after init has been called
*/
void make_classes (const char *mod_name = 0);
/**
* @brief Gets the GSI class for a Python class
*/
static const gsi::ClassBase *cls_for_type (PyTypeObject *type);
/**
* @brief The reverse: gets a Python class for a GSI class or NULL if there is no binding
*/
static PyTypeObject *type_for_cls (const gsi::ClassBase *cls);
/**
* @brief Returns additional Python-specific documentation for the given method
* If no specific documentation exists, an empty string is returned.
*/
static std::string python_doc (const gsi::MethodBase *method);
/**
* @brief Gets the PyModule object
*/
PyObject *module ();
/**
* @brief Gets the PyModule object
* This method will release the ownership over the PyObject
*/
PyObject *take_module ();
private:
void add_python_doc (const gsi::ClassBase &cls, const MethodTable *mt, int mid, const std::string &doc);
PyMethodDef *make_method_def ();
PyGetSetDef *make_getset_def ();
char *make_string (const std::string &s);
static void check (const char *mod_name);
std::list<std::string> m_string_heap;
std::vector<PyMethodDef *> m_methods_heap;
std::vector<PyGetSetDef *> m_getseters_heap;
std::string m_mod_name, m_mod_description;
std::string m_base_class_name;
PythonRef mp_module;
PythonRef mp_base_class;
char *mp_mod_def;
static std::map<const gsi::MethodBase *, std::string> m_python_doc;
static std::map <PyTypeObject *, const gsi::ClassBase *> m_cls_map;
static std::map <const gsi::ClassBase *, PyTypeObject *> m_rev_cls_map;
};
class PythonModule;
/**
* @brief The python interpreter wrapper class
@ -358,6 +273,12 @@ public:
*/
int trace_func (PyFrameObject *frame, int event, PyObject *arg);
/**
* @brief Returns additional Python-specific documentation for the given method
* If no specific documentation exists, an empty string is returned.
*/
static std::string python_doc (const gsi::MethodBase *);
/**
* @brief Returns the singleton reference
*/
@ -394,7 +315,7 @@ private:
PyFrameObject *mp_current_frame;
std::map<PyObject *, size_t> m_file_id_map;
wchar_t *mp_py3_app_name;
pya::PythonModule m_pya_module;
std::auto_ptr<pya::PythonModule> m_pya_module;
};
}

View File

@ -15,6 +15,7 @@ SOURCES = \
pyaObject.cc \
pyaRefs.cc \
pyaUtils.cc \
pyaModule.cc
HEADERS += \
pya.h \
@ -25,7 +26,8 @@ HEADERS += \
pyaMarshal.h \
pyaObject.h \
pyaRefs.h \
pyaUtils.h
pyaUtils.h \
pyaModule.h
INCLUDEPATH += $$PYTHONINCLUDE $$TL_INC $$GSI_INC
DEPENDPATH += $$PYTHONINCLUDE $$TL_INC $$GSI_INC

View File

@ -23,8 +23,7 @@
#include "pyaConvert.h"
#include "pyaObject.h"
#include "pya.h"
#include "pyaModule.h"
#include "pyaUtils.h"
#include <string>
@ -33,7 +32,7 @@ namespace pya
{
template <>
long python2c<long> (PyObject *rval, tl::Heap *)
long python2c_func<long>::operator() (PyObject *rval)
{
#if PY_MAJOR_VERSION < 3
if (PyInt_Check (rval)) {
@ -50,13 +49,13 @@ long python2c<long> (PyObject *rval, tl::Heap *)
}
template <>
bool python2c<bool> (PyObject *rval, tl::Heap *)
bool python2c_func<bool>::operator() (PyObject *rval)
{
return PyObject_IsTrue (rval);
}
template <>
char python2c<char> (PyObject *rval, tl::Heap *)
char python2c_func<char>::operator() (PyObject *rval)
{
#if PY_MAJOR_VERSION < 3
if (PyInt_Check (rval)) {
@ -73,7 +72,7 @@ char python2c<char> (PyObject *rval, tl::Heap *)
}
template <>
unsigned long python2c<unsigned long> (PyObject *rval, tl::Heap *)
unsigned long python2c_func<unsigned long>::operator() (PyObject *rval)
{
#if PY_MAJOR_VERSION < 3
if (PyInt_Check (rval)) {
@ -90,7 +89,7 @@ unsigned long python2c<unsigned long> (PyObject *rval, tl::Heap *)
}
template <>
long long python2c<long long> (PyObject *rval, tl::Heap *)
long long python2c_func<long long>::operator() (PyObject *rval)
{
#if PY_MAJOR_VERSION < 3
if (PyInt_Check (rval)) {
@ -107,7 +106,7 @@ long long python2c<long long> (PyObject *rval, tl::Heap *)
}
template <>
unsigned long long python2c<unsigned long long> (PyObject *rval, tl::Heap *)
unsigned long long python2c_func<unsigned long long>::operator() (PyObject *rval)
{
#if PY_MAJOR_VERSION < 3
if (PyInt_Check (rval)) {
@ -125,7 +124,7 @@ unsigned long long python2c<unsigned long long> (PyObject *rval, tl::Heap *)
#if defined(HAVE_64BIT_COORD)
template <>
__int128 python2c<__int128> (PyObject *rval, tl::Heap *)
__int128 python2c_func<__int128>::operator() (PyObject *rval)
{
// TOOD: this is pretty simplistic
#if PY_MAJOR_VERSION < 3
@ -144,7 +143,7 @@ __int128 python2c<__int128> (PyObject *rval, tl::Heap *)
#endif
template <>
double python2c<double> (PyObject *rval, tl::Heap *)
double python2c_func<double>::operator() (PyObject *rval)
{
#if PY_MAJOR_VERSION < 3
if (PyInt_Check (rval)) {
@ -161,7 +160,7 @@ double python2c<double> (PyObject *rval, tl::Heap *)
}
template <>
std::string python2c<std::string> (PyObject *rval, tl::Heap *)
std::string python2c_func<std::string>::operator() (PyObject *rval)
{
#if PY_MAJOR_VERSION < 3
if (PyString_Check (rval)) {
@ -186,7 +185,7 @@ std::string python2c<std::string> (PyObject *rval, tl::Heap *)
}
template <>
QByteArray python2c<QByteArray> (PyObject *rval, tl::Heap *)
QByteArray python2c_func<QByteArray>::operator() (PyObject *rval)
{
#if PY_MAJOR_VERSION < 3
if (PyString_Check (rval)) {
@ -211,66 +210,36 @@ QByteArray python2c<QByteArray> (PyObject *rval, tl::Heap *)
}
template <>
const char *python2c<const char *> (PyObject *rval, tl::Heap *heap)
{
#if PY_MAJOR_VERSION < 3
if (PyString_Check (rval)) {
return PyString_AsString (rval);
} else
#else
if (PyBytes_Check (rval)) {
return PyBytes_AsString (rval);
} else
#endif
if (PyUnicode_Check (rval)) {
tl_assert (heap);
// for creating a const char * we need a temporary object. Otherwise we cannot keep that
// value.
std::string *converted_value = new std::string (python2c<std::string> (rval, heap));
heap->push (converted_value);
return converted_value->c_str ();
} else if (PyByteArray_Check (rval)) {
return PyByteArray_AsString (rval);
} else {
throw tl::Exception (tl::to_string (QObject::tr ("Argument cannot be converted to a string")));
}
}
template <>
QString python2c<QString> (PyObject *rval, tl::Heap *heap)
QString python2c_func<QString>::operator() (PyObject *rval)
{
// TODO: directly convert Unicode strings to QString if possible
return tl::to_qstring (python2c<std::string> (rval, heap));
return tl::to_qstring (python2c<std::string> (rval));
}
template <>
tl::Variant python2c<tl::Variant> (PyObject *rval, tl::Heap *heap)
tl::Variant python2c_func<tl::Variant>::operator() (PyObject *rval)
{
if (rval == NULL || rval == Py_None) {
return tl::Variant ();
} else if (PyBool_Check (rval)) {
return tl::Variant (python2c<bool> (rval, heap));
return tl::Variant (python2c<bool> (rval));
} else if (PyLong_Check (rval)) {
return tl::Variant (python2c<long long> (rval, heap));
return tl::Variant (python2c<long long> (rval));
#if PY_MAJOR_VERSION < 3
} else if (PyInt_Check (rval)) {
return tl::Variant (python2c<int> (rval, heap));
return tl::Variant (python2c<int> (rval));
#endif
} else if (PyFloat_Check (rval)) {
return tl::Variant (python2c<double> (rval, heap));
return tl::Variant (python2c<double> (rval));
#if PY_MAJOR_VERSION < 3
} else if (PyString_Check (rval)) {
return tl::Variant (python2c<std::string> (rval, heap));
return tl::Variant (python2c<std::string> (rval));
#else
} else if (PyBytes_Check (rval)) {
return tl::Variant (python2c<std::string> (rval, heap));
return tl::Variant (python2c<std::string> (rval));
#endif
} else if (PyUnicode_Check (rval) || PyByteArray_Check (rval)) {
return tl::Variant (python2c<std::string> (rval, heap));
return tl::Variant (python2c<std::string> (rval));
} else if (PyList_Check (rval)) {
size_t len = PyList_Size (rval);
@ -279,7 +248,7 @@ tl::Variant python2c<tl::Variant> (PyObject *rval, tl::Heap *heap)
tl::Variant r (empty.begin (), empty.end ());
r.get_list ().reserve (len);
for (size_t i = 0; i < len; ++i) {
r.get_list ().push_back (python2c<tl::Variant> (PyList_GetItem (rval, i), heap));
r.get_list ().push_back (python2c<tl::Variant> (PyList_GetItem (rval, i)));
}
return r;
@ -291,7 +260,7 @@ tl::Variant python2c<tl::Variant> (PyObject *rval, tl::Heap *heap)
tl::Variant r (empty.begin (), empty.end ());
r.get_list ().reserve (len);
for (size_t i = 0; i < len; ++i) {
r.get_list ().push_back (python2c<tl::Variant> (PyTuple_GetItem (rval, i), heap));
r.get_list ().push_back (python2c<tl::Variant> (PyTuple_GetItem (rval, i)));
}
return r;
@ -349,7 +318,7 @@ tl::Variant python2c<tl::Variant> (PyObject *rval, tl::Heap *heap)
std::string m ("<unknown type>");
PythonRef msg_str (PyObject_Str (rval));
if (msg_str) {
m = python2c<std::string> (msg_str.get (), heap);
m = python2c<std::string> (msg_str.get ());
}
return tl::Variant (m);
@ -472,7 +441,7 @@ object_to_python (void *obj, PYAObjectBase *self, const gsi::ClassBase *cls, boo
}
template <>
PyObject *c2python<tl::Variant> (const tl::Variant &c)
PyObject *c2python_func<const tl::Variant &>::operator() (const tl::Variant &c)
{
if (c.is_double ()) {
return c2python<double> (c.to_double ());
@ -522,31 +491,7 @@ PyObject *c2python<tl::Variant> (const tl::Variant &c)
}
template <>
PyObject *c2python<gsi::ObjectType> (const gsi::ObjectType &)
{
throw tl::Exception (tl::to_string (QObject::tr ("Internal error: abstract object type read")));
}
template <>
PyObject *c2python<gsi::VectorType> (const gsi::VectorType &)
{
throw tl::Exception (tl::to_string (QObject::tr ("Internal error: abstract vector type read")));
}
template <>
PyObject *c2python<gsi::MapType> (const gsi::MapType &)
{
throw tl::Exception (tl::to_string (QObject::tr ("Internal error: abstract map type read")));
}
template <>
PyObject *c2python<gsi::VoidType> (const gsi::VoidType &)
{
throw tl::Exception (tl::to_string (QObject::tr ("Internal error: abstract void type read")));
}
template <>
PyObject *c2python<std::string> (const std::string &c)
PyObject *c2python_func<const std::string &>::operator() (const std::string &c)
{
#if PY_MAJOR_VERSION < 3
return PyString_FromStringAndSize (c.c_str (), Py_ssize_t (c.size ()));
@ -560,7 +505,7 @@ PyObject *c2python<std::string> (const std::string &c)
}
template <>
PyObject *c2python<const char *> (const char * const &p)
PyObject *c2python_func<const char *>::operator() (const char *p)
{
const char *s = p;
if (! s) {
@ -579,7 +524,7 @@ PyObject *c2python<const char *> (const char * const &p)
}
template <>
PyObject *c2python<QByteArray> (const QByteArray &qba)
PyObject *c2python_func<const QByteArray &>::operator() (const QByteArray &qba)
{
if (qba.isNull ()) {
Py_RETURN_NONE;
@ -593,7 +538,7 @@ PyObject *c2python<QByteArray> (const QByteArray &qba)
}
template <>
PyObject *c2python<QString> (const QString &qs)
PyObject *c2python_func<const QString &>::operator() (const QString &qs)
{
if (qs.isNull ()) {
Py_RETURN_NONE;

View File

@ -26,6 +26,10 @@
#include "Python.h"
#include "pyaModule.h"
#include "pyaObject.h"
#include "gsiClassBase.h"
#include "tlVariant.h"
#include "tlException.h"
#include "tlHeap.h"
@ -36,8 +40,8 @@
namespace gsi
{
class GSI_PUBLIC ClassBase;
class GSI_PUBLIC ArgType;
class ClassBase;
class ArgType;
}
namespace pya
@ -72,6 +76,159 @@ object_to_python (void *obj, PYAObjectBase *self, const gsi::ArgType &atype);
// -------------------------------------------------------------------
// Type checks
template <class T>
struct test_type_func
{
bool operator() (PyObject * /*rval*/, bool /*loose*/)
{
return false;
}
};
template <>
struct test_type_func<bool>
{
bool operator() (PyObject *rval, bool loose)
{
if (loose) {
return true; // everything can be converted to bool
} else {
return PyBool_Check (rval) || rval == Py_None;
}
}
};
// used for other integer types as well:
template <>
struct test_type_func<int>
{
bool operator() (PyObject *rval, bool loose)
{
// bool values don't count as int in strict mode
if (!loose && PyBool_Check (rval)) {
return false;
}
#if PY_MAJOR_VERSION < 3
return PyInt_Check (rval) || PyLong_Check (rval) || (PyFloat_Check (rval) && loose);
#else
return PyLong_Check (rval) || (PyFloat_Check (rval) && loose);
#endif
}
};
template <> struct test_type_func<unsigned int> : public test_type_func<int> { };
template <> struct test_type_func<char> : public test_type_func<int> { };
template <> struct test_type_func<signed char> : public test_type_func<int> { };
template <> struct test_type_func<unsigned char> : public test_type_func<int> { };
template <> struct test_type_func<short> : public test_type_func<int> { };
template <> struct test_type_func<unsigned short> : public test_type_func<int> { };
template <> struct test_type_func<long> : public test_type_func<int> { };
template <> struct test_type_func<unsigned long> : public test_type_func<int> { };
template <> struct test_type_func<long long> : public test_type_func<int> { };
template <> struct test_type_func<unsigned long long> : public test_type_func<int> { };
#if defined(HAVE_64BIT_COORD)
template <>
struct test_type_func<__int128>
{
bool operator() (PyObject *rval, bool loose)
{
return test_type<int> (rval, loose);
}
};
#endif
template <>
struct test_type_func<double>
{
bool operator() (PyObject *rval, bool loose)
{
// bool values don't count as int in strict mode
if (!loose && PyBool_Check (rval)) {
return false;
}
#if PY_MAJOR_VERSION < 3
return PyFloat_Check (rval) || (PyInt_Check (rval) && loose) || (PyLong_Check (rval) && loose);
#else
return PyFloat_Check (rval) || (PyLong_Check (rval) && loose);
#endif
}
};
template <>
struct test_type_func<float> : public test_type_func<double> { };
template <>
struct test_type_func<void *> : public test_type_func<size_t> { };
// used for strings in general:
template <>
struct test_type_func<const char *>
{
bool operator() (PyObject *rval, bool /*loose*/)
{
#if PY_MAJOR_VERSION < 3
return PyString_Check (rval) || PyUnicode_Check (rval) || PyByteArray_Check (rval);
#else
return PyBytes_Check (rval) || PyUnicode_Check (rval) || PyByteArray_Check (rval);
#endif
}
};
template <> struct test_type_func<std::string> : public test_type_func<const char *> { };
template <> struct test_type_func<QString> : public test_type_func<const char *> { };
template <> struct test_type_func<QByteArray> : public test_type_func<const char *> { };
template <>
struct test_type_func<tl::Variant>
{
bool operator() (PyObject * /*rval*/, bool /*loose*/)
{
return true;
}
};
template <class T>
struct test_type_func<T &>
{
bool operator() (PyObject *rval, bool /*loose*/)
{
// 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)));
}
};
template <class T>
struct test_type_func<const T &>
{
bool operator() (PyObject *rval, bool loose)
{
return test_type_func<T &> () (rval, loose);
}
};
template <class T>
struct test_type_func<const T *>
{
bool operator() (PyObject *rval, bool loose)
{
// for the pointer types, None is an allowed value
return rval == Py_None || test_type_func<T &> () (rval, loose);
}
};
template <class T>
struct test_type_func<T *>
{
bool operator() (PyObject *rval, bool loose)
{
// for the pointer types, None is an allowed value
return rval == Py_None || test_type_func<T &> () (rval, loose);
}
};
/**
* @brief Checks whether the Python object is compatible with the given type
*
@ -82,163 +239,9 @@ object_to_python (void *obj, PYAObjectBase *self, const gsi::ArgType &atype);
* @param loose If true, the type is checked more loosely. Use for second-pass matching.
*/
template <class T>
bool test_type (PyObject * /*rval*/, bool /*loose*/)
inline bool test_type (PyObject * rval, bool loose)
{
return false;
}
template <>
inline bool test_type<bool> (PyObject *rval, bool loose)
{
if (loose) {
return true; // everything can be converted to bool
} else {
return PyBool_Check (rval) || rval == Py_None;
}
}
// used for other integer types as well:
template <>
inline bool test_type<int> (PyObject *rval, bool loose)
{
// bool values don't count as int in strict mode
if (!loose && PyBool_Check (rval)) {
return false;
}
#if PY_MAJOR_VERSION < 3
return PyInt_Check (rval) || PyLong_Check (rval) || (PyFloat_Check (rval) && loose);
#else
return PyLong_Check (rval) || (PyFloat_Check (rval) && loose);
#endif
}
template <>
inline bool test_type<char> (PyObject *rval, bool loose)
{
return test_type<int> (rval, loose);
}
template <>
inline bool test_type<signed char> (PyObject *rval, bool loose)
{
return test_type<int> (rval, loose);
}
template <>
inline bool test_type<unsigned char> (PyObject *rval, bool loose)
{
return test_type<int> (rval, loose);
}
template <>
inline bool test_type<short> (PyObject *rval, bool loose)
{
return test_type<int> (rval, loose);
}
template <>
inline bool test_type<unsigned short> (PyObject *rval, bool loose)
{
return test_type<int> (rval, loose);
}
template <>
inline bool test_type<unsigned int> (PyObject *rval, bool loose)
{
return test_type<int> (rval, loose);
}
template <>
inline bool test_type<long> (PyObject *rval, bool loose)
{
return test_type<int> (rval, loose);
}
template <>
inline bool test_type<unsigned long> (PyObject *rval, bool loose)
{
return test_type<int> (rval, loose);
}
template <>
inline bool test_type<long long> (PyObject *rval, bool loose)
{
return test_type<int> (rval, loose);
}
template <>
inline bool test_type<unsigned long long> (PyObject *rval, bool loose)
{
return test_type<int> (rval, loose);
}
#if defined(HAVE_64BIT_COORD)
template <>
inline bool test_type<__int128> (PyObject *rval, bool loose)
{
return test_type<int> (rval, loose);
}
#endif
template <>
inline bool test_type<double> (PyObject *rval, bool loose)
{
// bool values don't count as int in strict mode
if (!loose && PyBool_Check (rval)) {
return false;
}
#if PY_MAJOR_VERSION < 3
return PyFloat_Check (rval) || (PyInt_Check (rval) && loose) || (PyLong_Check (rval) && loose);
#else
return PyFloat_Check (rval) || (PyLong_Check (rval) && loose);
#endif
}
template <>
inline bool test_type<float> (PyObject *rval, bool loose)
{
return test_type<double> (rval, loose);
}
template <>
inline bool test_type<void *> (PyObject *rval, bool loose)
{
return test_type<size_t> (rval, loose);
}
// used for strings in general:
template <>
inline bool test_type<const char *> (PyObject *rval, bool /*loose*/)
{
#if PY_MAJOR_VERSION < 3
return PyString_Check (rval) || PyUnicode_Check (rval) || PyByteArray_Check (rval);
#else
return PyBytes_Check (rval) || PyUnicode_Check (rval) || PyByteArray_Check (rval);
#endif
}
template <>
inline bool test_type<std::string> (PyObject *rval, bool loose)
{
return test_type<const char *> (rval, loose);
}
template <>
inline bool test_type<QString> (PyObject *rval, bool loose)
{
return test_type<const char *> (rval, loose);
}
template <>
inline bool test_type<QByteArray> (PyObject *rval, bool loose)
{
return test_type<const char *> (rval, loose);
}
template <>
inline bool test_type<tl::Variant> (PyObject * /*rval*/, bool /*loose*/)
{
return true;
return test_type_func<T> () (rval, loose);
}
/**
@ -251,7 +254,7 @@ inline bool test_vector (PyObject *arr, bool loose)
size_t len = PyList_Size (arr);
for (size_t i = 0; i < len; ++i) {
if (! test_type<R> (PyList_GetItem (arr, i), loose)) {
if (! test_type_func<R> () (PyList_GetItem (arr, i), loose)) {
return false;
}
}
@ -262,7 +265,7 @@ inline bool test_vector (PyObject *arr, bool loose)
size_t len = PyTuple_Size (arr);
for (size_t i = 0; i < len; ++i) {
if (! test_type<R> (PyTuple_GetItem (arr, i), loose)) {
if (! test_type_func<R> () (PyTuple_GetItem (arr, i), loose)) {
return false;
}
}
@ -274,210 +277,365 @@ inline bool test_vector (PyObject *arr, bool loose)
}
}
// -------------------------------------------------------------------
// Python to C conversion
template <class T>
struct python2c_func
{
T operator() (PyObject *rval);
};
template <> long python2c_func<long>::operator() (PyObject *rval);
template <> unsigned long python2c_func<unsigned long>::operator() (PyObject *rval);
template <> bool python2c_func<bool>::operator() (PyObject *rval);
template <> char python2c_func<char>::operator() (PyObject *rval);
template <class D, class C>
struct python2c_func_cast
: public python2c_func<C>
{
D operator() (PyObject *rval)
{
return (D) (python2c_func<C>::operator() (rval));
}
};
template <> struct python2c_func<signed char> : public python2c_func_cast<signed char, char> { };
template <> struct python2c_func<unsigned char> : public python2c_func_cast<unsigned char, char> { };
template <> struct python2c_func<short> : public python2c_func_cast<short, long> { };
template <> struct python2c_func<unsigned short> : public python2c_func_cast<unsigned short, long> { };
template <> struct python2c_func<int> : public python2c_func_cast<int, long> { };
template <> struct python2c_func<unsigned int> : public python2c_func_cast<unsigned int, long> { };
template <> long long python2c_func<long long>::operator() (PyObject *rval);
template <> unsigned long long python2c_func<unsigned long long>::operator() (PyObject *rval);
#if defined(HAVE_64BIT_COORD)
template <> __int128 python2c_func<__int128>::operator() (PyObject *rval);
#endif
template <> double python2c_func<double>::operator() (PyObject *rval);
template <> struct python2c_func<float> : public python2c_func_cast<float, double> { };
template <> std::string python2c_func<std::string>::operator() (PyObject *rval);
template <> QByteArray python2c_func<QByteArray>::operator() (PyObject *rval);
template <> QString python2c_func<QString>::operator() (PyObject *rval);
template <> struct python2c_func<void *> : public python2c_func_cast<void *, size_t> { };
template <> tl::Variant python2c_func<tl::Variant>::operator() (PyObject *rval);
template <class T> struct python2c_func<T &>
{
T &operator() (PyObject *rval)
{
tl_assert (rval != Py_None);
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))));
PYAObjectBase *p = (PYAObjectBase *) (rval);
return *((T *)p->obj ());
}
};
template <class T> struct python2c_func<const T &>
{
const T &operator() (PyObject *rval)
{
return python2c_func<T &>() (rval);
}
};
template <class T> struct python2c_func<T *>
{
T *operator() (PyObject *rval)
{
tl_assert (rval != Py_None);
if (rval == Py_None) {
return 0;
} else {
return &python2c_func<T &>() (rval);
}
}
};
template <class T> struct python2c_func<const T *>
{
const T *operator() (PyObject *rval)
{
return python2c_func<T *> (rval);
}
};
/**
* @brief Converts the Python object to the given type
*/
template <class T>
inline T python2c (PyObject *, tl::Heap * = 0)
inline T python2c (PyObject *rval)
{
tl_assert (false);
return T ();
return python2c_func<T> () (rval);
}
template <> long python2c<long> (PyObject *rval, tl::Heap *heap);
template <> bool python2c<bool> (PyObject *rval, tl::Heap *heap);
template <> char python2c<char> (PyObject *rval, tl::Heap *heap);
template <>
inline signed char python2c<signed char> (PyObject *rval, tl::Heap *)
{
return (signed char) python2c<char> (rval);
}
template <>
inline unsigned char python2c<unsigned char> (PyObject *rval, tl::Heap *)
{
return (unsigned char) python2c<char> (rval);
}
template <>
inline short python2c<short> (PyObject *rval, tl::Heap *)
{
return (short) python2c<long> (rval);
}
template <>
inline unsigned short python2c<unsigned short> (PyObject *rval, tl::Heap *)
{
return (unsigned short) python2c<long> (rval);
}
template <>
inline int python2c<int> (PyObject *rval, tl::Heap *)
{
return (int) python2c<long> (rval);
}
template <>
inline unsigned int python2c<unsigned int> (PyObject *rval, tl::Heap *)
{
return (unsigned int) python2c<long> (rval);
}
template <> unsigned long python2c<unsigned long> (PyObject *rval, tl::Heap *heap);
template <> long long python2c<long long> (PyObject *rval, tl::Heap *heap);
template <> unsigned long long python2c<unsigned long long> (PyObject *rval, tl::Heap *heap);
#if defined(HAVE_64BIT_COORD)
template <> __int128 python2c<__int128> (PyObject *rval, tl::Heap *heap);
#endif
template <> double python2c<double> (PyObject *rval, tl::Heap *heap);
template <>
inline float python2c<float> (PyObject *rval, tl::Heap *)
{
return (float) python2c<double> (rval);
}
template <> std::string python2c<std::string> (PyObject *rval, tl::Heap *heap);
template <> QByteArray python2c<QByteArray> (PyObject *rval, tl::Heap *heap);
template <> QString python2c<QString> (PyObject *rval, tl::Heap *heap);
template <>
inline void *python2c<void *> (PyObject *rval, tl::Heap *)
{
return (void *) python2c<size_t> (rval);
}
template <> const char *python2c<const char *> (PyObject *rval, tl::Heap *heap);
template <> tl::Variant python2c<tl::Variant> (PyObject *rval, tl::Heap *heap);
// -------------------------------------------------------------------
// C to Python conversion
template <class T>
struct c2python_func
{
PyObject *operator() (T t);
};
/**
* @brief Converts the given type to a Python object
* @brief Converts a C++ object reference to a Python object
* T must be a registered type.
*/
template <class T>
PyObject *c2python (const T &);
template <>
inline PyObject *c2python<bool> (const bool &c)
struct c2python_func<T &>
{
if (c) {
Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
PyObject *operator() (T &p)
{
return object_to_python ((void *) &p, 0, gsi::class_by_typeinfo_no_assert (typeid (T)), false /*==don't pass*/, false /*==non-const*/, false, false /*==can't destroy*/);
}
}
};
/**
* @brief Converts a const C++ object reference to a Python object
* T must be a registered type.
*/
template <class T>
struct c2python_func<const T &>
{
PyObject *operator() (const T &p)
{
return object_to_python ((void *) &p, 0, gsi::class_by_typeinfo_no_assert (typeid (T)), false /*==don't pass*/, true /*==const*/, false, false /*==can't destroy*/);
}
};
/**
* @brief Converts a C++ object pointer to a Python object
* This version does not transfer ownership over the object to Python. The pointer will
* still be held by the caller. To transer the ownership to Python, use python2c_new(p).
* T must be a registered type.
*/
template <class T>
struct c2python_func<T *>
{
PyObject *operator() (T *p)
{
if (! p) {
Py_RETURN_NONE;
} else {
return object_to_python ((void *) p, 0, gsi::class_by_typeinfo_no_assert (typeid (T)), false /*==don't pass*/, false /*==non-const*/, false, false /*==can't destroy*/);
}
}
};
/**
* @brief Converts a C++ object pointer to a Python object
* This version will not transfer the ownership over the pointer as the pointer is const.
* T must be a registered type.
*/
template <class T>
struct c2python_func<const T *>
{
PyObject *operator() (const T *p)
{
if (! p) {
Py_RETURN_NONE;
} else {
return object_to_python ((void *) p, 0, gsi::class_by_typeinfo_no_assert (typeid (T)), false /*==don't pass*/, true /*==const*/, false, false /*==can't destroy*/);
}
}
};
template <>
inline PyObject *c2python<char> (const char &c)
struct c2python_func<bool>
{
return PyLong_FromLong (long (c));
}
PyObject *operator() (bool c)
{
if (c) {
Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
}
};
template <>
inline PyObject *c2python<signed char> (const signed char &c)
struct c2python_func<char>
{
return PyLong_FromLong (long (c));
}
PyObject *operator() (char c)
{
return PyLong_FromLong (long (c));
}
};
template <>
inline PyObject *c2python<unsigned char> (const unsigned char &c)
struct c2python_func<signed char>
{
return PyLong_FromLong (long (c));
}
PyObject *operator() (signed char c)
{
return PyLong_FromLong (long (c));
}
};
template <>
inline PyObject *c2python<short> (const short &c)
struct c2python_func<unsigned char>
{
return PyLong_FromLong (long (c));
}
PyObject *operator() (unsigned char c)
{
return PyLong_FromLong (long (c));
}
};
template <>
inline PyObject *c2python<unsigned short> (const unsigned short &c)
struct c2python_func<short>
{
return PyLong_FromLong (long (c));
}
PyObject *operator() (short c)
{
return PyLong_FromLong (long (c));
}
};
template <>
inline PyObject *c2python<int> (const int &c)
struct c2python_func<unsigned short>
{
return PyLong_FromLong (long (c));
}
PyObject *operator() (unsigned short c)
{
return PyLong_FromLong (long (c));
}
};
template <>
inline PyObject *c2python<unsigned int> (const unsigned int &c)
struct c2python_func<int>
{
return PyLong_FromLong (long (c));
}
PyObject *operator() (int c)
{
return PyLong_FromLong (long (c));
}
};
template <>
inline PyObject *c2python<long> (const long &c)
struct c2python_func<unsigned int>
{
return PyLong_FromLong (c);
}
PyObject *operator() (unsigned int c)
{
return PyLong_FromLong (long (c));
}
};
template <>
inline PyObject *c2python<unsigned long> (const unsigned long &c)
struct c2python_func<long>
{
return PyLong_FromUnsignedLong (c);
}
PyObject *operator() (long c)
{
return PyLong_FromLong (c);
}
};
template <>
inline PyObject *c2python<long long> (const long long &c)
struct c2python_func<unsigned long>
{
return PyLong_FromLongLong (c);
}
PyObject *operator() (unsigned long c)
{
return PyLong_FromUnsignedLong (c);
}
};
template <>
inline PyObject *c2python<unsigned long long> (const unsigned long long &c)
struct c2python_func<long long>
{
return PyLong_FromUnsignedLongLong (c);
}
PyObject *operator() (long long c)
{
return PyLong_FromLongLong (c);
}
};
template <>
struct c2python_func<unsigned long long>
{
PyObject *operator() (unsigned long long c)
{
return PyLong_FromUnsignedLongLong (c);
}
};
#if defined(HAVE_64BIT_COORD)
template <>
inline PyObject *c2python<__int128> (const __int128 &c)
struct c2python_func<const __int128 &>
{
return PyLong_FromUnsignedLongLong (c);
}
PyObject *operator() (const __int128 &c)
{
return PyLong_FromUnsignedLongLong (c);
}
};
#endif
template <>
inline PyObject *c2python<double> (const double &c)
struct c2python_func<double>
{
return PyFloat_FromDouble (c);
}
PyObject *operator() (double c)
{
return PyFloat_FromDouble (double (c));
}
};
template <>
inline PyObject *c2python<float> (const float &c)
struct c2python_func<float>
{
return PyFloat_FromDouble (double (c));
}
PyObject *operator() (float c)
{
return PyFloat_FromDouble (double (c));
}
};
template <> PyObject *c2python<std::string> (const std::string &c);
template <> PyObject *c2python<QByteArray> (const QByteArray &qba);
template <> PyObject *c2python<QString> (const QString &qs);
template <> PyObject *c2python_func<const char *>::operator() (const char *);
template <> PyObject *c2python_func<const QString &>::operator() (const QString &c);
template <> PyObject *c2python_func<const QByteArray &>::operator() (const QByteArray &c);
template <> PyObject *c2python_func<const std::string &>::operator() (const std::string &c);
template <>
inline PyObject *c2python<void *> (void * const &s)
struct c2python_func<void *>
: public c2python_func<size_t>
{
return c2python<size_t> (size_t (s));
PyObject *operator() (void *p)
{
return c2python_func<size_t>::operator () (size_t (p));
}
};
template <> PyObject *c2python_func<const tl::Variant &>::operator() (const tl::Variant &c);
/**
* @brief Converts the Python object to the given type
*/
template <class T>
inline PyObject *c2python (T t)
{
return c2python_func<T> () (t);
}
template <>
PyObject *c2python<tl::Variant> (const tl::Variant &c);
template <> PyObject *c2python<const char *> (const char * const &p);
/**
* @brief Converts a C++ object pointer to a Python object
* This version transfers ownership over the object to Python. The pointer will
* be help by Python and the object will be destroyed when Python no longer needs the
* object. To keep the ownership, use python2c(p).
* T must be a registered type.
*/
template <class T>
inline PyObject *c2python_new (T *p)
{
if (! p) {
Py_RETURN_NONE;
} else {
return object_to_python ((void *) p, 0, gsi::class_by_typeinfo_no_assert (typeid (T)), true /*==pass*/, false /*==non-const*/, false, true /*==can destroy*/);
}
}
}
#endif

View File

@ -24,7 +24,7 @@
#include "pyaMarshal.h"
#include "pyaObject.h"
#include "pyaConvert.h"
#include "pya.h"
#include "pyaModule.h"
#include "gsiTypes.h"
#include "gsiObjectHolder.h"
@ -175,7 +175,7 @@ struct get_boxed_value_func
const gsi::ClassBase *cls_decl = PythonModule::cls_for_type (Py_TYPE (arg));
if (! cls_decl) {
R *v = new R (python2c<R> (arg, heap));
R *v = new R (python2c<R> (arg));
heap->push (v);
*ret = v;
@ -240,14 +240,14 @@ struct writer
} else if (atype.is_cref ()) {
// Note: POD's are written as copies for const refs, so we can pass a temporary here:
// (avoids having to create a temp object)
aa->write<const R &> (python2c<R> (arg, heap));
aa->write<const R &> (python2c<R> (arg));
} else if (atype.is_cptr ()) {
// Note: POD's are written as copies for const ptrs, so we can pass a temporary here:
// (avoids having to create a temp object)
R r = python2c<R> (arg, heap);
R r = python2c<R> (arg);
aa->write<const R *> (&r);
} else {
aa->write<R> (python2c<R> (arg, heap));
aa->write<R> (python2c<R> (arg));
}
}

2929
src/pya/pya/pyaModule.cc Normal file

File diff suppressed because it is too large Load Diff

119
src/pya/pya/pyaModule.h Normal file
View File

@ -0,0 +1,119 @@
/*
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_pyaModule
#define _HDR_pyaModule
#include "pya.h"
namespace pya
{
class MethodTable;
/**
* @brief A representative for a Python module
* Instantiate this object to represent a python module.
* If used externally (for a library), call init with the module name.
* Then call make_classes to create the individual classes.
*/
class PYA_PUBLIC PythonModule
{
public:
/**
* @brief Constructor
*/
PythonModule ();
/**
* @brief Destructor
*/
~PythonModule ();
/**
* @brief Initializes the module
* This entry point is for external use where the module has not been created yet
*/
void init (const char *mod_name, const char *description);
/**
* @brief Initializes the module
* This entry point is for internal use where the module is created by the interpreter
*/
void init (const char *mod_name, PyObject *module);
/**
* @brief Creates the classes after init has been called
*/
void make_classes (const char *mod_name = 0);
/**
* @brief Gets the GSI class for a Python class
*/
static const gsi::ClassBase *cls_for_type (PyTypeObject *type);
/**
* @brief The reverse: gets a Python class for a GSI class or NULL if there is no binding
*/
static PyTypeObject *type_for_cls (const gsi::ClassBase *cls);
/**
* @brief Returns additional Python-specific documentation for the given method
* If no specific documentation exists, an empty string is returned.
*/
static std::string python_doc (const gsi::MethodBase *method);
/**
* @brief Gets the PyModule object
*/
PyObject *module ();
/**
* @brief Gets the PyModule object
* This method will release the ownership over the PyObject
*/
PyObject *take_module ();
private:
void add_python_doc (const gsi::ClassBase &cls, const MethodTable *mt, int mid, const std::string &doc);
PyMethodDef *make_method_def ();
PyGetSetDef *make_getset_def ();
char *make_string (const std::string &s);
static void check (const char *mod_name);
std::list<std::string> m_string_heap;
std::vector<PyMethodDef *> m_methods_heap;
std::vector<PyGetSetDef *> m_getseters_heap;
std::string m_mod_name, m_mod_description;
std::string m_base_class_name;
PythonRef mp_module;
PythonRef mp_base_class;
char *mp_mod_def;
static std::map<const gsi::MethodBase *, std::string> m_python_doc;
};
}
#endif

View File

@ -157,7 +157,7 @@ public:
* @brief Returns additional Python-specific documentation for the given method
* If no specific documentation exists, an empty string is returned.
*/
std::string python_doc (const gsi::MethodBase *) const
static std::string python_doc (const gsi::MethodBase *)
{
return std::string ();
}

View File

@ -31,7 +31,7 @@
*/
#include <Python.h>
#include "pya.h"
#include "pyaModule.h"
#include "gsi.h"
#include "gsiExpression.h"