From 8362bf63dea22bbf6736609b0f49c152f975eb63 Mon Sep 17 00:00:00 2001 From: tpearson Date: Wed, 20 Jan 2010 01:29:50 +0000 Subject: Added old abandoned KDE3 version of koffice git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- lib/kross/python/cxx/Config.hxx | 74 + lib/kross/python/cxx/Exception.hxx | 212 ++ lib/kross/python/cxx/Extensions.hxx | 756 ++++++ lib/kross/python/cxx/IndirectPythonInterface.cxx | 550 +++++ lib/kross/python/cxx/IndirectPythonInterface.hxx | 156 ++ lib/kross/python/cxx/Legal.html | 40 + lib/kross/python/cxx/Makefile.am | 19 + lib/kross/python/cxx/Objects.hxx | 2804 ++++++++++++++++++++++ lib/kross/python/cxx/PyCXX.html | 2131 ++++++++++++++++ lib/kross/python/cxx/README.html | 436 ++++ lib/kross/python/cxx/Readme.Kross.txt | 16 + lib/kross/python/cxx/Version.txt | 1 + lib/kross/python/cxx/cxx_extensions.cxx | 1287 ++++++++++ lib/kross/python/cxx/cxxextensions.c | 19 + lib/kross/python/cxx/cxxsupport.cxx | 142 ++ 15 files changed, 8643 insertions(+) create mode 100644 lib/kross/python/cxx/Config.hxx create mode 100644 lib/kross/python/cxx/Exception.hxx create mode 100644 lib/kross/python/cxx/Extensions.hxx create mode 100644 lib/kross/python/cxx/IndirectPythonInterface.cxx create mode 100644 lib/kross/python/cxx/IndirectPythonInterface.hxx create mode 100755 lib/kross/python/cxx/Legal.html create mode 100644 lib/kross/python/cxx/Makefile.am create mode 100644 lib/kross/python/cxx/Objects.hxx create mode 100644 lib/kross/python/cxx/PyCXX.html create mode 100644 lib/kross/python/cxx/README.html create mode 100644 lib/kross/python/cxx/Readme.Kross.txt create mode 100644 lib/kross/python/cxx/Version.txt create mode 100644 lib/kross/python/cxx/cxx_extensions.cxx create mode 100644 lib/kross/python/cxx/cxxextensions.c create mode 100644 lib/kross/python/cxx/cxxsupport.cxx (limited to 'lib/kross/python/cxx') diff --git a/lib/kross/python/cxx/Config.hxx b/lib/kross/python/cxx/Config.hxx new file mode 100644 index 000000000..65bbc2d3b --- /dev/null +++ b/lib/kross/python/cxx/Config.hxx @@ -0,0 +1,74 @@ +#ifndef __PyCXX_config_hh__ +#define __PyCXX_config_hh__ + +// +// Microsoft VC++ 6.0 has no traits +// +#if defined( _MSC_VER ) + +# define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 1 + +#elif defined( __GNUC__ ) +# if __GNUC__ >= 3 +# define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 1 +# else +# define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 0 +#endif + +// +// Assume all other compilers do +// +#else + +// Macros to deal with deficiencies in compilers +# define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 1 +#endif + +#if STANDARD_LIBRARY_HAS_ITERATOR_TRAITS +# define random_access_iterator_parent(itemtype) std::iterator +#else +# define random_access_iterator_parent(itemtype) std::random_access_iterator +#endif + +// +// Which C++ standard is in use? +// +#if defined( _MSC_VER ) +# if _MSC_VER <= 1200 +// MSVC++ 6.0 +# define PYCXX_ISO_CPP_LIB 0 +# define STR_STREAM +# define TEMPLATE_TYPENAME class +# else +# define PYCXX_ISO_CPP_LIB 1 +# define STR_STREAM +# define TEMPLATE_TYPENAME typename +# endif +#elif defined( __GNUC__ ) +# if __GNUC__ >= 3 +# define PYCXX_ISO_CPP_LIB 1 +# define STR_STREAM +# define TEMPLATE_TYPENAME typename +# else +# define PYCXX_ISO_CPP_LIB 0 +# define STR_STREAM +# define TEMPLATE_TYPENAME class +# endif +#endif + +#if PYCXX_ISO_CPP_LIB +# define STR_STREAM +# define OSTRSTREAM ostringstream +# define EXPLICIT_TYPENAME typename +# define EXPLICIT_CLASS class +# define TEMPLATE_TYPENAME typename +#else +# define STR_STREAM +# define OSTRSTREAM ostrstream +# define EXPLICIT_TYPENAME +# define EXPLICIT_CLASS +# define TEMPLATE_TYPENAME class +#endif + + +#endif // __PyCXX_config_hh__ diff --git a/lib/kross/python/cxx/Exception.hxx b/lib/kross/python/cxx/Exception.hxx new file mode 100644 index 000000000..afcff489f --- /dev/null +++ b/lib/kross/python/cxx/Exception.hxx @@ -0,0 +1,212 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 1998 The Regents of the University of California. +// All rights reserved. See LEGAL.LLNL for full text and disclaimer. +//---------------------------------------------------------------------------// + +#ifndef __CXX_Exception_h +#define __CXX_Exception_h + +#include "Python.h" +#include "Config.hxx" +#include "IndirectPythonInterface.hxx" + +#include +#include + +// This mimics the Python structure, in order to minimize confusion +namespace Py + { + class ExtensionExceptionType; + + class Exception + { + public: + Exception( ExtensionExceptionType &exception, const std::string& reason ); + + explicit Exception () + {} + + Exception (const std::string& reason) + { + PyErr_SetString (Py::_Exc_RuntimeError(), reason.c_str()); + } + + Exception (PyObject* exception, const std::string& reason) + { + PyErr_SetString (exception, reason.c_str()); + } + + + void clear() // clear the error + // technically but not philosophically const + { + PyErr_Clear(); + } + }; + + + // Abstract + class StandardError: public Exception + { + protected: + explicit StandardError() + {} + }; + + class LookupError: public StandardError + { + protected: + explicit LookupError() + {} + }; + + class ArithmeticError: public StandardError + { + protected: + explicit ArithmeticError() + {} + }; + + class EnvironmentError: public StandardError + { + protected: + explicit EnvironmentError() + {} + }; + + // Concrete + + class TypeError: public StandardError + { + public: + TypeError (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_TypeError(),reason.c_str()); + } + }; + + class IndexError: public LookupError + { + public: + IndexError (const std::string& reason) + : LookupError() + { + PyErr_SetString (Py::_Exc_IndexError(), reason.c_str()); + } + }; + + class AttributeError: public StandardError + { + public: + AttributeError (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_AttributeError(), reason.c_str()); + } + }; + + class NameError: public StandardError + { + public: + NameError (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_NameError(), reason.c_str()); + } + }; + + class RuntimeError: public StandardError + { + public: + RuntimeError (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_RuntimeError(), reason.c_str()); + } + }; + + class SystemError: public StandardError + { + public: + SystemError (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_SystemError(),reason.c_str()); + } + }; + + class KeyError: public LookupError + { + public: + KeyError (const std::string& reason) + : LookupError() + { + PyErr_SetString (Py::_Exc_KeyError(),reason.c_str()); + } + }; + + + class ValueError: public StandardError + { + public: + ValueError (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_ValueError(), reason.c_str()); + } + }; + + class OverflowError: public ArithmeticError + { + public: + OverflowError (const std::string& reason) + : ArithmeticError() + { + PyErr_SetString (Py::_Exc_OverflowError(), reason.c_str()); + } + }; + + class ZeroDivisionError: public ArithmeticError + { + public: + ZeroDivisionError (const std::string& reason) + : ArithmeticError() + { + PyErr_SetString (Py::_Exc_ZeroDivisionError(), reason.c_str()); + } + }; + + class FloatingPointError: public ArithmeticError + { + public: + FloatingPointError (const std::string& reason) + : ArithmeticError() + { + PyErr_SetString (Py::_Exc_FloatingPointError(), reason.c_str()); + } + }; + + class MemoryError: public StandardError + { + public: + MemoryError (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_MemoryError(), reason.c_str()); + } + }; + + class SystemExit: public StandardError + { + public: + SystemExit (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_SystemExit(),reason.c_str()); + } + }; + + }// Py + +#endif diff --git a/lib/kross/python/cxx/Extensions.hxx b/lib/kross/python/cxx/Extensions.hxx new file mode 100644 index 000000000..69ce9a14b --- /dev/null +++ b/lib/kross/python/cxx/Extensions.hxx @@ -0,0 +1,756 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 1998 The Regents of the University of California. +// All rights reserved. See LEGAL.LLNL for full text and disclaimer. +//---------------------------------------------------------------------------// + +#ifndef __CXX_Extensions__h +#define __CXX_Extensions__h + + +#ifdef _MSC_VER +// disable warning C4786: symbol greater than 255 character, +// okay to ignore +#pragma warning(disable: 4786) +#endif + + +#include "Config.hxx" +#include "Objects.hxx" + +extern "C" + { + extern PyObject py_object_initializer; + } + +#include +#include + +namespace Py + { + class ExtensionModuleBase; + + // Make an Exception Type for use in raising custom exceptions + class ExtensionExceptionType : public Object + { + public: + ExtensionExceptionType(); + virtual ~ExtensionExceptionType(); + + // call init to create the type + void init( ExtensionModuleBase &module, const std::string& name ); + }; + + + class MethodTable + { + public: + MethodTable(); + virtual ~MethodTable(); + + void add(const char* method_name, PyCFunction f, const char* doc="", int flag=1); + PyMethodDef* table(); + + protected: + std::vector t; // accumulator of PyMethodDef's + PyMethodDef *mt; // Actual method table produced when full + + static PyMethodDef method (const char* method_name, PyCFunction f, int flags = 1, const char* doc=""); + + private: + // + // prevent the compiler generating these unwanted functions + // + MethodTable(const MethodTable& m); //unimplemented + void operator=(const MethodTable& m); //unimplemented + + }; // end class MethodTable + + extern "C" + { + typedef PyObject *(*method_varargs_call_handler_t)( PyObject *_self, PyObject *_args ); + typedef PyObject *(*method_keyword_call_handler_t)( PyObject *_self, PyObject *_args, PyObject *_dict ); + } + + template + class MethodDefExt : public PyMethodDef + { + public: + typedef Object (T::*method_varargs_function_t)( const Tuple &args ); + typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws ); + + MethodDefExt + ( + const char *_name, + method_varargs_function_t _function, + method_varargs_call_handler_t _handler, + const char *_doc + ) + { + ext_meth_def.ml_name = const_cast(_name); + ext_meth_def.ml_meth = _handler; + ext_meth_def.ml_flags = METH_VARARGS; + ext_meth_def.ml_doc = const_cast(_doc); + + ext_varargs_function = _function; + ext_keyword_function = NULL; + } + + MethodDefExt + ( + const char *_name, + method_keyword_function_t _function, + method_keyword_call_handler_t _handler, + const char *_doc + ) + { + ext_meth_def.ml_name = const_cast(_name); + ext_meth_def.ml_meth = method_varargs_call_handler_t( _handler ); + ext_meth_def.ml_flags = METH_VARARGS|METH_KEYWORDS; + ext_meth_def.ml_doc = const_cast(_doc); + + ext_varargs_function = NULL; + ext_keyword_function = _function; + } + + ~MethodDefExt() + {} + + PyMethodDef ext_meth_def; + method_varargs_function_t ext_varargs_function; + method_keyword_function_t ext_keyword_function; + }; + + class ExtensionModuleBase + { + public: + ExtensionModuleBase( const char *name ); + virtual ~ExtensionModuleBase(); + + Module module(void) const; // only valid after initialize() has been called + Dict moduleDictionary(void) const; // only valid after initialize() has been called + + virtual Object invoke_method_keyword( const std::string &_name, const Tuple &_args, const Dict &_keywords ) = 0; + virtual Object invoke_method_varargs( const std::string &_name, const Tuple &_args ) = 0; + + const std::string &name() const; + const std::string &fullName() const; + + protected: + // Initialize the module + void initialize( const char *module_doc ); + + const std::string module_name; + const std::string full_module_name; + MethodTable method_table; + + private: + + // + // prevent the compiler generating these unwanted functions + // + ExtensionModuleBase( const ExtensionModuleBase & ); //unimplemented + void operator=( const ExtensionModuleBase & ); //unimplemented + + }; + + extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords ); + extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args ); + extern "C" void do_not_dealloc( void * ); + + + template + class ExtensionModule : public ExtensionModuleBase + { + public: + ExtensionModule( const char *name ) + : ExtensionModuleBase( name ) + {} + virtual ~ExtensionModule() + {} + + protected: + typedef Object (T::*method_varargs_function_t)( const Tuple &args ); + typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws ); + typedef std::map *> method_map_t; + + static void add_varargs_method( const char *name, method_varargs_function_t function, const char *doc="" ) + { + method_map_t &mm = methods(); + + MethodDefExt *method_definition = new MethodDefExt + ( + name, + function, + method_varargs_call_handler, + doc + ); + + mm[std::string( name )] = method_definition; + } + + static void add_keyword_method( const char *name, method_keyword_function_t function, const char *doc="" ) + { + method_map_t &mm = methods(); + + MethodDefExt *method_definition = new MethodDefExt + ( + name, + function, + method_keyword_call_handler, + doc + ); + + mm[std::string( name )] = method_definition; + } + + void initialize( const char *module_doc="" ) + { + ExtensionModuleBase::initialize( module_doc ); + Dict dict( moduleDictionary() ); + + // + // put each of the methods into the modules dictionary + // so that we get called back at the function in T. + // + method_map_t &mm = methods(); + EXPLICIT_TYPENAME method_map_t::iterator i; + + for( i=mm.begin(); i != mm.end(); ++i ) + { + MethodDefExt *method_definition = (*i).second; + + static PyObject *self = PyCObject_FromVoidPtr( this, do_not_dealloc ); + + Tuple args( 2 ); + args[0] = Object( self ); + args[1] = String( (*i).first ); + + PyObject *func = PyCFunction_New + ( + &method_definition->ext_meth_def, + new_reference_to( args ) + ); + + dict[ (*i).first ] = Object( func ); + } + } + + protected: // Tom Malcolmson reports that derived classes need access to these + + static method_map_t &methods(void) + { + static method_map_t *map_of_methods = NULL; + if( map_of_methods == NULL ) + map_of_methods = new method_map_t; + + return *map_of_methods; + } + + + // this invoke function must be called from within a try catch block + virtual Object invoke_method_keyword( const std::string &name, const Tuple &args, const Dict &keywords ) + { + method_map_t &mm = methods(); + MethodDefExt *meth_def = mm[ name ]; + if( meth_def == NULL ) + { + std::string error_msg( "CXX - cannot invoke keyword method named " ); + error_msg += name; + throw RuntimeError( error_msg ); + } + + // cast up to the derived class + T *self = static_cast(this); + + return (self->*meth_def->ext_keyword_function)( args, keywords ); + } + + // this invoke function must be called from within a try catch block + virtual Object invoke_method_varargs( const std::string &name, const Tuple &args ) + { + method_map_t &mm = methods(); + MethodDefExt *meth_def = mm[ name ]; + if( meth_def == NULL ) + { + std::string error_msg( "CXX - cannot invoke varargs method named " ); + error_msg += name; + throw RuntimeError( error_msg ); + } + + // cast up to the derived class + T *self = static_cast(this); + + return (self->*meth_def->ext_varargs_function)( args ); + } + + private: + // + // prevent the compiler generating these unwanted functions + // + ExtensionModule( const ExtensionModule & ); //unimplemented + void operator=( const ExtensionModule & ); //unimplemented + }; + + + class PythonType + { + public: + // if you define one sequence method you must define + // all of them except the assigns + + PythonType (size_t base_size, int itemsize, const char *default_name ); + virtual ~PythonType (); + + const char *getName () const; + const char *getDoc () const; + + PyTypeObject* type_object () const; + void name (const char* nam); + void doc (const char* d); + void dealloc(void (*f)(PyObject*)); + + void supportPrint(void); + void supportGetattr(void); + void supportSetattr(void); + void supportGetattro(void); + void supportSetattro(void); + void supportCompare(void); + void supportRepr(void); + void supportStr(void); + void supportHash(void); + void supportCall(void); + + void supportSequenceType(void); + void supportMappingType(void); + void supportNumberType(void); + void supportBufferType(void); + + protected: + PyTypeObject *table; + PySequenceMethods *sequence_table; + PyMappingMethods *mapping_table; + PyNumberMethods *number_table; + PyBufferProcs *buffer_table; + + void init_sequence(); + void init_mapping(); + void init_number(); + void init_buffer(); + + private: + // + // prevent the compiler generating these unwanted functions + // + PythonType (const PythonType& tb); // unimplemented + void operator=(const PythonType& t); // unimplemented + + }; // end of PythonType + + + + // Class PythonExtension is what you inherit from to create + // a new Python extension type. You give your class itself + // as the template paramter. + + // There are two ways that extension objects can get destroyed. + // 1. Their reference count goes to zero + // 2. Someone does an explicit delete on a pointer. + // In (1) the problem is to get the destructor called + // We register a special deallocator in the Python type object + // (see behaviors()) to do this. + // In (2) there is no problem, the dtor gets called. + + // PythonExtension does not use the usual Python heap allocator, + // instead using new/delete. We do the setting of the type object + // and reference count, usually done by PyObject_New, in the + // base class ctor. + + // This special deallocator does a delete on the pointer. + + + class PythonExtensionBase : public PyObject + { + public: + PythonExtensionBase(); + virtual ~PythonExtensionBase(); + + public: + virtual int print( FILE *, int ); + virtual Object getattr( const char * ) = 0; + virtual int setattr( const char *, const Object & ); + virtual Object getattro( const Object & ); + virtual int setattro( const Object &, const Object & ); + virtual int compare( const Object & ); + virtual Object repr(); + virtual Object str(); + virtual long hash(); + virtual Object call( const Object &, const Object & ); + + // Sequence methods + virtual int sequence_length(); + virtual Object sequence_concat( const Object & ); + virtual Object sequence_repeat( int ); + virtual Object sequence_item( int ); + virtual Object sequence_slice( int, int ); + virtual int sequence_ass_item( int, const Object & ); + virtual int sequence_ass_slice( int, int, const Object & ); + + // Mapping + virtual int mapping_length(); + virtual Object mapping_subscript( const Object & ); + virtual int mapping_ass_subscript( const Object &, const Object & ); + + // Number + virtual int number_nonzero(); + virtual Object number_negative(); + virtual Object number_positive(); + virtual Object number_absolute(); + virtual Object number_invert(); + virtual Object number_int(); + virtual Object number_float(); + virtual Object number_long(); + virtual Object number_oct(); + virtual Object number_hex(); + virtual Object number_add( const Object & ); + virtual Object number_subtract( const Object & ); + virtual Object number_multiply( const Object & ); + virtual Object number_divide( const Object & ); + virtual Object number_remainder( const Object & ); + virtual Object number_divmod( const Object & ); + virtual Object number_lshift( const Object & ); + virtual Object number_rshift( const Object & ); + virtual Object number_and( const Object & ); + virtual Object number_xor( const Object & ); + virtual Object number_or( const Object & ); + virtual Object number_power( const Object &, const Object & ); + + // Buffer + virtual int buffer_getreadbuffer( int, void** ); + virtual int buffer_getwritebuffer( int, void** ); + virtual int buffer_getsegcount( int* ); + + private: + void missing_method( void ); + static PyObject *method_call_handler( PyObject *self, PyObject *args ); + }; + + template + class PythonExtension: public PythonExtensionBase + { + public: + static PyTypeObject* type_object() + { + return behaviors().type_object(); + } + + static int check( PyObject *p ) + { + // is p like me? + return p->ob_type == type_object(); + } + + static int check( const Object& ob ) + { + return check( ob.ptr()); + } + + + // + // every object needs getattr implemented + // to support methods + // + virtual Object getattr( const char *name ) + { + return getattr_methods( name ); + } + + protected: + explicit PythonExtension() + : PythonExtensionBase() + { + #ifdef PyObject_INIT + (void)PyObject_INIT( this, type_object() ); + #else + ob_refcnt = 1; + ob_type = type_object(); + #endif + + // every object must support getattr + behaviors().supportGetattr(); + } + + virtual ~PythonExtension() + {} + + static PythonType &behaviors() + { + static PythonType* p; + if( p == NULL ) + { +#if defined( _CPPRTTI ) + const char *default_name = (typeid ( T )).name(); +#else + const char *default_name = "unknown"; +#endif + p = new PythonType( sizeof( T ), 0, default_name ); + p->dealloc( extension_object_deallocator ); + } + + return *p; + } + + + typedef Object (T::*method_varargs_function_t)( const Tuple &args ); + typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws ); + typedef std::map *> method_map_t; + + // support the default attributes, __name__, __doc__ and methods + virtual Object getattr_default( const char *_name ) + { + std::string name( _name ); + + if( name == "__name__" && type_object()->tp_name != NULL ) + { + return Py::String( type_object()->tp_name ); + } + else if( name == "__doc__" && type_object()->tp_doc != NULL ) + { + return Py::String( type_object()->tp_doc ); + } + +// trying to fake out being a class for help() +// else if( name == "__bases__" ) +// { +// return Py::Tuple(0); +// } +// else if( name == "__module__" ) +// { +// return Py::Nothing(); +// } +// else if( name == "__dict__" ) +// { +// return Py::Dict(); +// } + else + { + return getattr_methods( _name ); + } + } + + // turn a name into function object + virtual Object getattr_methods( const char *_name ) + { + std::string name( _name ); + + method_map_t &mm = methods(); + + if( name == "__methods__" ) + { + List methods; + + for( EXPLICIT_TYPENAME method_map_t::iterator i = mm.begin(); i != mm.end(); ++i ) + methods.append( String( (*i).first ) ); + + return methods; + } + + // see if name exists + if( mm.find( name ) == mm.end() ) + throw AttributeError( "method '" + name + "' does not exist." ); + + Tuple self( 2 ); + + self[0] = Object( this ); + self[1] = String( name ); + + MethodDefExt *method_definition = mm[ name ]; + + PyObject *func = PyCFunction_New( &method_definition->ext_meth_def, self.ptr() ); + + return Object(func, true); + } + + static void add_varargs_method( const char *name, method_varargs_function_t function, const char *doc="" ) + { + method_map_t &mm = methods(); + + MethodDefExt *method_definition = new MethodDefExt + ( + name, + function, + method_varargs_call_handler, + doc + ); + + mm[std::string( name )] = method_definition; + } + + static void add_keyword_method( const char *name, method_keyword_function_t function, const char *doc="" ) + { + method_map_t &mm = methods(); + + MethodDefExt *method_definition = new MethodDefExt + ( + name, + function, + method_keyword_call_handler, + doc + ); + + mm[std::string( name )] = method_definition; + } + + private: + static method_map_t &methods(void) + { + static method_map_t *map_of_methods = NULL; + if( map_of_methods == NULL ) + map_of_methods = new method_map_t; + + return *map_of_methods; + } + + static PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords ) + { + try + { + Tuple self_and_name_tuple( _self_and_name_tuple ); + + PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); + T *self = static_cast( self_in_cobject ); + + String name( self_and_name_tuple[1] ); + + method_map_t &mm = methods(); + MethodDefExt *meth_def = mm[ name ]; + if( meth_def == NULL ) + return 0; + + Tuple args( _args ); + + // _keywords may be NULL so be careful about the way the dict is created + Dict keywords; + if( _keywords != NULL ) + keywords = Dict( _keywords ); + + Object result( (self->*meth_def->ext_keyword_function)( args, keywords ) ); + + return new_reference_to( result.ptr() ); + } + catch( Exception & ) + { + return 0; + } + } + + static PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args ) + { + try + { + Tuple self_and_name_tuple( _self_and_name_tuple ); + + PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); + T *self = static_cast( self_in_cobject ); + + String name( self_and_name_tuple[1] ); + + method_map_t &mm = methods(); + MethodDefExt *meth_def = mm[ name ]; + if( meth_def == NULL ) + return 0; + + Tuple args( _args ); + + Object result; + + // TMM: 7Jun'01 - Adding try & catch in case of STL debug-mode exceptions. + #ifdef _STLP_DEBUG + try + { + result = (self->*meth_def->ext_varargs_function)( args ); + } + catch (std::__stl_debug_exception) + { + // throw cxx::RuntimeError( sErrMsg ); + throw cxx::RuntimeError( "Error message not set yet." ); + } + #else + result = (self->*meth_def->ext_varargs_function)( args ); + #endif // _STLP_DEBUG + + return new_reference_to( result.ptr() ); + } + catch( Exception & ) + { + return 0; + } + } + + static void extension_object_deallocator ( PyObject* t ) + { + delete (T *)( t ); + } + + // + // prevent the compiler generating these unwanted functions + // + explicit PythonExtension( const PythonExtension& other ); + void operator=( const PythonExtension& rhs ); + }; + + // + // ExtensionObject is an Object that will accept only T's. + // + template + class ExtensionObject: public Object + { + public: + + explicit ExtensionObject ( PyObject *pyob ) + : Object( pyob ) + { + validate(); + } + + ExtensionObject( const ExtensionObject& other ) + : Object( *other ) + { + validate(); + } + + ExtensionObject( const Object& other ) + : Object( *other ) + { + validate(); + } + + ExtensionObject& operator= ( const Object& rhs ) + { + return (*this = *rhs ); + } + + ExtensionObject& operator= ( PyObject* rhsp ) + { + if( ptr() == rhsp ) + return *this; + set( rhsp ); + return *this; + } + + virtual bool accepts ( PyObject *pyob ) const + { + return ( pyob && T::check( pyob )); + } + + // + // Obtain a pointer to the PythonExtension object + // + T *extensionObject(void) + { + return static_cast( ptr() ); + } + }; + + } // Namespace Py +// End of CXX_Extensions.h +#endif diff --git a/lib/kross/python/cxx/IndirectPythonInterface.cxx b/lib/kross/python/cxx/IndirectPythonInterface.cxx new file mode 100644 index 000000000..caaa09134 --- /dev/null +++ b/lib/kross/python/cxx/IndirectPythonInterface.cxx @@ -0,0 +1,550 @@ +// +// IndirectPythonInterface.cxx +// +#undef _XOPEN_SOURCE +#include "IndirectPythonInterface.hxx" + +namespace Py +{ +bool _Buffer_Check( PyObject *op ) { return (op)->ob_type == _Buffer_Type(); } +bool _CFunction_Check( PyObject *op ) { return (op)->ob_type == _CFunction_Type(); } +bool _Class_Check( PyObject *op ) { return (op)->ob_type == _Class_Type(); } +bool _CObject_Check( PyObject *op ) { return (op)->ob_type == _CObject_Type(); } +bool _Complex_Check( PyObject *op ) { return (op)->ob_type == _Complex_Type(); } +bool _Dict_Check( PyObject *op ) { return (op)->ob_type == _Dict_Type(); } +bool _File_Check( PyObject *op ) { return (op)->ob_type == _File_Type(); } +bool _Float_Check( PyObject *op ) { return (op)->ob_type == _Float_Type(); } +bool _Function_Check( PyObject *op ) { return (op)->ob_type == _Function_Type(); } +bool _Instance_Check( PyObject *op ) { return (op)->ob_type == _Instance_Type(); } +bool _Int_Check( PyObject *op ) { return (op)->ob_type == _Int_Type(); } +bool _List_Check( PyObject *o ) { return o->ob_type == _List_Type(); } +bool _Long_Check( PyObject *op ) { return (op)->ob_type == _Long_Type(); } +bool _Method_Check( PyObject *op ) { return (op)->ob_type == _Method_Type(); } +bool _Module_Check( PyObject *op ) { return (op)->ob_type == _Module_Type(); } +bool _Range_Check( PyObject *op ) { return (op)->ob_type == _Range_Type(); } +bool _Slice_Check( PyObject *op ) { return (op)->ob_type == _Slice_Type(); } +bool _String_Check( PyObject *o ) { return o->ob_type == _String_Type(); } +bool _TraceBack_Check( PyObject *v ) { return (v)->ob_type == _TraceBack_Type(); } +bool _Tuple_Check( PyObject *op ) { return (op)->ob_type == _Tuple_Type(); } +bool _Type_Check( PyObject *op ) { return (op)->ob_type == _Type_Type(); } + +#if PY_MAJOR_VERSION >= 2 +bool _Unicode_Check( PyObject *op ) { return (op)->ob_type == _Unicode_Type(); } +#endif + + + +#if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL) + +#if defined(MS_WINDOWS) +#include + + +static HMODULE python_dll; + +static PyObject *ptr__Exc_ArithmeticError = NULL; +static PyObject *ptr__Exc_AssertionError = NULL; +static PyObject *ptr__Exc_AttributeError = NULL; +static PyObject *ptr__Exc_EnvironmentError = NULL; +static PyObject *ptr__Exc_EOFError = NULL; +static PyObject *ptr__Exc_Exception = NULL; +static PyObject *ptr__Exc_FloatingPointError = NULL; +static PyObject *ptr__Exc_ImportError = NULL; +static PyObject *ptr__Exc_IndexError = NULL; +static PyObject *ptr__Exc_IOError = NULL; +static PyObject *ptr__Exc_KeyboardInterrupt = NULL; +static PyObject *ptr__Exc_KeyError = NULL; +static PyObject *ptr__Exc_LookupError = NULL; +static PyObject *ptr__Exc_MemoryError = NULL; +static PyObject *ptr__Exc_MemoryErrorInst = NULL; +static PyObject *ptr__Exc_NameError = NULL; +static PyObject *ptr__Exc_NotImplementedError = NULL; +static PyObject *ptr__Exc_OSError = NULL; +static PyObject *ptr__Exc_OverflowError = NULL; +static PyObject *ptr__Exc_RuntimeError = NULL; +static PyObject *ptr__Exc_StandardError = NULL; +static PyObject *ptr__Exc_SyntaxError = NULL; +static PyObject *ptr__Exc_SystemError = NULL; +static PyObject *ptr__Exc_SystemExit = NULL; +static PyObject *ptr__Exc_TypeError = NULL; +static PyObject *ptr__Exc_ValueError = NULL; +static PyObject *ptr__Exc_ZeroDivisionError = NULL; + +#ifdef MS_WINDOWS +static PyObject *ptr__Exc_WindowsError = NULL; +#endif + +#if PY_MAJOR_VERSION >= 2 +static PyObject *ptr__Exc_IndentationError = NULL; +static PyObject *ptr__Exc_TabError = NULL; +static PyObject *ptr__Exc_UnboundLocalError = NULL; +static PyObject *ptr__Exc_UnicodeError = NULL; +#endif + +static PyObject *ptr__PyNone = NULL; + +static PyTypeObject *ptr__Buffer_Type = NULL; +static PyTypeObject *ptr__CFunction_Type = NULL; +static PyTypeObject *ptr__Class_Type = NULL; +static PyTypeObject *ptr__CObject_Type = NULL; +static PyTypeObject *ptr__Complex_Type = NULL; +static PyTypeObject *ptr__Dict_Type = NULL; +static PyTypeObject *ptr__File_Type = NULL; +static PyTypeObject *ptr__Float_Type = NULL; +static PyTypeObject *ptr__Function_Type = NULL; +static PyTypeObject *ptr__Instance_Type = NULL; +static PyTypeObject *ptr__Int_Type = NULL; +static PyTypeObject *ptr__List_Type = NULL; +static PyTypeObject *ptr__Long_Type = NULL; +static PyTypeObject *ptr__Method_Type = NULL; +static PyTypeObject *ptr__Module_Type = NULL; +static PyTypeObject *ptr__Range_Type = NULL; +static PyTypeObject *ptr__Slice_Type = NULL; +static PyTypeObject *ptr__String_Type = NULL; +static PyTypeObject *ptr__TraceBack_Type = NULL; +static PyTypeObject *ptr__Tuple_Type = NULL; +static PyTypeObject *ptr__Type_Type = NULL; + +#if PY_MAJOR_VERSION >= 2 +static PyTypeObject *ptr__Unicode_Type = NULL; +#endif + +static int *ptr_Py_DebugFlag = NULL; +static int *ptr_Py_InteractiveFlag = NULL; +static int *ptr_Py_OptimizeFlag = NULL; +static int *ptr_Py_NoSiteFlag = NULL; +static int *ptr_Py_TabcheckFlag = NULL; +static int *ptr_Py_VerboseFlag = NULL; + +#if PY_MAJOR_VERSION >= 2 +static int *ptr_Py_UnicodeFlag = NULL; +#endif + +static char **ptr__Py_PackageContext = NULL; + +#ifdef Py_REF_DEBUG +int *ptr_Py_RefTotal; +#endif + + +//-------------------------------------------------------------------------------- +class GetAddressException + { +public: + GetAddressException( const char *_name ) + : name( _name ) + {} + virtual ~GetAddressException() {} + const char *name; + }; + + +//-------------------------------------------------------------------------------- +static PyObject *GetPyObjectPointer_As_PyObjectPointer( const char *name ) + { + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return *(PyObject **)addr; + } + +static PyObject *GetPyObject_As_PyObjectPointer( const char *name ) + { + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return (PyObject *)addr; + } + +static PyTypeObject *GetPyTypeObjectPointer_As_PyTypeObjectPointer( const char *name ) + { + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return *(PyTypeObject **)addr; + } + +static PyTypeObject *GetPyTypeObject_As_PyTypeObjectPointer( const char *name ) + { + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return (PyTypeObject *)addr; + } + +static int *GetInt_as_IntPointer( const char *name ) + { + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return (int *)addr; + } + +static char **GetCharPointer_as_CharPointerPointer( const char *name ) + { + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return (char **)addr; + } + + +#ifdef _DEBUG +static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d_D.DLL"; +#else +static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d.DLL"; +#endif + +//-------------------------------------------------------------------------------- +bool InitialisePythonIndirectInterface() + { + char python_dll_name[sizeof(python_dll_name_format)]; + + sprintf( python_dll_name, python_dll_name_format, PY_MAJOR_VERSION, PY_MINOR_VERSION ); + + python_dll = LoadLibrary( python_dll_name ); + if( python_dll == NULL ) + return false; + + try + { +#ifdef Py_REF_DEBUG + ptr_Py_RefTotal = GetInt_as_IntPointer( "_Py_RefTotal" ); +#endif + ptr_Py_DebugFlag = GetInt_as_IntPointer( "Py_DebugFlag" ); + ptr_Py_InteractiveFlag = GetInt_as_IntPointer( "Py_InteractiveFlag" ); + ptr_Py_OptimizeFlag = GetInt_as_IntPointer( "Py_OptimizeFlag" ); + ptr_Py_NoSiteFlag = GetInt_as_IntPointer( "Py_NoSiteFlag" ); + ptr_Py_TabcheckFlag = GetInt_as_IntPointer( "Py_TabcheckFlag" ); + ptr_Py_VerboseFlag = GetInt_as_IntPointer( "Py_VerboseFlag" ); +#if PY_MAJOR_VERSION >= 2 + ptr_Py_UnicodeFlag = GetInt_as_IntPointer( "Py_UnicodeFlag" ); +#endif + ptr__Py_PackageContext = GetCharPointer_as_CharPointerPointer( "_Py_PackageContext" ); + + ptr__Exc_ArithmeticError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ArithmeticError" ); + ptr__Exc_AssertionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AssertionError" ); + ptr__Exc_AttributeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AttributeError" ); + ptr__Exc_EnvironmentError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EnvironmentError" ); + ptr__Exc_EOFError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EOFError" ); + ptr__Exc_Exception = GetPyObjectPointer_As_PyObjectPointer( "PyExc_Exception" ); + ptr__Exc_FloatingPointError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_FloatingPointError" ); + ptr__Exc_ImportError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ImportError" ); + ptr__Exc_IndexError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndexError" ); + ptr__Exc_IOError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IOError" ); + ptr__Exc_KeyboardInterrupt = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyboardInterrupt" ); + ptr__Exc_KeyError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyError" ); + ptr__Exc_LookupError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_LookupError" ); + ptr__Exc_MemoryError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_MemoryError" ); + ptr__Exc_MemoryErrorInst = GetPyObjectPointer_As_PyObjectPointer( "PyExc_MemoryErrorInst" ); + ptr__Exc_NameError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_NameError" ); + ptr__Exc_NotImplementedError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_NotImplementedError" ); + ptr__Exc_OSError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OSError" ); + ptr__Exc_OverflowError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OverflowError" ); + ptr__Exc_RuntimeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_RuntimeError" ); + ptr__Exc_StandardError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_StandardError" ); + ptr__Exc_SyntaxError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SyntaxError" ); + ptr__Exc_SystemError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemError" ); + ptr__Exc_SystemExit = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemExit" ); + ptr__Exc_TypeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TypeError" ); + ptr__Exc_ValueError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ValueError" ); +#ifdef MS_WINDOWS + ptr__Exc_WindowsError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_WindowsError" ); +#endif + ptr__Exc_ZeroDivisionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ZeroDivisionError" ); + +#if PY_MAJOR_VERSION >= 2 + ptr__Exc_IndentationError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndentationError" ); + ptr__Exc_TabError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TabError" ); + ptr__Exc_UnboundLocalError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnboundLocalError" ); + ptr__Exc_UnicodeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnicodeError" ); +#endif + ptr__PyNone = GetPyObject_As_PyObjectPointer( "_Py_NoneStruct" ); + + ptr__Buffer_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyBuffer_Type" ); + ptr__CFunction_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCFunction_Type" ); + ptr__Class_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyClass_Type" ); + ptr__CObject_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCObject_Type" ); + ptr__Complex_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyComplex_Type" ); + ptr__Dict_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyDict_Type" ); + ptr__File_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFile_Type" ); + ptr__Float_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFloat_Type" ); + ptr__Function_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFunction_Type" ); + ptr__Instance_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyInstance_Type" ); + ptr__Int_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyInt_Type" ); + ptr__List_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyList_Type" ); + ptr__Long_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyLong_Type" ); + ptr__Method_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyMethod_Type" ); + ptr__Module_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyModule_Type" ); + ptr__Range_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyRange_Type" ); + ptr__Slice_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PySlice_Type" ); + ptr__String_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyString_Type" ); + ptr__TraceBack_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTraceBack_Type" ); + ptr__Tuple_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTuple_Type" ); + ptr__Type_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyType_Type" ); + +#if PY_MAJOR_VERSION >= 2 + ptr__Unicode_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyUnicode_Type" ); +#endif + } + catch( GetAddressException &e ) + { + OutputDebugString( python_dll_name ); + OutputDebugString( " does not contain symbol "); + OutputDebugString( e.name ); + OutputDebugString( "\n" ); + + return false; + } + + return true; + } + +// +// Wrap variables as function calls +// +PyObject * _Exc_ArithmeticError() { return ptr__Exc_ArithmeticError; } +PyObject * _Exc_AssertionError() { return ptr__Exc_AssertionError; } +PyObject * _Exc_AttributeError() { return ptr__Exc_AttributeError; } +PyObject * _Exc_EnvironmentError() { return ptr__Exc_EnvironmentError; } +PyObject * _Exc_EOFError() { return ptr__Exc_EOFError; } +PyObject * _Exc_Exception() { return ptr__Exc_Exception; } +PyObject * _Exc_FloatingPointError() { return ptr__Exc_FloatingPointError; } +PyObject * _Exc_ImportError() { return ptr__Exc_ImportError; } +PyObject * _Exc_IndexError() { return ptr__Exc_IndexError; } +PyObject * _Exc_IOError() { return ptr__Exc_IOError; } +PyObject * _Exc_KeyboardInterrupt() { return ptr__Exc_KeyboardInterrupt; } +PyObject * _Exc_KeyError() { return ptr__Exc_KeyError; } +PyObject * _Exc_LookupError() { return ptr__Exc_LookupError; } +PyObject * _Exc_MemoryError() { return ptr__Exc_MemoryError; } +PyObject * _Exc_MemoryErrorInst() { return ptr__Exc_MemoryErrorInst; } +PyObject * _Exc_NameError() { return ptr__Exc_NameError; } +PyObject * _Exc_NotImplementedError() { return ptr__Exc_NotImplementedError; } +PyObject * _Exc_OSError() { return ptr__Exc_OSError; } +PyObject * _Exc_OverflowError() { return ptr__Exc_OverflowError; } +PyObject * _Exc_RuntimeError() { return ptr__Exc_RuntimeError; } +PyObject * _Exc_StandardError() { return ptr__Exc_StandardError; } +PyObject * _Exc_SyntaxError() { return ptr__Exc_SyntaxError; } +PyObject * _Exc_SystemError() { return ptr__Exc_SystemError; } +PyObject * _Exc_SystemExit() { return ptr__Exc_SystemExit; } +PyObject * _Exc_TypeError() { return ptr__Exc_TypeError; } +PyObject * _Exc_ValueError() { return ptr__Exc_ValueError; } +#ifdef MS_WINDOWS +PyObject * _Exc_WindowsError() { return ptr__Exc_WindowsError; } +#endif +PyObject * _Exc_ZeroDivisionError() { return ptr__Exc_ZeroDivisionError; } + +#if PY_MAJOR_VERSION >= 2 +PyObject * _Exc_IndentationError() { return ptr__Exc_IndentationError; } +PyObject * _Exc_TabError() { return ptr__Exc_TabError; } +PyObject * _Exc_UnboundLocalError() { return ptr__Exc_UnboundLocalError; } +PyObject * _Exc_UnicodeError() { return ptr__Exc_UnicodeError; } +#endif + +// +// wrap items in Object.h +// +PyObject * _None() { return ptr__PyNone; } + + +PyTypeObject * _Buffer_Type() { return ptr__Buffer_Type; } +PyTypeObject * _CFunction_Type() { return ptr__CFunction_Type; } +PyTypeObject * _Class_Type() { return ptr__Class_Type; } +PyTypeObject * _CObject_Type() { return ptr__CObject_Type; } +PyTypeObject * _Complex_Type() { return ptr__Complex_Type; } +PyTypeObject * _Dict_Type() { return ptr__Dict_Type; } +PyTypeObject * _File_Type() { return ptr__File_Type; } +PyTypeObject * _Float_Type() { return ptr__Float_Type; } +PyTypeObject * _Function_Type() { return ptr__Function_Type; } +PyTypeObject * _Instance_Type() { return ptr__Instance_Type; } +PyTypeObject * _Int_Type() { return ptr__Int_Type; } +PyTypeObject * _List_Type() { return ptr__List_Type; } +PyTypeObject * _Long_Type() { return ptr__Long_Type; } +PyTypeObject * _Method_Type() { return ptr__Method_Type; } +PyTypeObject * _Module_Type() { return ptr__Module_Type; } +PyTypeObject * _Range_Type() { return ptr__Range_Type; } +PyTypeObject * _Slice_Type() { return ptr__Slice_Type; } +PyTypeObject * _String_Type() { return ptr__String_Type; } +PyTypeObject * _TraceBack_Type() { return ptr__TraceBack_Type; } +PyTypeObject * _Tuple_Type() { return ptr__Tuple_Type; } +PyTypeObject * _Type_Type() { return ptr__Type_Type; } + +#if PY_MAJOR_VERSION >= 2 +PyTypeObject * _Unicode_Type() { return ptr__Unicode_Type; } +#endif + +char *__Py_PackageContext() { return *ptr__Py_PackageContext; } + + +// +// wrap the Python Flag variables +// +int &_Py_DebugFlag() { return *ptr_Py_DebugFlag; } +int &_Py_InteractiveFlag() { return *ptr_Py_InteractiveFlag; } +int &_Py_OptimizeFlag() { return *ptr_Py_OptimizeFlag; } +int &_Py_NoSiteFlag() { return *ptr_Py_NoSiteFlag; } +int &_Py_TabcheckFlag() { return *ptr_Py_TabcheckFlag; } +int &_Py_VerboseFlag() { return *ptr_Py_VerboseFlag; } +#if PY_MAJOR_VERSION >= 2 +int &_Py_UnicodeFlag() { return *ptr_Py_UnicodeFlag; } +#endif + +void _XINCREF( PyObject *op ) + { + // This function must match the contents of Py_XINCREF(op) + if( op == NULL ) + return; + +#ifdef Py_REF_DEBUG + (*ptr_Py_RefTotal)++; +#endif + (op)->ob_refcnt++; + + } + +void _XDECREF( PyObject *op ) + { + // This function must match the contents of Py_XDECREF(op); + if( op == NULL ) + return; + +#ifdef Py_REF_DEBUG + (*ptr_Py_RefTotal)--; +#endif + + if (--(op)->ob_refcnt == 0) + _Py_Dealloc((PyObject *)(op)); + } + + +#else +#error "Can only delay load under Win32" +#endif + +#else + +// +// Duplicated these declarations from rangeobject.h which is missing the +// extern "C". This has been reported as a bug upto and include 2.1 +// +extern "C" DL_IMPORT(PyTypeObject) PyRange_Type; +extern "C" DL_IMPORT(PyObject *) PyRange_New(long, long, long, int); + + +//================================================================================ +// +// Map onto Macros +// +//================================================================================ + +// +// Wrap variables as function calls +// + +PyObject * _Exc_ArithmeticError() { return ::PyExc_ArithmeticError; } +PyObject * _Exc_AssertionError() { return ::PyExc_AssertionError; } +PyObject * _Exc_AttributeError() { return ::PyExc_AttributeError; } +PyObject * _Exc_EnvironmentError() { return ::PyExc_EnvironmentError; } +PyObject * _Exc_EOFError() { return ::PyExc_EOFError; } +PyObject * _Exc_Exception() { return ::PyExc_Exception; } +PyObject * _Exc_FloatingPointError() { return ::PyExc_FloatingPointError; } +PyObject * _Exc_ImportError() { return ::PyExc_ImportError; } +PyObject * _Exc_IndexError() { return ::PyExc_IndexError; } +PyObject * _Exc_IOError() { return ::PyExc_IOError; } +PyObject * _Exc_KeyboardInterrupt() { return ::PyExc_KeyboardInterrupt; } +PyObject * _Exc_KeyError() { return ::PyExc_KeyError; } +PyObject * _Exc_LookupError() { return ::PyExc_LookupError; } +PyObject * _Exc_MemoryError() { return ::PyExc_MemoryError; } +PyObject * _Exc_MemoryErrorInst() { return ::PyExc_MemoryErrorInst; } +PyObject * _Exc_NameError() { return ::PyExc_NameError; } +PyObject * _Exc_NotImplementedError() { return ::PyExc_NotImplementedError; } +PyObject * _Exc_OSError() { return ::PyExc_OSError; } +PyObject * _Exc_OverflowError() { return ::PyExc_OverflowError; } +PyObject * _Exc_RuntimeError() { return ::PyExc_RuntimeError; } +PyObject * _Exc_StandardError() { return ::PyExc_StandardError; } +PyObject * _Exc_SyntaxError() { return ::PyExc_SyntaxError; } +PyObject * _Exc_SystemError() { return ::PyExc_SystemError; } +PyObject * _Exc_SystemExit() { return ::PyExc_SystemExit; } +PyObject * _Exc_TypeError() { return ::PyExc_TypeError; } +PyObject * _Exc_ValueError() { return ::PyExc_ValueError; } +PyObject * _Exc_ZeroDivisionError() { return ::PyExc_ZeroDivisionError; } + +#ifdef MS_WINDOWS +PyObject * _Exc_WindowsError() { return ::PyExc_WindowsError; } +#endif + + +#if PY_MAJOR_VERSION >= 2 +PyObject * _Exc_IndentationError() { return ::PyExc_IndentationError; } +PyObject * _Exc_TabError() { return ::PyExc_TabError; } +PyObject * _Exc_UnboundLocalError() { return ::PyExc_UnboundLocalError; } +PyObject * _Exc_UnicodeError() { return ::PyExc_UnicodeError; } +#endif + + +// +// wrap items in Object.h +// +PyObject * _None() { return &::_Py_NoneStruct; } + +PyTypeObject * _Buffer_Type() { return &PyBuffer_Type; } +PyTypeObject * _CFunction_Type() { return &PyCFunction_Type; } +PyTypeObject * _Class_Type() { return &PyClass_Type; } +PyTypeObject * _CObject_Type() { return &PyCObject_Type; } +PyTypeObject * _Complex_Type() { return &PyComplex_Type; } +PyTypeObject * _Dict_Type() { return &PyDict_Type; } +PyTypeObject * _File_Type() { return &PyFile_Type; } +PyTypeObject * _Float_Type() { return &PyFloat_Type; } +PyTypeObject * _Function_Type() { return &PyFunction_Type; } +PyTypeObject * _Instance_Type() { return &PyInstance_Type; } +PyTypeObject * _Int_Type() { return &PyInt_Type; } +PyTypeObject * _List_Type() { return &PyList_Type; } +PyTypeObject * _Long_Type() { return &PyLong_Type; } +PyTypeObject * _Method_Type() { return &PyMethod_Type; } +PyTypeObject * _Module_Type() { return &PyModule_Type; } +PyTypeObject * _Range_Type() { return &PyRange_Type; } +PyTypeObject * _Slice_Type() { return &PySlice_Type; } +PyTypeObject * _String_Type() { return &PyString_Type; } +PyTypeObject * _TraceBack_Type() { return &PyTraceBack_Type; } +PyTypeObject * _Tuple_Type() { return &PyTuple_Type; } +PyTypeObject * _Type_Type() { return &PyType_Type; } + +#if PY_MAJOR_VERSION >= 2 +PyTypeObject * _Unicode_Type() { return &PyUnicode_Type; } +#endif + +// +// wrap flags +// +int &_Py_DebugFlag() { return Py_DebugFlag; } +int &_Py_InteractiveFlag() { return Py_InteractiveFlag; } +int &_Py_OptimizeFlag() { return Py_OptimizeFlag; } +int &_Py_NoSiteFlag() { return Py_NoSiteFlag; } +int &_Py_TabcheckFlag() { return Py_TabcheckFlag; } +int &_Py_VerboseFlag() { return Py_VerboseFlag; } +#if PY_MAJOR_VERSION >= 2 +int &_Py_UnicodeFlag() { return Py_UnicodeFlag; } +#endif +char *__Py_PackageContext() { return _Py_PackageContext; } + +// +// Needed to keep the abstactions for delayload interface +// +void _XINCREF( PyObject *op ) + { + Py_XINCREF(op); + } + +void _XDECREF( PyObject *op ) + { + Py_XDECREF(op); + } + +#endif +} diff --git a/lib/kross/python/cxx/IndirectPythonInterface.hxx b/lib/kross/python/cxx/IndirectPythonInterface.hxx new file mode 100644 index 000000000..8f2d275dd --- /dev/null +++ b/lib/kross/python/cxx/IndirectPythonInterface.hxx @@ -0,0 +1,156 @@ +#ifndef __CXX_INDIRECT_PYTHON_INTERFACE__HXX__ +#define __CXX_INDIRECT_PYTHON_INTERFACE__HXX__ + +#include + +namespace Py +{ +bool InitialisePythonIndirectInterface(); + +// +// Wrap Exception variables as function calls +// +PyObject * _Exc_Exception(); +PyObject * _Exc_StandardError(); +PyObject * _Exc_ArithmeticError(); +PyObject * _Exc_LookupError(); + +PyObject * _Exc_AssertionError(); +PyObject * _Exc_AttributeError(); +PyObject * _Exc_EOFError(); +PyObject * _Exc_FloatingPointError(); +PyObject * _Exc_EnvironmentError(); +PyObject * _Exc_IOError(); +PyObject * _Exc_OSError(); +PyObject * _Exc_ImportError(); +PyObject * _Exc_IndexError(); +PyObject * _Exc_KeyError(); +PyObject * _Exc_KeyboardInterrupt(); +PyObject * _Exc_MemoryError(); +PyObject * _Exc_NameError(); +PyObject * _Exc_OverflowError(); +PyObject * _Exc_RuntimeError(); +PyObject * _Exc_NotImplementedError(); +PyObject * _Exc_SyntaxError(); +PyObject * _Exc_SystemError(); +PyObject * _Exc_SystemExit(); +PyObject * _Exc_TypeError(); +PyObject * _Exc_ValueError(); +PyObject * _Exc_ZeroDivisionError(); +#ifdef MS_WINDOWS +PyObject * _Exc_WindowsError(); +#endif + +PyObject * _Exc_MemoryErrorInst(); + +#if PY_MAJOR_VERSION >= 2 +PyObject * _Exc_IndentationError(); +PyObject * _Exc_TabError(); +PyObject * _Exc_UnboundLocalError(); +PyObject * _Exc_UnicodeError(); +#endif + +// +// Wrap Object variables as function calls +// +PyObject * _None(); + + +// +// Wrap Type variables as function calls +// +PyTypeObject * _List_Type(); +bool _List_Check( PyObject *o ); + +PyTypeObject * _Buffer_Type(); +bool _Buffer_Check( PyObject *op ); + +PyTypeObject * _Class_Type(); +bool _Class_Check( PyObject *op ); + +PyTypeObject * _Instance_Type(); +bool _Instance_Check( PyObject *op ); + +PyTypeObject * _Method_Type(); +bool _Method_Check( PyObject *op ); + +PyTypeObject * _CObject_Type(); +bool _CObject_Check( PyObject *op ); + +PyTypeObject * _Complex_Type(); +bool _Complex_Check( PyObject *op ); + +PyTypeObject * _Dict_Type(); +bool _Dict_Check( PyObject *op ); + +PyTypeObject * _File_Type(); +bool _File_Check( PyObject *op ); + +PyTypeObject * _Float_Type(); +bool _Float_Check( PyObject *op ); + +PyTypeObject * _Frame_Type(); +bool _Frame_Check( PyObject *op ); + +PyTypeObject * _Function_Type(); +bool _Function_Check( PyObject *op ); + +PyTypeObject * _Int_Type(); +bool _Int_Check( PyObject *op ); + +PyTypeObject * _List_Type(); +bool _List_Check( PyObject *op ); + +PyTypeObject * _Long_Type(); +bool _Long_Check( PyObject *op ); + +PyTypeObject * _CFunction_Type(); +bool _CFunction_Check( PyObject *op ); + +PyTypeObject * _Module_Type(); +bool _Module_Check( PyObject *op ); + +PyTypeObject * _Type_Type(); +bool _Type_Check( PyObject *op ); + +PyTypeObject * _Range_Type(); +bool _Range_Check( PyObject *op ); + +PyTypeObject * _Slice_Type(); +bool _Slice_Check( PyObject *op ); + +PyTypeObject * _String_Type(); +bool _String_Check( PyObject *op ); + +PyTypeObject * _Unicode_Type(); +bool _Unicode_Check( PyObject *op ); + +PyTypeObject * _TraceBack_Type(); +bool _TraceBack_Check( PyObject *v ); + +PyTypeObject * _Tuple_Type(); +bool _Tuple_Check( PyObject *op ); + +#if PY_MAJOR_VERSION >= 2 +PyTypeObject * _Unicode_Type(); +bool _Unicode_Check( PyObject *op ); +#endif + +int &_Py_DebugFlag(); +int &_Py_InteractiveFlag(); +int &_Py_OptimizeFlag(); +int &_Py_NoSiteFlag(); +int &_Py_TabcheckFlag(); +int &_Py_VerboseFlag(); + +#if PY_MAJOR_VERSION >= 2 +int &_Py_UnicodeFlag(); +#endif + +void _XINCREF( PyObject *op ); +void _XDECREF( PyObject *op ); + +char *__Py_PackageContext(); +} + +#endif // __CXX_INDIRECT_PYTHON_INTERFACE__HXX__ diff --git a/lib/kross/python/cxx/Legal.html b/lib/kross/python/cxx/Legal.html new file mode 100755 index 000000000..cf6a530f0 --- /dev/null +++ b/lib/kross/python/cxx/Legal.html @@ -0,0 +1,40 @@ + + + +Legal Notice + + + + + +

Legal Notice

+ +

*** Legal Notice for all LLNL-contributed files ***

+ +

Copyright (c) 1996. The Regents of the University of California. All rights reserved.

+ +

Permission to use, copy, modify, and distribute this software for any purpose without +fee is hereby granted, provided that this entire notice is included in all copies of any +software which is or includes a copy or modification of this software and in all copies of +the supporting documentation for such software.

+ +

This work was produced at the University of California, Lawrence Livermore National +Laboratory under contract no. W-7405-ENG-48 between the U.S. Department of Energy and The +Regents of the University of California for the operation of UC LLNL.

+ +

DISCLAIMER

+ +

This software was prepared as an account of work sponsored by an agency of the United +States Government. Neither the United States Government nor the University of California +nor any of their employees, makes any warranty, express or implied, or assumes any +liability or responsibility for the accuracy, completeness, or usefulness of any +information, apparatus, product, or process disclosed, or represents that its use would +not infringe privately-owned rights. Reference herein to any specific commercial products, +process, or service by trade name, trademark, manufacturer, or otherwise, does not +necessarily constitute or imply its endorsement, recommendation, or favoring by the United +States Government or the University of California. The views and opinions of authors +expressed herein do not necessarily state or reflect those of the United States Government +or the University of California, and shall not be used for advertising or product +endorsement purposes.

+ + diff --git a/lib/kross/python/cxx/Makefile.am b/lib/kross/python/cxx/Makefile.am new file mode 100644 index 000000000..d1c72c873 --- /dev/null +++ b/lib/kross/python/cxx/Makefile.am @@ -0,0 +1,19 @@ +include $(top_srcdir)/lib/kross/Makefile.global + +noinst_LTLIBRARIES = libkrosspythoncxx.la + +libkrosspythoncxx_la_SOURCES = \ + cxxsupport.cxx \ + cxx_extensions.cxx \ + cxxextensions.c \ + IndirectPythonInterface.cxx + +libkrosspythoncxx_la_LDFLAGS = $(LIBPYTHON) $(all_libraries) -Wnounresolved + +METASOURCES = AUTO +INCLUDES = $(KROSS_INCLUDES) $(PYTHONINC) $(all_includes) +SUBDIRS = . + +clean: + @rm -f *.o 2> /dev/null + @rm -f $(BIN) 2> /dev/null diff --git a/lib/kross/python/cxx/Objects.hxx b/lib/kross/python/cxx/Objects.hxx new file mode 100644 index 000000000..416483206 --- /dev/null +++ b/lib/kross/python/cxx/Objects.hxx @@ -0,0 +1,2804 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 1998 The Regents of the University of California. +// All rights reserved. See LEGAL.LLNL for full text and disclaimer. +//---------------------------------------------------------------------------// + +#ifndef __CXX_Objects__h +#define __CXX_Objects__h + +// Prevent warnings +#if defined(_XOPEN_SOURCE) +#undef _XOPEN_SOURCE +#endif + +#include "Python.h" +#include "Config.hxx" +#include "Exception.hxx" + + +#include +#include STR_STREAM +#include +#include +#include +#include + +namespace Py + { + typedef int sequence_index_type; // type of an index into a sequence + + // Forward declarations + class Object; + class Type; + template class SeqBase; + class String; + class List; + template class MapBase; + + // new_reference_to also overloaded below on Object + inline PyObject* new_reference_to(PyObject* p) + { + Py::_XINCREF(p); + return p; + } + + // returning Null() from an extension method triggers a + // Python exception + inline PyObject* Null() + { + return (static_cast(0)); + } + + //===========================================================================// + // class Object + // The purpose of this class is to serve as the most general kind of + // Python object, for the purpose of writing C++ extensions in Python + // Objects hold a PyObject* which they own. This pointer is always a + // valid pointer to a Python object. In children we must maintain this behavior. + // + // Instructions on how to make your own class MyType descended from Object: + // (0) Pick a base class, either Object or perhaps SeqBase or MapBase. + // This example assumes Object. + + // (1) Write a routine int MyType_Check (PyObject *) modeled after PyInt_Check, + // PyFloat_Check, etc. + + // (2) Add method accepts: + // virtual bool accepts (PyObject *pyob) const { + // return pyob && MyType_Check (pyob); + // } + + // (3) Include the following constructor and copy constructor + // + /* + explicit MyType (PyObject *pyob): Object(pyob) { + validate(); + } + + MyType(const Object& other): Object(other.ptr()) { + validate(); + } + */ + + // Alernate version for the constructor to allow for construction from owned pointers: + /* + explicit MyType (PyObject *pyob): Object(pyob) { + validate(); + } + */ + + // You may wish to add other constructors; see the classes below for examples. + // Each constructor must use "set" to set the pointer + // and end by validating the pointer you have created. + + // (4) Each class needs at least these two assignment operators: + /* + MyType& operator= (const Object& rhs) { + return (*this = *rhs); + } + + Mytype& operator= (PyObject* rhsp) { + if(ptr() == rhsp) return *this; + set(rhsp); + return *this; + } + */ + // Note on accepts: constructors call the base class + // version of a virtual when calling the base class constructor, + // so the test has to be done explicitly in a descendent. + + // If you are inheriting from PythonExtension to define an object + // note that it contains PythonExtension::check + // which you can use in accepts when writing a wrapper class. + // See Demo/range.h and Demo/range.cxx for an example. + + class Object + { + private: + // the pointer to the Python object + // Only Object sets this directly. + // The default constructor for Object sets it to Py_None and + // child classes must use "set" to set it + // + PyObject* p; + + protected: + + void set (PyObject* pyob, bool owned = false) + { + release(); + p = pyob; + if (!owned) + { + Py::_XINCREF (p); + } + validate(); + } + + void release () + { + Py::_XDECREF (p); + p = 0; + } + + void validate() + { + // release pointer if not the right type + if (! accepts (p)) + { + release (); + if(PyErr_Occurred()) + { // Error message already set + throw Exception(); + } + // Better error message if RTTI available +#if defined( _CPPRTTI ) + std::string s("Error creating object of type "); + s += (typeid (*this)).name(); + throw TypeError (s); +#else + throw TypeError ("CXX: type error."); +#endif + } + } + + public: + // Constructor acquires new ownership of pointer unless explicitly told not to. + explicit Object (PyObject* pyob=Py::_None(), bool owned = false): p (pyob) + { + if(!owned) + { + Py::_XINCREF (p); + } + validate(); + } + + // Copy constructor acquires new ownership of pointer + Object (const Object& ob): p(ob.p) + { + Py::_XINCREF (p); + validate(); + } + + // Assignment acquires new ownership of pointer + Object& operator= (const Object& rhs) + { + set(rhs.p); + return *this; + } + + Object& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + + // Destructor + virtual ~Object () + { + release (); + } + + // Loaning the pointer to others, retain ownership + PyObject* operator* () const + { + return p; + } + + // Explicit reference_counting changes + void increment_reference_count() + { + Py::_XINCREF(p); + } + + void decrement_reference_count() + { + // not allowed to commit suicide, however + if(reference_count() == 1) + throw RuntimeError("Object::decrement_reference_count error."); + Py::_XDECREF(p); + } + // Would like to call this pointer() but messes up STL in SeqBase + PyObject* ptr () const + { + return p; + } + + // + // Queries + // + + // Can pyob be used in this object's constructor? + virtual bool accepts (PyObject *pyob) const + { + return (pyob != 0); + } + + int reference_count () const + { // the reference count + return p ? p->ob_refcnt : 0; + } + + Type type () const; // the type object associated with this one + + String str () const; // the str() representation + + std::string as_string() const; + + String repr () const; // the repr () representation + + List dir () const; // the dir() list + + bool hasAttr (const std::string& s) const + { + return PyObject_HasAttrString (p, const_cast(s.c_str())) ? true: false; + } + + Object getAttr (const std::string& s) const + { + return Object (PyObject_GetAttrString (p, const_cast(s.c_str())), true); + } + + Object getItem (const Object& key) const + { + return Object (PyObject_GetItem(p, *key), true); + } + + long hashValue () const + { + return PyObject_Hash (p); + } + + // + // int print (FILE* fp, int flags=Py_Print_RAW) + // { + // return PyObject_Print (p, fp, flags); + // } + // + bool is(PyObject *pother) const + { // identity test + return p == pother; + } + + bool is(const Object& other) const + { // identity test + return p == other.p; + } + + bool isCallable () const + { + return PyCallable_Check (p) != 0; + } + + bool isInstance () const + { + return PyInstance_Check (p) != 0; + } + + bool isDict () const + { + return Py::_Dict_Check (p); + } + + bool isList () const + { + return Py::_List_Check (p); + } + + bool isMapping () const + { + return PyMapping_Check (p) != 0; + } + + bool isNumeric () const + { + return PyNumber_Check (p) != 0; + } + + bool isSequence () const + { + return PySequence_Check (p) != 0; + } + + bool isTrue () const + { + return PyObject_IsTrue (p) != 0; + } + + bool isType (const Type& t) const; + + bool isTuple() const + { + return Py::_Tuple_Check(p); + } + + bool isString() const + { + return Py::_String_Check(p) || Py::_Unicode_Check(p); + } + + bool isUnicode() const + { + return Py::_Unicode_Check(p); + } + + // Commands + void setAttr (const std::string& s, const Object& value) + { + if(PyObject_SetAttrString (p, const_cast(s.c_str()), *value) == -1) + throw AttributeError ("getAttr failed."); + } + + void delAttr (const std::string& s) + { + if(PyObject_DelAttrString (p, const_cast(s.c_str())) == -1) + throw AttributeError ("delAttr failed."); + } + + // PyObject_SetItem is too weird to be using from C++ + // so it is intentionally omitted. + + void delItem (const Object& /*key*/) + { + //if(PyObject_DelItem(p, *key) == -1) + // failed to link on Windows? + throw KeyError("delItem failed."); + } + // Equality and comparison use PyObject_Compare + + bool operator==(const Object& o2) const + { + int k = PyObject_Compare (p, *o2); + if (PyErr_Occurred()) throw Exception(); + return k == 0; + } + + bool operator!=(const Object& o2) const + { + int k = PyObject_Compare (p, *o2); + if (PyErr_Occurred()) throw Exception(); + return k != 0; + + } + + bool operator>=(const Object& o2) const + { + int k = PyObject_Compare (p, *o2); + if (PyErr_Occurred()) throw Exception(); + return k >= 0; + } + + bool operator<=(const Object& o2) const + { + int k = PyObject_Compare (p, *o2); + if (PyErr_Occurred()) throw Exception(); + return k <= 0; + } + + bool operator<(const Object& o2) const + { + int k = PyObject_Compare (p, *o2); + if (PyErr_Occurred()) throw Exception(); + return k < 0; + } + + bool operator>(const Object& o2) const + { + int k = PyObject_Compare (p, *o2); + if (PyErr_Occurred()) throw Exception(); + return k > 0; + } + }; + // End of class Object + inline PyObject* new_reference_to(const Object& g) + { + PyObject* p = g.ptr(); + Py::_XINCREF(p); + return p; + } + + // Nothing() is what an extension method returns if + // there is no other return value. + inline Object Nothing() + { + return Object(Py::_None()); + } + + // Python special None value + inline Object None() + { + return Object(Py::_None()); + } + + // TMM: 31May'01 - Added the #ifndef so I can exlude iostreams. +#ifndef CXX_NO_IOSTREAMS + std::ostream& operator<< (std::ostream& os, const Object& ob); +#endif + + // Class Type + class Type: public Object + { + public: + explicit Type (PyObject* pyob, bool owned = false): Object(pyob, owned) + { + validate(); + } + + Type (const Object& ob): Object(*ob) + { + validate(); + } + + Type(const Type& t): Object(t) + { + validate(); + } + + Type& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Type& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + virtual bool accepts (PyObject *pyob) const + { + return pyob && Py::_Type_Check (pyob); + } + }; + + + // + // Convert an owned Python pointer into a CXX Object + // + inline Object asObject (PyObject *p) + { + return Object(p, true); + } + + + + + // =============================================== + // class Int + class Int: public Object + { + public: + // Constructor + explicit Int (PyObject *pyob, bool owned = false): Object (pyob, owned) + { + validate(); + } + + Int (const Int& ob): Object(*ob) + { + validate(); + } + + // create from long + explicit Int (long v = 0L): Object(PyInt_FromLong(v), true) + { + validate(); + } + + // create from int + explicit Int (int v) + { + long w = v; + set(PyInt_FromLong(w), true); + validate(); + } + + Int (const Object& ob) + { + set(PyNumber_Int(*ob), true); + validate(); + } + + // Assignment acquires new ownership of pointer + + Int& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Int& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (PyNumber_Int(rhsp), true); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && Py::_Int_Check (pyob); + } + // convert to long + operator long() const + { + return PyInt_AsLong (ptr()); + } + // assign from an int + Int& operator= (int v) + { + set (PyInt_FromLong (long(v)), true); + return *this; + } + // assign from long + Int& operator= (long v) + { + set (PyInt_FromLong (v), true); + return *this; + } + }; + + // =============================================== + // class Long + class Long: public Object + { + public: + // Constructor + explicit Long (PyObject *pyob, bool owned = false): Object (pyob, owned) + { + validate(); + } + + Long (const Long& ob): Object(ob.ptr()) + { + validate(); + } + + // create from long + explicit Long (long v = 0L) + : Object(PyLong_FromLong(v), true) + { + validate(); + } + // create from int + explicit Long (int v) + : Object(PyLong_FromLong(static_cast(v)), true) + { + validate(); + } + + // create from unsigned long + explicit Long (unsigned long v) + : Object(PyLong_FromUnsignedLong(v), true) + { + validate(); + } + + // try to create from any object + Long (const Object& ob) + : Object(PyNumber_Long(*ob), true) + { + validate(); + } + + // Assignment acquires new ownership of pointer + + Long& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Long& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (PyNumber_Long(rhsp), true); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && Py::_Long_Check (pyob); + } + // convert to long + operator long() const + { + return PyLong_AsLong (ptr()); + } + operator double() const + { + return PyLong_AsDouble (ptr()); + } + operator unsigned long() const + { + return PyLong_AsUnsignedLong (ptr()); + } + // assign from an int + Long& operator= (int v) + { + set(PyLong_FromLong (long(v)), true); + return *this; + } + // assign from long + Long& operator= (long v) + { + set(PyLong_FromLong (v), true); + return *this; + } + // assign from unsigned long + Long& operator= (unsigned long v) + { + set(PyLong_FromUnsignedLong (v), true); + return *this; + } + }; + + // =============================================== + // class Float + // + class Float: public Object + { + public: + // Constructor + explicit Float (PyObject *pyob, bool owned = false): Object(pyob, owned) + { + validate(); + } + + Float (const Float& f): Object(f) + { + validate(); + } + + // make from double + explicit Float (double v=0.0) + : Object(PyFloat_FromDouble (v), true) + { + validate(); + } + + // try to make from any object + Float (const Object& ob) + : Object(PyNumber_Float(*ob), true) + { + validate(); + } + + Float& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Float& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (PyNumber_Float(rhsp), true); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && Py::_Float_Check (pyob); + } + // convert to double + operator double () const + { + return PyFloat_AsDouble (ptr()); + } + // assign from a double + Float& operator= (double v) + { + set(PyFloat_FromDouble (v), true); + return *this; + } + // assign from an int + Float& operator= (int v) + { + set(PyFloat_FromDouble (double(v)), true); + return *this; + } + // assign from long + Float& operator= (long v) + { + set(PyFloat_FromDouble (double(v)), true); + return *this; + } + // assign from an Int + Float& operator= (const Int& iob) + { + set(PyFloat_FromDouble (double(long(iob))), true); + return *this; + } + }; + + // =============================================== + // class Complex + class Complex: public Object + { + public: + // Constructor + explicit Complex (PyObject *pyob, bool owned = false): Object(pyob, owned) + { + validate(); + } + + Complex (const Complex& f): Object(f) + { + validate(); + } + + // make from double + explicit Complex (double v=0.0, double w=0.0) + :Object(PyComplex_FromDoubles (v, w), true) + { + validate(); + } + + Complex& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Complex& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && Py::_Complex_Check (pyob); + } + // convert to Py_complex + operator Py_complex () const + { + return PyComplex_AsCComplex (ptr()); + } + // assign from a Py_complex + Complex& operator= (const Py_complex& v) + { + set(PyComplex_FromCComplex (v), true); + return *this; + } + // assign from a double + Complex& operator= (double v) + { + set(PyComplex_FromDoubles (v, 0.0), true); + return *this; + } + // assign from an int + Complex& operator= (int v) + { + set(PyComplex_FromDoubles (double(v), 0.0), true); + return *this; + } + // assign from long + Complex& operator= (long v) + { + set(PyComplex_FromDoubles (double(v), 0.0), true); + return *this; + } + // assign from an Int + Complex& operator= (const Int& iob) + { + set(PyComplex_FromDoubles (double(long(iob)), 0.0), true); + return *this; + } + + double real() const + { + return PyComplex_RealAsDouble(ptr()); + } + + double imag() const + { + return PyComplex_ImagAsDouble(ptr()); + } + }; + // Sequences + // Sequences are here represented as sequences of items of type T. + // The base class SeqBase represents that. + // In basic Python T is always "Object". + + // seqref is what you get if you get elements from a non-const SeqBase. + // Note: seqref could probably be a nested class in SeqBase but that might stress + // some compilers needlessly. Simlarly for mapref later. + + // While this class is not intended for enduser use, it needs some public + // constructors for the benefit of the STL. + + // See Scott Meyer's More Essential C++ for a description of proxies. + // This application is even more complicated. We are doing an unusual thing + // in having a double proxy. If we want the STL to work + // properly we have to compromise by storing the rvalue inside. The + // entire Object API is repeated so that things like s[i].isList() will + // work properly. + + // Still, once in a while a weird compiler message may occur using expressions like x[i] + // Changing them to Object(x[i]) helps the compiler to understand that the + // conversion of a seqref to an Object is wanted. + + template + class seqref + { + protected: + SeqBase& s; // the sequence + int offset; // item number + T the_item; // lvalue + public: + + seqref (SeqBase& seq, sequence_index_type j) + : s(seq), offset(j), the_item (s.getItem(j)) + {} + + seqref (const seqref& range) + : s(range.s), offset(range.offset), the_item(range.the_item) + {} + + // TMM: added this seqref ctor for use with STL algorithms + seqref (Object& obj) + : s(dynamic_cast< SeqBase&>(obj)) + , offset( NULL ) + , the_item(s.getItem(offset)) + {} + ~seqref() + {} + + operator T() const + { // rvalue + return the_item; + } + + seqref& operator=(const seqref& rhs) + { //used as lvalue + the_item = rhs.the_item; + s.setItem(offset, the_item); + return *this; + } + + seqref& operator=(const T& ob) + { // used as lvalue + the_item = ob; + s.setItem(offset, ob); + return *this; + } + + // forward everything else to the item + PyObject* ptr () const + { + return the_item.ptr(); + } + + int reference_count () const + { // the reference count + return the_item.reference_count(); + } + + Type type () const + { + return the_item.type(); + } + + String str () const; + + String repr () const; + + bool hasAttr (const std::string& attr_name) const + { + return the_item.hasAttr(attr_name); + } + + Object getAttr (const std::string& attr_name) const + { + return the_item.getAttr(attr_name); + } + + Object getItem (const Object& key) const + { + return the_item.getItem(key); + } + + long hashValue () const + { + return the_item.hashValue(); + } + + bool isCallable () const + { + return the_item.isCallable(); + } + + bool isInstance () const + { + return the_item.isInstance(); + } + + bool isDict () const + { + return the_item.isDict(); + } + + bool isList () const + { + return the_item.isList(); + } + + bool isMapping () const + { + return the_item.isMapping(); + } + + bool isNumeric () const + { + return the_item.isNumeric(); + } + + bool isSequence () const + { + return the_item.isSequence(); + } + + bool isTrue () const + { + return the_item.isTrue(); + } + + bool isType (const Type& t) const + { + return the_item.isType (t); + } + + bool isTuple() const + { + return the_item.isTuple(); + } + + bool isString() const + { + return the_item.isString(); + } + // Commands + void setAttr (const std::string& attr_name, const Object& value) + { + the_item.setAttr(attr_name, value); + } + + void delAttr (const std::string& attr_name) + { + the_item.delAttr(attr_name); + } + + void delItem (const Object& key) + { + the_item.delItem(key); + } + + bool operator==(const Object& o2) const + { + return the_item == o2; + } + + bool operator!=(const Object& o2) const + { + return the_item != o2; + } + + bool operator>=(const Object& o2) const + { + return the_item >= o2; + } + + bool operator<=(const Object& o2) const + { + return the_item <= o2; + } + + bool operator<(const Object& o2) const + { + return the_item < o2; + } + + bool operator>(const Object& o2) const + { + return the_item > o2; + } + }; // end of seqref + + + // class SeqBase + // ...the base class for all sequence types + + template + class SeqBase: public Object + { + public: + // STL definitions + typedef size_t size_type; + typedef seqref reference; + typedef T const_reference; + typedef seqref* pointer; + typedef int difference_type; + typedef T value_type; // TMM: 26Jun'01 + + virtual size_type max_size() const + { + return std::string::npos; // ? + } + + virtual size_type capacity() const + { + return size(); + } + + virtual void swap(SeqBase& c) + { + SeqBase temp = c; + c = ptr(); + set(temp.ptr()); + } + + virtual size_type size () const + { + return PySequence_Length (ptr()); + } + + explicit SeqBase () + :Object(PyTuple_New(0), true) + { + validate(); + } + + explicit SeqBase (PyObject* pyob, bool owned=false) + : Object(pyob, owned) + { + validate(); + } + + SeqBase (const Object& ob): Object(ob) + { + validate(); + } + + // Assignment acquires new ownership of pointer + + SeqBase& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + SeqBase& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + + virtual bool accepts (PyObject *pyob) const + { + return pyob && PySequence_Check (pyob); + } + + size_type length () const + { + return PySequence_Length (ptr()); + } + + // Element access + const T operator[](sequence_index_type index) const + { + return getItem(index); + } + + seqref operator[](sequence_index_type index) + { + return seqref(*this, index); + } + + virtual T getItem (sequence_index_type i) const + { + return T(asObject(PySequence_GetItem (ptr(), i))); + } + + virtual void setItem (sequence_index_type i, const T& ob) + { + if (PySequence_SetItem (ptr(), i, *ob) == -1) + { + throw Exception(); + } + } + + SeqBase repeat (int count) const + { + return SeqBase (PySequence_Repeat (ptr(), count), true); + } + + SeqBase concat (const SeqBase& other) const + { + return SeqBase (PySequence_Concat(ptr(), *other), true); + } + + // more STL compatability + const T front () const + { + return getItem(0); + } + + seqref front() + { + return seqref(this, 0); + } + + const T back () const + { + return getItem(size()-1); + } + + seqref back() + { + return seqref(this, size()-1); + } + + void verify_length(size_type required_size) const + { + if (size() != required_size) + throw IndexError ("Unexpected SeqBase length."); + } + + void verify_length(size_type min_size, size_type max_size) const + { + size_type n = size(); + if (n < min_size || n > max_size) + throw IndexError ("Unexpected SeqBase length."); + } + + class iterator + : public random_access_iterator_parent(seqref) + { + protected: + friend class SeqBase; + SeqBase* seq; + int count; + + public: + ~iterator () + {} + + iterator () + : seq( 0 ) + , count( 0 ) + {} + + iterator (SeqBase* s, int where) + : seq( s ) + , count( where ) + {} + + iterator (const iterator& other) + : seq( other.seq ) + , count( other.count ) + {} + + bool eql (const iterator& other) const + { + return (*seq == *other.seq) && (count == other.count); + } + + bool neq (const iterator& other) const + { + return (*seq != *other.seq) || (count != other.count); + } + + bool lss (const iterator& other) const + { + return (count < other.count); + } + + bool gtr (const iterator& other) const + { + return (count > other.count); + } + + bool leq (const iterator& other) const + { + return (count <= other.count); + } + + bool geq (const iterator& other) const + { + return (count >= other.count); + } + + seqref operator*() + { + return seqref(*seq, count); + } + + seqref operator[] (sequence_index_type i) + { + return seqref(*seq, count + i); + } + + iterator& operator=(const iterator& other) + { + if (this == &other) return *this; + seq = other.seq; + count = other.count; + return *this; + } + + iterator operator+(int n) const + { + return iterator(seq, count + n); + } + + iterator operator-(int n) const + { + return iterator(seq, count - n); + } + + iterator& operator+=(int n) + { + count = count + n; + return *this; + } + + iterator& operator-=(int n) + { + count = count - n; + return *this; + } + + int operator-(const iterator& other) const + { + if (*seq != *other.seq) + throw RuntimeError ("SeqBase::iterator comparison error"); + return count - other.count; + } + + // prefix ++ + iterator& operator++ () + { count++; return *this;} + // postfix ++ + iterator operator++ (int) + { return iterator(seq, count++);} + // prefix -- + iterator& operator-- () + { count--; return *this;} + // postfix -- + iterator operator-- (int) + { return iterator(seq, count--);} + + std::string diagnose() const + { + std::OSTRSTREAM oss; + oss << "iterator diagnosis " << seq << ", " << count << std::ends; + return std::string(oss.str()); + } + }; // end of class SeqBase::iterator + + iterator begin () + { + return iterator(this, 0); + } + + iterator end () + { + return iterator(this, length()); + } + + class const_iterator + : public random_access_iterator_parent(const Object) + { + protected: + friend class SeqBase; + const SeqBase* seq; + sequence_index_type count; + + public: + ~const_iterator () + {} + + const_iterator () + : seq( 0 ) + , count( 0 ) + {} + + const_iterator (const SeqBase* s, int where) + : seq( s ) + , count( where ) + {} + + const_iterator(const const_iterator& other) + : seq( other.seq ) + , count( other.count ) + {} + + const T operator*() const + { + return seq->getItem(count); + } + + const T operator[] (sequence_index_type i) const + { + return seq->getItem(count + i); + } + + const_iterator& operator=(const const_iterator& other) + { + if (this == &other) return *this; + seq = other.seq; + count = other.count; + return *this; + } + + const_iterator operator+(int n) const + { + return const_iterator(seq, count + n); + } + + bool eql (const const_iterator& other) const + { + return (*seq == *other.seq) && (count == other.count); + } + + bool neq (const const_iterator& other) const + { + return (*seq != *other.seq) || (count != other.count); + } + + bool lss (const const_iterator& other) const + { + return (count < other.count); + } + + bool gtr (const const_iterator& other) const + { + return (count > other.count); + } + + bool leq (const const_iterator& other) const + { + return (count <= other.count); + } + + bool geq (const const_iterator& other) const + { + return (count >= other.count); + } + + const_iterator operator-(int n) + { + return const_iterator(seq, count - n); + } + + const_iterator& operator+=(int n) + { + count = count + n; + return *this; + } + + const_iterator& operator-=(int n) + { + count = count - n; + return *this; + } + + int operator-(const const_iterator& other) const + { + if (*seq != *other.seq) + throw RuntimeError ("SeqBase::const_iterator::- error"); + return count - other.count; + } + // prefix ++ + const_iterator& operator++ () + { count++; return *this;} + // postfix ++ + const_iterator operator++ (int) + { return const_iterator(seq, count++);} + // prefix -- + const_iterator& operator-- () + { count--; return *this;} + // postfix -- + const_iterator operator-- (int) + { return const_iterator(seq, count--);} + }; // end of class SeqBase::const_iterator + + const_iterator begin () const + { + return const_iterator(this, 0); + } + + const_iterator end () const + { + return const_iterator(this, length()); + } + }; + + // Here's an important typedef you might miss if reading too fast... + typedef SeqBase Sequence; + + template bool operator==(const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); + template bool operator!=(const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); + template bool operator< (const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); + template bool operator> (const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); + template bool operator<=(const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); + template bool operator>=(const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); + + template bool operator==(const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); + template bool operator!=(const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); + template bool operator< (const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); + template bool operator> (const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); + template bool operator<=(const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); + template bool operator>=(const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); + + + extern bool operator==(const Sequence::iterator& left, const Sequence::iterator& right); + extern bool operator!=(const Sequence::iterator& left, const Sequence::iterator& right); + extern bool operator< (const Sequence::iterator& left, const Sequence::iterator& right); + extern bool operator> (const Sequence::iterator& left, const Sequence::iterator& right); + extern bool operator<=(const Sequence::iterator& left, const Sequence::iterator& right); + extern bool operator>=(const Sequence::iterator& left, const Sequence::iterator& right); + + extern bool operator==(const Sequence::const_iterator& left, const Sequence::const_iterator& right); + extern bool operator!=(const Sequence::const_iterator& left, const Sequence::const_iterator& right); + extern bool operator< (const Sequence::const_iterator& left, const Sequence::const_iterator& right); + extern bool operator> (const Sequence::const_iterator& left, const Sequence::const_iterator& right); + extern bool operator<=(const Sequence::const_iterator& left, const Sequence::const_iterator& right); + extern bool operator>=(const Sequence::const_iterator& left, const Sequence::const_iterator& right); + + // ================================================== + // class Char + // Python strings return strings as individual elements. + // I'll try having a class Char which is a String of length 1 + // + typedef std::basic_string unicodestring; + extern Py_UNICODE unicode_null_string[1]; + + class Char: public Object + { + public: + explicit Char (PyObject *pyob, bool owned = false): Object(pyob, owned) + { + validate(); + } + + Char (const Object& ob): Object(ob) + { + validate(); + } + + Char (const std::string& v = "") + :Object(PyString_FromStringAndSize (const_cast(v.c_str()),1), true) + { + validate(); + } + + Char (char v) + : Object(PyString_FromStringAndSize (&v, 1), true) + { + validate(); + } + + Char (Py_UNICODE v) + : Object(PyUnicode_FromUnicode (&v, 1), true) + { + validate(); + } + // Assignment acquires new ownership of pointer + Char& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Char& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && (Py::_String_Check(pyob) || Py::_Unicode_Check(pyob)) && PySequence_Length (pyob) == 1; + } + + // Assignment from C string + Char& operator= (const std::string& v) + { + set(PyString_FromStringAndSize (const_cast(v.c_str()),1), true); + return *this; + } + + Char& operator= (char v) + { + set(PyString_FromStringAndSize (&v, 1), true); + return *this; + } + + Char& operator= (const unicodestring& v) + { + set(PyUnicode_FromUnicode (const_cast(v.data()),1), true); + return *this; + } + + Char& operator= (Py_UNICODE v) + { + set(PyUnicode_FromUnicode (&v, 1), true); + return *this; + } + + // Conversion + operator String() const; + + operator std::string () const + { + return std::string(PyString_AsString (ptr())); + } + }; + + class String: public SeqBase + { + public: + virtual size_type capacity() const + { + return max_size(); + } + + explicit String (PyObject *pyob, bool owned = false): SeqBase(pyob, owned) + { + validate(); + } + + String (const Object& ob): SeqBase(ob) + { + validate(); + } + + String() + : SeqBase( PyString_FromStringAndSize( "", 0 ), true ) + { + validate(); + } + + String( const std::string& v ) + : SeqBase( PyString_FromStringAndSize( const_cast(v.data()), + static_cast( v.length() ) ), true ) + { + validate(); + } + + String( const char *s, const char *encoding, const char *error="strict" ) + : SeqBase( PyUnicode_Decode( s, strlen( s ), encoding, error ), true ) + { + validate(); + } + + String( const char *s, int len, const char *encoding, const char *error="strict" ) + : SeqBase( PyUnicode_Decode( s, len, encoding, error ), true ) + { + validate(); + } + + String( const std::string &s, const char *encoding, const char *error="strict" ) + : SeqBase( PyUnicode_Decode( s.c_str(), s.length(), encoding, error ), true ) + { + validate(); + } + + String( const std::string& v, std::string::size_type vsize ) + : SeqBase(PyString_FromStringAndSize( const_cast(v.data()), + static_cast( vsize ) ), true) + { + validate(); + } + + String( const char *v, int vsize ) + : SeqBase(PyString_FromStringAndSize( const_cast(v), vsize ), true ) + { + validate(); + } + + String( const char* v ) + : SeqBase( PyString_FromString( v ), true ) + { + validate(); + } + + // Assignment acquires new ownership of pointer + String& operator= ( const Object& rhs ) + { + return *this = *rhs; + } + + String& operator= (PyObject* rhsp) + { + if( ptr() == rhsp ) + return *this; + set (rhsp); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && (Py::_String_Check(pyob) || Py::_Unicode_Check(pyob)); + } + + // Assignment from C string + String& operator= (const std::string& v) + { + set( PyString_FromStringAndSize( const_cast( v.data() ), + static_cast( v.length() ) ), true ); + return *this; + } + String& operator= (const unicodestring& v) + { + set( PyUnicode_FromUnicode( const_cast( v.data() ), + static_cast( v.length() ) ), true ); + return *this; + } + + + // Encode + String encode( const char *encoding, const char *error="strict" ) + { + if( isUnicode() ) + { + return String( PyUnicode_AsEncodedString( ptr(), encoding, error ) ); + } + else + { + return String( PyString_AsEncodedObject( ptr(), encoding, error ) ); + } + } + + String decode( const char *encoding, const char *error="strict" ) + { + return Object( PyString_AsDecodedObject( ptr(), encoding, error ) ); + } + + // Queries + virtual size_type size () const + { + if( isUnicode() ) + { + return static_cast( PyUnicode_GET_SIZE (ptr()) ); + } + else + { + return static_cast( PyString_Size (ptr()) ); + } + } + + operator std::string () const + { + return as_std_string(); + } + + std::string as_std_string() const + { + if( isUnicode() ) + { + throw TypeError("cannot return std::string from Unicode object"); + } + else + { + return std::string( PyString_AsString( ptr() ), static_cast( PyString_Size( ptr() ) ) ); + } + } + + unicodestring as_unicodestring() const + { + if( isUnicode() ) + { + return unicodestring( PyUnicode_AS_UNICODE( ptr() ), + static_cast( PyUnicode_GET_SIZE( ptr() ) ) ); + } + else + { + throw TypeError("can only return unicodestring from Unicode object"); + } + } + }; + + // ================================================== + // class Tuple + class Tuple: public Sequence + { + public: + virtual void setItem (sequence_index_type offset, const Object&ob) + { + // note PyTuple_SetItem is a thief... + if(PyTuple_SetItem (ptr(), offset, new_reference_to(ob)) == -1) + { + throw Exception(); + } + } + + // Constructor + explicit Tuple (PyObject *pyob, bool owned = false): Sequence (pyob, owned) + { + validate(); + } + + Tuple (const Object& ob): Sequence(ob) + { + validate(); + } + + // New tuple of a given size + explicit Tuple (int size = 0) + { + set(PyTuple_New (size), true); + validate (); + for (sequence_index_type i=0; i < size; i++) + { + if(PyTuple_SetItem (ptr(), i, new_reference_to(Py::_None())) == -1) + { + throw Exception(); + } + } + } + // Tuple from any sequence + explicit Tuple (const Sequence& s) + { + sequence_index_type limit( sequence_index_type( s.length() ) ); + + set(PyTuple_New (limit), true); + validate(); + + for(sequence_index_type i=0; i < limit; i++) + { + if(PyTuple_SetItem (ptr(), i, new_reference_to(s[i])) == -1) + { + throw Exception(); + } + } + } + // Assignment acquires new ownership of pointer + + Tuple& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Tuple& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && Py::_Tuple_Check (pyob); + } + + Tuple getSlice (int i, int j) const + { + return Tuple (PySequence_GetSlice (ptr(), i, j), true); + } + + }; + + // ================================================== + // class List + + class List: public Sequence + { + public: + // Constructor + explicit List (PyObject *pyob, bool owned = false): Sequence(pyob, owned) + { + validate(); + } + List (const Object& ob): Sequence(ob) + { + validate(); + } + // Creation at a fixed size + List (int size = 0) + { + set(PyList_New (size), true); + validate(); + for (sequence_index_type i=0; i < size; i++) + { + if(PyList_SetItem (ptr(), i, new_reference_to(Py::_None())) == -1) + { + throw Exception(); + } + } + } + + // List from a sequence + List (const Sequence& s): Sequence() + { + int n = s.length(); + set(PyList_New (n), true); + validate(); + for (sequence_index_type i=0; i < n; i++) + { + if(PyList_SetItem (ptr(), i, new_reference_to(s[i])) == -1) + { + throw Exception(); + } + } + } + + virtual size_type capacity() const + { + return max_size(); + } + // Assignment acquires new ownership of pointer + + List& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + List& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && Py::_List_Check (pyob); + } + + List getSlice (int i, int j) const + { + return List (PyList_GetSlice (ptr(), i, j), true); + } + + void setSlice (int i, int j, const Object& v) + { + if(PyList_SetSlice (ptr(), i, j, *v) == -1) + { + throw Exception(); + } + } + + void append (const Object& ob) + { + if(PyList_Append (ptr(), *ob) == -1) + { + throw Exception(); + } + } + + void insert (int i, const Object& ob) + { + if(PyList_Insert (ptr(), i, *ob) == -1) + { + throw Exception(); + } + } + + void sort () + { + if(PyList_Sort(ptr()) == -1) + { + throw Exception(); + } + } + + void reverse () + { + if(PyList_Reverse(ptr()) == -1) + { + throw Exception(); + } + } + }; + + + // Mappings + // ================================================== + template + class mapref + { + protected: + MapBase& s; // the map + Object key; // item key + T the_item; + + public: + mapref (MapBase& map, const std::string& k) + : s(map), the_item() + { + key = String(k); + if(map.hasKey(key)) the_item = map.getItem(key); + }; + + mapref (MapBase& map, const Object& k) + : s(map), key(k), the_item() + { + if(map.hasKey(key)) the_item = map.getItem(key); + }; + + ~mapref() + {} + + // MapBase stuff + // lvalue + mapref& operator=(const mapref& other) + { + if(this == &other) return *this; + the_item = other.the_item; + s.setItem(key, other.the_item); + return *this; + }; + + mapref& operator= (const T& ob) + { + the_item = ob; + s.setItem (key, ob); + return *this; + } + + // rvalue + operator T() const + { + return the_item; + } + + // forward everything else to the_item + PyObject* ptr () const + { + return the_item.ptr(); + } + + int reference_count () const + { // the mapref count + return the_item.reference_count(); + } + + Type type () const + { + return the_item.type(); + } + + String str () const + { + return the_item.str(); + } + + String repr () const + { + return the_item.repr(); + } + + bool hasAttr (const std::string& attr_name) const + { + return the_item.hasAttr(attr_name); + } + + Object getAttr (const std::string& attr_name) const + { + return the_item.getAttr(attr_name); + } + + Object getItem (const Object& k) const + { + return the_item.getItem(k); + } + + long hashValue () const + { + return the_item.hashValue(); + } + + bool isCallable () const + { + return the_item.isCallable(); + } + + bool isList () const + { + return the_item.isList(); + } + + bool isMapping () const + { + return the_item.isMapping(); + } + + bool isNumeric () const + { + return the_item.isNumeric(); + } + + bool isSequence () const + { + return the_item.isSequence(); + } + + bool isTrue () const + { + return the_item.isTrue(); + } + + bool isType (const Type& t) const + { + return the_item.isType (t); + } + + bool isTuple() const + { + return the_item.isTuple(); + } + + bool isString() const + { + return the_item.isString(); + } + + // Commands + void setAttr (const std::string& attr_name, const Object& value) + { + the_item.setAttr(attr_name, value); + } + + void delAttr (const std::string& attr_name) + { + the_item.delAttr(attr_name); + } + + void delItem (const Object& k) + { + the_item.delItem(k); + } + }; // end of mapref + + // TMM: now for mapref + template< class T > + bool operator==(const mapref& left, const mapref& right) + { + return true; // NOT completed. + } + + template< class T > + bool operator!=(const mapref& left, const mapref& right) + { + return true; // not completed. + } + + template + class MapBase: public Object + { + protected: + explicit MapBase() + {} + public: + // reference: proxy class for implementing [] + // TMM: 26Jun'01 - the types + // If you assume that Python mapping is a hash_map... + // hash_map::value_type is not assignable, but + // (*it).second = data must be a valid expression + typedef size_t size_type; + typedef Object key_type; + typedef mapref data_type; + typedef std::pair< const T, T > value_type; + typedef std::pair< const T, mapref > reference; + typedef const std::pair< const T, const T > const_reference; + typedef std::pair< const T, mapref > pointer; + + // Constructor + explicit MapBase (PyObject *pyob, bool owned = false): Object(pyob, owned) + { + validate(); + } + + // TMM: 02Jul'01 - changed MapBase to Object in next line + MapBase (const Object& ob): Object(ob) + { + validate(); + } + + // Assignment acquires new ownership of pointer + MapBase& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + MapBase& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && PyMapping_Check(pyob); + } + + // Clear -- PyMapping Clear is missing + // + + void clear () + { + List k = keys(); + for(List::iterator i = k.begin(); i != k.end(); i++) + { + delItem(*i); + } + } + + virtual size_type size() const + { + return PyMapping_Length (ptr()); + } + + // Element Access + T operator[](const std::string& key) const + { + return getItem(key); + } + + T operator[](const Object& key) const + { + return getItem(key); + } + + mapref operator[](const std::string& key) + { + return mapref(*this, key); + } + + mapref operator[](const Object& key) + { + return mapref(*this, key); + } + + int length () const + { + return PyMapping_Length (ptr()); + } + + bool hasKey (const std::string& s) const + { + return PyMapping_HasKeyString (ptr(),const_cast(s.c_str())) != 0; + } + + bool hasKey (const Object& s) const + { + return PyMapping_HasKey (ptr(), s.ptr()) != 0; + } + + T getItem (const std::string& s) const + { + return T( + asObject(PyMapping_GetItemString (ptr(),const_cast(s.c_str()))) + ); + } + + T getItem (const Object& s) const + { + return T( + asObject(PyObject_GetItem (ptr(), s.ptr())) + ); + } + + virtual void setItem (const char *s, const Object& ob) + { + if (PyMapping_SetItemString (ptr(), const_cast(s), *ob) == -1) + { + throw Exception(); + } + } + + virtual void setItem (const std::string& s, const Object& ob) + { + if (PyMapping_SetItemString (ptr(), const_cast(s.c_str()), *ob) == -1) + { + throw Exception(); + } + } + + virtual void setItem (const Object& s, const Object& ob) + { + if (PyObject_SetItem (ptr(), s.ptr(), ob.ptr()) == -1) + { + throw Exception(); + } + } + + void delItem (const std::string& s) + { + if (PyMapping_DelItemString (ptr(), const_cast(s.c_str())) == -1) + { + throw Exception(); + } + } + + void delItem (const Object& s) + { + if (PyMapping_DelItem (ptr(), *s) == -1) + { + throw Exception(); + } + } + // Queries + List keys () const + { + return List(PyMapping_Keys(ptr()), true); + } + + List values () const + { // each returned item is a (key, value) pair + return List(PyMapping_Values(ptr()), true); + } + + List items () const + { + return List(PyMapping_Items(ptr()), true); + } + + // iterators for MapBase + // Added by TMM: 2Jul'01 - NOT COMPLETED + // There is still a bug. I decided to stop, before fixing the bug, because + // this can't be halfway efficient until Python gets built-in iterators. + // My current soln is to iterate over the map by getting a copy of its keys + // and iterating over that. Not a good solution. + + // The iterator holds a MapBase* rather than a MapBase because that's + // how the sequence iterator is implemented and it works. But it does seem + // odd to me - we are iterating over the map object, not the reference. + +#if 0 // here is the test code with which I found the (still existing) bug + typedef cxx::Dict d_t; + d_t d; + cxx::String s1("blah"); + cxx::String s2("gorf"); + d[ "one" ] = s1; + d[ "two" ] = s1; + d[ "three" ] = s2; + d[ "four" ] = s2; + + d_t::iterator it; + it = d.begin(); // this (using the assignment operator) is causing + // a problem; if I just use the copy ctor it works fine. + for( ; it != d.end(); ++it ) + { + d_t::value_type vt( *it ); + cxx::String rs = vt.second.repr(); + std::string ls = rs.operator std::string(); + fprintf( stderr, "%s\n", ls ); + } +#endif // 0 + + class iterator + { + // : public forward_iterator_parent( std::pair ) { + protected: + typedef std::forward_iterator_tag iterator_category; + typedef std::pair< const T, T > value_type; + typedef int difference_type; + typedef std::pair< const T, mapref > pointer; + typedef std::pair< const T, mapref > reference; + + friend class MapBase; + // + MapBase* map; + List keys; // for iterating over the map + List::iterator pos; // index into the keys + + public: + ~iterator () + {} + + iterator () + : map( 0 ) + , keys() + , pos() + {} + + iterator (MapBase* m, bool end = false ) + : map( m ) + , keys( m->keys() ) + , pos( end ? keys.end() : keys.begin() ) + {} + + iterator (const iterator& other) + : map( other.map ) + , keys( other.keys ) + , pos( other.pos ) + {} + + reference operator*() + { + Object key = *pos; + return std::make_pair(key, mapref(*map,key)); + } + + iterator& operator=(const iterator& other) + { + if (this == &other) + return *this; + map = other.map; + keys = other.keys; + pos = other.pos; + return *this; + } + + bool eql(const iterator& right) const + { + return *map == *right.map && pos == right.pos; + } + bool neq( const iterator& right ) const + { + return *map != *right.map || pos != right.pos; + } + + // pointer operator->() { + // return ; + // } + + // prefix ++ + iterator& operator++ () + { pos++; return *this;} + // postfix ++ + iterator operator++ (int) + { return iterator(map, keys, pos++);} + // prefix -- + iterator& operator-- () + { pos--; return *this;} + // postfix -- + iterator operator-- (int) + { return iterator(map, keys, pos--);} + + std::string diagnose() const + { + std::OSTRSTREAM oss; + oss << "iterator diagnosis " << map << ", " << pos << std::ends; + return std::string(oss.str()); + } + }; // end of class MapBase::iterator + + iterator begin () + { + return iterator(this); + } + + iterator end () + { + return iterator(this, true); + } + + class const_iterator + { + protected: + typedef std::forward_iterator_tag iterator_category; + typedef const std::pair< const T, T > value_type; + typedef int difference_type; + typedef const std::pair< const T, T > pointer; + typedef const std::pair< const T, T > reference; + + friend class MapBase; + const MapBase* map; + List keys; // for iterating over the map + List::iterator pos; // index into the keys + + public: + ~const_iterator () + {} + + const_iterator () + : map( 0 ) + , keys() + , pos() + {} + + const_iterator (const MapBase* m, List k, List::iterator p ) + : map( m ) + , keys( k ) + , pos( p ) + {} + + const_iterator(const const_iterator& other) + : map( other.map ) + , keys( other.keys ) + , pos( other.pos ) + {} + + bool eql(const const_iterator& right) const + { + return *map == *right.map && pos == right.pos; + } + bool neq( const const_iterator& right ) const + { + return *map != *right.map || pos != right.pos; + } + + + // const_reference operator*() { + // Object key = *pos; + // return std::make_pair( key, map->[key] ); + // GCC < 3 barfes on this line at the '['. + // } + + const_iterator& operator=(const const_iterator& other) + { + if (this == &other) return *this; + map = other.map; + keys = other.keys; + pos = other.pos; + return *this; + } + + // prefix ++ + const_iterator& operator++ () + { pos++; return *this;} + // postfix ++ + const_iterator operator++ (int) + { return const_iterator(map, keys, pos++);} + // prefix -- + const_iterator& operator-- () + { pos--; return *this;} + // postfix -- + const_iterator operator-- (int) + { return const_iterator(map, keys, pos--);} + }; // end of class MapBase::const_iterator + + const_iterator begin () const + { + return const_iterator(this, 0); + } + + const_iterator end () const + { + return const_iterator(this, length()); + } + + }; // end of MapBase + + typedef MapBase Mapping; + + template bool operator==(const EXPLICIT_TYPENAME MapBase::iterator& left, const EXPLICIT_TYPENAME MapBase::iterator& right); + template bool operator!=(const EXPLICIT_TYPENAME MapBase::iterator& left, const EXPLICIT_TYPENAME MapBase::iterator& right); + template bool operator==(const EXPLICIT_TYPENAME MapBase::const_iterator& left, const EXPLICIT_TYPENAME MapBase::const_iterator& right); + template bool operator!=(const EXPLICIT_TYPENAME MapBase::const_iterator& left, const EXPLICIT_TYPENAME MapBase::const_iterator& right); + + extern bool operator==(const Mapping::iterator& left, const Mapping::iterator& right); + extern bool operator!=(const Mapping::iterator& left, const Mapping::iterator& right); + extern bool operator==(const Mapping::const_iterator& left, const Mapping::const_iterator& right); + extern bool operator!=(const Mapping::const_iterator& left, const Mapping::const_iterator& right); + + + // ================================================== + // class Dict + class Dict: public Mapping + { + public: + // Constructor + explicit Dict (PyObject *pyob, bool owned=false): Mapping (pyob, owned) + { + validate(); + } + Dict (const Dict& ob): Mapping(ob) + { + validate(); + } + // Creation + Dict () + { + set(PyDict_New (), true); + validate(); + } + // Assignment acquires new ownership of pointer + + Dict& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Dict& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set(rhsp); + return *this; + } + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && Py::_Dict_Check (pyob); + } + }; + + class Callable: public Object + { + protected: + explicit Callable (): Object() + {} + public: + // Constructor + explicit Callable (PyObject *pyob, bool owned = false): Object (pyob, owned) + { + validate(); + } + + Callable (const Object& ob): Object(ob) + { + validate(); + } + + // Assignment acquires new ownership of pointer + + Callable& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Callable& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set (rhsp); + return *this; + } + + // Membership + virtual bool accepts (PyObject *pyob) const + { + return pyob && PyCallable_Check (pyob); + } + + // Call + Object apply(const Tuple& args) const + { + return asObject(PyObject_CallObject(ptr(), args.ptr())); + } + + // Call with keywords + Object apply(const Tuple& args, const Dict& kw) const + { + return asObject( PyEval_CallObjectWithKeywords( ptr(), args.ptr(), kw.ptr() ) ); + } + + Object apply(PyObject* pargs = 0) const + { + return apply (Tuple(pargs)); + } + }; + + class Module: public Object + { + public: + explicit Module (PyObject* pyob, bool owned = false): Object (pyob, owned) + { + validate(); + } + + // Construct from module name + explicit Module (const std::string&s): Object() + { + PyObject *m = PyImport_AddModule( const_cast(s.c_str()) ); + set( m, false ); + validate (); + } + + // Copy constructor acquires new ownership of pointer + Module (const Module& ob): Object(*ob) + { + validate(); + } + + Module& operator= (const Object& rhs) + { + return (*this = *rhs); + } + + Module& operator= (PyObject* rhsp) + { + if(ptr() == rhsp) return *this; + set(rhsp); + return *this; + } + + Dict getDict() + { + return Dict(PyModule_GetDict(ptr())); + // Caution -- PyModule_GetDict returns borrowed reference! + } + }; + + // Numeric interface + inline Object operator+ (const Object& a) + { + return asObject(PyNumber_Positive(*a)); + } + inline Object operator- (const Object& a) + { + return asObject(PyNumber_Negative(*a)); + } + + inline Object abs(const Object& a) + { + return asObject(PyNumber_Absolute(*a)); + } + + inline std::pair coerce(const Object& a, const Object& b) + { + PyObject *p1, *p2; + p1 = *a; + p2 = *b; + if(PyNumber_Coerce(&p1,&p2) == -1) + { + throw Exception(); + } + return std::pair(asObject(p1), asObject(p2)); + } + + inline Object operator+ (const Object& a, const Object& b) + { + return asObject(PyNumber_Add(*a, *b)); + } + inline Object operator+ (const Object& a, int j) + { + return asObject(PyNumber_Add(*a, *Int(j))); + } + inline Object operator+ (const Object& a, double v) + { + return asObject(PyNumber_Add(*a, *Float(v))); + } + inline Object operator+ (int j, const Object& b) + { + return asObject(PyNumber_Add(*Int(j), *b)); + } + inline Object operator+ (double v, const Object& b) + { + return asObject(PyNumber_Add(*Float(v), *b)); + } + + inline Object operator- (const Object& a, const Object& b) + { + return asObject(PyNumber_Subtract(*a, *b)); + } + inline Object operator- (const Object& a, int j) + { + return asObject(PyNumber_Subtract(*a, *Int(j))); + } + inline Object operator- (const Object& a, double v) + { + return asObject(PyNumber_Subtract(*a, *Float(v))); + } + inline Object operator- (int j, const Object& b) + { + return asObject(PyNumber_Subtract(*Int(j), *b)); + } + inline Object operator- (double v, const Object& b) + { + return asObject(PyNumber_Subtract(*Float(v), *b)); + } + + inline Object operator* (const Object& a, const Object& b) + { + return asObject(PyNumber_Multiply(*a, *b)); + } + inline Object operator* (const Object& a, int j) + { + return asObject(PyNumber_Multiply(*a, *Int(j))); + } + inline Object operator* (const Object& a, double v) + { + return asObject(PyNumber_Multiply(*a, *Float(v))); + } + inline Object operator* (int j, const Object& b) + { + return asObject(PyNumber_Multiply(*Int(j), *b)); + } + inline Object operator* (double v, const Object& b) + { + return asObject(PyNumber_Multiply(*Float(v), *b)); + } + + inline Object operator/ (const Object& a, const Object& b) + { + return asObject(PyNumber_Divide(*a, *b)); + } + inline Object operator/ (const Object& a, int j) + { + return asObject(PyNumber_Divide(*a, *Int(j))); + } + inline Object operator/ (const Object& a, double v) + { + return asObject(PyNumber_Divide(*a, *Float(v))); + } + inline Object operator/ (int j, const Object& b) + { + return asObject(PyNumber_Divide(*Int(j), *b)); + } + inline Object operator/ (double v, const Object& b) + { + return asObject(PyNumber_Divide(*Float(v), *b)); + } + + inline Object operator% (const Object& a, const Object& b) + { + return asObject(PyNumber_Remainder(*a, *b)); + } + inline Object operator% (const Object& a, int j) + { + return asObject(PyNumber_Remainder(*a, *Int(j))); + } + inline Object operator% (const Object& a, double v) + { + return asObject(PyNumber_Remainder(*a, *Float(v))); + } + inline Object operator% (int j, const Object& b) + { + return asObject(PyNumber_Remainder(*Int(j), *b)); + } + inline Object operator% (double v, const Object& b) + { + return asObject(PyNumber_Remainder(*Float(v), *b)); + } + + inline Object type(const Exception&) // return the type of the error + { + PyObject *ptype, *pvalue, *ptrace; + PyErr_Fetch(&ptype, &pvalue, &ptrace); + Object result(ptype); + PyErr_Restore(ptype, pvalue, ptrace); + return result; + } + + inline Object value(const Exception&) // return the value of the error + { + PyObject *ptype, *pvalue, *ptrace; + PyErr_Fetch(&ptype, &pvalue, &ptrace); + Object result; + if(pvalue) result = pvalue; + PyErr_Restore(ptype, pvalue, ptrace); + return result; + } + + inline Object trace(const Exception&) // return the traceback of the error + { + PyObject *ptype, *pvalue, *ptrace; + PyErr_Fetch(&ptype, &pvalue, &ptrace); + Object result; + if(ptrace) result = ptrace; + PyErr_Restore(ptype, pvalue, ptrace); + return result; + } + + + +template +String seqref::str () const + { + return the_item.str(); + } + +template +String seqref::repr () const + { + return the_item.repr(); + } + + + } // namespace Py +#endif // __CXX_Objects__h diff --git a/lib/kross/python/cxx/PyCXX.html b/lib/kross/python/cxx/PyCXX.html new file mode 100644 index 000000000..566974c14 --- /dev/null +++ b/lib/kross/python/cxx/PyCXX.html @@ -0,0 +1,2131 @@ + + + + +Writing Python Extensions in C++ + + + + + + +

Writing Python Extensions in C++

+ +

Barry Scott
+Reading, Berkshire, England
+barry@barrys-emacs.org
+

+ +

Paul F. Dubois, dubois1@llnl.gov
+Lawrence Livermore National Laboratory
+Livermore, California, U.S.A.

+ + +

PyCXX is designed to make it easier to extend Python with C++

+ + +

PyCXX is a set of C++ facilities to make it easier to write Python extensions. +The chief way in which PyCXX makes it easier to write Python extensions is that it greatly +increases the probability that your program will not make a reference-counting error and +will not have to continually check error returns from the Python C API. PyCXX +integrates Python with C++ in these ways:

+ +
    +
  • C++ exception handling is relied on to detect errors and clean up. In a complicated + function this is often a tremendous problem when writing in C. With PyCXX, we let the + compiler keep track of what objects need to be dereferenced when an error occurs. +
  • The Standard Template Library (STL) and its many algorithms plug and play with Python + containers such as lists and tuples. +
  • The optional CXX_Extensions facility allows you to replace the clumsy C tables with + objects and method calls that define your modules and extension objects. +
+ +

Download and Installation

+ +

Download PyCXX from http://sourceforge.net/projects/cxx/.

+ +

The distribution layout is:

+ + + + + + + +
DirectoryDescription
.Makefile for Unix and Windows, Release documentation
./CXXHeader files
./SrcSource files
./DocDocumentation
./DemoTesting and Demonstartion files
+ +

To use PyCXX you use its include files and add its source routines to your module.

+ +

Installation:

+
    +
  • Install the PyCXX files into a directory of your choice. For example:
    +Windows: C:\PyCXX
    +Unix: /usr/local/PyCXX +
  • Tell your compiler where the PyCXX header files are:
    +Windows: cl /I=C:\PyCXX ...
    +Unix: g++ -I/usr/local/PyCXX ... +
  • Include PyCXX headers files in your code using the CXX prefix:
    +#include "CXX/Object.hxx" +
+ +

The header file CXX/config.h may need to be adjusted for the +compiler you use. As of this writing, only a fairly obscure reference to part of the +standard library needs this adjustment. Unlike prior releases, PyCXX now assumes namespace +support and a standard C++ library.

+ +

Use of namespaces

+ +

All PyCXX assets are in namespace "Py". You need to include +the Py:: prefix when referring to them, or include the statement:

+ +

using namespace Py;

+ +

Wrappers for standard objects: CXX_Objects.h

+ +

Header file CXX_Objects.h requires adding file Src/cxxsupport.cxx to +your module sources. CXX_Objects provides a set of wrapper classes that allow you access +to most of the Python C API using a C++ notation that closely resembles Python. For +example, this Python:

+ +
d = {}
+d["a"] = 1
+d["b"] = 2
+alist = d.keys()
+print alist
+ +

Can be written in C++:

+ +
Dict d;
+List alist;
+d["a"] = Int(1);
+d["b"] = Int(2);
+alist = d.keys();
+std::cout << alist << std::endl;
+
+ +

You can optionally use the CXX/Extensions.hxx facility described later +to define Python extension modules and extension objects.

+ +

We avoid programming with Python object pointers

+ +

The essential idea is that we avoid, as much as possible, programming with pointers to +Python objects, that is, variables of type PyObject*. Instead, +we use instances of a family of C++ classes that represent the +usual Python objects. This family is easily extendible to include new kinds of Python +objects.

+ +

For example, consider the case in which we wish to write a method, taking a single +integer argument, that will create a Python dict + and insert into it that the integer plus one under the key value. + In C we might do that as follows:

+ +
static PyObject* mymodule_addvalue (PyObject* self, PyObject* args)
+        {
+	PyObject *d;
+	PyObject* f;
+	int k;
+	PyArgs_ParseTuple(args, "i", &k);
+	d = PyDict_New();
+	if (!d)
+		return NULL;
+
+	f = PyInt_NEW(k+1);
+	if(!f)
+                {
+		Py_DECREF(d); /* have to get rid of d first */
+		return NULL;
+	        }
+	if(PyDict_SetItemString(d, "value", f) == -1)
+                {
+		Py_DECREF(f);
+		Py_DECREF(d);
+		return NULL;
+                }
+
+	return d;
+        }
+ +

If you have written a significant Python extension, this tedium looks all too familiar. +The vast bulk of the coding is error checking and cleanup. Now compare the same thing +written in C++ using CXX/Objects.hxx. The things with Python-like names (Int, Dict, Tuple) are +from CXX/Objects.hxx.

+ +
static PyObject* mymodule_addvalue (PyObject* self, PyObject* pargs)
+        { 
+	try     { 
+		Tuple args(pargs); 
+		args.verify_length(1); 
+
+		Dict d; 
+		Int k = args[0]; 
+		d["value"] = k + 1;
+
+		return new_reference_to(d); 
+	        } 
+	catch (const PyException&)
+                { 
+		return NULL;
+	        }
+        }
+ +

If there are not the right number of arguments or the argument is not an +integer, an exception is thrown. In this case we choose to catch it and convert it into a +Python exception. The C++ exception handling mechanism takes care all the cleanup.

+ +

Note that the creation of the Int k got the first argument and verified +that it is an Int.

+ +

Just to peek ahead, if you wrote this method in an +ExtensionModule-derived module of your own, it would be a method and it could be written +even more simply:

+ +
+Object addvalue (Object & self, const Tuple & args)
+      {
+      args.verify_length(1);
+      Dict d;
+      Int k = args[0];
+      d["value"] = k + 1;
+      return d;
+      }
+
+ +

The basic concept is to wrap Python pointers

+ + +

The basic concept of CXX/Objects.hxx is to create a wrapper around +each PyObject * so that the reference counting can be +done automatically, thus eliminating the most frequent source of errors. In addition, we +can then add methods and operators so that Python objects can be manipulated in C++ +much like you would in Python.

+ +

Each Object contains a PyObject * +to which it owns a reference. When an Object is destroyed, it releases its ownership on +the pointer. Since C++ calls the destructors on objects that are about to go out of scope, +we are guaranteed that we will keep the reference counts right even if we unexpectedly +leave a routine with an exception.

+ +

As a matter of philosophy, CXX/Objects.hxx prevents the creation of instances of its +classes unless the instance will be a valid instance of its class. When an attempt is made +to create an object that will not be valid, an exception is thrown.

+ +

Class Object represents the most general kind of Python object. The rest of the classes +that represent Python objects inherit from it.

+ +
Object
+    Type
+    Int
+    Float
+    Long
+    Complex
+    Char
+    Sequence -> SeqBase<T>
+        String
+        Tuple
+        List
+    Mapping -> MapBase<T>
+        Dict
+    Callable
+    Module
+ +

There are several constructors for each of these classes. For example, you can create +an Int from an integer as in

+ +
Int s(3)
+ +

However, you can also create an instance of one of these classes using any PyObject* or +another Object. If the corresponding Python object does not actually have the type +desired, an exception is thrown. This is accomplished as follows. Class Object defines a +virtual function accepts:

+ +
virtual bool accepts(PyObject* p)
+ +

The base class version of accepts returns true for any pointer p except 0. This means +we can create an Object using any PyObject *, or from any other +Object. However, if we attempt to create an Int from a PyObject *, +the overridding version +of accepts in class Int will only accept pointers that correspond to Python ints. +Therefore if we have a Tuple t and we wish to get the first element and be sure it is an +Int, we do

+ +
Int first_element = t[0]
+ +

This will not only accomplish the goal of extracting the first element of the Tuple t, +but it will ensure that the result is an Int. If not, an exception is thrown. The +exception mechanism is discussed later.

+ +

Class Object

+ +

Class Object serves as the base class for the other classes. Its default constructor +constructs a Py_None, the unique object of Python type None. The interface to Object +consists of a large number of methods corresponding to the operations that are defined for +every Python object. In each case, the methods throw an exception if anything goes +wrong.

+ +

There is no method corresponding to PyObject_SetItem with an arbitrary Python object +as a key. Instead, create an instance of a more specific child of Object and use the +appropriate facilities.

+ +

The comparison operators use the Python comparison function to compare values. The +method is is available to test for absolute identity.

+ +

A conversion to standard library string type std::string is supplied using method +as_string. Stream output of PyCXX Object instances uses this conversion, +which in turn uses the Python object's str() representation.

+ +

All the numeric operators are defined on all possible combinations of Object, +long, and double. These use the corresponding Python operators, +and should the operation fail for some reason, an exception is thrown.

+ +

Dealing with pointers returned by the Python C API

+ +

Often, PyObject * pointers are acquired from some function, +particularly functions in the Python C API. If you wish to make an object from the pointer +returned by such a function, you need to know if the function returns you an owned +or unowned reference. Unowned references are unusual but there are some cases where +unowned references are returned.

+ +

Usually, Object and its children acquire a new reference when constructed from a +PyObject *. This is usually not the right behavior if the reference comes from one +of the Python C API calls.

+ +

If p is an owned reference, you can add the boolean true as an extra +argument in the creation routine, Object(p, true), or use the function asObject(p) which +returns an Object created using the owned reference. For example, the routine +PyString_FromString returns an owned reference to a Python string object. You could write:

+ +
Object w = asObject( PyString_FromString("my string") );
+ +

or using the constructor,

+ +
Object w( PyString_FromString("my string"), true );
+ +

In fact, you would never do this, since PyCXX has a class String and you can just say:

+ +
String w( "my string" );
+ +

Indeed, since most of the Python C API is similarly embodied in Object +and its descendents, you probably will not use asObject all that often.

+

Table 1: Class Object

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ReturnsName(signature)Comment

Basic Methods

explicit Object (PyObject* pyob=Py_None, bool owned=false) Construct from pointer.
explicitObject (const Object& ob)Copycons; acquires an owned reference.
Object&operator= (const Object& rhs) Acquires an owned reference.
Object&operator= (PyObject* rhsp) Acquires an owned reference.
virtual~Object () Releases the reference.
voidincrement_reference_count() Explicitly increment the count
voiddecrement_reference_count()Explicitly decrement count but not to zero
PyObject*operator* () constLends the pointer
PyObject*ptr () constLends the pointer
virtual boolaccepts (PyObject *pyob) constWould assignment of pyob to this object succeed?
std::stringas_string() conststr() representation
Python API Interface
intreference_count () const reference count
Typetype () constassociated type object
Stringstr () conststr() representation
Stringrepr () constrepr () representation
boolhasAttr (const std::string& s) consthasattr(this, s)
ObjectgetAttr (const std::string& s) constgetattr(this, s)
ObjectgetItem (const Object& key) constgetitem(this, key)
longhashValue () consthash(this)
voidsetAttr (const std::string& s,
const Object& value)
this.s = value
voiddelAttr (const std::string& s) del this.s
voiddelItem (const Object& key) del this[key]
boolisCallable () constdoes this have callable behavior?
boolisList () constis this a Python list?
boolisMapping () constdoes this have mapping behaviors?
boolisNumeric () constdoes this have numeric behaviors?
boolisSequence () const does this have sequence behaviors?
boolisTrue () constis this true in the Python sense?
boolisType (const Type& t) constis type(this) == t?
boolisTuple() constis this a Python tuple?
boolisString() constis this a Python string?
boolisUnicode() constis this a Python Unicode string?
boolisDict() constis this a Python dictionary?
Comparison Operators
boolis(PyObject* pother) consttest for identity
boolis(const Object& other) consttest for identity
bool operator==(const Object& o2) constComparisons use Python cmp
booloperator!=(const Object& o2) constComparisons use Python cmp
booloperator>=(const Object& o2) constComparisons use Python cmp
booloperator<=(const Object& o2) const Comparisons use Python cmp
booloperator<(const Object& o2) constComparisons use Python cmp
booloperator>(const Object& o2) constComparisons use Python cmp
+ +

The Basic Types

+ +

Corresponding to each of the basic Python types is a class that inherits from Object. +Here are the interfaces for those types. Each of them inherits from Object and therefore +has all of the inherited methods listed for Object. Where a virtual function is overridden +in a class, the name is underlined.

+ +

Class Type

+ +

Class Type corresponds to Python type objects. There is no default constructor.

+ +

Table 2: class Type

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ReturnsName and SignatureComments
explicitType (PyObject* pyob, bool owned = false)Constructor
explicitType (const Object& ob)Constructor
explicitType(const Type& t)Copycons
Type&operator= (const Object& rhs) Assignment
Type&operator= (PyObject* rhsp) Assignment
virtual boolaccepts (PyObject *pyob) constUses PyType_Check
+ +

Class Int

+ +

Class Int, derived publically from Object, corresponds to Python ints. Note that the +latter correspond to C long ints. Class Int has an implicit user-defined conversion to +long int. All constructors, on the other hand, are explicit. The default constructor +creates a Python int zero.

+ +

Table 3: class Int

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Returns + Name and Signature + Comments +
explicitInt (PyObject *pyob, bool owned= false, bool owned = false)Constructor
explicitInt (const Int& ob)Constructor
explicitInt (long v = 0L)Construct from long
explicitInt (int v)Contruct from int
explicitInt (const Object& ob)Copycons
Int&operator= (const Object& rhs)Assignment
Int&operator= (PyObject* rhsp)Assignment
virtual bool   (PyObject *pyob) const Based on PyInt_Check
longoperator long() const Implicit conversion to long int
Int&operator= (int v)Assign from int
Int&operator= (long v) Assign from long
+ +
+ +

Class Long

+ +

Class Long, derived publically from Object, corresponds to Python type long. In Python, +a long is an integer type of unlimited size, and is usually used for applications such as +cryptography, not as a normal integer. Implicit conversions to both double and long are +provided, although the latter may of course fail if the number is actually too big. All +constructors are explicit. The default constructor produces a Python long zero.

+ +

Table 4: Class Long

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Returns + Name and Signature + Comments +
explicitLong (PyObject *pyob, bool owned = false)Constructor
explicitLong (const Int& ob)Constructor
explicitLong (long v = 0L)Construct from long
explicitLong (int v)Contruct from int
explicitLong (const Object& ob)Copycons
Long&operator= (const Object& rhs)Assignment
Long&operator= (PyObject* rhsp)Assignment
virtual bool(PyObject *pyob) const Based on PyLong_Check
doubleoperator double() const Implicit conversion to double
longoperator long() constImplicit conversion to long
Long&operator= (int v)Assign from int
Long&operator= (long v) Assign from long
+ +

Class Float

+ +

Class Float corresponds to Python floats, which in turn correspond to C double. The +default constructor produces the Python float 0.0.

+ +

Table 5: Class Float

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Returns + Name and Signature + Comments +
explicitFloat (PyObject *pyob, bool owned = false) + Constructor
Float (const Float& f)   Construct from float
explicitFloat (double v=0.0)Construct from double
explicitFloat (const Object& ob)Copycons
Float&operator= (const Object& rhs)Assignment
Float&operator= (PyObject* rhsp)Assignment
virtual bool accepts (PyObject *pyob) constBased on PyFloat_Check
double operator double () constImplicit conversion to double
Float& operator= (double v)Assign from double
Float& operator= (int v)Assign from int
Float& operator= (long v)Assign from long
Float& operator= (const Int& iob)Assign from Int
+ +

Sequences

+ +

PyCXX implements a quite sophisticated wrapper class for Python sequences. While every +effort has been made to disguise the sophistication, it may pop up in the form of obscure +compiler error messages, so in this documentation we will first detail normal usage and +then discuss what is under the hood.

+ +

The basic idea is that we would like the subscript operator [] to work properly, and to +be able to use STL-style iterators and STL algorithms across the elements of the sequence.

+ +

Sequences are implemented in terms of a templated base class, SeqBase<T>. The +parameter T is the answer to the question, sequence of what? For Lists, for example, T is +Object, because the most specific thing we know about an element of a List is simply that +it is an Object. (Class List is defined below; it is a descendent of Object that holds a +pointer to a Python list). For strings, T is Char, which is a wrapper in turn of Python +strings whose length is one.

+ +

For convenience, the word Sequence is a typedef of SeqBase<Object>.

+ +

General sequences

+ +

Suppose you are writing an extension module method that expects the first argument to +be any kind of Python sequence, and you wish to return the length of that sequence. You +might write:

+ +
static PyObject*
+my_module_seqlen (PyObject *self, PyObject* args) {
+    try
+        {
+        Tuple t(args);       // set up a Tuple pointing to the arguments.
+        if(t.length() != 1) 
+             throw PyException("Incorrect number of arguments to seqlen.");
+        Sequence s = t[0];   // get argument and be sure it is a sequence
+        return new_reference_to(Int(s.length()));
+        }
+    catch(const PyException&)
+        {
+        return Py_Null;
+        }
+}
+ +

As we will explain later, the try/catch structure converts any errors, such as the +first argument not being a sequence, into a Python exception.

+ +

Subscripting

+ +

When a sequence is subscripted, the value returned is a special kind of object which +serves as a proxy object. The general idea of proxy objects is discussed in Scott Meyers' +book, "More Effective C++". Proxy objects are necessary because when one +subscripts a sequence it is not clear whether the value is to be used or the location +assigned to. Our proxy object is even more complicated than normal because a sequence +reference such as s[i] is not a direct reference to the i'th object of s.

+ +

In normal use, you are not supposed to notice this magic going on behind your back. You +write:

+ +
Object t;
+Sequence s;
+s[2] = t + s[1]
+ +

and here is what happens: s[1] returns a proxy object. Since there is no addition +operator in Object that takes a proxy as an argument, the compiler decides to invoke an +automatic conversion of the proxy to an Object, which returns the desired component of s. +The addition takes place, and then there is an assignment operator in the proxy class +created by the s[2], and that assignment operator stuffs the result into the 2 component +of s.

+ +

It is possible to fool this mechanism and end up with a compiler failing to admit that +a s[i] is an Object. If that happens, you can work around it by writing Object(s[i]), +which makes the desired implicit conversion, explicit.

+ +

Iterators

+ +

Each sequence class provides the following interface. The class seqref<T> is the +proxy class. We omit the details of the iterator, const_iterator, and seqref<T> +here. See CXX_Objects.h if necessary. The purpose of most of this interface is to satisfy +requirements of the STL.

+ +

The SeqBase<T> Interface

+ +

SeqBase<T> inherits from Object.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type + Name +
typedef int size_type
typedef seqref<T>reference
typedef T const_reference
typedef seqref<T>*pointer
typedef int difference_type
virtual size_typemax_size() const
virtual size_type capacity() const;
virtual void swap(SeqBase<T>& c);
virtual size_type size () const;
explicit SeqBase<T> ();
explicit SeqBase<T> (PyObject* pyob, bool owned = false);
explicit SeqBase<T> (const Object& ob);
SeqBase<T>& operator= (const Object& rhs);
SeqBase<T>& operator= (PyObject* rhsp);
virtual bool accepts (PyObject *pyob) const;
size_type length () const ;
const T operator[](size_type index) const;
seqref<T> operator[](size_type index);
virtual T getItem (size_type i) const;
virtual void setItem (size_type i, const T& ob);
SeqBase<T> repeat (int count) const;
SeqBase<T> concat (const SeqBase<T>& other) const ;
const T front () const;
seqref<T> front();
const T back () const;
seqref<T> back();
void verify_length(size_type required_size);
void verify_length(size_type min_size, size_type max_size);
classiterator;
iterator begin ();
iterator end ();
class const_iterator;
const_iterator begin () const;
const_iterator end () const;
+ +

Any heir of class Object that has a sequence behavior should inherit from class +SeqBase<T>, where T is specified as the type of object that represents the +individual elements of the sequence. The requirements on T are that it has a constructor +that takes a PyObject* as an argument, that it has a default constructor, a copy +constructor, and an assignment operator. In short, any properly defined heir of Object +will work.

+ +

Classes Char and String

+ +

Python strings are unusual in that they are immutable sequences of characters. However, +there is no character type per se; rather, when subscripted strings return a string of +length one. To simulate this, we define two classes Char and String. The Char class +represents a Python string object of length one. The String class represents a Python +string, and its elements make up a sequence of Char's.

+ +

The user interface for Char is limited. Unlike String, for example, it is not a +sequence.

+ +

The Char interface

+ +

Char inherits from Object.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type + Name +
explicitChar (PyObject *pyob, bool owned = false)
Char (const Object& ob)
Char (const std::string& v = "")
Char (char v)
Char (Py_UNICODE v)
Char&operator= (const std::string& v)
Char&operator= (char v)
Char&operator= (Py_UNICODE v)
Char&operator= (std::basic_string v)
operator String() const
operator std::string () const
+ +

The String Interface

+ +

String inherits from SeqBase<Char>.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type + Name +
explicit String (PyObject *pyob, bool owned = false)
String (const Object& ob)
String (const std::string& v = "")
String (const std::string& v, const char *encoding, const char *error="strict")
String (const char *s, const char *encoding, const char *error="strict")
String (const char *s, int len, const char *encoding, const char *error="strict")
String (const std::string& v, std::string::size_type vsize)
String (const char* v)
String&operator= (const std::string& v)
std::stringoperator std::string () const
Stringencode( const char *encoding, const char *error="strict" )
Stringdecode( const char *encoding, const char *error="strict" )
std::stringas_std_string() const
unicodestringas_unicodestring() const
+ +

Class Tuple

+ +

Class Tuple represents Python tuples. A Tuple is a Sequence. There are two kinds of +constructors: one takes a PyObject* as usual, the other takes an integer number as an +argument and returns a Tuple of that length, each component initialized to Py_None. The +default constructor produces an empty Tuple.

+ +

Tuples are not immutable, but attempts to assign to their components will fail if the +reference count is not 1. That is, it is safe to set the elements of a Tuple you have just +made, but not thereafter.

+ +

Example: create a Tuple containing (1, 2, 4)

+ +
Tuple t(3)
+t[0] = Int(1)
+t[1] = Int(2)
+t[2] = Int(4)
+ +

Example: create a Tuple from a list:

+ +
Dict d
+...
+Tuple t(d.keys())
+ +

The Tuple Interface

+ +

Tuple inherits from Sequence.. Special run-time checks prevent modification if the +reference count is greater than one.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type + Name + Comment +
virtual voidsetItem (int offset, const Object&ob) setItem is overriden to handle tuples properly.
explicitTuple (PyObject *pyob, bool owned = false)
Tuple (const Object& ob)
explicitTuple (int size = 0)Create a tuple of the given size. Items initialize to Py_None. Default is an empty + tuple.
explicitTuple (const Sequence& s)Create a tuple from any sequence.
Tuple&operator= (const Object& rhs)
Tuple&operator= (PyObject* rhsp)
TuplegetSlice (int i, int j) const Equivalent to python's t[i:j]
+ +

Class List

+ +

Class List represents a Python list, and the methods available faithfully reproduce the +Python API for lists. A List is a Sequence.

+ +

The List Interface

+ +

List inherits from Sequence.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type + Name + Comment +
explicitList (PyObject *pyob, bool owned = false)
List (const Object& ob)
List (int size = 0)Create a list of the given size. Items initialized to Py_None. Default is an empty list.
List (const Sequence& s)Create a list from any sequence.
List&operator= (const Object& rhs)
List&operator= (PyObject* rhsp)
ListgetSlice (int i, int j) const
voidsetSlice (int i, int j, const Object& v)
voidappend (const Object& ob)
voidinsert (int i, const Object& ob)
voidsort ()Sorts the list in place, using Python's member function. You can also use + the STL sort function on any List instance.
voidreverse ()Reverses the list in place, using Python's member function.
+ +

Mappings

+ +

A class MapBase<T> is used as the base class for Python objects with a mapping +behavior. The key behavior of this class is the ability to set and use items by +subscripting with strings. A proxy class mapref<T> is defined to produce the correct +behavior for both use and assignment.

+ +

For convenience, Mapping is a typedef for MapBase<Object>.

+ +

The MapBase<T> interface

+ +

MapBase<T> inherits from Object. T should be chosen to reflect the kind of +element returned by the mapping.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type + Name + Comment +
Toperator[](const std::string& key) const
mapref<T> operator[](const std::string& key)
intlength () constNumber of entries.
inthasKey (const std::string& s) const Is m[s] defined?
TgetItem (const std::string& s) constm[s]
virtual voidsetItem (const std::string& s, const Object& ob)m[s] = ob
voiddelItem (const std::string& s)del m[s]
voiddelItem (const Object& s)
Listkeys () constA list of the keys.
Listvalues () constA list of the values.
Listitems () constEach item is a key-value pair.
+ +

Class Dict

+ +

Class Dict represents Python dictionarys. A Dict is a Mapping. Assignment to +subscripts can be used to set the components.

+ +
Dict d
+d["Paul Dubois"] = "(925)-422-5426"
+ +

Interface for Class Dict

+ +

Dict inherits from MapBase<Object>.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type + Name + Comment +
explicitDict (PyObject *pyob, bool owned = false)
Dict (const Dict& ob)
Dict () Creates an empty dictionary
Dict&operator= (const Object& rhs)
Dict&operator= (PyObject* rhsp)
+ +

Other classes and facilities.

+ +

Class Callable provides an interface to those Python objects that support a call +method. Class Module holds a pointer to a module. If you want to create an extension +module, however, see the extension facility. There is a large set of numeric operators.

+ +

Interface to class Callable

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type + Name + Comment +
explicitCallable (PyObject *pyob, bool owned = false)
Callable& operator= (const Object& rhs)
Callable& operator= (PyObject* rhsp)
Objectapply(const Tuple& args) constCall the object with the given arguments
Objectapply(PyObject* pargs = 0) const Call the object with args as the arguments. Checks that pargs is a tuple.
+ +

Interface to class Module

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type + Name + Comment +
explicitModule (PyObject* pyob, bool owned = false)
explicitModule (const std::string name)Construct from name of module; does the import if needed.
Module (const Module& ob) Copy constructor
Module&operator= (const Object& rhs) Assignment
Module&operator= (PyObject* rhsp) Assignment
+ +

Numeric interface

+ +

Unary operators for plus and minus, and binary operators +, -, *, /, and % are defined +for pairs of objects and for objects with scalar integers or doubles (in either +order). Functions abs(ob) and coerce(o1, o2) are also defined.

+ +

The signature for coerce is:

+ +
inline std::pair<Object,Object> coerce(const Object& a, const Object& b)
+ +

Unlike the C API function, this simply returns the pair after coercion.

+ +

Stream I/O

+ +

Any object can be printed using stream I/O, using std::ostream& operator<< +(std::ostream& os, const Object& ob). The object's str() representation is +converted to a standard string which is passed to std::ostream& operator<< +(std::ostream& os, const std::string&).

+ +

Exceptions

+ +

The Python exception facility and the C++ exception facility can be merged via the use +of try/catch blocks in the bodies of extension objects and module functions.

+ +

Class Exception and its children

+ +

A set of classes is provided. Each is derived from class Exception, and represents a +particular sort of Python exception, such as IndexError, RuntimeError, ValueError. Each of +them (other than Exception) has a constructor which takes an explanatory string as an +argument, and is used in a throw statement such as:

+ +
throw IndexError("Index too large in MyObject access.");
+ +

If in using a routine from the Python API, you discover that it has returned a NULL +indicating an error, then Python has already set the error message. In that case you +merely throw Exception.

+ +

List of Exceptions

+ +

The exception hierarchy mirrors the Python exception hierarchy. The concrete exception +classes are shown here.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeInterface for class Exception
explicit Exception()
Exception (const std::string& reason)
Exception (PyObject* exception, const std::string& reason)
void clear()
Constructors for other children of class Exception
TypeError (const std::string& reason)
IndexError (const std::string& reason)
AttributeError (const std::string& reason)
NameError (const std::string& reason)
RuntimeError (const std::string& reason)
SystemError (const std::string& reason)
KeyError (const std::string& reason)
ValueError (const std::string& reason)
OverflowError (const std::string& reason)
ZeroDivisionError (const std::string& reason)
MemoryError (const std::string& reason)
SystemExit (const std::string& reason)
+ +

Using Exceptions in extension methods

+ +

The exception facility allows you to integrate the C++ and Python exception mechanisms. +To do this, you must use the style described below when writing module methods in the old +C style.

+ +

Note: If using the ExtensionModule or PythonExtension mechanisms described below, the +method handlers include exception handling so that you only need to use exceptions +explicitly in unusual cases.

+ +

Catching Exceptions from the Python API or PyCXX.

+ +

When writing an extension module method, you can use the following boilerplate. Any +exceptions caused by the Python API or PyCXX itself will be converted into a Python +exception. Note that Exception is the most general of the exceptions listed above, and +therefore this one catch clause will serve to catch all of them. You may wish to catch +other exceptions, not in the Exception family, in the same way. If so, you need to make +sure you set the error in Python before returning.

+ +
static PyObject *
+some_module_method(PyObject* self, PyObject* args)
+{
+    Tuple a(args); // we know args is a Tuple
+    try {
+        ...calculate something from a...
+        return ...something, usually of the form new_reference_to(some Object);
+    }
+    catch(const Exception&) {
+        //Exception caught, passing it on to Python
+        return Null ();
+    }
+}
+
+ +

How to clear an Exception

+ +

If you anticipate that an Exception may be thrown and wish to recover from it, change +the catch phrase to set a reference to an Exception, and use the method clear() from class +Exception to clear it.:

+ +
catch(Exception& e)
+    {
+    e.clear();
+    ...now decide what to do about it...
+    }
+
+ +

Extension Facilities

+ +

CXX/Extensions.hxx provides facilities for: + +

    +
  • Creating a Python extension module
  • +
  • Creating new Python extension types
  • +
+ +

These facilities use CXX/Objects.hxx and its support file cxxsupport.cxx.

+ +

If you use CXX/Extensions.hxx you must also include source files cxxextensions.c and +cxx_extensions.cxx

+ +

Creating an Python extension module

+ +

The usual method of creating a Python extension module is to declare and initialize its +method table in C. This requires knowledge of the correct form for the table and the order +in which entries are to be made into it, and requires casts to get everything to compile +without warning. The PyCXX header file CXX/Extensions.h offers a simpler method. Here is a +sample usage, in which a module named "example" is created. Note that two +details are necessary: + +

    +
  • The initialization function must be declared to have external C linkage and to have the + expected name. This is a requirement imposed by Python
  • +
  • The ExtensionModule object must have a storage class that survives the call to the + initialization function. This is most easily accomplished by using a static local inside + the initialization function, as in initexample below.
  • +
+ +

To create an extension module, you inherit from class ExtensionModule templated on +yourself: In the constructor, you make calls to register methods of this class with Python +as extension module methods. In this example, two methods are added (this is a simplified +form of the example in Demo/example.cxx):

+ +
class example_module : public ExtensionModule<example_module>
+{
+public:
+    example_module()
+        : ExtensionModule<example_module>( "example" )
+        {
+        add_varargs_method("sum", &example_module::ex_sum, "sum(arglist) = sum of arguments");
+        add_varargs_method("test", &example_module::ex_test, "test(arglist) runs a test suite");
+
+        initialize( "documentation for the example module" );
+        }
+
+     virtual ~example_module() {}
+
+private:
+     Object ex_sum(const Tuple &a) { ... }
+     Object ex_test(const Tuple &a) { ... }
+};
+
+ +

To initialize the extension, you just instantiate one static instance (static so it +does not destroy itself!):

+ +
void initexample()
+{
+static example_module* example = new example_module;
+}
+ +

The methods can be written to take Tuples as arguments and return Objects. If +exceptions occur they are trapped for you and a Python exception is generated. So, for +example, the implementation of ex_sum might be:

+ +
Object ex_sum (const Tuple &a)
+    {
+        Float f(0.0);
+        for( int i = 0; i < a.length(); i++ )
+        {
+            Float g(a[i]);
+            f = f + g;
+        }
+        return f;
+    }
+ +

class ExtensionModule contains methods to return itself as a Module object, or to +return its dictionary.

+ +

Interface to class ExtensionModule

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type + Name + Comment +
explicitExtensionModule (char* name) Create an extension module named "name"
virtual ~ExtensionModule () Destructor
DictmoduleDictionary() constReturns the module dictionary; module must be initialized.
Modulemodule() constThis module as a Module.
void add_varargs_method (char *name, method_varargs_function_t method, char *documentation="")Add a method to the module.
void add_keyword_method (char *name, method_keyword_function_t method, char *documentation=""Add a method that takes keywords
voidinitialize() (protected, call from constructor)Initialize the module once all methods have been added.
+ +

The signatures above are:

+ +
typedef Object (T::*method_varargs_function_t)( const Tuple &args );
+typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws
+);
+ +

That is, the methods take a Tuple or a Tuple and a Dict, and return an Object. The +example below has an & in front of the name of the method; we found one compiler that +needed this.

+ +

Creating a Python extension type

+ +

One of the great things about Python is the way you can create your own object types +and have Python welcome them as first-class citizens. Unfortunately, part of the way you +have to do this is not great. Key to the process is the creation of a Python "type +object". All instances of this type must share a reference to this one unique type +object. The type object itself has a multitude of "slots" into which the +addresses of functions can be added in order to give the object the desired behavior.

+ +

Creating extension objects is of course harder since you must specify +how the object behaves and give it methods. This is shown in some detail in the example +range.h and range.cxx, with the test routine rangetest.cxx, in directory Demo. If you have never +created a Python extension before, you should read the Extension manual first and be very +familiar with Python's "special class methods". Then what follows will make more +sense.

+ +

The basic idea is to inherit from PythonExtension templated on your self

+ +
class MyObject: public PythonExtension<MyObject> {...}
+ +

As a consequence: + +

    +
  • MyObject is a child of PyObject, so that a MyObject* is-a PyObject*.
  • +
  • A static method check(PyObject*) is created in class MyObject. This function + returns a boolean, testing whether or not the argument is in fact a pointer to an instance + of MyObject.
  • +
  • The user can connect methods of MyObject to Python so that they are methods on MyObject + objects. Each such method has the signature:
    + Object method_name (const Tuple& args).
  • +
  • The user can override virtual methods of PythonExtension in order to set behaviors.
  • +
  • A method is created to handle the deletion of an instance if and when its reference + count goes to zero. This method ensures the calling of the class destructor ~MyObject(), + if any, and releases the memory (see below).
  • +
  • Both automatic and heap-based instances of MyObject can be created.
  • +
+ +

Sample usage of PythonExtension

+ +

Here is a brief overview. You create a class that inherits from PythonExtension +templated upon itself. You override various methods from PythonExtension to implement +behaviors, such as getattr, sequence_item, etc. You can also add methods to the object +that are usable from Python using a similar scheme as for module methods above.

+ +

One of the consequences of inheriting from PythonExtension is that you are inheriting +from PyObject itself. So your class is-a PyObject and instances of it can be passed to the +Python C API. Note: this example uses the namespace feature of PyCXX.

+ +

Hint: You can avoid needing to specify the Py:: prefix if you include the C++ statement +using Py; at the top of your files.

+ +
class range: public Py::PythonExtension<range> {
+public:
+    ... constructors, data, etc.
+    ... methods not callable from Python
+    // initializer, see below
+    static void init_type();
+    // override functions from PythonExtension
+    virtual Py::Object repr();
+    virtual Py::Object getattr( const char *name );
+
+    virtual int sequence_length();
+    virtual Py::Object sequence_item( int i );
+    virtual Py::Object sequence_concat( const Py::Object &j );
+    virtual Py::Object sequence_slice( int i, int j );
+
+    // define python methods of this object
+    Py::Object amethod (const Py::Tuple& args);
+    Py::Object value (const Py::Tuple& args);
+    Py::Object assign (const Py::Tuple& args); 
+};
+ +

+To initialize the type we provide a static method that we can call from some module's +initializer. We set the name, doc string, and indicate which behaviors range objects +support. Then we adds the methods.

+ +
void range::init_type()
+{
+    behaviors().name("range");
+    behaviors().doc("range objects: start, stop, step");
+    behaviors().supportRepr();
+    behaviors().supportGetattr();
+    behaviors().supportSequenceType();
+
+    add_varargs_method("amethod", &range::amethod,
+        "demonstrate how to document amethod");
+    add_varargs_method("assign", &range::assign);
+    add_varargs_method("value", &range::value);
+}
+ + +

Do not forget to add the call range::init_type() to some module's init function. You will want +a method in some module that can create range objects, too.

+ +

Interface to PythonExtension <T>

+ +

Your extension class T inherits PythonExtension<T>.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type + Name + Comment +
virtual ~PythonExtension<T>() Destructor
PyTypeObject* type_object() constReturns the object type object.
intcheck (PyObject* p)Is p a T?
Protected
void add_varargs_method (char *name, method_keyword_function_t method, char *documentation=""Add a method that takes arguments
void add_keyword_method (char *name, method_keyword_function_t method, char *documentation=""Add a method that takes keywords
static PythonType&behaviors()The type object
voidinitialize() (protected, call from constructor)Initialize the module once all methods have been added.
+ +

As before the signatures for the methods are Object mymethod(const Tuple& +args) and Object mykeywordmethod (const Tuple& args, const Dict& keys). In this +case, the methods must be methods of T.

+ +

To set the behaviors of the object you override some or all of these methods from +PythonExtension<T>:

+ +
    virtual int print( FILE *, int );
+    virtual Object getattr( const char * );
+    virtual int setattr( const char *, const Object & );
+    virtual Object getattro( const Object & );
+    virtual int setattro( const Object &, const Object & );
+    virtual int compare( const Object & );
+    virtual Object repr();
+    virtual Object str();
+    virtual long hash();
+    virtual Object call( const Object &, const Object & );
+
+    // Sequence methods
+    virtual int sequence_length();
+    virtual Object sequence_concat( const Object & );
+    virtual Object sequence_repeat( int );
+    virtual Object sequence_item( int );
+    virtual Object sequence_slice( int, int );
+    virtual int sequence_ass_item( int, const Object & );
+    virtual int sequence_ass_slice( int, int, const Object & );
+
+    // Mapping
+    virtual int mapping_length();
+    virtual Object mapping_subscript( const Object & );
+    virtual int mapping_ass_subscript( const Object &, const Object & );
+
+    // Number
+    virtual int number_nonzero();
+    virtual Object number_negative();
+    virtual Object number_positive();
+    virtual Object number_absolute();
+    virtual Object number_invert();
+    virtual Object number_int();
+    virtual Object number_float();
+    virtual Object number_long();
+    virtual Object number_oct();
+    virtual Object number_hex();
+    virtual Object number_add( const Object & );
+    virtual Object number_subtract( const Object & );
+    virtual Object number_multiply( const Object & );
+    virtual Object number_divide( const Object & );
+    virtual Object number_remainder( const Object & );
+    virtual Object number_divmod( const Object & );
+    virtual Object number_lshift( const Object & );
+    virtual Object number_rshift( const Object & );
+    virtual Object number_and( const Object & );
+    virtual Object number_xor( const Object & );
+    virtual Object number_or( const Object & );
+    virtual Object number_power( const Object &, const Object & );
+
+    // Buffer
+    virtual int buffer_getreadbuffer( int, void** );
+    virtual int buffer_getwritebuffer( int, void** );
+    virtual int buffer_getsegcount( int* );
+ +

Note that dealloc is not one of the functions you can override. That is what your +destructor is for. As noted below, dealloc behavior is provided for you by +PythonExtension.

+ +

Type initialization

+ +

To initialize your type, supply a static public member function that can be called +from the extension module. In that function, obtain the PythonType object by calling +behaviors() and apply appropriate "support" methods from PythonType to turn on +the support for that behavior or set of behaviors.

+ +
    void supportPrint(void);
+    void supportGetattr(void);
+    void supportSetattr(void);
+    void supportGetattro(void);
+    void supportSetattro(void);
+    void supportCompare(void);
+    void supportRepr(void);
+    void supportStr(void);
+    void supportHash(void);
+    void supportCall(void);
+
+    void supportSequenceType(void);
+    void supportMappingType(void);
+    void supportNumberType(void);
+    void supportBufferType(void);
+ +

Then call add_varargs_method or add_keyword_method to add any methods desired to the +object.

+ +

Notes on memory management and extension objects

+ +

Normal Python objects exist only on the heap. That is unfortunate, as object creation +and destruction can be relatively expensive. Class PythonExtension allows creation of both +local and heap-based objects.

+ +

If an extension object is created using operator new, as in:

+ +
range* my_r_ref = new range(1, 20, 3)
+ +

then the entity my_r_ref can be thought of as "owning" the reference created +in the new object. Thus, the object will never have a reference count of zero. If the +creator wishes to delete this object, they should either make sure the reference count is +1 and then do delete my_r_ref, or decrement the reference with Py_DECREF(my_r_ref).

+ +

Should my_r_ref give up ownership by being used in an Object constructor, all will +still be well. When the Object goes out of scope its destructor will be called, and that +will decrement the reference count, which in turn will trigger the special dealloc routine +that calls the destructor and deletes the pointer.

+ +

If the object is created with automatic scope, as in:

+ +
range my_r(1, 20, 3)
+ +

then my_r can be thought of as owning the reference, and when my_r goes out of scope +the object will be destroyed. Of course, care must be taken not to have kept any permanent +reference to this object. Fortunately, in the case of an exception, the C++ exception +facility will call the destructor of my_r. Naturally, care must be taken not to end up +with a dangling reference, but such objects can be created and destroyed more efficiently +than heap-based PyObjects.

+ +

Putting it all together

+ +

The Demo directory of the distribution contains an extensive example of how to use many +of the facilities in PyCXX. It also serves as a test routine. This test is not completely +exhaustive but does excercise much of the facility.

+ +

Acknowledgment

+ +

Thank you to Geoffrey Furnish for patiently teaching me the finer points of C++ and its +template facility, and his critique of PyCXX in particular. With version 4 I welcome Barry +Scott as co-author. -- Paul Dubois

+ + + diff --git a/lib/kross/python/cxx/README.html b/lib/kross/python/cxx/README.html new file mode 100644 index 000000000..d698725a2 --- /dev/null +++ b/lib/kross/python/cxx/README.html @@ -0,0 +1,436 @@ + + + +PyCXX README + + + + + + +

PyCXX -- Python C++ Extensions Support

+ +

Installation using distutils

+ +

Windows Installation and Demo

+
    +
  1. Fetch +http://prdownloads.sourceforge.net/cxx/pycxx_5_3_1.tar.gz +
  2. Expand the archive into a directory of your choosing C:\ for example. Note: WinZip can expand .tar.gz files. +
  3. Install the PyCXX files: +
      +
    1. C:> cd \pycxx_5_3_1
      +
    2. C:\pycxx_5_3_1> python setup.py install
      +
    +
  4. Install the PyCXX Demo: +
      +
    1. C:> cd \PYCXX_5_3_1\Demo
      +
    2. C:\PYCXX_5_3_1\Demo> python setup.py install
      +
    +
  5. Run the demo: +
      +
    1. C:> python
      +
    2. >>> import CXX.example
      +
    3. >>> CXX.example.test()
      +
    4. >>> r = CXX.example.range( 11, 100, 13 )
      +
    5. >>> for i in r: print i
      +
    6. ...
      +
    + +
+ + +

Unix Installation and Demo

+

Note: distutils is not available for Python 1.5.2

+ +
    +
  1. Fetch +http://prdownloads.sourceforge.net/cxx/PyCXX-V5.3.0.tar.gz +
  2. Login as root. root access is typically needed on Unix systems to install the PyCXX files into the Python directories. +
  3. Expand the archive into a directory of your choosing ~\ for example. +
  4. Install the PyCXX files: +
      +
    1. # cd ~\PYCXX_5_3_1
      +
    2. # python setup.py install
      +
    +
  5. Install the PyCXX Demo: +
      +
    1. # cd ~\PYCXX_5_3_1\Demo
      +
    2. # python setup.py install
      +
    +
  6. Run the demo: +
      +
    1. ~ python
      +
    2. >>> import CXX.example
      +
    3. >>> CXX.example.test()
      +
    4. >>> r = CXX.example.range( 11, 100, 13 )
      +
    5. >>> for i in r: print i
      +
    6. ...
      +
    + +
+ +

Installation using Project and Makefile

+ +

If you cannot or do not wish to use the distutils methods to work with PyCXX a set +of Makefiles and Project files are provided.

+ +

Windows Installation and Demo

+

+

    +
  1. Fetch +http://prdownloads.sourceforge.net/cxx/pycxx_5_3_1.tar.gz +
  2. Expand the archive into a directory of your choosing C:\ for example. WinZip can expand .tar.gz files. +
  3. Build the example. Using Microsoft Visual C++ 6.0 load the workspace corresponsing to the version of +Python you wish the work with. +
      +
    • example_py15.dsw - Python 1.5.2 +
    • example_py20.dsw - Python 2.0 and 2.0.1 +
    • example_py21.dsw - Python 2.1 and 2.1.1 +
    • example_py22.dsw - Python 2.2 and its maintanence release +
    • example_py23.dsw - Python 2.3 and its maintanence release +
    +
  4. Run the example. (I'll assume you are testing Python 2.3) +
      +
    • cd c:\PYCXX_5_3_1\pyds23 +
    • c:\python21\python -c "import example;example.test()" +
    +
+

+

Unix Installation and Demo

+

+

    +
  1. Fetch +http://prdownloads.sourceforge.net/cxx/PyCXX-V5.3.0.tar.gz +
  2. Expand the archive into a directory of your choosing ~/ for example. +
  3. Select to makefile for your system and python version. +
      +
    • example_freebsd_py15.mak - FreeBSD Python 1.5.2 (see note below) +
    • example_freebsd_py20.mak - FreeBSD Python 2.0, 2.0.1 +
    • example_freebsd_py21.mak - FreeBSD Python 2.1, 2.1.1 +
    • example_freebsd_py22.mak - FreeBSD Python 2.2 +
    • example_linux_py15.mak - Linux Python 1.5.2 +
    • example_linux_py20.mak - Linux Python 2.0, 2.0.1 +
    • example_linux_py21.mak - Linux Python 2.1, 2.1.1 +
    • example_linux_py22.mak - Linux Python 2.2 +
    +
  4. Build the example. Use GNU make
    +$ make -f example-makefile example.so +
  5. Run the example.
    +$ make -f example-makefile test +
+

+ +

Note: The Unix version of python 1.5.2 may need to be rebuilt so that C++ is support. +If you get reports of undefined symbols like cout or cerr then its likely that python +is not compiled and linked to support C and C++.

+ +

To create a makefile for another vendors Unix follow these steps:

+
    +
  1. copy one of the example make files above. +
  2. edit the variables to match your Python installation and C++ compile needs +
  3. Proceed to build and test as above. +
+

Note: most of the makefile rules to build PyCXX and its example are contained in example_common.mak. +

+ +

Revision History

+

Version 5.3.1 (19-Jan-2005)

+

Support GCC4 and Microsoft .NET 2003 aka MSVC 7.1 + +

Version 5.3 (21-Oct-2004)

+

String object now support python string and unicode string objects. +

Fix most bugs reported on SourceForge + +

Version 5.2 (27-Nov-2003)

+

PyCXX supports Python version 2.3, 2.2, 2.1, 2.0 and 1.5.2 on Windows and Unix.

+

Fixed problems with keyword functions.

+

Improve Extension API to give access to names and docs +

Support GCC 3.

+

Added support for custom Exceptions

+

+ +

Version 5.1 (2-Aug-2001)

+

I'm using the name PyCXX for this package, CXX is far to close to a compilers name.

+ +

PyCXX supports Python version 2.2, 2.1.1, 2.1, 2.0, 2.0.1 and 1.5.2 on Windows and Unix.

+ +

New in this release:

+
    +
  • Support for the Windows Linker /DELAYLOAD feature. Enable this feature by +defining PY_WIN32_DELAYLOAD_PYTHON_DLL when compiling IndirectPythonInterface.cxx +
  • Remove "CXX/Array.hxx" and associated code - its does not belong in PyCXX +
  • Work on the docs. Mostly to clean up the HTML to allow more extensive work. +
  • Reformated the sources to a consistent style. The mix of styles and tabs sizes +was making working on the sources error prone. +
  • Added workaround to setup.py to allow GCC to compile c++ code. +
  • Added Microsoft Visual C++ 6.0 project files for 1.5, 2.0 and 2.1 builds +
  • Added Unix make files for Linux (tested on RedHat 7.1) and FreeBSD (tested on 4.3) +
  • Merged changes from Tom Malcolmson +
+ +

(July 9, 2000)

+

Renamed all header files to reflect the CXX include name space and that they are +C++ header files. +

+ + + + + + +
OldNew
#include "CXX_Config.h"#include "CXX/Config.hxx"
#include "CXX_Exception.h"#include "CXX/Exception.hxx"
#include "CXX_Extensions.h"#include "CXX/Extensions.hxx"
#include "CXX_Objects.h"#include "CXX/Objects.hxx"
+ +

Version 5 (May 18, 2000)

+

This version adds Distutils support for installation and some code cleanup.

+ +

Version 4 (October 11, 1999)

+ +

This version contains a massive revision to the part of CXX that supports creating +extension objects and extension modules. Barry Scott contributed these changes.

+ +

CXX has always consisted of two parts: the basic CXX_Objects.h and the more +experimental CXX_Extensions.h. We will describe the changes to CXX_Objects first, and then +the changes to CXX_Extensions.h.

+ +

Changes to CXX_Objects

+ +

1. Owned option eliminates need for FromAPI in most cases

+ +

Object's constructor from PyObject* and method set have a new (backward compatible) +signature:

+ +
+Object (PyObject* pyob, bool owned = false);
+void set(PyObject* pyob, bool owned = false);
+
+ +

Users may call these with owned = true if they own the reference pyob already and want +the Object instance to take over ownership.

+ +

A new inline function Object asObject(PyObject* pyob) returns Object(pyob, true); thus, +one way to construct an object from a pointer returned by the Python API is to call +asObject on it.

+ +

Previously a class FromAPI was provided to solve the problem of taking over an owned +reference. FromAPI will be eliminated in the next release. It is no longer used by CXX +itself or its demos. The new mechanism is much cleaner and more efficient.

+ +

Other classes in CXX have been given the same "owned" option on their +constructors: Int, Float, Long, Complex, SeqBase<T>, Tuple, List, Dict, Module, +Callable.

+ +

2. Namespace support in compiler assumed

+ +

Since EGCS / GCC now supports namespaces and the standard library, the need for +CXX_config.h is almost gone. We have eliminated all the macros except for one obscure one +dealing with iterator traits in the standard library.

+ +

Changes to CXX_Extensions

+ +

The changes to CXX_Extensions.h are not backward compatible. However, they simplify +coding so much that we think it is worth the disruption.

+ +

1. Creating an extension module

+ +

To create an extension module, you inherit from class ExtensionModule templated on +yourself: In the constructor, you make calls to register methods of this class with Python +as extension module methods. In this example, two methods are added (this is a simplified +form of the example in Demo/example.cxx):

+ +
class example_module : public ExtensionModule<example_module>
+{
+public:
+    example_module()
+	: ExtensionModule<example_module>( "example" )
+	{
+	add_varargs_method("sum", &example_module::ex_sum, "sum(arglist) = sum of arguments");
+	add_varargs_method("test", &example_module::ex_test, "test(arglist) runs a test suite");
+
+	initialize( "documentation for the example module" );
+	}
+
+    virtual ~example_module() {}
+
+private:
+    Object ex_sum (const Tuple &a) { ... }
+    Object ex_test( const Tuple &a) { ... }
+};
+
+ +

To initialize the extension, you just instantiate one static instance (static so it +doesn't destroy itself!):

+ +
+void initexample()
+    {
+    static example_module* example = new example_module;
+    }
+
+ +

The methods can be written to take Tuples as arguments and return Objects. If +exceptions occur they are trapped for you and a Python exception is generated. So, for +example, the implementation of ex_sum might be:

+ +
+Object ex_sum (const Tuple &a)
+    {
+        Float f(0.0);
+        for( int i = 0; i < a.length(); i++ )
+        { 
+            Float g(a[i]);
+            f = f + g;
+        }
+        return f;
+    }
+
+ +

class ExtensionModule contains methods to return itself as a Module object, or to +return its dictionary.

+ +

Creating extension objects

+ +

Creating extension objects is of course harder since you must specify how the object +behaves and give it methods. This is shown in some detail in the example range.h and range.cxx, +with the test routine rangetest.cxx, in directory Demo.

+ +

Here is a brief overview. You create a class that inherits from PythonExtension +templated upon itself. You override various methods from PythonExtension to implement +behaviors, such as getattr, sequence_item, etc. You can also add methods to the object +that are usable from Python using a similar scheme as for module methods above.

+ +

One of the consequences of inheriting from PythonExtension is that you are inheriting +from PyObject itself. So your class is-a PyObject and instances of it can be passed to the +Python C API. Note: this example uses the namespace feature of CXX. The Py:: 's are not +required if you use the namespace instead.

+ +
+class range: public Py::PythonExtension<range> {
+public:
+    ... constructors, etc.
+
+    ... methods
+    // initializer, see below
+    static void init_type();
+    // override functions from PythonExtension
+    virtual Py::Object repr();
+    virtual Py::Object getattr( const char *name );
+
+    virtual int sequence_length();
+    virtual Py::Object sequence_item( int i );
+    virtual Py::Object sequence_concat( const Py::Object &j );
+    virtual Py::Object sequence_slice( int i, int j );
+
+    // define python methods of this object
+    Py::Object amethod (const Py::Tuple& args);
+    Py::Object value (const Py::Tuple& args);
+    Py::Object assign (const Py::Tuple& args); 
+};
+
+ +

+To initialize the type you provide a static method that you can call from some module's +initializer. This method sets the name, doc string, and indicates which behaviors it +supports. It then adds the methods.

+ +
+void range::init_type()
+{
+    behaviors().name("range");
+    behaviors().doc("range objects: start, stop, step");
+    behaviors().supportRepr();
+    behaviors().supportGetattr();
+    behaviors().supportSequenceType();
+
+    add_varargs_method("amethod", &range::amethod,
+        "demonstrate how to document amethod");
+    add_varargs_method("assign", &range::assign);
+    add_varargs_method("value", &range::value);
+}
+
+ +

Version 3 (June 18, 1999)

+ +

1. CXX compiles with EGCS snapshot 19990616. EGCS requires a standard library class +random_access_iterator that is not yet available in some other compilers (such as Windows +VC6). Therefore a new switch:

+ +

STANDARD_LIBRARY_HAS_ITERATOR_TRAITS

+ +

has been added to CXX_Config.h that you may need to toggle if you get an error on the +two lines that mention random_access_iterator. The current definition is correct for VC6 +and EGCS-19990616.

+ +

2. A new constructor was added to Module to allow construction from a string containing +the module name. A test was added for this to the demo.

+ +

Version 2 (Dec. 28, 1998)

+ +

Fixed definition of extension type to match 1.5.2. This version will presumably not +compile with older versions of Python. This can be fixed by using the previous version's +definition. I did not take the time to find out what these new "flags" are for +nor put in any methods to deal with them.

+ +

Version 1

+ +

This is an experimental set of files for supporting the creation of Python extensions +in C++.

+ +

Documentation is in progress at http://xfiles.llnl.gov. +

+ +

To use CXX you use the header files in Include, such as CXX_Objects.h or +CXX_Extensions.h. You must include the sources in Src in your sources to supply parts of +the CXX classes required.

+ +

A demo is included. The Setup file in this directory compiles this demo named +"example". To try the demo, which is also a test routine, you import example and +then execute:

+ +
+example.test()
+
+ +

You can also play with the extension object whose constructor is named "range":

+ +
+s = range(1, 100, 2)
+print s[2]  # should print 5
+
+ +

Compilation with Microsoft Visual C++ 5.0 will succeed but only if you have Service +Pack 3 installed. Compilation has been known to succeed on a Unix system using KCC by +using:

+ +
+setenv CCC "KCC -x"
+
+ +

before running makethis.py.

+ +

There is also a python.cxx file for making a stand-alone Python containing this +example, as well as a similar file arraytest.cxx for testing Array.

+ +

Comments to barry@barrys-emacs.org, please.

+ +

Barry Scott

+ + diff --git a/lib/kross/python/cxx/Readme.Kross.txt b/lib/kross/python/cxx/Readme.Kross.txt new file mode 100644 index 000000000..ec00230af --- /dev/null +++ b/lib/kross/python/cxx/Readme.Kross.txt @@ -0,0 +1,16 @@ +Kross uses PyCXX 5.3.1 (http://cxx.sourceforge.net/) +to access the Python C API. + +Following patches where applied and send back to the PyCXX team. + +- Unsigned patch + http://sourceforge.net/tracker/index.php?func=detail&aid=1085205&group_id=3180&atid=303180 +- isInstance patch + http://sourceforge.net/tracker/index.php?func=detail&aid=1178048&group_id=3180&atid=303180 +- dir patch + http://sourceforge.net/tracker/index.php?func=detail&aid=1186676&group_id=3180&atid=303180 +- fixed typos + http://sourceforge.net/tracker/index.php?func=detail&aid=1266579&group_id=3180&atid=103180 + http://sourceforge.net/tracker/index.php?func=detail&aid=1293777&group_id=3180&atid=103180 + +I also changed the includes to get PyCXX compiled the way we use it. diff --git a/lib/kross/python/cxx/Version.txt b/lib/kross/python/cxx/Version.txt new file mode 100644 index 000000000..27be42b3f --- /dev/null +++ b/lib/kross/python/cxx/Version.txt @@ -0,0 +1 @@ +PyCxx 5.3.1 diff --git a/lib/kross/python/cxx/cxx_extensions.cxx b/lib/kross/python/cxx/cxx_extensions.cxx new file mode 100644 index 000000000..f9c942adf --- /dev/null +++ b/lib/kross/python/cxx/cxx_extensions.cxx @@ -0,0 +1,1287 @@ +#include "Extensions.hxx" +#include "Exception.hxx" + +#include + +namespace Py +{ + +//================================================================================ +// +// Implementation of MethodTable +// +//================================================================================ + +PyMethodDef MethodTable::method( const char* method_name, PyCFunction f, int flags, const char* doc ) + { + PyMethodDef m; + m.ml_name = const_cast( method_name ); + m.ml_meth = f; + m.ml_flags = flags; + m.ml_doc = const_cast( doc ); + return m; + } + +MethodTable::MethodTable() + { + t.push_back( method( 0, 0, 0, 0 ) ); + mt = 0; + } + +MethodTable::~MethodTable() + { + delete [] mt; + } + +void MethodTable::add( const char* method_name, PyCFunction f, const char* doc, int flag ) + { + if( !mt ) + { + t.insert( t.end()-1, method( method_name, f, flag, doc ) ); + } + else + { + throw RuntimeError( "Too late to add a module method!" ); + } + } + +PyMethodDef* MethodTable::table() + { + if( !mt ) + { + int t1size = t.size(); + mt = new PyMethodDef[t1size]; + int j = 0; + for( std::vector::iterator i = t.begin(); i != t.end(); i++ ) + { + mt[j++] = *i; + } + } + return mt; + } + +//================================================================================ +// +// Implementation of ExtensionModule +// +//================================================================================ +ExtensionModuleBase::ExtensionModuleBase( const char *name ) + : module_name( name ) + , full_module_name( __Py_PackageContext() != NULL ? std::string( __Py_PackageContext() ) : module_name ) + , method_table() + {} + +ExtensionModuleBase::~ExtensionModuleBase() + {} + +const std::string &ExtensionModuleBase::name() const + { + return module_name; + } + +const std::string &ExtensionModuleBase::fullName() const + { + return full_module_name; + } + +class ExtensionModuleBasePtr : public PythonExtension + { +public: + ExtensionModuleBasePtr( ExtensionModuleBase *_module ) + : module( _module ) + {} + virtual ~ExtensionModuleBasePtr() + {} + + ExtensionModuleBase *module; + }; + + +void ExtensionModuleBase::initialize( const char *module_doc ) + { + PyObject *module_ptr = new ExtensionModuleBasePtr( this ); + + Py_InitModule4 + ( + const_cast( module_name.c_str() ), // name + method_table.table(), // methods + const_cast( module_doc ), // docs + module_ptr, // pass to functions as "self" + PYTHON_API_VERSION // API version + ); + } + +Py::Module ExtensionModuleBase::module(void) const + { + return Module( full_module_name ); + } + +Py::Dict ExtensionModuleBase::moduleDictionary(void) const + { + return module().getDict(); + } + +//-------------------------------------------------------------------------------- + +//================================================================================ +// +// Implementation of PythonType +// +//================================================================================ + +extern "C" + { + static void standard_dealloc(PyObject* p); + // + // All the following functions redirect the call from Python + // onto the matching virtual function in PythonExtensionBase + // + static int print_handler (PyObject*, FILE *, int); + static PyObject* getattr_handler (PyObject*, char*); + static int setattr_handler (PyObject*, char*, PyObject*); + static PyObject* getattro_handler (PyObject*, PyObject*); + static int setattro_handler (PyObject*, PyObject*, PyObject*); + static int compare_handler (PyObject*, PyObject*); + static PyObject* repr_handler (PyObject*); + static PyObject* str_handler (PyObject*); + static long hash_handler (PyObject*); + static PyObject* call_handler (PyObject*, PyObject*, PyObject*); + +#if PY_VERSION_HEX < 0x02050000 + typedef int Py_ssize_t; +#endif + // Sequence methods + static Py_ssize_t sequence_length_handler(PyObject*); + static PyObject* sequence_concat_handler(PyObject*,PyObject*); + static PyObject* sequence_repeat_handler(PyObject*, Py_ssize_t); + static PyObject* sequence_item_handler(PyObject*, Py_ssize_t); + static PyObject* sequence_slice_handler(PyObject*, Py_ssize_t, Py_ssize_t); + static int sequence_ass_item_handler(PyObject*, Py_ssize_t, PyObject*); + static int sequence_ass_slice_handler(PyObject*, Py_ssize_t, Py_ssize_t, PyObject*); + // Mapping + static Py_ssize_t mapping_length_handler(PyObject*); + static PyObject* mapping_subscript_handler(PyObject*, PyObject*); + static int mapping_ass_subscript_handler(PyObject*, PyObject*, PyObject*); + + // Numeric methods + static int number_nonzero_handler (PyObject*); + static PyObject* number_negative_handler (PyObject*); + static PyObject* number_positive_handler (PyObject*); + static PyObject* number_absolute_handler (PyObject*); + static PyObject* number_invert_handler (PyObject*); + static PyObject* number_int_handler (PyObject*); + static PyObject* number_float_handler (PyObject*); + static PyObject* number_long_handler (PyObject*); + static PyObject* number_oct_handler (PyObject*); + static PyObject* number_hex_handler (PyObject*); + static PyObject* number_add_handler (PyObject*, PyObject*); + static PyObject* number_subtract_handler (PyObject*, PyObject*); + static PyObject* number_multiply_handler (PyObject*, PyObject*); + static PyObject* number_divide_handler (PyObject*, PyObject*); + static PyObject* number_remainder_handler (PyObject*, PyObject*); + static PyObject* number_divmod_handler (PyObject*, PyObject*); + static PyObject* number_lshift_handler (PyObject*, PyObject*); + static PyObject* number_rshift_handler (PyObject*, PyObject*); + static PyObject* number_and_handler (PyObject*, PyObject*); + static PyObject* number_xor_handler (PyObject*, PyObject*); + static PyObject* number_or_handler (PyObject*, PyObject*); + static PyObject* number_power_handler(PyObject*, PyObject*, PyObject*); + + // Buffer + static Py_ssize_t buffer_getreadbuffer_handler (PyObject*, Py_ssize_t, void**); + static Py_ssize_t buffer_getwritebuffer_handler (PyObject*, Py_ssize_t, void**); + static Py_ssize_t buffer_getsegcount_handler (PyObject*, Py_ssize_t*); + } + + +extern "C" void standard_dealloc( PyObject* p ) + { + PyMem_DEL( p ); + } + +void PythonType::supportSequenceType() + { + if( !sequence_table ) + { + sequence_table = new PySequenceMethods; + table->tp_as_sequence = sequence_table; + sequence_table->sq_length = sequence_length_handler; + sequence_table->sq_concat = sequence_concat_handler; + sequence_table->sq_repeat = sequence_repeat_handler; + sequence_table->sq_item = sequence_item_handler; + sequence_table->sq_slice = sequence_slice_handler; + + sequence_table->sq_ass_item = sequence_ass_item_handler; // BAS setup seperately? + sequence_table->sq_ass_slice = sequence_ass_slice_handler; // BAS setup seperately? + } + } + +void PythonType::supportMappingType() + { + if( !mapping_table ) + { + mapping_table = new PyMappingMethods; + table->tp_as_mapping = mapping_table; + mapping_table->mp_length = mapping_length_handler; + mapping_table->mp_subscript = mapping_subscript_handler; + mapping_table->mp_ass_subscript = mapping_ass_subscript_handler; // BAS setup seperately? + } + } + +void PythonType::supportNumberType() + { + if( !number_table ) + { + number_table = new PyNumberMethods; + table->tp_as_number = number_table; + number_table->nb_add = number_add_handler; + number_table->nb_subtract = number_subtract_handler; + number_table->nb_multiply = number_multiply_handler; + number_table->nb_divide = number_divide_handler; + number_table->nb_remainder = number_remainder_handler; + number_table->nb_divmod = number_divmod_handler; + number_table->nb_power = number_power_handler; + number_table->nb_negative = number_negative_handler; + number_table->nb_positive = number_positive_handler; + number_table->nb_absolute = number_absolute_handler; + number_table->nb_nonzero = number_nonzero_handler; + number_table->nb_invert = number_invert_handler; + number_table->nb_lshift = number_lshift_handler; + number_table->nb_rshift = number_rshift_handler; + number_table->nb_and = number_and_handler; + number_table->nb_xor = number_xor_handler; + number_table->nb_or = number_or_handler; + number_table->nb_coerce = 0; + number_table->nb_int = number_int_handler; + number_table->nb_long = number_long_handler; + number_table->nb_float = number_float_handler; + number_table->nb_oct = number_oct_handler; + number_table->nb_hex = number_hex_handler; + } + } + +void PythonType::supportBufferType() + { + if( !buffer_table ) + { + buffer_table = new PyBufferProcs; + table->tp_as_buffer = buffer_table; + buffer_table->bf_getreadbuffer = buffer_getreadbuffer_handler; + buffer_table->bf_getwritebuffer = buffer_getwritebuffer_handler; + buffer_table->bf_getsegcount = buffer_getsegcount_handler; + } + } + +// if you define one sequence method you must define +// all of them except the assigns + +PythonType::PythonType( size_t basic_size, int itemsize, const char *default_name ) + : table( new PyTypeObject ) + , sequence_table( NULL ) + , mapping_table( NULL ) + , number_table( NULL ) + , buffer_table( NULL ) + { + *reinterpret_cast( table ) = py_object_initializer; + table->ob_type = _Type_Type(); + table->ob_size = 0; + table->tp_name = const_cast( default_name ); + table->tp_basicsize = basic_size; + table->tp_itemsize = itemsize; + table->tp_dealloc = ( destructor ) standard_dealloc; + table->tp_print = 0; + table->tp_getattr = 0; + table->tp_setattr = 0; + table->tp_compare = 0; + table->tp_repr = 0; + table->tp_as_number = 0; + table->tp_as_sequence = 0; + table->tp_as_mapping = 0; + table->tp_hash = 0; + table->tp_call = 0; + table->tp_str = 0; + table->tp_getattro = 0; + table->tp_setattro = 0; + table->tp_as_buffer = 0; + table->tp_flags = 0L; + table->tp_doc = 0; +#if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 0) + // first use in 2.0 + table->tp_traverse = 0L; + table->tp_clear = 0L; +#else + table->tp_xxx5 = 0L; + table->tp_xxx6 = 0L; +#endif +#if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 1) + // first defined in 2.1 + table->tp_richcompare = 0L; + table->tp_weaklistoffset = 0L; +#else + table->tp_xxx7 = 0L; + table->tp_xxx8 = 0L; +#endif + +#ifdef COUNT_ALLOCS + table->tp_alloc = 0; + table->tp_free = 0; + table->tp_maxalloc = 0; + table->tp_next = 0; +#endif + } + +PythonType::~PythonType( ) + { + delete table; + delete sequence_table; + delete mapping_table; + delete number_table; + delete buffer_table; + } + +PyTypeObject* PythonType::type_object( ) const + {return table;} + +void PythonType::name( const char* nam ) + { + table->tp_name = const_cast( nam ); + } + +const char *PythonType::getName() const + { + return table->tp_name; + } + +void PythonType::doc( const char* d ) + { + table->tp_doc = const_cast( d ); + } + +const char *PythonType::getDoc() const + { + return table->tp_doc; + } + +void PythonType::dealloc( void( *f )( PyObject* )) + { + table->tp_dealloc = f; + } + +void PythonType::supportPrint() + { + table->tp_print = print_handler; + } + +void PythonType::supportGetattr() + { + table->tp_getattr = getattr_handler; + } + +void PythonType::supportSetattr() + { + table->tp_setattr = setattr_handler; + } + +void PythonType::supportGetattro() + { + table->tp_getattro = getattro_handler; + } + +void PythonType::supportSetattro() + { + table->tp_setattro = setattro_handler; + } + +void PythonType::supportCompare() + { + table->tp_compare = compare_handler; + } + +void PythonType::supportRepr() + { + table->tp_repr = repr_handler; + } + +void PythonType::supportStr() + { + table->tp_str = str_handler; + } + +void PythonType::supportHash() + { + table->tp_hash = hash_handler; + } + +void PythonType::supportCall() + { + table->tp_call = call_handler; + } + +//-------------------------------------------------------------------------------- +// +// Handlers +// +//-------------------------------------------------------------------------------- +extern "C" int print_handler( PyObject *self, FILE *fp, int flags ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return p->print( fp, flags ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" PyObject* getattr_handler( PyObject *self, char *name ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->getattr( name ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" int setattr_handler( PyObject *self, char *name, PyObject *value ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return p->setattr( name, Py::Object( value ) ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" PyObject* getattro_handler( PyObject *self, PyObject *name ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->getattro( Py::Object( name ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" int setattro_handler( PyObject *self, PyObject *name, PyObject *value ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return p->setattro( Py::Object( name ), Py::Object( value ) ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" int compare_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return p->compare( Py::Object( other ) ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" PyObject* repr_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->repr() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* str_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->str() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" long hash_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return p->hash(); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" PyObject* call_handler( PyObject *self, PyObject *args, PyObject *kw ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->call( Py::Object( args ), Py::Object( kw ) ) ); + if( kw != NULL ) + return new_reference_to( p->call( Py::Object( args ), Py::Object( kw ) ) ); + else + return new_reference_to( p->call( Py::Object( args ), Py::Object() ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + + +// Sequence methods +extern "C" Py_ssize_t sequence_length_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return p->sequence_length(); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" PyObject* sequence_concat_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->sequence_concat( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* sequence_repeat_handler( PyObject *self, Py_ssize_t count ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->sequence_repeat( count ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* sequence_item_handler( PyObject *self, Py_ssize_t index ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->sequence_item( index ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* sequence_slice_handler( PyObject *self, Py_ssize_t first, Py_ssize_t last ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->sequence_slice( first, last ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" int sequence_ass_item_handler( PyObject *self, Py_ssize_t index, PyObject *value ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return p->sequence_ass_item( index, Py::Object( value ) ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" int sequence_ass_slice_handler( PyObject *self, Py_ssize_t first, Py_ssize_t last, PyObject *value ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return p->sequence_ass_slice( first, last, Py::Object( value ) ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +// Mapping +extern "C" Py_ssize_t mapping_length_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return p->mapping_length(); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" PyObject* mapping_subscript_handler( PyObject *self, PyObject *key ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->mapping_subscript( Py::Object( key ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" int mapping_ass_subscript_handler( PyObject *self, PyObject *key, PyObject *value ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return p->mapping_ass_subscript( Py::Object( key ), Py::Object( value ) ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +// Number +extern "C" int number_nonzero_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return p->number_nonzero(); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" PyObject* number_negative_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_negative() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_positive_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_positive() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_absolute_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_absolute() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_invert_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_invert() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_int_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_int() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_float_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_float() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_long_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_long() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_oct_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_oct() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_hex_handler( PyObject *self ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_hex() ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_add_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_add( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_subtract_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_subtract( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_multiply_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_multiply( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_divide_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_divide( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_remainder_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_remainder( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_divmod_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_divmod( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_lshift_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_lshift( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_rshift_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_rshift( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_and_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_and( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_xor_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_xor( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_or_handler( PyObject *self, PyObject *other ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_or( Py::Object( other ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +extern "C" PyObject* number_power_handler( PyObject *self, PyObject *x1, PyObject *x2 ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return new_reference_to( p->number_power( Py::Object( x1 ), Py::Object( x2 ) ) ); + } + catch( Py::Exception & ) + { + return NULL; // indicate error + } + } + +// Buffer +extern "C" Py_ssize_t buffer_getreadbuffer_handler( PyObject *self, Py_ssize_t index, void **pp ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return p->buffer_getreadbuffer( index, pp ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" Py_ssize_t buffer_getwritebuffer_handler( PyObject *self, Py_ssize_t index, void **pp ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + return p->buffer_getwritebuffer( index, pp ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + +extern "C" Py_ssize_t buffer_getsegcount_handler( PyObject *self, Py_ssize_t *count ) + { + try + { + PythonExtensionBase *p = static_cast( self ); + int i_count = *count; + Py_ssize_t r = p->buffer_getsegcount( &i_count ); + *count = i_count; + return r; + } + catch( Py::Exception & ) + { + return -1; // indicate error + } + } + + +//================================================================================ +// +// Implementation of PythonExtensionBase +// +//================================================================================ +#define missing_method( method ) \ +throw RuntimeError( "Extension object does not support method " #method ); + +PythonExtensionBase::PythonExtensionBase() + { + } + +PythonExtensionBase::~PythonExtensionBase() + { + assert( ob_refcnt == 0 ); + } + +int PythonExtensionBase::print( FILE *, int ) + { missing_method( print ); return -1; } + +int PythonExtensionBase::setattr( const char*, const Py::Object & ) + { missing_method( setattr ); return -1; } + +Py::Object PythonExtensionBase::getattro( const Py::Object & ) + { missing_method( getattro ); return Py::Nothing(); } + +int PythonExtensionBase::setattro( const Py::Object &, const Py::Object & ) + { missing_method( setattro ); return -1; } + +int PythonExtensionBase::compare( const Py::Object & ) + { missing_method( compare ); return -1; } + +Py::Object PythonExtensionBase::repr() + { missing_method( repr ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::str() + { missing_method( str ); return Py::Nothing(); } + +long PythonExtensionBase::hash() + { missing_method( hash ); return -1; } + +Py::Object PythonExtensionBase::call( const Py::Object &, const Py::Object & ) + { missing_method( call ); return Py::Nothing(); } + + +// Sequence methods +int PythonExtensionBase::sequence_length() + { missing_method( sequence_length ); return -1; } + +Py::Object PythonExtensionBase::sequence_concat( const Py::Object & ) + { missing_method( sequence_concat ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::sequence_repeat( int ) + { missing_method( sequence_repeat ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::sequence_item( int ) + { missing_method( sequence_item ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::sequence_slice( int, int ) + { missing_method( sequence_slice ); return Py::Nothing(); } + +int PythonExtensionBase::sequence_ass_item( int, const Py::Object & ) + { missing_method( sequence_ass_item ); return -1; } + +int PythonExtensionBase::sequence_ass_slice( int, int, const Py::Object & ) + { missing_method( sequence_ass_slice ); return -1; } + + +// Mapping +int PythonExtensionBase::mapping_length() + { missing_method( mapping_length ); return -1; } + +Py::Object PythonExtensionBase::mapping_subscript( const Py::Object & ) + { missing_method( mapping_subscript ); return Py::Nothing(); } + +int PythonExtensionBase::mapping_ass_subscript( const Py::Object &, const Py::Object & ) + { missing_method( mapping_ass_subscript ); return -1; } + + +// Number +int PythonExtensionBase::number_nonzero() + { missing_method( number_nonzero ); return -1; } + +Py::Object PythonExtensionBase::number_negative() + { missing_method( number_negative ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_positive() + { missing_method( number_positive ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_absolute() + { missing_method( number_absolute ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_invert() + { missing_method( number_invert ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_int() + { missing_method( number_int ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_float() + { missing_method( number_float ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_long() + { missing_method( number_long ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_oct() + { missing_method( number_oct ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_hex() + { missing_method( number_hex ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_add( const Py::Object & ) + { missing_method( number_add ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_subtract( const Py::Object & ) + { missing_method( number_subtract ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_multiply( const Py::Object & ) + { missing_method( number_multiply ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_divide( const Py::Object & ) + { missing_method( number_divide ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_remainder( const Py::Object & ) + { missing_method( number_remainder ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_divmod( const Py::Object & ) + { missing_method( number_divmod ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_lshift( const Py::Object & ) + { missing_method( number_lshift ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_rshift( const Py::Object & ) + { missing_method( number_rshift ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_and( const Py::Object & ) + { missing_method( number_and ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_xor( const Py::Object & ) + { missing_method( number_xor ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_or( const Py::Object & ) + { missing_method( number_or ); return Py::Nothing(); } + +Py::Object PythonExtensionBase::number_power( const Py::Object &, const Py::Object & ) + { missing_method( number_power ); return Py::Nothing(); } + + +// Buffer +int PythonExtensionBase::buffer_getreadbuffer( int, void** ) + { missing_method( buffer_getreadbuffer ); return -1; } + +int PythonExtensionBase::buffer_getwritebuffer( int, void** ) + { missing_method( buffer_getwritebuffer ); return -1; } + +int PythonExtensionBase::buffer_getsegcount( int* ) + { missing_method( buffer_getsegcount ); return -1; } + +//-------------------------------------------------------------------------------- +// +// Method call handlers for +// PythonExtensionBase +// ExtensionModuleBase +// +//-------------------------------------------------------------------------------- + +extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords ) + { + try + { + Tuple self_and_name_tuple( _self_and_name_tuple ); + + PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); + void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); + if( self_as_void == NULL ) + return NULL; + + ExtensionModuleBase *self = static_cast( self_as_void ); + + String py_name( self_and_name_tuple[1] ); + std::string name( py_name.as_std_string() ); + + Tuple args( _args ); + if( _keywords == NULL ) + { + Dict keywords; // pass an empty dict + + Object result( self->invoke_method_keyword( name, args, keywords ) ); + return new_reference_to( result.ptr() ); + } + else + { + Dict keywords( _keywords ); + + Object result( self->invoke_method_keyword( name, args, keywords ) ); + return new_reference_to( result.ptr() ); + } + } + catch( Exception & ) + { + return 0; + } + } + +extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args ) + { + try + { + Tuple self_and_name_tuple( _self_and_name_tuple ); + + PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); + void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); + if( self_as_void == NULL ) + return NULL; + + ExtensionModuleBase *self = static_cast( self_as_void ); + + String py_name( self_and_name_tuple[1] ); + std::string name( py_name.as_std_string() ); + + Tuple args( _args ); + + Object result( self->invoke_method_varargs( name, args ) ); + + return new_reference_to( result.ptr() ); + } + catch( Exception & ) + { + return 0; + } + } + +extern "C" void do_not_dealloc( void * ) + {} + + +//-------------------------------------------------------------------------------- +// +// ExtensionExceptionType +// +//-------------------------------------------------------------------------------- +ExtensionExceptionType::ExtensionExceptionType() + : Py::Object() + { + } + +void ExtensionExceptionType::init( ExtensionModuleBase &module, const std::string& name ) + { + std::string module_name( module.fullName() ); + module_name += "."; + module_name += name; + + set( PyErr_NewException( const_cast( module_name.c_str() ), NULL, NULL ), true ); + } + +ExtensionExceptionType::~ExtensionExceptionType() + { + } + +Exception::Exception( ExtensionExceptionType &exception, const std::string& reason ) + { + PyErr_SetString (exception.ptr(), reason.c_str()); + } + + +} // end of namespace Py diff --git a/lib/kross/python/cxx/cxxextensions.c b/lib/kross/python/cxx/cxxextensions.c new file mode 100644 index 000000000..6f369b2db --- /dev/null +++ b/lib/kross/python/cxx/cxxextensions.c @@ -0,0 +1,19 @@ +/* + Copyright 1998 The Regents of the University of California. + All rights reserved. See Legal.htm for full text and disclaimer. +*/ + +#include "Python.h" +#ifdef __cplusplus +extern "C" { +#endif +PyObject py_object_initializer = {PyObject_HEAD_INIT(0)}; +#ifdef __cplusplus +} +#endif + + + + + + diff --git a/lib/kross/python/cxx/cxxsupport.cxx b/lib/kross/python/cxx/cxxsupport.cxx new file mode 100644 index 000000000..61329b604 --- /dev/null +++ b/lib/kross/python/cxx/cxxsupport.cxx @@ -0,0 +1,142 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 1998 The Regents of the University of California. +// All rights reserved. See Legal.htm for full text and disclaimer. +//---------------------------------------------------------------------------// + +#include "Objects.hxx" +namespace Py { + +Py_UNICODE unicode_null_string[1] = { 0 }; + +Type Object::type () const + { + return Type (PyObject_Type (p), true); + } + +String Object::str () const + { + return String (PyObject_Str (p), true); + } + +String Object::repr () const + { + return String (PyObject_Repr (p), true); + } + +std::string Object::as_string() const + { + return static_cast(str()); + } + +List Object::dir () const + { + return List (PyObject_Dir (p), true); + } + +bool Object::isType (const Type& t) const + { + return type ().ptr() == t.ptr(); + } + +Char::operator String() const + { + return String(ptr()); + } + +// TMM: non-member operaters for iterators - see above +// I've also made a bug fix in respect to the cxx code +// (dereffed the left.seq and right.seq comparison) +bool operator==(const Sequence::iterator& left, const Sequence::iterator& right) + { + return left.eql( right ); + } + +bool operator!=(const Sequence::iterator& left, const Sequence::iterator& right) + { + return left.neq( right ); + } + +bool operator< (const Sequence::iterator& left, const Sequence::iterator& right) + { + return left.lss( right ); + } + +bool operator> (const Sequence::iterator& left, const Sequence::iterator& right) + { + return left.gtr( right ); + } + +bool operator<=(const Sequence::iterator& left, const Sequence::iterator& right) + { + return left.leq( right ); + } + +bool operator>=(const Sequence::iterator& left, const Sequence::iterator& right) + { + return left.geq( right ); + } + +// now for const_iterator +bool operator==(const Sequence::const_iterator& left, const Sequence::const_iterator& right) + { + return left.eql( right ); + } + +bool operator!=(const Sequence::const_iterator& left, const Sequence::const_iterator& right) + { + return left.neq( right ); + } + +bool operator< (const Sequence::const_iterator& left, const Sequence::const_iterator& right) + { + return left.lss( right ); + } + +bool operator> (const Sequence::const_iterator& left, const Sequence::const_iterator& right) + { + return left.gtr( right ); + } + +bool operator<=(const Sequence::const_iterator& left, const Sequence::const_iterator& right) + { + return left.leq( right ); + } + +bool operator>=(const Sequence::const_iterator& left, const Sequence::const_iterator& right) + { + return left.geq( right ); + } + +// For mappings: +bool operator==(const Mapping::iterator& left, const Mapping::iterator& right) + { + return left.eql( right ); + } + +bool operator!=(const Mapping::iterator& left, const Mapping::iterator& right) + { + return left.neq( right ); + } + +// now for const_iterator +bool operator==(const Mapping::const_iterator& left, const Mapping::const_iterator& right) + { + return left.eql( right ); + } + +bool operator!=(const Mapping::const_iterator& left, const Mapping::const_iterator& right) + { + return left.neq( right ); + } + +// TMM: 31May'01 - Added the #ifndef so I can exclude iostreams. +#ifndef CXX_NO_IOSTREAMS +// output + +std::ostream& operator<< (std::ostream& os, const Object& ob) + { + return (os << static_cast(ob.str())); + } +#endif + +} // Py -- cgit v1.2.3