lib
pythonextension.cpp00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "pythonextension.h"
00021 #include "pythonobject.h"
00022
00023 #include "../api/variant.h"
00024 #include "../api/dict.h"
00025 #include "../api/exception.h"
00026
00027 #include <kdebug.h>
00028
00029 using namespace Kross::Python;
00030
00031 PythonExtension::PythonExtension(Kross::Api::Object::Ptr object)
00032 : Py::PythonExtension<PythonExtension>()
00033 , m_object(object)
00034 {
00035 #ifdef KROSS_PYTHON_EXTENSION_CTOR_DEBUG
00036 kdDebug() << QString("Kross::Python::PythonExtension::Constructor objectname='%1' objectclass='%2'").arg(m_object->getName()).arg(m_object->getClassName()) << endl;
00037 #endif
00038
00039 behaviors().name("KrossPythonExtension");
00040
00041
00042
00043
00044
00045
00046
00047 behaviors().supportGetattr();
00048
00049 m_proxymethod = new Py::MethodDefExt<PythonExtension>(
00050 "",
00051 0,
00052 Py::method_varargs_call_handler_t( proxyhandler ),
00053 ""
00054 );
00055 }
00056
00057 PythonExtension::~PythonExtension()
00058 {
00059 #ifdef KROSS_PYTHON_EXTENSION_DTOR_DEBUG
00060 kdDebug() << QString("Kross::Python::PythonExtension::Destructor objectname='%1' objectclass='%2'").arg(m_object->getName()).arg(m_object->getClassName()) << endl;
00061 #endif
00062 delete m_proxymethod;
00063 }
00064
00065 Py::Object PythonExtension::str()
00066 {
00067 QString s = m_object->getName();
00068 return toPyObject(s.isEmpty() ? m_object->getClassName() : s);
00069 }
00070
00071 Py::Object PythonExtension::repr()
00072 {
00073 return toPyObject( m_object->toString() );
00074 }
00075
00076 Py::Object PythonExtension::getattr(const char* n)
00077 {
00078 #ifdef KROSS_PYTHON_EXTENSION_GETATTR_DEBUG
00079 kdDebug() << QString("Kross::Python::PythonExtension::getattr name='%1'").arg(n) << endl;
00080 #endif
00081
00082 if(n[0] == '_') {
00083 if(n == "__methods__") {
00084 Py::List methods;
00085 QStringList calls = m_object->getCalls();
00086 for(QStringList::Iterator it = calls.begin(); it != calls.end(); ++it) {
00087 #ifdef KROSS_PYTHON_EXTENSION_GETATTR_DEBUG
00088 kdDebug() << QString("Kross::Python::PythonExtension::getattr name='%1' callable='%2'").arg(n).arg(*it) << endl;
00089 #endif
00090 methods.append(Py::String( (*it).latin1() ));
00091 }
00092 return methods;
00093 }
00094
00095 if(n == "__members__") {
00096 Py::List members;
00097 QMap<QString, Kross::Api::Object::Ptr> children = m_object->getChildren();
00098 QMap<QString, Kross::Api::Object::Ptr>::Iterator it( children.begin() );
00099 for(; it != children.end(); ++it) {
00100 #ifdef KROSS_PYTHON_EXTENSION_GETATTR_DEBUG
00101 kdDebug() << QString("Kross::Python::PythonExtension::getattr n='%1' child='%2'").arg(n).arg(it.key()) << endl;
00102 #endif
00103 members.append(Py::String( it.key().latin1() ));
00104 }
00105 return members;
00106 }
00107
00108
00109
00110
00111 #ifdef KROSS_PYTHON_EXTENSION_GETATTR_DEBUG
00112 kdDebug() << QString("Kross::Python::PythonExtension::getattr name='%1' is a internal name.").arg(n) << endl;
00113 #endif
00114 return Py::PythonExtension<PythonExtension>::getattr_methods(n);
00115 }
00116
00117
00118
00119 Py::Tuple self(2);
00120 self[0] = Py::Object(this);
00121 self[1] = Py::String(n);
00122 return Py::Object(PyCFunction_New( &m_proxymethod->ext_meth_def, self.ptr() ), true);
00123 }
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 Kross::Api::List::Ptr PythonExtension::toObject(const Py::Tuple& tuple)
00144 {
00145 #ifdef KROSS_PYTHON_EXTENSION_TOOBJECT_DEBUG
00146 kdDebug() << QString("Kross::Python::PythonExtension::toObject(Py::Tuple)") << endl;
00147 #endif
00148
00149 QValueList<Kross::Api::Object::Ptr> l;
00150 uint size = tuple.size();
00151 for(uint i = 0; i < size; i++)
00152 l.append( toObject( tuple[i] ) );
00153 return new Kross::Api::List(l);
00154 }
00155
00156 Kross::Api::List::Ptr PythonExtension::toObject(const Py::List& list)
00157 {
00158 #ifdef KROSS_PYTHON_EXTENSION_TOOBJECT_DEBUG
00159 kdDebug() << QString("Kross::Python::PythonExtension::toObject(Py::List)") << endl;
00160 #endif
00161
00162 QValueList<Kross::Api::Object::Ptr> l;
00163 uint length = list.length();
00164 for(uint i = 0; i < length; i++)
00165 l.append( toObject( list[i] ) );
00166 return new Kross::Api::List(l);
00167 }
00168
00169 Kross::Api::Dict::Ptr PythonExtension::toObject(const Py::Dict& dict)
00170 {
00171 QMap<QString, Kross::Api::Object::Ptr> map;
00172 Py::List l = dict.keys();
00173 uint length = l.length();
00174 for(Py::List::size_type i = 0; i < length; ++i) {
00175 const char* n = l[i].str().as_string().c_str();
00176 map.replace(n, toObject( dict[n] ));
00177 }
00178 return new Kross::Api::Dict(map);
00179 }
00180
00181 Kross::Api::Object::Ptr PythonExtension::toObject(const Py::Object& object)
00182 {
00183 #ifdef KROSS_PYTHON_EXTENSION_TOOBJECT_DEBUG
00184 kdDebug() << QString("Kross::Python::PythonExtension::toObject(Py::Object) object='%1'").arg(object.as_string().c_str()) << endl;
00185 #endif
00186 if(object == Py::None())
00187 return 0;
00188 PyTypeObject *type = (PyTypeObject*) object.type().ptr();
00189 #ifdef KROSS_PYTHON_EXTENSION_TOOBJECT_DEBUG
00190 kdDebug() << QString("Kross::Python::PythonExtension::toObject(Py::Object) type='%1'").arg(type->tp_name) << endl;
00191 #endif
00192 if(type == &PyInt_Type)
00193 return new Kross::Api::Variant(int(Py::Int(object)));
00194 if(type == &PyBool_Type)
00195 return new Kross::Api::Variant(QVariant(object.isTrue(),0));
00196 if(type == &PyLong_Type)
00197 return new Kross::Api::Variant(Q_LLONG(long(Py::Long(object))));
00198 if(type == &PyFloat_Type)
00199 return new Kross::Api::Variant(double(Py::Float(object)));
00200
00201 if( PyType_IsSubtype(type,&PyString_Type) ) {
00202 #ifdef Py_USING_UNICODE
00203 if(type == &PyUnicode_Type) {
00204 Py::unicodestring u = Py::String(object).as_unicodestring();
00205 std::string s;
00206 std::copy(u.begin(), u.end(), std::back_inserter(s));
00207 return new Kross::Api::Variant(s.c_str());
00208 }
00209 #endif
00210 return new Kross::Api::Variant(object.as_string().c_str());
00211 }
00212
00213 if(type == &PyTuple_Type)
00214 return toObject(Py::Tuple(object)).data();
00215 if(type == &PyList_Type)
00216 return toObject(Py::List(object)).data();
00217 if(type == &PyDict_Type)
00218 return toObject(Py::Dict(object.ptr())).data();
00219
00220 if(object.isInstance())
00221 return new PythonObject(object);
00222
00223 Py::ExtensionObject<PythonExtension> extobj(object);
00224 PythonExtension* extension = extobj.extensionObject();
00225 if(! extension) {
00226 kdWarning() << "EXCEPTION in PythonExtension::toObject(): Failed to determinate PythonExtension object." << endl;
00227 throw Py::Exception("Failed to determinate PythonExtension object.");
00228 }
00229 if(! extension->m_object) {
00230 kdWarning() << "EXCEPTION in PythonExtension::toObject(): Failed to convert the PythonExtension object into a Kross::Api::Object." << endl;
00231 throw Py::Exception("Failed to convert the PythonExtension object into a Kross::Api::Object.");
00232 }
00233
00234 #ifdef KROSS_PYTHON_EXTENSION_TOOBJECT_DEBUG
00235 kdDebug() << "Kross::Python::PythonExtension::toObject(Py::Object) successfully converted into Kross::Api::Object." << endl;
00236 #endif
00237 return extension->m_object;
00238 }
00239
00240 const Py::Object PythonExtension::toPyObject(const QString& s)
00241 {
00242 #ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
00243 kdDebug() << QString("Kross::Python::PythonExtension::toPyObject(QString)") << endl;
00244 #endif
00245 return s.isNull() ? Py::String() : Py::String(s.latin1());
00246 }
00247
00248 const Py::List PythonExtension::toPyObject(const QStringList& list)
00249 {
00250 #ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
00251 kdDebug() << QString("Kross::Python::PythonExtension::toPyObject(QStringList)") << endl;
00252 #endif
00253 Py::List l;
00254 for(QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it)
00255 l.append(toPyObject(*it));
00256 return l;
00257 }
00258
00259 const Py::Dict PythonExtension::toPyObject(const QMap<QString, QVariant>& map)
00260 {
00261 #ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
00262 kdDebug() << QString("Kross::Python::PythonExtension::toPyObject(QMap<QString,QVariant>)") << endl;
00263 #endif
00264 Py::Dict d;
00265 for(QMap<QString, QVariant>::ConstIterator it = map.constBegin(); it != map.constEnd(); ++it)
00266 d.setItem(it.key().latin1(), toPyObject(it.data()));
00267 return d;
00268 }
00269
00270 const Py::List PythonExtension::toPyObject(const QValueList<QVariant>& list)
00271 {
00272 #ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
00273 kdDebug() << QString("Kross::Python::PythonExtension::toPyObject(QValueList<QVariant>)") << endl;
00274 #endif
00275 Py::List l;
00276 for(QValueList<QVariant>::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it)
00277 l.append(toPyObject(*it));
00278 return l;
00279 }
00280
00281 const Py::Object PythonExtension::toPyObject(const QVariant& variant)
00282 {
00283 #ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
00284 kdDebug() << QString("Kross::Python::PythonExtension::toPyObject(QVariant) typename='%1'").arg(variant.typeName()) << endl;
00285 #endif
00286
00287 switch(variant.type()) {
00288 case QVariant::Invalid:
00289 return Py::None();
00290 case QVariant::Bool:
00291 return Py::Int(variant.toBool());
00292 case QVariant::Int:
00293 return Py::Int(variant.toInt());
00294 case QVariant::UInt:
00295 return Py::Long((unsigned long)variant.toUInt());
00296 case QVariant::Double:
00297 return Py::Float(variant.toDouble());
00298 case QVariant::Date:
00299 case QVariant::Time:
00300 case QVariant::DateTime:
00301 case QVariant::ByteArray:
00302 case QVariant::BitArray:
00303 case QVariant::CString:
00304 case QVariant::String:
00305 return toPyObject(variant.toString());
00306 case QVariant::StringList:
00307 return toPyObject(variant.toStringList());
00308 case QVariant::Map:
00309 return toPyObject(variant.toMap());
00310 case QVariant::List:
00311 return toPyObject(variant.toList());
00312
00313
00314
00315
00316
00317 case QVariant::LongLong: {
00318 Q_LLONG l = variant.toLongLong();
00319
00320 return Py::Long((long)l);
00321
00322 } break;
00323 case QVariant::ULongLong: {
00324 return Py::Long((unsigned long)variant.toULongLong());
00325 } break;
00326
00327 default: {
00328 kdWarning() << QString("Kross::Python::PythonExtension::toPyObject(QVariant) Not possible to convert the QVariant type '%1' to a Py::Object.").arg(variant.typeName()) << endl;
00329 return Py::None();
00330 }
00331 }
00332 }
00333
00334 const Py::Object PythonExtension::toPyObject(Kross::Api::Object::Ptr object)
00335 {
00336 if(! object) {
00337 #ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
00338 kdDebug() << "Kross::Python::PythonExtension::toPyObject(Kross::Api::Object) is NULL => Py::None" << endl;
00339 #endif
00340 return Py::None();
00341 }
00342
00343 const QString classname = object->getClassName();
00344 if(classname == "Kross::Api::Variant") {
00345 QVariant v = static_cast<Kross::Api::Variant*>( object.data() )->getValue();
00346 #ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
00347 kdDebug() << QString("Kross::Python::PythonExtension::toPyObject(Kross::Api::Object) is Kross::Api::Variant %1").arg(v.toString()) << endl;
00348 #endif
00349 return toPyObject(v);
00350 }
00351
00352 if(classname == "Kross::Api::List") {
00353 #ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
00354 kdDebug() << "Kross::Python::PythonExtension::toPyObject(Kross::Api::Object) is Kross::Api::List" << endl;
00355 #endif
00356 Py::List pylist;
00357 Kross::Api::List* list = static_cast<Kross::Api::List*>( object.data() );
00358 QValueList<Kross::Api::Object::Ptr> valuelist = list->getValue();
00359 for(QValueList<Kross::Api::Object::Ptr>::Iterator it = valuelist.begin(); it != valuelist.end(); ++it)
00360 pylist.append( toPyObject(*it) );
00361 return pylist;
00362 }
00363
00364 if(classname == "Kross::Api::Dict") {
00365 #ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
00366 kdDebug() << "Kross::Python::PythonExtension::toPyObject(Kross::Api::Object) is Kross::Api::Dict" << endl;
00367 #endif
00368 Py::Dict pydict;
00369 Kross::Api::Dict* dict = static_cast<Kross::Api::Dict*>( object.data() );
00370 QMap<QString, Kross::Api::Object::Ptr> valuedict = dict->getValue();
00371 for(QMap<QString, Kross::Api::Object::Ptr>::Iterator it = valuedict.begin(); it != valuedict.end(); ++it) {
00372 const char* n = it.key().latin1();
00373 pydict[ n ] = toPyObject( it.data() );
00374 }
00375 return pydict;
00376 }
00377
00378 #ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
00379 kdDebug() << QString("Trying to handle PythonExtension::toPyObject(%1) as PythonExtension").arg(object->getClassName()) << endl;
00380 #endif
00381 return Py::asObject( new PythonExtension(object) );
00382 }
00383
00384 const Py::Tuple PythonExtension::toPyTuple(Kross::Api::List::Ptr list)
00385 {
00386 #ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
00387 kdDebug() << QString("Kross::Python::PythonExtension::toPyTuple(Kross::Api::List) name='%1'").arg(list ? list->getName() : "NULL") << endl;
00388 #endif
00389 uint count = list ? list->count() : 0;
00390 Py::Tuple tuple(count);
00391 for(uint i = 0; i < count; i++)
00392 tuple.setItem(i, toPyObject(list->item(i)));
00393 return tuple;
00394 }
00395
00396 PyObject* PythonExtension::proxyhandler(PyObject *_self_and_name_tuple, PyObject *args)
00397 {
00398 Py::Tuple tuple(_self_and_name_tuple);
00399 PythonExtension *self = static_cast<PythonExtension*>( tuple[0].ptr() );
00400 QString methodname = Py::String(tuple[1]).as_string().c_str();
00401
00402 try {
00403 Kross::Api::List::Ptr arguments = toObject( Py::Tuple(args) );
00404
00405 #ifdef KROSS_PYTHON_EXTENSION_CALL_DEBUG
00406 kdDebug() << QString("Kross::Python::PythonExtension::proxyhandler methodname='%1' arguments='%2'").arg(methodname).arg(arguments->toString()) << endl;
00407 #endif
00408
00409 if(self->m_object->hasChild(methodname)) {
00410 #ifdef KROSS_PYTHON_EXTENSION_CALL_DEBUG
00411 kdDebug() << QString("Kross::Python::PythonExtension::proxyhandler methodname='%1' is a child object of '%2'.").arg(methodname).arg(self->m_object->getName()) << endl;
00412 #endif
00413 Py::Object result = toPyObject( self->m_object->getChild(methodname)->call(QString::null, arguments) );
00414 result.increment_reference_count();
00415 return result.ptr();
00416 }
00417 #ifdef KROSS_PYTHON_EXTENSION_CALL_DEBUG
00418 kdDebug() << QString("Kross::Python::PythonExtension::proxyhandler try to call function with methodname '%1' in object '%2'.").arg(methodname).arg(self->m_object->getName()) << endl;
00419 #endif
00420 Py::Object result = toPyObject( self->m_object->call(methodname, arguments) );
00421 result.increment_reference_count();
00422 return result.ptr();
00423 }
00424 catch(Py::Exception& e) {
00425 const QString err = Py::value(e).as_string().c_str();
00426 kdWarning() << QString("Py::Exception in Kross::Python::PythonExtension::proxyhandler %1").arg(err) << endl;
00427
00428 }
00429 catch(Kross::Api::Exception::Ptr e) {
00430 const QString err = e->toString();
00431 kdWarning() << QString("Kross::Api::Exception in Kross::Python::PythonExtension::proxyhandler %1").arg(err) << endl;
00432
00433
00434
00435 }
00436
00437 return Py_None;
00438 }
|