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