- keep the entire wrapping tool in just 3 header files (no library or code generator required) - keep the C++ code essentially independent of Python (no inheritance from PyObject or similar required)
At LLNL, we are using a home grown "bridge language" to glue the two pieces together. We too want to keep the C++ looking and acting like C++, but have the python looking and acting like python. Here's what we do in the header file (your class with some additions to show other features) class Foo { public: Foo(); Foo(int); virtual ~Foo(); virtual int foo_method(int, int); int getX(); void setX(int); }; class Bar : public Foo { public: Bar(); Bar(int,int); int getY(); void setY(int); }; class FooBar { public: FooBar(Foo&,Bar&); }; /*#!python wrapper('Foo', '#include "Foo.h"', ctor(), ctor(int), mfunc('void','foo_method(int,int)'), mfunc('void','foo_method(int,int,char*)'), attr('int','x','@->getX()','@->setX($1)',doc='an x attr'), doc='A foo is half of a foobar'), wrapper('Bar', inherit('Foo'), ctor(), ctor('int','int'), attr('int','y','@->getY()','@->setY($1)'), doc='A bar is half of a foobar'), ), wrapper('FooBar', ctor('Foo&','Bar&') ) */ We run our PYFFLE script over it to create method.cc and a foomodule.c file for the extensions.
from foo import Foo,Bar,FooBar # These are FUNCTIONS that create # the new types f = foo() print f # The default string method can be overriden <foo 0xdeadbeef> print f.x 0 f.x = 3 f.foo_method() ValueError: needs 2 or 3 arguments f.foo_method(1,2) I'm in foo_method b = Bar() b.foo_method(1,2) I'm in foo_method fb = FooBar(f,b)
----------------------------------------------- PYFFLE has other features too like building python sequence types (add a __len__ mfunc and a seq('kfsdkf','[int]', <get code>, <set code>) line to any PYFFLE wrapper), We also build and use a lot of STL containers, so we have support for vector<T> and list<T>. PYFFLE also will "build on the fly" to support type coercion. For instance, we have a class "Triplet" which is a triple of doubles. However, we don't want users to have to do things like wrapper('Take2Triples',ctor('Triplet&','Triplet&'),....)
F = Take2Triples(Triplet(1,2,3),Triplet(1,2,3))
when
F = Take2Triples((1,2,3),(1,2,3)) reads so much better!
So we have added a "contstructable" flag to PYFFLE that allows either the "correct" type to be at an argument site OR something from which the correct type can be built. This is real nice for things that take vector<int> arguments because we can arrange to allow ANY python sequence (something that supports integer __getitem__ and __len__) to be used directly
class myseq: def __init__(self,x): pass def __len__(self): return 3 def __getitem__(self,i): return 5 v = F([1,2,3,4]) w = F(range(0,100)) z = F(myseq('abc'))
instead of
v = F(vector_of_int(1,2,3,4)) w = F(vector_of_int(tuple(range(0,100))) ms = myseq('abc') z = F(vector_of_int(lambda x,i: x[i],ms,range(0,len(ms)))
Is there general interest in this? I am hoping to clean it up enough to put on the Starship Pat