From klm at python.org Tue Mar 17 03:17:05 1998
From: klm at python.org (Ken Manheimer)
Date: Mon, 16 Mar 1998 21:17:05 -0500 (EST)
Subject: [C++-SIG] Testing transition to mailman list processor
Message-ID: <199803170217.VAA11762@glyph.CNRI.Reston.Va.US>
The C++-SIG mailing list has just been migrated to mailman, a
python-based maillist management system.
All subscribers should have received a "welcome" message informing
you about how to access their membership account. In summary, the
crucial piece of information is to visit:
http://www.python.org/mailman/listinfo/objc-sig
for the introductory page. You should be able to find your account
from there. In any case, postings to the maillist itself should work
pretty much as they did before.
If you have questions, feel free to contact me or your list manager,
geoffrey furnish, furnish at lanl.gov...
Thanks!
Ken Manheimer klm at python.org 703 620-8990 x268
(orporation for National Research |nitiatives
# If you appreciate Python, consider joining the PSA! #
# . #
From ulli at egd.igd.fhg.de Thu Mar 19 14:38:14 1998
From: ulli at egd.igd.fhg.de (Ullrich Koethe)
Date: Thu, 19 Mar 1998 14:38:14 +0100
Subject: [C++-SIG] Automatic Python/C++ Wrapper
Message-ID: <35111FC6.1CFB@egd.igd.fhg.de>
Hi Everybody,
since I would like to use Python as a high level control language in a
C++ project, I'm interested in a simple way to wrap C++ objects into
Python objects. However, the existing solutions (like SWIG) seem to be
rather complicated. So I implemented an new tool 'Python', which is
inlcuded below. Unlike previous approaches, my tool makes use of
templates to automate the generation of wrapper objects. This allows to:
- 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)
Suppose, you want to wrap this function:
double foo(double, double);
To wrap it, you simply write:
pyWrapFunction(foo, foo);
where the first argument will become the Python identifier of the
function, while the second is a pointer to the C++ function. In Python,
you would call the function like this:
>>> foo(1.0, 2.0)
Likewise, a class
class Foo
{
public:
Foo();
virtual ~Foo();
virtual int foo_method(int, int);
};
is wrapped as follows:
pyWrapClass(Foo, Foo);
where the first argument is the Python class name, the second the C++
class name. Methods are wrapped similarly to functions:
pyWrapMethod(Foo, bar, &Foo::foo_method);
whith the first two arguments being the Python class and method names,
and the last a pointer to a C++ member function. To wrap constructors,
the argument list is given instead of a function pointer (pointers to
constructors do not exist in C++):
pyWrapDefaultConstructor(Foo, Foo);
We use class Foo in Python like this:
>>> x = Foo()
>>> x.foo_method(1,2);
>>> del x
Inheritance is also supported:
class Bar : public Foo
{};
pyWrapClass(Bar, Bar);
pyDeclareBaseClass(Bar, Foo);
pyWrapDefaultConstructor(Bar, Bar);
Thus, the Python class Bar is declared a subclass of the Python class
Foo - it inherits all methods and is convertible into a base object in
an expression. (This code only compiles iff the C++ class Bar is indeed
a direct or indirect subclass of the C++ class Foo). In Python, we use
Bar like this:
>>> x = Bar()
>>> x.foo_method(1,2); # inherited from Foo
>>> del x
Other features of 'Python' include support for multiple
inheritance, virtual base classes, abstract classes, translation of C++
exceptions into Python exceptions, mapping of Python tuples (up to 5
members) and (homogeneous) lists onto PyWrapperTuple and
PyWrapperArray.
The module 'cxxmodule.cxx' included in the tar file illustrates some of
these features (sorry, no documentation exists yet). I have successfully
compiled and used the module under Python 1.5, GNU g++ 2.8.0, on a UNIX
machine. The script 'test.py' is provided to test the module. The
expected output is contained in 'testout.txt'. To try:
g++ -fpic -I$PYTHON_INCLUDE -c cxxmodule.cxx -o cxxmodule.o
g++ -shared -o cxxmodule.so cxxmodule.o
python test.py >& out.txt
diff out.txt testout.txt
I hope you enjoy the package. Any comments are very welcome.
Regards, Ulli
--
_____________________________________________________________
| |
| Ullrich Koethe Fraunhofer Institute for Computer Graphics |
| Rostock |
| |
| Phone: +49-381-4024-114 Joachim-Jungius-Str. 9 |
| Fax: +49-381-4024-199 D - 18059 Rostock |
| Email: koethe at egd.igd.fhg.de Germany |
|_____________________________________________________________|
-------------- next part --------------
A non-text attachment was scrubbed...
Name: pythoncplusplus.tar.gz
Type: x-world/x-vrml
Size: 14441 bytes
Desc: not available
URL:
From patmiller at llnl.gov Thu Mar 19 17:21:00 1998
From: patmiller at llnl.gov (Patrick Miller)
Date: Thu, 19 Mar 1998 08:21:00 -0800
Subject: [C++-SIG] Automatic Python/C++ Wrapper
References: <35111FC6.1CFB@egd.igd.fhg.de>
Message-ID: <351145EC.469CC2B2@llnl.gov>
> - 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
>>> 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]', , ) line to any
PYFFLE wrapper),
We also build and use a lot of STL containers, so we have
support for vector and list.
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 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
From dubois1 at llnl.gov Thu Mar 26 18:30:11 1998
From: dubois1 at llnl.gov (Paul F. Dubois)
Date: Thu, 26 Mar 1998 09:30:11 -0800
Subject: [C++-SIG] [Announce] CXX Alpha 2
Message-ID: <001c01bd58dc$d4bdcd60$998a7380@pduboispc>
On ftp-icf.llnl.gov/pub/python/CXX-2a.zip is a Windows zip file containing
CXX Alpha 2.
CXX is a facility for writing Python extensions in C++. While I have begun
the documentation at http://xfiles.llnl.gov, I have thus far only documented
a minor fraction of the package. However, the Demo directory (which is also
the tester) contains an example of a module extension (example.cxx) and an
extension object (r.h, r.cxx, rtest.cxx). A Setup file is included at the
top level, and as with NumPy you can run makethis.py to create Windows
project files.
I have tested this package under Windows using Microsoft Visual C++ 5.0 +
Service Patch 3. It is known NOT to work without at least Service Pack 2. I
have compiled the package fairly recently using KCC on a HPUX-10 system but
it doesn't work as a dynamic package. We have used a fairly recent version
in a static application on an SGI system.
The package is known not to work with any compiler that does not support
namespaces.
In short, the package is known not to work a lot more ways than it is known
to work.
As a sampler, here is the header file definition of an extension object.
This is the most experimental part of the package at the moment. And yes,
that is not a misprint: r inherits from something templated on itself. Scott
Meyers told me he calls this the "Curiously Recusive Template Pattern" or
something like that. (The class R that follows is not necessary; it is
essentially a type-safe smart pointer to an "r" object. In this case I am
also giving the object a sequence behavior).
#ifndef __r__h
#define __r__h
#include "CXX_Extensions.h"
#include
using std::ostrstream;
using namespace CXX;
// Making an extension object
extern void init_rtype();
extern PyObject* r_new(PyObject*,PyObject*);
class r: public PythonExtension {
public:
long start;
long stop;
long step;
r(long start_, long stop_, long step_ = 1L) {
start = start_;
stop = stop_;
step = step_;
}
long length() const {
return (stop - start + 1)/step;
}
long item(int i) const {
return start + i * step;
}
r* slice(int i, int j) const {
int first = start + i * step;
int last = start + j * step;
return new r(first, last, step);
}
r* extend(int k) const {
return new r(start, stop + k, step);
}
std::string asString() const {
ostrstream s;
s << "r(" << start << ", " << stop << ", " << step << ")" <<
std::ends;
return std::string(s.str());
}
};
class R: public SeqBase {
public:
explicit R (PyObject *pyob): SeqBase(pyob) {
validate();
}
explicit R (long start, long stop, long step = 1)
:SeqBase(FromAPI(new r(start,stop, step))) {}
R(const R& other): SeqBase(*other) {
validate();
}
R& operator= (const Object& rhs) {
return (*this = *rhs);
}
R& operator= (PyObject* rhsp) {
if(ptr() == rhsp) return *this;
set(rhsp);
return *this;
}
virtual bool accepts(PyObject *pyob) {
return pyob && r::check(pyob);
}
};
#endif
And here is r.cxx that contains the connection to Python.
#include "r.h"
// Connect r objects to Python
PyObject*
r_new (PyObject* self, PyObject* args) {
try {
Tuple rargs(args);
if (rargs.length() < 2 || rargs.length() > 3) {
throw PyException_RuntimeError("Incorrect # of args to
r(start,stop [,step]).");
}
Int start(rargs[0]);
Int stop(rargs[1]);
Int step(1);
if (rargs.length() == 3) {
step = rargs[2];
}
if (long(start) > long(stop) + 1 || long(step) == 0) {
throw PyException_RuntimeError("Bad arguments to r(start,stop
[,step]).");
}
return new r(start, stop, step);
}
catch(const PyException&) {
return Py_Null;
}
}
static PyObject *
r_repr(r *robj)
{
return new_reference_to(String(robj->asString()));
}
static int
r_length(r* robj)
{
return robj->length();
}
static PyObject*
r_item(r* robj, int i)
{
return new_reference_to(Int(robj->item(i)));
}
static PyObject*
r_concat(r* robj, PyObject *j) {
Int k(j);
return robj->extend(int(k));
}
static PyObject*
r_slice(r* robj, int i, int j) {
return robj->slice(i,j);
}
static PyObject *
r_getattr(r* robj, char *name)
{
static MethodTable rmethods;
if(std::string(name) == "c") return new_reference_to(Float(300.0));
return Py_FindMethod(rmethods.table(), static_cast(robj),
name);
}
void init_rtype () {
r::methods().name("r");
r::methods().doc("r objects: start, stop, step");
r::methods().repr(r_repr);
r::methods().sequence_length(r_length);
r::methods().item(r_item);
r::methods().slice(r_slice);
r::methods().concat(r_concat);
r::methods().getattr(r_getattr);
}
And finally, here is the test routine rtest.cxx. The class
ExtensionObject is an automatically available class that is a type-safe
smart container of an "r", so that one can create something to hold an "r"
and keep the reference count right without going to the trouble of writing
something like R above. (I know, I've lost you...I'm typing the
documentation as fast as I can, sorry). The part below that where we use R
is more interesting. r::check() supplies the usual PySomething_Check you
usually have to write. Note that r inherited an operator new from
PythonExtension that calls PyObject_NEW to initialize the object, so it
is all kosher.
#include "CXX_Extensions.h"
#include "r.h"
std::string test_extension_object()
Tuple a; // just something that isn't an r...
ExtensionObject r1(FromAPI(new r(1,10,2)));
if(r::check(a)) {
std::cout << "r::check failed (1).";
}
if(!r::check(r1)) {
return "r::check failed (2).";
}
R r2(1, 10, 2);
if(r2[1] != Int(3)) {
return "R check failed. ";
}
return "ok.";
}
From dubois1 at llnl.gov Fri Mar 27 17:48:50 1998
From: dubois1 at llnl.gov (Paul F. Dubois)
Date: Fri, 27 Mar 1998 08:48:50 -0800
Subject: [C++-SIG] [Announce] CXX Alpha 2
Message-ID: <003401bd59a0$38b3f880$998a7380@pduboispc>
>
>I wanted to let you know that I have developed a Python extension
>package using the same "curiosly recursive template" pattern.
>Perhaps it is worth comparing notes?
Obviously. I'm anxious to see your code. The part I can see has some
interesting differences.
I knew that using member template functions was not going to fly except with
a few compilers. We have KCC (Kuck and Associates) on our Unix box, which is
slow to compile, quick to run, and very close to the standard. Is your
"latest SGI compiler" from SGI? If so maybe we ought to get it. My stuff
didn't work with egcs but maybe yours would. I used namespaces and lots of
the STL.
>
>There are two techniques that I used that take advantage of the
>recursive template pattern. The first is automatic management
>of reference-counted objects, so that your C++ application can use
>the objects in a reference-counted way (using smart pointers), and
>also interchange the objects with Python code. There is nothing
>too magical about this.
Well, for the basics, no. But maybe you'll like what I've done. In
particular, I have put in enough machinery that you can use STL algorithms
on Python containers. If PyObject* p points to a Python list, for example,
you can do:
List mylist(p);
sort(mylist);
for(List::iterator j = mylist.begin(); j != mylist.end(); ++j) {
do_something_to_the_element (*j);
}
Also stuff like
Dict m;
m["hello"] = "world";
>The second trick is to handle automatic
>argument conversion for member functions. This is the part that
>breaks the compiler :-).
Geoff Furnish has also worked on and off on a scheme to allow direct calling
of member functions. I didn't try to do any of that because he is working on
it. You stuff looks interestingly different. I'm sure we'd both like to
study it.
>A pass-by-value extension class looks like:
>
>class MRTest : public Scripting::ValueBase< MRTest >
>{
>public:
> MRTest( ) { }
> MRTest Create( );
>
> static void SetupScripting( )
> {
> RegisterClassName( "MRTest" );
>
> GlobalRegistry::Register( "MRTest", Create );
>
> RegisterMember( "Func0", Func0 );
> RegisterMember( "Func1", Func1 );
> RegisterMember( "Func2", Func2 );
> RegisterMember( "Func3", Func3 );
> RegisterMember( "Func4", Func4 );
> }
>
> const char * Func0( );
> int Func1( int a );
> double Func2( int a, double b );
> MRTest Func3( int a, int b, int c );
> MRTest const & Func4( double a, int b, char const * c, int d );
>};
>
>Unfortunately, I stretched the compiler a bit too far. When I start
>building real test cases, the Visual C++ 5.0sp3 compiler crashes :-).
>The lack of out-of-line templates and proper handling of template
>members of template classes also cause trouble, so that the code
>becomes very ugly. The most recent SGI compiler is great for all
>of this, but obviously doesn't do much good for Windows development.
>
>Regards,
>Garth A. Dickie
>
I hope you can pick up my distribution at
ftp-icf.llnl.gov/pub/python/CXX-2a.zip and (a) see if it works with your SGI
compiler, and (b) let me know what you think of it. I worked about 80% of
the effort on the CXX_Objects.h file; the CXX_Extensions.h I view as purely
a first attempt and I would be glad to merge with something better from you
and/or Geoff. CXX_Objects does not depend on the extension stuff.
The start of my documentation, which covers class Object at least, is at
http://xfiles.llnl.gov. The basic philosophy is that an Object owns a
reference to the PyObject* it contains.