QPy
Python-Qt dynamic bindings
PyContext.h
Go to the documentation of this file.
00001 #pragma once
00002 // QPy - Copyright (c) 2012,2013 Ugo Varetto
00003 // All rights reserved.
00004 //
00005 // Redistribution and use in source and binary forms, with or without
00006 // modification, are permitted provided that the following conditions are met:
00007 //     * Redistributions of source code must retain the above copyright
00008 //       notice, this list of conditions and the following disclaimer.
00009 //     * Redistributions in binary form must reproduce the above copyright
00010 //       notice, this list of conditions and the following disclaimer in the
00011 //       documentation and/or other materials provided with the distribution.
00012 //     * Neither the name of the author and copyright holder nor the
00013 //       names of contributors to the project may be used to endorse or promote products
00014 //       derived from this software without specific prior written permission.
00015 //
00016 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00017 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019 // DISCLAIMED. IN NO EVENT SHALL UGO VARETTO BE LIABLE FOR ANY
00020 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026 
00029 
00030 #include <Python.h>
00031 #include <structmember.h>
00032 #include <stdexcept>
00033 #include <cassert>
00034 #include <iostream>
00035 #include <QObject>
00036 #include <QMetaObject>
00037 #include <QMetaMethod>
00038 #include <QList>
00039 #include <QString>
00040 #include <QSet>
00041 #include <string>
00042 #include <vector>
00043 #include <QDebug>
00044 #include "detail/PyDefaultArguments.h"
00045 #include "detail/PyArgWrappers.h"
00046 #include "detail/PyCallbackDispatcher.h"
00047 #include "detail/PyQVariantDefault.h"
00048 #include "PyMemberNameMapper.h"
00049 
00050 
00051 #define PY_CHECK( f ) {if( f != 0 ) throw std::runtime_error( "Python error" );}
00052 
00053 namespace qpy {
00054 
00056 inline void RaisePyError( const char* errMsg = 0, 
00057                           PyObject* errType = PyExc_Exception  ) {
00058     PyErr_SetString( errType, errMsg );
00059 }
00060 
00065 
00066 //------------------------------------------------------------------------------
00074 class PyContext {
00075     typedef QList< QArgWrapper > QArgWrappers;
00076     typedef QList< QByteArray > ArgumentTypes;
00083     struct Method {
00084         //for overloading purposes:
00085         //QMap< int, tuple< QMetaMethod, QArgWrappers, PyArgWrapper> >
00086         //select the one matching the number of arguments
00087         QMetaMethod metaMethod_;
00088         QArgWrappers argumentWrappers_;
00089         PyArgWrapper returnWrapper_;
00090         const QMetaObject* metaObject_;
00091         Method( const QMetaMethod& mm,
00092                 const QArgWrappers& pw,
00093                 const PyArgWrapper& rw,
00094                 const QMetaObject* mo ) :
00095             metaMethod_( mm ), argumentWrappers_( pw ),
00096             returnWrapper_( rw ), metaObject_( mo ) {}
00097     };
00098     static const int MAX_GENERIC_ARGS = 10;
00099 public:
00100     typedef QList< Method > Methods;
00101 public:  //must be public because type access might be needed
00102          //from PyArguments; declaring some PyArguments as friend
00103          //won't work when new argument constructors provided by
00104          //client code need to be registered
00110     struct Type {
00111         const QMetaObject* metaObject; 
00112         //for overloading purposes:
00113         //QMap< int, QArgWrappers >
00114         //currently overloading is done through a run-time search
00115         QList< QArgWrappers > ctorParams;
00116         Methods methods;
00117         PyTypeObject pyType;
00118         //required to keep char* to be passed around
00119         std::vector< std::string > pyMethodNames;
00120         std::vector< PyGetSetDef > pyMembers;
00121         // need string to pass references to
00122         // contained c_str
00123         std::string fullClassName;
00124         std::string className;
00125         std::string doc;
00126         PyObject* pyModule;
00127         PyContext* pyContext;
00128     };
00129     typedef QList< Type > Types;
00131     struct PyQObject {
00132         PyObject_HEAD
00133         char qobjectTag;
00134         QObject* obj;
00135         Type* type;
00136         PyObject* invoke; //method invocation function
00137         bool foreignOwned;
00138         PyObject* pyModule;
00139     };
00140 public:
00142     PyContext() {
00143         InitArgFactory();
00144         InitQVariantPyObjectMaps();
00145     }
00148     ~PyContext() {
00149         for( QVariantToPyObjectMapType::iterator i = qvariantToPyObject_.begin();
00150              i != qvariantToPyObject_.end(); ++i ) {
00151             if( !i.value()->ForeignOwned() ) delete i.value();
00152         }
00153         for( PyObjectToQVariantMapType::iterator i = pyObjectToQVariant_.begin();
00154              i != pyObjectToQVariant_.end(); ++i ) {
00155             if( !i.value()->ForeignOwned() ) delete i.value();
00156         }      
00157     }
00159     static const char* Version();
00161     void AddGlobals( PyObject* module ) {
00162         PyModule_AddStringConstant( module, "__version__", Version() );
00163     }    
00178     PyTypeObject* AddType( const QMetaObject* mo, 
00179                            PyObject* module,
00180                            bool checkConstructor = true,
00181                            const QSet< QString >& selectedMembers = QSet< QString >(),
00182                            const PyMemberNameMapper& mm = DefaultMemberNameMapper(),
00183                            const char* className = 0,
00184                            const char* doc = 0 );
00196     template < typename T > void Add( PyObject* module,
00197                                       bool checkConstructor = true,
00198                                       const QSet< QString >& selectedMembers = QSet< QString >(),
00199                                       const PyMemberNameMapper& mm = DefaultMemberNameMapper(),
00200                                       const char* className = 0,
00201                                       const char* doc = 0 ) {
00202         AddType( &T::staticMetaObject, module, checkConstructor, selectedMembers,
00203                  mm, className, doc );    
00204     }
00208     PyMethodDef* ModuleFunctions();
00210     PyObject* AddObject( QObject* qobj, 
00211                          PyObject* targetModule, // where instance is added 
00212                          PyObject* typeModule, // where type is defined
00213                          const char* instanceName,
00214                          bool pythonOwned = false,
00215                          const QSet< QString >& selectedMembers = QSet< QString >(),
00216                          const PyMemberNameMapper& mm = DefaultMemberNameMapper() );
00220     template < typename QArgConstructorT, typename PyArgConstructorT > 
00221     bool RegisterType( const QString& typeName, bool overwrite = false ) {
00222         return RegisterType( typeName, new QArgConstructorT, new PyArgConstructorT, overwrite );
00223     }
00224     template < typename QArgConstructorT, typename PyArgConstructorT > 
00225     bool RegisterType( QMetaType::Type t, bool overwrite = false ) {
00226         return RegisterType( QMetaType::typeName( t ), 
00227                              new QArgConstructorT, new PyArgConstructorT, overwrite );
00228     }
00232     template < typename T, typename QArgConstructorT, typename PyArgConstructorT > 
00233     bool RegisterType( const QString& typeName, bool overwrite = false ) {
00234         return RegisterType( qRegisterMetaType< T >( typeName.toAscii().constData() ),
00235                              new QArgConstructorT, new PyArgConstructorT, overwrite );
00236     }
00237     void RegisterQVariantToPyObject( QVariant::Type t,  QVariantToPyObject* qp ) {
00238         if( qvariantToPyObject_.contains( t ) ) {
00239             if( !qvariantToPyObject_[ t ]->ForeignOwned() ) delete qvariantToPyObject_[ t ];
00240         }
00241         qvariantToPyObject_[ t ] = qp;
00242     }
00243     template < typename T >
00244     int RegisterQVariantToPyObject( QVariantToPyObject* qp ) {
00245         const int id = qRegisterMetaType< T >();
00246         RegisterQVariantToPyObject( QVariant::Type( id ), qp );
00247         return id;
00248     }
00249     void RegisterPyObjectToQVariant( QVariant::Type t,  PyObjectToQVariant* qp ) {
00250         if( pyObjectToQVariant_.contains( t ) ) {
00251             if( !pyObjectToQVariant_[ t ]->ForeignOwned() ) delete pyObjectToQVariant_[ t ];
00252         }
00253         pyObjectToQVariant_[ t ] = qp;
00254     }
00255     template < typename T >
00256     int RegisterPyObjectToQVariant( PyObjectToQVariant* qp ) {
00257         const int id = qRegisterMetaType< T >();
00258         RegisterPyObjectToQVariant( qMetaTypeId< T >, qp );
00259         return id;
00260     }
00261     void UnRegisterType( const QString& typeName ) {
00262         if( !argFactory_.contains( typeName ) ) return;    
00263         argFactory_.erase( argFactory_.find( typeName ) );
00264     }
00269     struct TypeConstruction {
00270         bool qtToPy;
00271         bool pyToQt;
00272         QString typeName;
00273         operator bool() const { return qtToPy || pyToQt; }
00274         TypeConstruction() : qtToPy( false ), pyToQt( false ) {}
00275     };
00278     TypeConstruction RegTypeInfo( const QString& t ) const {
00279         TypeConstruction tc;
00280         if( !argFactory_.contains( t ) ) return tc;
00281         tc.pyToQt = dynamic_cast< const NoQArgConstructor* >( argFactory_[ t ].QArgCtor() ) == 0;
00282         tc.qtToPy = dynamic_cast< const NoPyArgConstructor* >( argFactory_[ t ].PyArgCtor() )  == 0;    
00283         tc.typeName = t;
00284         return tc;
00285     }
00287     QList< TypeConstruction > RegisteredTypes() const {
00288         QList< TypeConstruction > tc;
00289         for( ArgFactory::const_iterator i = argFactory_.begin(); i != argFactory_.end(); ++i ) {
00290             tc.push_back( RegTypeInfo( i.key() ) );
00291         }
00292         return tc;
00293     }
00294 private:
00296     void InitArgFactory();
00298     void InitQVariantPyObjectMaps();
00301     QArgWrappers GenerateQArgWrappers( const ArgumentTypes& at );
00303     PyArgWrapper GeneratePyArgWrapper( QString typeName );
00304 private:
00305     class ArgFactoryEntry {
00306     public:
00307         ArgFactoryEntry() : qac_( 0 ), pac_( 0 ) {}
00308         ArgFactoryEntry( const ArgFactoryEntry& fe ) 
00309             : typeName_( fe.typeName_ ), qac_( 0 ), pac_( 0 ) {
00310                 if( fe.qac_ ) qac_ = fe.qac_->Clone();
00311                 if( fe.pac_ ) pac_ = fe.pac_->Clone();
00312         }
00313         ArgFactoryEntry( const QString& tn, QArgConstructor* qac, PyArgConstructor* pac )
00314             : typeName_( tn ), qac_( qac ), pac_( pac ) {}
00315         const ArgFactoryEntry& operator=( const ArgFactoryEntry& fe ) {
00316             typeName_ = fe.typeName_;
00317             qac_ = fe.qac_ ? fe.qac_->Clone() : 0;
00318             pac_ = fe.pac_ ? fe.pac_->Clone() : 0;
00319             return *this;
00320         }    
00321         ~ArgFactoryEntry() {
00322             delete qac_;
00323             delete pac_;
00324         }
00325         const QArgConstructor* QArgCtor() const { return qac_; }
00326         const PyArgConstructor* PyArgCtor() const { return pac_; }
00327         QArgConstructor* MakeQArgConstructor() const { return qac_->Clone(); }
00328         PyArgConstructor* MakePyArgConstructor() const { return pac_->Clone(); }
00329         const QString& TypeName() const { return typeName_; }
00330     private:
00331         QString typeName_;
00332         QArgConstructor* qac_;
00333         PyArgConstructor* pac_;
00334     };
00335     typedef QMap< QString, ArgFactoryEntry > ArgFactory;
00336     bool RegisterType( const QString& typeName, QArgConstructor* qac, PyArgConstructor* pac, bool overwrite ) {
00337         const bool typeExist = argFactory_.contains( typeName );
00338         if( typeExist && !overwrite ) return false;
00339         argFactory_[ typeName ] = ArgFactoryEntry( typeName, qac, pac );
00340         return true; 
00341     }
00342     Type* ExistingType( const QMetaObject* mo, PyObject* module ) {
00343         for( Types::iterator i = types_.begin(); i != types_.end(); ++i ) {
00344             if( i->metaObject->className() == mo->className() && 
00345                 i->pyModule == module ) return &( *i );
00346         }
00347         return 0;    
00348     }
00349     typedef QMap< QVariant::Type, QVariantToPyObject* > QVariantToPyObjectMapType;
00350     typedef QMap< QVariant::Type, PyObjectToQVariant* > PyObjectToQVariantMapType;    
00351 private:
00352     static PyObject* PyQObjectConnect( PyObject* self, PyObject* args );
00353     static PyObject* PyQObjectDisconnect( PyObject* self, PyObject* args );
00354     static PyObject* PyQObjectIsForeignOwned( PyObject* self, PyObject* args );
00355     static PyObject* PyQObjectIsQObject( PyObject* self, PyObject* args );
00356     static PyObject* PyQObjectAcquire( PyObject* self, PyObject* args );
00357     static PyObject* PyQObjectRelease( PyObject* self, PyObject* args );
00358     static PyObject* PyQObjectPtr( PyObject* self, PyObject* args );
00359     static PyObject* PyQObjectGetter( PyQObject* qobj, void* closure /*method id*/ );
00360     static int PyQObjectSetter( PyQObject*, PyObject*, void* closure );
00361     static PyObject* PyQObjectNew( PyTypeObject* type, PyObject*, PyObject* );
00362     static PyObject* PyQObjectInvokeMethod( PyQObject* self, PyObject* args );
00363     static int PyQObjectInit( PyQObject* self, PyObject* args, PyObject* kwds );
00364     static PyObject* PyQObjectTr( PyObject* self, PyObject* args );
00365     static void PyQObjectDealloc( PyQObject* self );
00366 private:
00367     PyTypeObject CreatePyType( const Type& type );
00368     struct ConnectEntry {
00369         PyQObject* pyqobj;
00370         int methodId;
00371         ConnectEntry() : pyqobj( 0 ), methodId( -1 ) {}
00372         ConnectEntry( PyQObject* p, int m ) : pyqobj( p ), methodId( m ) {}
00373     };
00374     typedef QList< ConnectEntry > ConnectList;
00375 private:
00378     Types types_;
00379     PyCallbackDispatcher dispatcher_;
00380     ArgFactory argFactory_;
00381     QVariantToPyObjectMapType qvariantToPyObject_;
00382     PyObjectToQVariantMapType pyObjectToQVariant_;
00383     static ConnectList endpoints_; //thread_local if needed
00384     static int getterMethodId_;
00385     static bool signal_;
00386 };
00387 
00388 }
 All Classes Namespaces Files Functions