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