/***************************************************************************
* pythonextension . cpp
* This file is part of the KDE project
* copyright ( C ) 2004 - 2005 by Sebastian Sauer ( mail @ dipe . org )
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details .
* You should have received a copy of the GNU Library General Public License
* along with this program ; see the file COPYING . If not , write to
* the Free Software Foundation , Inc . , 51 Franklin Street , Fifth Floor ,
* Boston , MA 02110 - 1301 , USA .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "pythonextension.h"
# include "pythonobject.h"
# include "../api/variant.h"
# include "../api/dict.h"
# include "../api/exception.h"
using namespace Kross : : Python ;
PythonExtension : : PythonExtension ( Kross : : Api : : Object : : Ptr object )
: Py : : PythonExtension < PythonExtension > ( )
, m_object ( object )
{
# ifdef KROSS_PYTHON_EXTENSION_CTOR_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::Constructor objectname='%1' objectclass='%2' " ) . arg ( m_object - > getName ( ) ) . arg ( m_object - > getClassName ( ) ) ) ;
# endif
behaviors ( ) . name ( " KrossPythonExtension " ) ;
/*
behaviors ( ) . doc (
" The common KrossPythonExtension object enables passing "
" of Kross::Api::Object's from C/C++ to Python and "
" backwards in a transparent way. "
) ;
*/
behaviors ( ) . supportGetattr ( ) ;
m_proxymethod = new Py : : MethodDefExt < PythonExtension > (
" " , // methodname, not needed cause we use the method only internaly.
0 , // method that should handle the callback, not needed cause proxyhandler will handle it.
Py : : method_varargs_call_handler_t ( proxyhandler ) , // callback handler
" " // documentation
) ;
}
PythonExtension : : ~ PythonExtension ( )
{
# ifdef KROSS_PYTHON_EXTENSION_DTOR_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::Destructor objectname='%1' objectclass='%2' " ) . arg ( m_object - > getName ( ) ) . arg ( m_object - > getClassName ( ) ) ) ;
# endif
delete m_proxymethod ;
}
#if 0
Py : : Object PythonExtension : : str ( )
{
Kross : : Api : : Callable * callable = dynamic_cast < Kross : : Api : : Callable * > ( m_object ) ;
TQString s = callable ? callable - > getName ( ) : m_object - > getClassName ( ) ;
return toPyObject ( s . isEmpty ( ) ? : s ) ;
}
Py : : Object PythonExtension : : repr ( )
{
return toPyObject ( m_object - > toString ( ) ) ;
}
# endif
Py : : Object PythonExtension : : getattr ( const char * n )
{
# ifdef KROSS_PYTHON_EXTENSION_GETATTR_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::getattr name='%1' " ) . arg ( n ) ) ;
# endif
if ( n [ 0 ] = = ' _ ' ) {
if ( ! strcmp ( n , " __methods__ " ) ) {
Py : : List methods ;
TQStringList calls = m_object - > getCalls ( ) ;
for ( TQStringList : : Iterator it = calls . begin ( ) ; it ! = calls . end ( ) ; + + it ) {
# ifdef KROSS_PYTHON_EXTENSION_GETATTR_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::getattr name='%1' callable='%2' " ) . arg ( n ) . arg ( * it ) ) ;
# endif
methods . append ( Py : : String ( ( * it ) . latin1 ( ) ) ) ;
}
return methods ;
}
if ( ! strcmp ( n , " __members__ " ) ) {
Py : : List members ;
Kross : : Api : : Callable * callable = dynamic_cast < Kross : : Api : : Callable * > ( m_object . data ( ) ) ;
if ( callable ) {
TQMap < TQString , Kross : : Api : : Object : : Ptr > children = callable - > getChildren ( ) ;
TQMap < TQString , Kross : : Api : : Object : : Ptr > : : Iterator it ( children . begin ( ) ) ;
for ( ; it ! = children . end ( ) ; + + it ) {
# ifdef KROSS_PYTHON_EXTENSION_GETATTR_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::getattr n='%1' child='%2' " ) . arg ( n ) . arg ( it . key ( ) ) ) ;
# endif
members . append ( Py : : String ( it . key ( ) . latin1 ( ) ) ) ;
}
}
return members ;
}
//if(n == "__dict__") { krosswarning( TQString("PythonExtension::getattr(%1) __dict__").arg(n) ); return Py::None(); }
//if(n == "__class__") { krosswarning( TQString("PythonExtension::getattr(%1) __class__").arg(n) ); return Py::None(); }
# ifdef KROSS_PYTHON_EXTENSION_GETATTR_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::getattr name='%1' is a internal name. " ) . arg ( n ) ) ;
# endif
return Py : : PythonExtension < PythonExtension > : : getattr_methods ( n ) ;
}
// Redirect the call to our static proxy method which will take care
// of handling the call.
Py : : Tuple self ( 2 ) ;
self [ 0 ] = Py : : Object ( this ) ;
self [ 1 ] = Py : : String ( n ) ;
return Py : : Object ( PyCFunction_New ( & m_proxymethod - > ext_meth_def , self . ptr ( ) ) , true ) ;
}
/*
Py : : Object PythonExtension : : getattr_methods ( const char * n )
{
# ifdef KROSS_PYTHON_EXTENSION_GETATTRMETHOD_DEBUG
krossdebug ( TQString ( " PythonExtension::getattr_methods name=%1 " ) . arg ( n ) ) ;
# endif
return Py : : PythonExtension < PythonExtension > : : getattr_methods ( n ) ;
}
int PythonExtension : : setattr ( const char * name , const Py : : Object & value )
{
# ifdef KROSS_PYTHON_EXTENSION_SETATTR_DEBUG
krossdebug ( TQString ( " PythonExtension::setattr name=%1 value=%2 " ) . arg ( name ) . arg ( value . as_string ( ) . c_str ( ) ) ) ;
# endif
return Py : : PythonExtension < PythonExtension > : : setattr ( name , value ) ;
}
*/
Kross : : Api : : List : : Ptr PythonExtension : : toObject ( const Py : : Tuple & tuple )
{
# ifdef KROSS_PYTHON_EXTENSION_TOOBJECT_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::toObject(Py::Tuple) " ) ) ;
# endif
TQValueList < Kross : : Api : : Object : : Ptr > l ;
uint size = tuple . size ( ) ;
for ( uint i = 0 ; i < size ; i + + )
l . append ( toObject ( tuple [ i ] ) ) ;
return new Kross : : Api : : List ( l ) ;
}
Kross : : Api : : List : : Ptr PythonExtension : : toObject ( const Py : : List & list )
{
# ifdef KROSS_PYTHON_EXTENSION_TOOBJECT_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::toObject(Py::List) " ) ) ;
# endif
TQValueList < Kross : : Api : : Object : : Ptr > l ;
uint length = list . length ( ) ;
for ( uint i = 0 ; i < length ; i + + )
l . append ( toObject ( list [ i ] ) ) ;
return new Kross : : Api : : List ( l ) ;
}
Kross : : Api : : Dict : : Ptr PythonExtension : : toObject ( const Py : : Dict & dict )
{
TQMap < TQString , Kross : : Api : : Object : : Ptr > map ;
Py : : List l = dict . keys ( ) ;
uint length = l . length ( ) ;
for ( Py : : List : : size_type i = 0 ; i < length ; + + i ) {
const char * n = l [ i ] . str ( ) . as_string ( ) . c_str ( ) ;
map . replace ( n , toObject ( dict [ n ] ) ) ;
}
return new Kross : : Api : : Dict ( map ) ;
}
Kross : : Api : : Object : : Ptr PythonExtension : : toObject ( const Py : : Object & object )
{
# ifdef KROSS_PYTHON_EXTENSION_TOOBJECT_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::toObject(Py::Object) object='%1' " ) . arg ( object . as_string ( ) . c_str ( ) ) ) ;
# endif
if ( object = = Py : : None ( ) )
return 0 ;
PyTypeObject * type = ( PyTypeObject * ) object . type ( ) . ptr ( ) ;
# ifdef KROSS_PYTHON_EXTENSION_TOOBJECT_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::toObject(Py::Object) type='%1' " ) . arg ( type - > tp_name ) ) ;
# endif
if ( type = = & PyInt_Type )
return new Kross : : Api : : Variant ( int ( Py : : Int ( object ) ) ) ;
if ( type = = & PyBool_Type )
return new Kross : : Api : : Variant ( TQVariant ( object . isTrue ( ) ) ) ;
if ( type = = & PyLong_Type )
return new Kross : : Api : : Variant ( TQ_LLONG ( long ( Py : : Long ( object ) ) ) ) ;
if ( type = = & PyFloat_Type )
return new Kross : : Api : : Variant ( double ( Py : : Float ( object ) ) ) ;
if ( PyType_IsSubtype ( type , & PyString_Type ) ) {
# ifdef Py_USING_UNICODE
/* TODO
if ( type = = & PyUnicode_Type ) {
Py : : unicodestring u = Py : : String ( object ) . as_unicodestring ( ) ;
std : : string s ;
std : : copy ( u . begin ( ) , u . end ( ) , std : : back_inserter ( s ) ) ;
return new Kross : : Api : : Variant ( s . c_str ( ) ) ;
}
*/
# endif
return new Kross : : Api : : Variant ( object . as_string ( ) . c_str ( ) ) ;
}
if ( type = = & PyTuple_Type )
return toObject ( Py : : Tuple ( object ) ) . data ( ) ;
if ( type = = & PyList_Type )
return toObject ( Py : : List ( object ) ) . data ( ) ;
if ( type = = & PyDict_Type )
return toObject ( Py : : Dict ( object . ptr ( ) ) ) . data ( ) ;
if ( object . isInstance ( ) )
return new PythonObject ( object ) ;
Py : : ExtensionObject < PythonExtension > extobj ( object ) ;
PythonExtension * extension = extobj . extensionObject ( ) ;
if ( ! extension ) {
krosswarning ( " EXCEPTION in PythonExtension::toObject(): Failed to determinate PythonExtension object. " ) ;
throw Py : : Exception ( " Failed to determinate PythonExtension object. " ) ;
}
if ( ! extension - > m_object ) {
krosswarning ( " EXCEPTION in PythonExtension::toObject(): Failed to convert the PythonExtension object into a Kross::Api::Object. " ) ;
throw Py : : Exception ( " Failed to convert the PythonExtension object into a Kross::Api::Object. " ) ;
}
# ifdef KROSS_PYTHON_EXTENSION_TOOBJECT_DEBUG
krossdebug ( " Kross::Python::PythonExtension::toObject(Py::Object) successfully converted into Kross::Api::Object. " ) ;
# endif
return extension - > m_object ;
}
const Py : : Object PythonExtension : : toPyObject ( const TQString & s )
{
# ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::toPyObject(TQString) " ) ) ;
# endif
return s . isNull ( ) ? Py : : String ( ) : Py : : String ( s . latin1 ( ) ) ;
}
const Py : : List PythonExtension : : toPyObject ( const TQStringList & list )
{
# ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::toPyObject(TQStringList) " ) ) ;
# endif
Py : : List l ;
for ( TQStringList : : ConstIterator it = list . constBegin ( ) ; it ! = list . constEnd ( ) ; + + it )
l . append ( toPyObject ( * it ) ) ;
return l ;
}
const Py : : Dict PythonExtension : : toPyObject ( const TQStringVariantMap & map )
{
# ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::toPyObject(TQStringVariantMap) " ) ) ;
# endif
Py : : Dict d ;
for ( TQStringVariantMap : : ConstIterator it = map . constBegin ( ) ; it ! = map . constEnd ( ) ; + + it )
d . setItem ( it . key ( ) . latin1 ( ) , toPyObject ( it . data ( ) ) ) ;
return d ;
}
const Py : : List PythonExtension : : toPyObject ( const TQValueList < TQVariant > & list )
{
# ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::toPyObject(TQValueList<TQVariant>) " ) ) ;
# endif
Py : : List l ;
for ( TQValueList < TQVariant > : : ConstIterator it = list . constBegin ( ) ; it ! = list . constEnd ( ) ; + + it )
l . append ( toPyObject ( * it ) ) ;
return l ;
}
const Py : : Object PythonExtension : : toPyObject ( const TQVariant & variant )
{
# ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::toPyObject(TQVariant) typename='%1' " ) . arg ( variant . typeName ( ) ) ) ;
# endif
switch ( variant . type ( ) ) {
case TQVariant : : Invalid :
return Py : : None ( ) ;
case TQVariant : : Bool :
return Py : : Int ( variant . toBool ( ) ) ;
case TQVariant : : Int :
return Py : : Int ( variant . toInt ( ) ) ;
case TQVariant : : UInt :
return Py : : Long ( ( unsigned long ) variant . toUInt ( ) ) ;
case TQVariant : : Double :
return Py : : Float ( variant . toDouble ( ) ) ;
case TQVariant : : Date :
case TQVariant : : Time :
case TQVariant : : DateTime :
case TQVariant : : ByteArray :
case TQVariant : : BitArray :
case TQVariant : : CString :
case TQVariant : : String :
return toPyObject ( variant . toString ( ) ) ;
case TQVariant : : StringList :
return toPyObject ( variant . toStringList ( ) ) ;
case TQVariant : : Map :
return toPyObject ( variant . toMap ( ) ) ;
case TQVariant : : List :
return toPyObject ( variant . toList ( ) ) ;
// To handle following both cases is a bit difficult
// cause Python doesn't spend an easy possibility
// for such large numbers (TODO maybe BigInt?). So,
// we risk overflows here, but well...
case TQVariant : : LongLong : {
TQ_LLONG l = variant . toLongLong ( ) ;
//return (l < 0) ? Py::Long((long)l) : Py::Long((unsigned long)l);
return Py : : Long ( ( long ) l ) ;
//return Py::Long(PyLong_FromLong( (long)l ), true);
} break ;
case TQVariant : : ULongLong : {
return Py : : Long ( ( unsigned long ) variant . toULongLong ( ) ) ;
} break ;
default : {
krosswarning ( TQString ( " Kross::Python::PythonExtension::toPyObject(TQVariant) Not possible to convert the TQVariant type '%1' to a Py::Object. " ) . arg ( variant . typeName ( ) ) ) ;
return Py : : None ( ) ;
}
}
}
const Py : : Object PythonExtension : : toPyObject ( Kross : : Api : : Object : : Ptr object )
{
if ( ! object ) {
# ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
krossdebug ( " Kross::Python::PythonExtension::toPyObject(Kross::Api::Object) is NULL => Py::None " ) ;
# endif
return Py : : None ( ) ;
}
const TQString classname = object - > getClassName ( ) ;
if ( classname = = " Kross::Api::Variant " ) {
TQVariant v = static_cast < Kross : : Api : : Variant * > ( object . data ( ) ) - > getValue ( ) ;
# ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::toPyObject(Kross::Api::Object) is Kross::Api::Variant %1 " ) . arg ( v . toString ( ) ) ) ;
# endif
return toPyObject ( v ) ;
}
if ( classname = = " Kross::Api::List " ) {
# ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
krossdebug ( " Kross::Python::PythonExtension::toPyObject(Kross::Api::Object) is Kross::Api::List " ) ;
# endif
Py : : List pylist ;
Kross : : Api : : List * list = static_cast < Kross : : Api : : List * > ( object . data ( ) ) ;
TQValueList < Kross : : Api : : Object : : Ptr > valuelist = list - > getValue ( ) ;
for ( TQValueList < Kross : : Api : : Object : : Ptr > : : Iterator it = valuelist . begin ( ) ; it ! = valuelist . end ( ) ; + + it )
pylist . append ( toPyObject ( * it ) ) ; // recursive
return pylist ;
}
if ( classname = = " Kross::Api::Dict " ) {
# ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
krossdebug ( " Kross::Python::PythonExtension::toPyObject(Kross::Api::Object) is Kross::Api::Dict " ) ;
# endif
Py : : Dict pydict ;
Kross : : Api : : Dict * dict = static_cast < Kross : : Api : : Dict * > ( object . data ( ) ) ;
TQMap < TQString , Kross : : Api : : Object : : Ptr > valuedict = dict - > getValue ( ) ;
for ( TQMap < TQString , Kross : : Api : : Object : : Ptr > : : Iterator it = valuedict . begin ( ) ; it ! = valuedict . end ( ) ; + + it ) {
const char * n = it . key ( ) . latin1 ( ) ;
pydict [ n ] = toPyObject ( it . data ( ) ) ; // recursive
}
return pydict ;
}
# ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
krossdebug ( TQString ( " Trying to handle PythonExtension::toPyObject(%1) as PythonExtension " ) . arg ( object - > getClassName ( ) ) ) ;
# endif
return Py : : asObject ( new PythonExtension ( object ) ) ;
}
const Py : : Tuple PythonExtension : : toPyTuple ( Kross : : Api : : List : : Ptr list )
{
# ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::toPyTuple(Kross::Api::List) name='%1' " ) . arg ( list ? list - > getName ( ) : " NULL " ) ) ;
# endif
uint count = list ? list - > count ( ) : 0 ;
Py : : Tuple tuple ( count ) ;
for ( uint i = 0 ; i < count ; i + + )
tuple . setItem ( i , toPyObject ( list - > item ( i ) ) ) ;
return tuple ;
}
PyObject * PythonExtension : : proxyhandler ( PyObject * _self_and_name_tuple , PyObject * args )
{
Py : : Tuple tuple ( _self_and_name_tuple ) ;
PythonExtension * self = static_cast < PythonExtension * > ( tuple [ 0 ] . ptr ( ) ) ;
TQString methodname = Py : : String ( tuple [ 1 ] ) . as_string ( ) . c_str ( ) ;
try {
Kross : : Api : : List : : Ptr arguments = toObject ( Py : : Tuple ( args ) ) ;
# ifdef KROSS_PYTHON_EXTENSION_CALL_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::proxyhandler methodname='%1' arguments='%2' " ) . arg ( methodname ) . arg ( arguments - > toString ( ) ) ) ;
# endif
Kross : : Api : : Callable * callable = dynamic_cast < Kross : : Api : : Callable * > ( self - > m_object . data ( ) ) ;
if ( callable & & callable - > hasChild ( methodname ) ) {
# ifdef KROSS_PYTHON_EXTENSION_CALL_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::proxyhandler methodname='%1' is a child object of '%2'. " ) . arg ( methodname ) . arg ( self - > m_object - > getName ( ) ) ) ;
# endif
Py : : Object result = toPyObject ( callable - > getChild ( methodname ) - > call ( TQString ( ) , arguments ) ) ;
result . increment_reference_count ( ) ;
return result . ptr ( ) ;
}
# ifdef KROSS_PYTHON_EXTENSION_CALL_DEBUG
krossdebug ( TQString ( " Kross::Python::PythonExtension::proxyhandler try to call function with methodname '%1' in object '%2'. " ) . arg ( methodname ) . arg ( self - > m_object - > getName ( ) ) ) ;
# endif
Py : : Object result = toPyObject ( self - > m_object - > call ( methodname , arguments ) ) ;
result . increment_reference_count ( ) ;
return result . ptr ( ) ;
}
catch ( Py : : Exception & e ) {
const TQString err = Py : : value ( e ) . as_string ( ) . c_str ( ) ;
krosswarning ( TQString ( " Py::Exception in Kross::Python::PythonExtension::proxyhandler %1 " ) . arg ( err ) ) ;
//throw e;
}
catch ( Kross : : Api : : Exception : : Ptr e ) {
const TQString err = e - > toString ( ) ;
krosswarning ( TQString ( " Kross::Api::Exception in Kross::Python::PythonExtension::proxyhandler %1 " ) . arg ( err ) ) ;
// Don't throw here cause it will end in a crash deep in python. The
// error is already handled anyway.
//throw Py::Exception( (char*) e->toString().latin1() );
}
return Py_None ;
}