[C++-sig] BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS with default args dumps core

2011-04-01 Thread Holger Joukl

Hi all,

I'm having trouble wrapping a very simple member function with Boost.Python
using the
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS macro, getting a segmentation fault.

I run into the problem both with Boost 1.44.0 and 1.46.1, running on
Solaris 10/Sparc
using gcc 4.5.1 and Python 2.7.1.

What's a bit strange is that I can run the offending Python code snippet
successfully
iff there is a Boost.Python induced exception raised before this code gets
invoked,
i.e. there are reproducable situations where the same code does not suffer
the segfault;
see "# test runs" below.


# wrapped class
$ cat default_arguments_class.hpp

class DefaultArgs {
 public: // member functions
int foo(int arg1=100, int arg2=10) { return arg1 - arg2; };
};


# wrapper code
$ cat default_arguments_wrap.cpp

// file default_arguments_wrap.cpp

#include 
#include "default_arguments_class.hpp"

namespace bp = boost::python;


BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(DefaultArgs_foo_overloads,
DefaultArgs::foo, 0, 2)

BOOST_PYTHON_MODULE(defaultargs)
{
bp::class_("DefaultArgs", "DefaultArgs class docstring")
.def("foo", &DefaultArgs::foo, (bp::arg("arg1")=100,
bp::arg("arg2")=10))
.def("foo_macro", &DefaultArgs::foo, DefaultArgs_foo_overloads())
.def("foo_macro_a1_a2_with_defaults", &DefaultArgs::foo,
DefaultArgs_foo_overloads((bp::arg("arg1")=100, bp::arg("arg2")=10)))
.def("foo_macro_a2", &DefaultArgs::foo,
DefaultArgs_foo_overloads((bp::arg("arg2"
;
};


# the Jamroot file
$ cat Jamroot

# get the environment variable "USER"
import os ;
local _USER = [ os.environ USER ] ;
#ECHO $(_USER) ;

local _BOOST_ROOT = /var/tmp/$(_USER)/boost_apps/boost ;
local _BOOST_VERSION = boost_1_46_1 ;
#local _BOOST_VERSION = boost_1_44_0 ;
#ECHO $(_BOOST_ROOT) ;


use-project boost : $(_BOOST_ROOT)/$(_BOOST_VERSION) ;


# Set up the project-wide requirements that everything uses the
# boost_python library from the project whose global ID is
# /boost/python.


project minimal
: requirements /boost/python//boost_python

debug:$(_BOOST_ROOT)/build/$(_BOOST_VERSION)/py2.7/stage/debug/lib

release:$(_BOOST_ROOT)/build/$(_BOOST_VERSION)/py2.7/stage/release/lib
;

python-extension defaultargs
: # sources + // Add all files here otherwise we get undefined
symbol errors like
default_arguments_wrap.cpp

: # requirements *
: # default-build *
: # usage-requirements *
;


# simple test script
$ cat test_defaultargs2.py

#!/apps/local/gcc/4.5.1/bin/python2.7

import os
import sys
import argparse

_USER=os.getenv("USER")
parser = argparse.ArgumentParser()
parser.add_argument(
'--path', type=str,
help='lib installation base path (default: %(default)s)',
default='/var/tmp/%s/boost_apps/boost/build/boost_1_44_0/py2.7/'
'minimal/gcc-4.5.1' % (_USER),)
parser.add_argument(
'--variant', type=str, default='debug',
help='lib installation path variant (default: %(default)s)')
parser.add_argument(
'--with-exception', action='store_true',
help='prepend a test with successful Boost exception')
args = parser.parse_args()


EXPATH = os.path.join(args.path, args.variant)

sys.path.insert(1, EXPATH)

try:
import defaultargs
except:
print "sys.path set correctly?", sys.path
raise


d = defaultargs.DefaultArgs()

if args.with_exception:
try:
print "d.foo_macro_a2(1, 2, 3):", d.foo_macro_a2(1, 2, 3)
except Exception, e:
print e

print "d.foo_macro_a2(arg2=60):", d.foo_macro_a2(arg2=60)

# Test run

$ ./test_defaultargs2.py
--path=/var/tmp/lb54320/boost_apps/boost/build/boost_1_44_0/py2.7/minimal/gcc-4.5.1
 --with-exception
d.foo_macro_a2(1, 2, 3): Python argument types in
DefaultArgs.foo_macro_a2(DefaultArgs, int, int, int)
did not match C++ signature:
foo_macro_a2(DefaultArgs {lvalue})
foo_macro_a2(DefaultArgs {lvalue}, int)
foo_macro_a2(DefaultArgs {lvalue}, int, int arg2)
d.foo_macro_a2(arg2=60):
Traceback (most recent call last):
  File "./test_defaultargs2.py", line 42, in 
print "d.foo_macro_a2(arg2=60):", d.foo_macro_a2(arg2=60)
Boost.Python.ArgumentError: Python argument types in
DefaultArgs.foo_macro_a2(DefaultArgs)
did not match C++ signature:
foo_macro_a2(DefaultArgs {lvalue})
foo_macro_a2(DefaultArgs {lvalue}, int)
foo_macro_a2(DefaultArgs {lvalue}, int, int arg2)

1 $ ./test_defaultargs2.py
--path=/var/tmp/lb54320/boost_apps/boost/build/boost_1_44_0/py2.7/minimal/gcc-4.5.1

Segmentation Fault (core dumped)

139  $ /apps/local/gcc/4.5.1/bin/gdb /apps/local/gcc/4.5.1/bin/python2.7 -c
core
GNU gdb (GDB) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later

This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "sparc-s

[C++-sig] BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS with default args dumps core

2011-04-01 Thread Holger Joukl

[ 2nd try due to user stupidity, please ignore if this is being delivered
twice ]

Hi all,

I'm having trouble wrapping a very simple member function with Boost.Python
using the
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS macro, getting a segmentation fault.

I run into the problem both with Boost 1.44.0 and 1.46.1, running on
Solaris 10/Sparc
using gcc 4.5.1 and Python 2.7.1.

What's a bit strange is that I can run the offending Python code snippet
successfully
iff there is a Boost.Python induced exception raised before this code gets
invoked,
i.e. there are reproducable situations where the same code does not suffer
the segfault;
see "# test runs" below.


# wrapped class
$ cat default_arguments_class.hpp

class DefaultArgs {
 public: // member functions
int foo(int arg1=100, int arg2=10) { return arg1 - arg2; };
};


# wrapper code
$ cat default_arguments_wrap.cpp

// file default_arguments_wrap.cpp

#include 
#include "default_arguments_class.hpp"

namespace bp = boost::python;


BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(DefaultArgs_foo_overloads,
DefaultArgs::foo, 0, 2)

BOOST_PYTHON_MODULE(defaultargs)
{
bp::class_("DefaultArgs", "DefaultArgs class docstring")
.def("foo", &DefaultArgs::foo, (bp::arg("arg1")=100,
bp::arg("arg2")=10))
.def("foo_macro", &DefaultArgs::foo, DefaultArgs_foo_overloads())
.def("foo_macro_a1_a2_with_defaults", &DefaultArgs::foo,
DefaultArgs_foo_overloads((bp::arg("arg1")=100, bp::arg("arg2")=10)))
.def("foo_macro_a2", &DefaultArgs::foo,
DefaultArgs_foo_overloads((bp::arg("arg2"
;
};


# the Jamroot file
$ cat Jamroot

# get the environment variable "USER"
import os ;
local _USER = [ os.environ USER ] ;
#ECHO $(_USER) ;

local _BOOST_ROOT = /var/tmp/$(_USER)/boost_apps/boost ;
local _BOOST_VERSION = boost_1_46_1 ;
#local _BOOST_VERSION = boost_1_44_0 ;
#ECHO $(_BOOST_ROOT) ;


use-project boost : $(_BOOST_ROOT)/$(_BOOST_VERSION) ;


# Set up the project-wide requirements that everything uses the
# boost_python library from the project whose global ID is
# /boost/python.


project minimal
: requirements /boost/python//boost_python

debug:$(_BOOST_ROOT)/build/$(_BOOST_VERSION)/py2.7/stage/debug/lib

release:$(_BOOST_ROOT)/build/$(_BOOST_VERSION)/py2.7/stage/release/lib
;

python-extension defaultargs
: # sources + // Add all files here otherwise we get undefined
symbol errors like
default_arguments_wrap.cpp

: # requirements *
: # default-build *
: # usage-requirements *
;


# simple test script
$ cat test_defaultargs2.py

#!/apps/local/gcc/4.5.1/bin/python2.7

import os
import sys
import argparse

_USER=os.getenv("USER")
parser = argparse.ArgumentParser()
parser.add_argument(
'--path', type=str,
help='lib installation base path (default: %(default)s)',
default='/var/tmp/%s/boost_apps/boost/build/boost_1_44_0/py2.7/'
'minimal/gcc-4.5.1' % (_USER),)
parser.add_argument(
'--variant', type=str, default='debug',
help='lib installation path variant (default: %(default)s)')
parser.add_argument(
'--with-exception', action='store_true',
help='prepend a test with successful Boost exception')
args = parser.parse_args()


EXPATH = os.path.join(args.path, args.variant)

sys.path.insert(1, EXPATH)

try:
import defaultargs
except:
print "sys.path set correctly?", sys.path
raise


d = defaultargs.DefaultArgs()

if args.with_exception:
try:
print "d.foo_macro_a2(1, 2, 3):", d.foo_macro_a2(1, 2, 3)
except Exception, e:
print e

print "d.foo_macro_a2(arg2=60):", d.foo_macro_a2(arg2=60)

# Test run

$ ./test_defaultargs2.py
--path=/var/tmp/lb54320/boost_apps/boost/build/boost_1_44_0/py2.7/minimal/gcc-4.5.1
 --with-exception
d.foo_macro_a2(1, 2, 3): Python argument types in
DefaultArgs.foo_macro_a2(DefaultArgs, int, int, int)
did not match C++ signature:
foo_macro_a2(DefaultArgs {lvalue})
foo_macro_a2(DefaultArgs {lvalue}, int)
foo_macro_a2(DefaultArgs {lvalue}, int, int arg2)
d.foo_macro_a2(arg2=60):
Traceback (most recent call last):
  File "./test_defaultargs2.py", line 42, in 
print "d.foo_macro_a2(arg2=60):", d.foo_macro_a2(arg2=60)
Boost.Python.ArgumentError: Python argument types in
DefaultArgs.foo_macro_a2(DefaultArgs)
did not match C++ signature:
foo_macro_a2(DefaultArgs {lvalue})
foo_macro_a2(DefaultArgs {lvalue}, int)
foo_macro_a2(DefaultArgs {lvalue}, int, int arg2)

1 $ ./test_defaultargs2.py
--path=/var/tmp/lb54320/boost_apps/boost/build/boost_1_44_0/py2.7/minimal/gcc-4.5.1

Segmentation Fault (core dumped)

139  $ /apps/local/gcc/4.5.1/bin/gdb /apps/local/gcc/4.5.1/bin/python2.7 -c
core
GNU gdb (GDB) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <
http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type

[C++-sig] BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS default args core dump

2011-05-09 Thread Holger Joukl

Hi,

this is basically a re-post of a problem I posted 5 weeks ago, on which
there's
been no echo whatsoever. Now, I'm unsure if this is because I posted on
April 1st,
nobody has ever seen this problem on his platform, nobody ever uses the
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS macro this way or I'm doing s.th.
blatantly
stupid.

What nags me is that I don't think I'm doing something exotic and,
moreover, that
I see different behaviour depending on execution context, i.e. run in a
script with
or without previous method call(s) vs interactive interpreter session.

I'll try to summarize the problem a bit more(see below for a link to the
original post
for reference):

I'm having trouble wrapping a very simple member function with Boost.Python
using the
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS macro, getting a segmentation fault
(sometimes
a bus error).

I run into the problem both with Boost 1.44.0 and 1.46.1, running on
Solaris 10/Sparc
using gcc 4.5.1 and Python 2.7.1.

I can reproducibly avoid the segfault and see an (expected) exception iff
the code is
 * not run in an interactive interpreter session and
 * if there is a boost-induced exception succesfully raised before the
critical call
(which I don't understand at all).

# wrapped class
// file default_arguments_class.hpp
class DefaultArgs {
 public: // member functions
int foo(int arg1=100, int arg2=10) { return arg1 - arg2; };
};

# wrapper code

// file default_arguments_wrap.cpp

#include 
#include "default_arguments_class.hpp"

namespace bp = boost::python;

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(DefaultArgs_foo_overloads,
DefaultArgs::foo, 0, 2)
BOOST_PYTHON_MODULE(defaultargs)
{
bp::class_("DefaultArgs", "DefaultArgs class docstring")
.def("foo_macro_a2", &DefaultArgs::foo,
DefaultArgs_foo_overloads((bp::arg("arg2"
;
};

# In use in interactive interpreter session:

>>> import defaultargs
>>> d = defaultargs.DefaultArgs()
>>>
>>> try:
... print "d.foo_macro_a2(1, 2, 3):", d.foo_macro_a2(1, 2, 3)
... except Exception, e:
... print e
...
d.foo_macro_a2(1, 2, 3): Python argument types in
DefaultArgs.foo_macro_a2(DefaultArgs, int, int, int)
did not match C++ signature:
foo_macro_a2(DefaultArgs {lvalue})
foo_macro_a2(DefaultArgs {lvalue}, int)
foo_macro_a2(DefaultArgs {lvalue}, int, int arg2)
>>> print "d.foo_macro_a2(arg2=60):", d.foo_macro_a2(arg2=60)
Bus Error (core dumped)

# In use within a script:
$ cat foo.py
import defaultargs
d = defaultargs.DefaultArgs()

try:
print "d.foo_macro_a2(1, 2, 3):", d.foo_macro_a2(1, 2, 3)
except Exception, e:
print e

print "d.foo_macro_a2(arg2=60):", d.foo_macro_a2(arg2=60)

$
PYTHONPATH=/var/tmp/boost_apps/boost/build/boost_1_46_1/py2.7/minimal/gcc-4.5.1
/debug/ /apps/local/gcc/4.5.1/bin/python2.7 foo.py
d.foo_macro_a2(1, 2, 3): Python argument types in
DefaultArgs.foo_macro_a2(DefaultArgs, int, int, int)
did not match C++ signature:
foo_macro_a2(DefaultArgs {lvalue})
foo_macro_a2(DefaultArgs {lvalue}, int)
foo_macro_a2(DefaultArgs {lvalue}, int, int arg2)
d.foo_macro_a2(arg2=60):
Traceback (most recent call last):
  File "/ae/data/tmp/hjoukl/foo.py", line 9, in 
print "d.foo_macro_a2(arg2=60):", d.foo_macro_a2(arg2=60)
Boost.Python.ArgumentError: Python argument types in
DefaultArgs.foo_macro_a2(DefaultArgs)
did not match C++ signature:
foo_macro_a2(DefaultArgs {lvalue})
foo_macro_a2(DefaultArgs {lvalue}, int)
foo_macro_a2(DefaultArgs {lvalue}, int, int arg2)

My original post complete with bjam etc. can be found here:
http://article.gmane.org/gmane.comp.python.c%2B%2B/15163

Holger


Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS default args core dump

2011-05-11 Thread Holger Joukl


Hi Ralf,

> You don't need the BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS macro if
> you support keyword arguments (which is usually best). It should be
> as simple as:
>
> .def("foo", &DefaultArgs::foo, (bp::arg("arg1")=100, bp::arg("arg2")=10))
>
>
> The FUNCTION_OVERLOADS macros are more or less a relict. It is
> almost always best to follow the recipe above.

I see. I had already successfully tried your proposed solution but was
curious if
I could use the macro mechanism for variable arg lists.

> General remarks: use valgrind to find sources of segmentation faults
> and bus errors; look in boost/libs/python/test for role models to
> follow (everything you see in there is certain to work).

Unfortunately, Solaris/Sparc is not supported by valgrind. Maybe I'll get
around to try
the same on Linux but for now I'll just stick to your advice.

Thanks a lot
Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


[C++-sig] py++ site down? Project moved?

2011-05-17 Thread Holger Joukl

Hi,

has py++ moved somewhere else?

This seems to be unreachable:

http://language-binding.net/pyplusplus/pyplusplus.html

Regards
Holger
Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


[C++-sig] void* (void pointer) function arguments

2011-08-15 Thread Holger Joukl

Hi,

I'm trying to wrap a C++-API that uses void* to pass around arbitrary,
application-specific stuff.

I am a bit unsure about how to work the void-pointers. A viable way seems
to wrap the original
API functions with thin wrappers that take a boost::python::object and hand
the "raw" PyObject*
into the original function:

// Expose the method as taking any bp::object and hand the "raw" PyObject
pointer to
// the void-ptr-expecting API-function
int Worker_destroy2_DestructionCallbackPtr_constVoidPtr(
Worker* worker, DestructionCallback* cb, bp::object& closure) {
return worker->destroy2(cb, closure.ptr());
}

The information available is then retrieved by some callback function
(which is pure virtual in the
API and needs to be overridden in Python). Before calling into Python I
then cast the void* back to
a PyObject*, make a boost::python::object from it and invoke the Python
override:

class DestructionCallbackWrap : public DestructionCallback, public
bp::wrapper {
virtual void callback(Worker* worker, void* closure) {
std::cout << ">>> " << __PRETTY_FUNCTION__ << std::endl;
// everything ending up here from Python side is a PyObject
bp::handle<> handle(bp::borrowed(reinterpret_cast
(closure)));
bp::object closureObj(handle);
this->get_override("callback")(bp::ptr(worker), closureObj);
std::cout << "<<< " << __PRETTY_FUNCTION__ << std::endl;
}
};

As I've tried to gather information about void* handling with boost.python
back and forth without
finding much (an FAQ entry seems to have existed once upon a time?) - is
this a sane approach?

Or is there some automagical void* or const void* handling in boost.python
that I am totally missing?

Any hint much appreciated,
Holger

P.S.:

Here's a full minimal example for reference:

// file void_ptr_cb.hpp

// API to wrap
class Worker;

class DestructionCallback {
public:
DestructionCallback() {}
virtual ~DestructionCallback() {}
virtual void callback(Worker* worker, void* closure) = 0;
};


class Worker {
public:
Worker() {}
virtual ~Worker() {}

virtual int destroy() { return 0; }
int destroy2(DestructionCallback* cb, const void* closure=NULL) {
std::cout << ">>> " << __PRETTY_FUNCTION__ << std::endl;
cb->callback(this, const_cast(closure));
std::cout << "<<< " << __PRETTY_FUNCTION__ << std::endl;
return 0;
}
private:
Worker(const Worker& worker);

};



// file wrap_void_ptr_cb.cpp

#include 
#include 
#include "void_ptr_cb.hpp"


namespace bp = boost::python;


// Helper classes needed for boost.python wrapping

class DestructionCallbackWrap : public DestructionCallback, public
bp::wrapper {
virtual void callback(Worker* worker, void* closure) {
std::cout << ">>> " << __PRETTY_FUNCTION__ << std::endl;
// everything ending up here from Python side is a PyObject
bp::handle<> handle(bp::borrowed(reinterpret_cast
(closure)));
bp::object closureObj(handle);
this->get_override("callback")(bp::ptr(worker), closureObj);
std::cout << "<<< " << __PRETTY_FUNCTION__ << std::endl;
}
};


class WorkerWrap : public Worker, public bp::wrapper {
public:
virtual int destroy() {
if (bp::override f = this->get_override("destroy"))
return f(); // *note*
return Worker::destroy();

}
int default_destroy() {
return this->Worker::destroy();
}

};


// Expose the method as taking any bp::object and hand the "raw" PyObject
pointer to
// the void-ptr-expecting API-function
int Worker_destroy2_DestructionCallbackPtr_constVoidPtr(
Worker* worker, DestructionCallback* cb, bp::object& closure) {
return worker->destroy2(cb, closure.ptr());
}


BOOST_PYTHON_MODULE(void_ptr_cb)
{
bp::class_
("DestructionCallback", bp::init<>())
.def("callback", bp::pure_virtual(&DestructionCallback::callback))
;
bp::class_("Worker")
.def("destroy", &Worker::destroy, &WorkerWrap::default_destroy)
.def("destroy2",
&Worker_destroy2_DestructionCallbackPtr_constVoidPtr, (bp::arg("cb"),
bp::arg("closure")=bp::object()))
;
};

# file Jamroot
# Run with:
# BOOST_ROOT=/var/tmp/lb54320/boost_apps/boost_1_46_1
BOOST_BUILD_PATH=/var/tmp/lb54320/boost_apps/boost_1_46_1 \
# /var/tmp/$USER/boost_apps/boost_1_46_1/bjam -d+2 toolset=gcc-4.5.1 \
#
--build-dir=/var/tmp/$USER/boost_apps/boost_1_46_1/build/py2.7/boost/1.46.1/
 cxxflags="-DDEBUG_HIGH \
# -DBOOST_PYTHON_TRACE_REGISTRY" link=shared threading=multi
variant=release void_ptr_cb
#
# get the environment variable "USER"
import os ;
local _USER = [ os.environ USER ] ;
#ECHO $(_USER) ;

local _WORKDIR = /var/tmp/$(_USER)/boost_apps ;
local _BOOST_MODULE = boost_1_46_1 ;
local _BOOST_ROOT = $(_WORKDIR)/$(_BOOST_MODULE) ;
local _BOOST_VERSION = 1.46.1 ;
#ECHO $(_BOOST_ROOT) ;


use-project boost : $(_BOOST_ROOT) ;


# Set up the project-wide requirements that everything uses the
# boost_python

Re: [C++-sig] void* (void pointer) function arguments

2011-08-16 Thread Holger Joukl
Hi Jim,

> > I am a bit unsure about how to work the void-pointers. A viable way
seems
> > to wrap the original
> > API functions with thin wrappers that take a boost::python::object and
hand
> > the "raw" PyObject*
> > into the original function:
> >
>
> I don't see anything wrong with this approach, aside from the fact that
> you have to make an explicit wrapper for all of your functions that take
> void pointers.  It might be a little less safe, but you should be able
> to make things more automatic by casting function pointers that accept a
> void* to a signature with void* replaced by PyObject*; Boost.Python does
> know how to wrap functions that take PyObject*.  For example, in the
> wrapper for your "Worker" class, you'd have:

Just tested, it works:

BOOST_PYTHON_MODULE(void_ptr_cb)
{
bp::class_
("DestructionCallback", bp::init<>())
.def("callback", bp::pure_virtual(&DestructionCallback::callback))
;
bp::class_("Worker")
.def("destroy", &Worker::destroy, &WorkerWrap::default_destroy)
.def("destroy2", (int (Worker::*)(DestructionCallback*,
PyObject*))&Worker::destroy2,
 (bp::arg("cb"), bp::arg("closure")=bp::object()))
;
};

So I could save the thin wrappers that get called from the Python side.

> I think this should do the same thing, though you may want to check that
> default arguments work as expected.  Of course this could lead to big
> problems if you pass around things that aren't in fact PyObject* as void
> pointers in the same places, though I think your solution suffers from
> this too.

Absolutely :).
The default args seem to work fine with your proposal, though.

> Good luck!

Thanks a lot and all the best

Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] Inheritance problem

2011-10-14 Thread Holger Joukl
Hi,

> currently i am facing a problem regarding inheritance with boost::python
>
> Here is a simple code snippet:
>
>
> class Base
> {
> public:
>  virtual void print() { std::cout << "hello" << std::endl; }
>
> };
>
> [...]
>
> And in python i want to have the following reslut:
>
>  >>import my_module
>  >> derived = my_module.Derived()
>  >> derived.printIt()
>
> Actually this should print "hello" but instead throws an error saying:
>
> derived.printIt()
> Boost.Python.ArgumentError: Python argument types in
> Base.printIt(Derived)
> did not match C++ signature:
>  printIt(_Base {lvalue})

Maybe I'm oversimplifying but if all you need is exposing some derived
class then
I don't see why you'd need all the BaseWrapper, self-pointer etc. stuff.

S.th. as simple as that should work:

// file cppcode.hpp

#include 

class Base
{
public:
 virtual void print() { std::cout << "hello Base" << std::endl; }

};


class Derived : public Base
{
public:
 virtual void print() { std::cout << "hello Derived" << std::endl; }


};

// only to show callback-into-python-overrides necessities
void callback(Base& base) {
base.print();
}

// file wrap.cpp

#include 
#include "cppcode.hpp"

namespace bp = boost::python;



BOOST_PYTHON_MODULE(cppcode)
{
bp::class_("Base")
.def("printIt", &Base::print)
 ;
bp::class_ >("Derived");
bp::def("callback", &callback);
};



When run:

# file test.py
import cppcode

derived = cppcode.Derived()
derived.printIt()
cppcode.callback(derived)

class PythonDerived(cppcode.Base):
def printIt(self):
print "hello PythonDerived"

pyderived = PythonDerived()
pyderived.printIt()
cppcode.callback(pyderived)

$ python2.7 -i ./test.py
hello Derived
hello Derived
hello PythonDerived
hello Base
>>>

Note that you'd need a Base wrapper class to actually make callbacks to
Python method-overrides work,
just as documented in
http://www.boost.org/doc/libs/1_47_0/libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions

Holger


Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] Inheritance problem

2011-10-14 Thread Holger Joukl
Hi,

 > Ok lets say my BaseClass has a member function called init( vector4 ):
>
> class Base
> {
> public:
>  void init( vector4 &vec ) { //doWhatEver }
>  //a lot of other functions
> };
>
> Unfortunetaly i can not expose this init function directly to python so
> i am writing a BaseWrapper

Why's that? Can't you expose vector4 to Python?


> So when i am exposing Base and Derived like:
>
>
> BOOST_PYTHON_MODULE( my_module )
> {
>
>  class_( "Base", init<>() )
>  .def("init", &BaseWrapper::_init)
>  ;
>  class_ >( "Derived", init<>() );
> }
>
> I want to have all functions for objects of Derived that are available
> in Base.
> The thing is, that e.g. ipython recognizes the functions.
> So in ipython, when i have an object of type Derived with tab completion
> i see the functions from Base.
> But when i try to call them i always get this "signature" error.

I think the problem is that the Derived class doesn't actually have any
inheritance
relationship with BaseWrapper, i.e.
Base
/   \
   / \
  /   \
BaseWrapper  Derived

So in an example like this

// file cppcode.hpp

#include 

class Base
{
protected:
int m_area;
public:
Base() : m_area(0) {}
void init(int area) {
m_area = area;
}
virtual void print() { std::cout << "hello Base " << m_area <<
std::endl; }

};


class Derived : public Base
{
public:
 virtual void print() { std::cout << "hello Derived "  << m_area <<
std::endl; }


};

// only to show callback-into-python-overrides necessities
void callback(Base& base) {
base.print();
}


// file wrap.cpp

#include 
#include "cppcode.hpp"

namespace bp = boost::python;


class BaseWrapper : public Base, public bp::wrapper
{
 public:
void _init(int x, int y) {
init(x * y);
}
};


BOOST_PYTHON_MODULE(cppcode)
{
bp::class_("Base")
.def("init", &BaseWrapper::_init)
.def("printIt", &Base::print)
 ;
bp::class_ >("Derived");
bp::def("callback", &callback);
};


#!/apps/local/gcc/4.5.1/bin/python2.7

# file test.py

import cppcode

print "---> base"
base = cppcode.Base()
base.printIt()
base.init(3, 4)
base.printIt()


print "---> derived"
derived = cppcode.Derived()
derived.printIt()
derived.init(3, 4)
derived.printIt()
cppcode.callback(derived)

class PythonDerived(cppcode.Base):
def printIt(self):
print "hello PythonDerived"

print "---> python derived"
pyderived = PythonDerived()
pyderived.printIt()
cppcode.callback(pyderived)

I run into this error when trying to call .init() on the Derived object:

$ python2.7 ./test.py
---> base
hello Base 0
hello Base 12
---> derived
hello Derived 0
Traceback (most recent call last):
  File "./test.py", line 23, in 
derived.init(3, 4)
Boost.Python.ArgumentError: Python argument types in
Base.init(Derived, int, int)
did not match C++ signature:
init(BaseWrapper {lvalue}, int, int)


Which makes sense since Derived does not inherit from BaseWrapper.

> So i do not know how to use those callback approach you suggested.
> Especially if you are using function overloading. And additionally, this
> would mean, that i have to write such a callback function for each
> function in my base class as a global function.

Never mind the callback, I might have just confused you. The callback is
only for showing
that you'd need a Wrapper class if you want to inherit in Python and be
able to call back
from C++ into Python and actually call methods overridden in Python.

> One thing i have to mention is, that it is perfectly working if i omit
> the BaseWrapper class. So if the functions of Base can be exposed
> without using a wrapper class:
> [...]
> ...works. But unfortunately not with the BaseWrapper Class :-(

Because now you don't have the problem that Derived has no inheritance
relationship with BaseWrapper.

Maybe you can just use a free function:

// file wrap.cpp

#include 
#include "cppcode.hpp"

namespace bp = boost::python;


void _init(Base& base, int x, int y) {
base.init(x * y);
}


BOOST_PYTHON_MODULE(cppcode)
{
bp::class_("Base")
.def("init", &_init)
.def("printIt", &Base::print)
 ;
bp::class_ >("Derived");
bp::def("callback", &callback);
};



# file test.py


import os
import sys


import cppcode

print "---> base"
base = cppcode.Base()
base.printIt()
base.init(3, 4)
base.printIt()


print "---> derived"
derived = cppcode.Derived()
derived.printIt()
derived.init(3, 4)
derived.printIt()
cppcode.callback(derived)

class PythonDerived(cppcode.Base):
def printIt(self):
print "hello PythonDerived"

print "---> python derived"
pyderived = PythonDerived()
pyderived.printIt()
# to make this invoke PythonDerived.printIt() you need a wrapper class
cppcode.callback(pyderived)

===>

$ python2.7 ./test.py
---> base
hello Base 0
hello Base 12
---> derived
hello Derived 0
hello Derived 12
hello Derived 12
---> python derived
hello PythonDerived
hello Base 0
>>>

Holger

Lan

[C++-sig] test if object instance is instance of extension class in C++

2012-02-23 Thread Holger Joukl

Hi,

what's the recommended way to check if an object instance is an instance of
my extension class
in C++ code?

I'm currently doing a very ugly

#define isMyExtensionClass(pyobj) (strcmp(pyobj->ob_type->tp_name,
"MyExtensionClass") == 0)

on PyObj* pyobj.

I bet there is a better way but just can't seem to find it.

Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


[C++-sig] how to override __setattr__ of an extension class

2012-02-23 Thread Holger Joukl

Hi,

I'm trying to instrument a wrapped class with  custom __setattr__
mechanics:

.def("__setattr__", &MyExtensionClass::setattr)

How can I call the base class __setattr__ from within setattr and not run
into infinite recursion?

I.e. the analogon in C++ to

>> class Foo(object):
... def __setattr__(self, attr, value):
... print "custom __setattr__"
... object.__setattr__(self, attr, value)
...
>>> foo = Foo()
>>> foo.x = 23
custom __setattr__
>>> foo.x
23
>>>

To actually write to my instance dict I currently do

PyObject* __dict__ = PyObject_GetAttrString(m_self, const_cast
("__dict__"));
PyDict_SetItemString(__dict__, name, value.ptr());

inside MyExtensionClass::setattr (where m_self is PyObj*)

Is there a better way?

On a sidenote, I initially thought I could wrap the __dict__ in bp::dict()
to
use its nice Python-like API for item assignment but this seems to always
make a copy of the __dict__.
I.e something like

bp::dict bp_dict(__dict__);
bp_dict[name] = value;

won't work.

Regards
Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] test if object instance is instance of extension class in C++

2012-02-24 Thread Holger Joukl
Stefan,

many thanks, that of course did the trick. I'm not seeing the wood for the
trees
any more, I fear.

> > what's the recommended way to check if an object instance is an
instance of
> > my extension class
> > in C++ code?
> >
> > I'm currently doing a very ugly
> >
> > #define isMyExtensionClass(pyobj) (strcmp(pyobj->ob_type->tp_name,
> > "MyExtensionClass") == 0)
> >
> > on PyObj* pyobj.
> >
> > I bet there is a better way but just can't seem to find it.
>
> bpl::extract e(pyobj);
> if (e.check()) ...
>
> Note that you may want to use a reference type as template argument to
> the boost::python::extract type, if you want to retrieve the object by
> reference instead of by value.
>
> See http://www.boost.org/doc/libs/1_40_0/libs/python/doc/v2/extract.html
> for details.

Just for the record, this is what I do now:

inline
bool isMyExtensionClass(PyObject* &pyobj) {
bp::extract extractor(pyobj);
return extractor.check();
}


inline
bool isMyExtensionClass(bp::object &obj) {
bp::extract extractor(obj);
return extractor.check();
}

Thanks again & have a nice weekend
Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] test if object instance is instance of extension class in C++

2012-02-24 Thread Holger Joukl
Hi,

> On 02/24/2012 05:44 AM, Holger Joukl wrote:
> > Just for the record, this is what I do now:
> >
> > inline
> > bool isMyExtensionClass(PyObject* &pyobj) {
> > bp::extract extractor(pyobj);
> > return extractor.check();
> > }
>
> I'm not sure why you use raw PyObject pointers in the first place. That
> should all be hidden behind bpl::object instances (which will then take
> care of the ref counting business for you).

We're porting a legacy boost.python v1-wrapped library to current
boost.python.
Some parts of its internal methods operate on raw PyObject pointers. While
we're probably going to change that for now I all I want is a running
version
and change as little as possible.

> > inline
> > bool isMyExtensionClass(bp::object &obj) {
> > bp::extract extractor(obj);
> > return extractor.check();
> > }
>
> bp::object itself has reference (smart pointer) semantics, so there is
> no need to pass objects by reference.

I see. Just out of curiosity:
If I pass by reference I do save a copy constructor call, don't I?
But I circumvent the bp::object refcount safety, though(?).
But in a type check like above this shouldn't be dangerous - right?

Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] test if object instance is instance of extension class in C++

2012-02-24 Thread Holger Joukl

> > bp::object itself has reference (smart pointer) semantics, so there is
> > no need to pass objects by reference.
> > I see. Just out of curiosity:
> > If I pass by reference I do save a copy constructor call, don't I?
>
> In principle, yes. I'm not sure how much of this the compiler would be
> able to optimize away, though.
>
> > But I circumvent the bp::object refcount safety, though(?).
>
> Well, yes, but you don't need that as C++ language semantics ensure the
> object lifetime.
>
> > But in a type check like above this shouldn't be dangerous - right?
>
> There is definitely no danger in doing this. It may just add a little
> bit of overhead (since in certain cases passing by value is cheaper than
> passing by reference, depending on the involved types and optimization
> level.

Ok, this sounds like its best to do

inline
bool isMyExtensionClass(PyObject* pyobj) {
bp::extract extractor(pyobj);
return extractor.check();
}


inline
bool isMyExtensionClass(bp::object obj) {
bp::extract extractor(obj);
return extractor.check();
}

Many thanks again Stefan,
Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] how to override __setattr__ of an extension class

2012-02-28 Thread Holger Joukl
> > To actually write to my instance dict I currently do
> >
> >  PyObject* __dict__ = PyObject_GetAttrString(m_self,
const_cast
> > ("__dict__"));
> >  PyDict_SetItemString(__dict__, name, value.ptr());
> >
> > inside MyExtensionClass::setattr (where m_self is PyObj*)
> >
> > Is there a better way?
> >
>
> Everything I can think of (e.g. extract the base class from __bases__[0]
> and call its setattr) is functionally equivalent and not any prettier.

Good to know. I'll stick to this, then.

> The trick is to do:
>
> bp::dict bp_dict = bp::extract(__dict__);
> bp_dict[name] = value;
>
> Just calling the bp::dict invokes Python's dict constructor, which does
> a copy.

...and now that you've told me what to do I've found that it's actually
documented
here:

http://www.boost.org/doc/libs/1_48_0/libs/python/doc/tutorial/doc/html/python/object.html#python.extracting_c___objects:

"[...]
The astute reader might have noticed that the extract facility in fact
solves the mutable copying problem:


dict d = extract(x.attr("__dict__"));
d["whatever"] = 3;  // modifies x.__dict__ !
[...]"


and there:



http://www.boost.org/doc/libs/1_48_0/libs/python/doc/v2/extract.html:
"[...] Because invoking a mutable python type with an argument of the same
type (e.g. list([1,2]) typically makes a copy of the argument object, this
may be the only way to access the ObjectWrapper's interface on the original
object.[...]"

Maybe that's only me but I don't think the info that gets you going here is
very obvious in the docs, more like
a casual side note. So for now I've added some info on this here:
http://wiki.python.org/moin/boost.python/extract

Many thanks
Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] how to override __setattr__ of an extension class

2012-02-28 Thread Holger Joukl
Hi,

> The docs regarding the mutable copying problem are very misleading.
> Following Python [1] and Boost [2] scripts do not produce the same
results:
>
>
> [1]
> b = a = []
> c = list(a)
> a.append("s1")
> print a.count("s1"), b.count("s1"), c.count("s1") #prints 1 1 0
>
> [2]
> list a, b, c;
> b = a;
> c = list(a);
> a.append("s1");
> list d = extract(a);
> printf("%i %i %i %i\n", a.count("s1"), b.count("s1"), c.count("s1"),
> d.count("s1")); //prints 1 1 1 1
>
> In [2] expected was 1 1 0 1 according to Pythonic behaviour (it states
> in docs that such behaviour is mimicked). This is in conflict with
> example provided in the tutorial.

Ok, so it seems behaviour is different when dealing with
boost::python::object vs
PyObject* as constructor arguments.

Using extract<> to modify mutable objects is only necessary when dealing
with PyObject*:

// boost_dict.cpp
/* build cmdline:

/apps/local/gcc/4.6.1/bin/g++ -g -Wall -R /apps/local/gcc/4.6.1/lib/
-R /var/tmp/boost/gcc/boost_1_47_0/stage/gcc-4.6.1/py2.7/boost/1.47.0/lib/
-L /var/tmp/boost/gcc/boost_1_47_0/stage/gcc-4.6.1/py2.7/boost/1.47.0/lib/
-I /var/tmp/boost/gcc/boost_1_47_0/
-I /apps/local/gcc/4.6.1/include/python2.7/  -L /apps/local/gcc/4.6.1/lib
boost_dict.cpp -lboost_python -lrt -lpython2.7
*/

#include 
#include 

namespace bp = boost::python;


int main(void) {
// otherwise we core dump
Py_Initialize();

bp::object value(1);

std::cout << "arg is bp::dict:" << std::endl;
{
bp::dict d1, d2, d3;
d2 = d1;
d3 = bp::dict(d1);
d1["k1"] = value;
bp::dict d4 = bp::extract(d1);

std::cout << d1.has_key("k1")
  << " " << d2.has_key("k1")
  << " " << d3.has_key("k1")
  << " " << d4.has_key("k1") << std::endl;
}

std::cout << std::endl;

std::cout << "arg is bp::handle<(PyObj*)" << std::endl;
{
bp::dict d1, d2, d3;

// must use a handle to feed PyObj* to bp::objects
bp::handle<> dict_pyobj_handle(d1.ptr());

// Note: no operator= for handle<>
d2 = bp::dict(dict_pyobj_handle);
d3 = bp::dict(dict_pyobj_handle);
d1["k1"] = value;
bp::dict d4 = bp::extract(d1.ptr());
std::cout << d1.has_key("k1")
  << " " << d2.has_key("k1")
  << " " << d3.has_key("k1")
  << " " << d4.has_key("k1") << std::endl;
}


Py_Finalize();
return 0;
}


$ ./a.out
arg is bp::dict:
1 1 1 1

arg is bp::handle<(PyObj*)
1 0 0 1

So I think the tutorial example (if that's what you meant?)
"
C++:


dict d(x.attr("__dict__"));  // copies x.__dict__
d['whatever'] = 3;   // modifies the copy
"


is pretty subtle, as - if I understand correctly - this


- retrieves an attribute proxy from x


- that returns the bp::object-wrapped __dict__ attribute (which copies the
original PyObject* __dict__)


- constructs d from this new bp::object (which increases the refcount but
doesn't make another copy)


and the assignment operates on this new bp::object.

Regards
Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] How to make a python function as callback of a c++ function

2012-09-03 Thread Holger Joukl
Hi,

"Cplusplus-sig" 
schrieb am 02.09.2012 17:00:38:


> I have to make a python function as callback of a c++ function.How
> to do?Where can I find some examples?? I want to use boost.python.
> I want my code look something like this: In C++ :

>  typedef void (*MyCallback_t) (CallbackInfo);
>  class MyClass
>  {...
>     void setcallback(MyCallback_t cb);
>   ...
>  }
>
> And to use it in python :

> import mylib
> class mypythonclass:
>     def myCallback(mylib_CallbackInfo):
>        
>     def mywork():
>         t = mylib.MyClass()
>         t.setcallback(self.myCallback)

A function pointer can not be wrapped in a way so that an arbitrary
python function can be used as a (callback) argument. This is due to C/C++
restrictions, see
http://www.boost.org/doc/libs/1_51_0/libs/python/doc/v2/faq.html#funcptr

Basically, a C/C++ function pointer needs to exist at compile time and
doesn't
have state while Python functions are stateful objects that come to life at
runtime.

If you have control over the C++ code you could change the signature to
take
a boost::python::object as an argument and call that, something like


//Instead of actually wrapping these...
char const * call(char const * (*func)()) {
std::cout << "--> call" << std::endl;
return (*func)();
}
char const * call_int(char const * (*func)(int), int i) {
std::cout << "--> call_int" << std::endl;
return (*func)(i);
}

// ...we expose these *instead* - note that the original call()/call_int()
aren't used at all

namespace bp = boost::python;

char const * call_wrap(bp::object &func) {
bp::object result = func();
return bp::extract(result);
}
char const * call_int_wrap(bp::object &func, int i) {
bp::object result = func(i);
return bp::extract(result);
}

BOOST_PYTHON_MODULE(func_ptr)
{
bp::def("call", &call_wrap);
bp::def("call_int", &call_int_wrap);
};


See also
http://boost.2283326.n4.nabble.com/Boost-Python-C-struct-with-a-function-pointer-td2699880.html
for some hints/discussion.

Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


[C++-sig] question on boost.python exception mechanisms

2013-03-26 Thread Holger Joukl

Hi,

I'm wrapping a C++ library that's actually just a thin wrapper around a C
lib.

Through a dispatch() method of a Dispatcher class there's an invocation of
callbacks which get implemented on the Python side, by subclassing callback
classes exposed through Boost.Python.

Now, for performing the actual dispatch the C++ library calls into the
underlying C library.

This hasn't been a problem so far as we've been targetting Solaris using
Sun/Oracle studio
compilers.

However, on Linux compiled with GCC, if an exception gets raised in the
Python callback the
program segfaults. Obviously the C part of the vendor library has not been
compiled with
(GCC-) exception support for Linux.

Unfortunately this isn't under my control and the library provider seems
not to be willing
to make the library robust against exceptions in user callback code.

So I need to keep the Boost C++ exception that "signals" the Python
exception from passing
through the C parts.

Instead of introducing some custom error/exception notification scheme I
*think* I can simply
do this:

As I need  wrapper classes for the virtual method override mechanisms
anyway I can
just ignore/suppress the exception in the callback wrapper layer and
re-throw the exception
again in the dispatcher, provided that in between we do not return to
Python and no other
call into Python is made:

I.e.

The callback wrapper simply suppresses the C++ exception "signalled" for
the Python exception:

class CallbackWrap : public Callback, public bp::wrapper {

// pure virtual so no need for default implementation
// virtual void onMsg(MsgListener* listener, Msg& msg) = 0;
virtual void onMsg(MsgListener* listener, Msg& msg) {
try {
this->get_override("onMsg")(bp::ptr(listener), boost::ref
(msg));
} catch (const bp::error_already_set& e) {
if (PyErr_Occurred()) {
// Do nothing: The Dispatcher  that invoked the callback
// MUST check if a Python error has been set and re-throw
}
}
}
};


The Dispatcher is then responsible for re-throwing, to not let the Python
exception
go undetected when returning to the Python world:

// virtual Status dispatch  ();
virtual Status dispatch() {
Status ret;
if (bp::override f = this->get_override("dispatch")) {
ret = f(); // *note*
} else {
ret = Queue::dispatch();
}
if (PyErr_Occurred()) {
// Re-throw the error that stems from the Python exception in
the dispatched callback
bp::throw_error_already_set();
}
return ret;
}


Does this sound sane?

Any hints appreciated,
Holger



Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] question on boost.python exception mechanisms

2013-04-03 Thread Holger Joukl
Hi Giuseppe,

thanks for answering and sorry for the delayed response. Easter
holidays :-)

Giuseppe Corbelli  wrote on 28.03.2013
09:37:39:

> On 26/03/2013 18:51, Holger Joukl wrote:
> >
> > Hi,
> >
> > I'm wrapping a C++ library that's actually just a thin wrapper around a
C
> > lib.
> >
> > Through a dispatch() method of a Dispatcher class there's an invocation
of
> > callbacks which get implemented on the Python side, by subclassing
callback
> > classes exposed through Boost.Python.
> >
> > Now, for performing the actual dispatch the C++ library calls into the
> > underlying C library.
> >
> > This hasn't been a problem so far as we've been targetting Solaris
using
> > Sun/Oracle studio
> > compilers.
> >
> > However, on Linux compiled with GCC, if an exception gets raised in the
> > Python callback the
> > program segfaults. Obviously the C part of the vendor library has not
been
> > compiled with
> > (GCC-) exception support for Linux.
> >
> > Unfortunately this isn't under my control and the library provider
seems
> > not to be willing
> > to make the library robust against exceptions in user callback code.
> >
> > So I need to keep the Boost C++ exception that "signals" the Python
> > exception from passing
> > through the C parts.
>
> How does the library handle callbacks? An event loop in a separate
thread? Do
> you have to explicitly call some blocking function to run the event loop?

Yes. There's a separate thread that schedules events to a queue being
dispatch in
the main loop, in the main thread.
And yes, there's a blocking call to a dispatch method with the possibility
of a
timeout or alternatively a non-blocking poll call (we make sure to properly
release & reacquire the Python GIL during blocking).

> If it's a C lib likely the callbacks are just function pointers. Being
called
> inside a C object I'd say you assumption is correct: no C++ exceptions to
be
> raised inside callbacks (the lib is gcc-compiled, it has no knowledge of
> exceptions).

Correct, the callbacks are function pointers from the C libs point of view.

> If you could recompile with g++ the exception would raise from the
> event loop,
> unless catched while calling the callback function pointer.

While I do have the C++ sources (to be able to recompile for different C++
compilers)
I don't have the C sources so I unfortunately I can't recompile the C-lib
parts with
exceptions support.
Sidenote: For Oracle/Sun Solaris Studio compilers this isn't a problem as
you basically can't
and don't need to switch the exception support of the compiler for mixing C
and C++ code
(http://www.oracle.com/technetwork/articles/servers-storage-dev/mixingcandcpluspluscode-305840.html)

> Sidenote: how does the C++ exception mechanism work under the hood? What
> happens if it's called inside a C compiled function?

Not sure if I understand your question correctly, but:
- Solaris Studio compilers: An exception raised in a C++ compiled function
that got called
from a C compiled function called from a C++ main will properly propagate
to the main caller
- GCC: An exception raised in a C++ compiled function that got called
from a C compiled function called from a C++ main will
  - segfault if the C compiled function hasn't been compiled with exception
support (-fexceptions)
  - properly propagate to the main caller if the C compiled function has
been compiled with exception support

Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] question on boost.python exception mechanisms

2013-04-08 Thread Holger Joukl
Hi,

Giuseppe Corbelli  wrote on 08.04.2013
11:29:10:

> On 03/04/2013 10:08, Holger Joukl wrote:
> > Hi Giuseppe,
> >
> > thanks for answering and sorry for the delayed response. Easter
> > holidays :-)
>
> To punish you here's another late reply.

;-)

> >>> However, on Linux compiled with GCC, if an exception gets raised in
the
> >>> Python callback the
> >>> program segfaults. Obviously the C part of the vendor library has not
> >>> been compiled with
> >>> (GCC-) exception support for Linux.
> >>>
> >>> Unfortunately this isn't under my control and the library provider
> >>> seems not to be willing
> >>> to make the library robust against exceptions in user callback code.
> >>>
> >>> So I need to keep the Boost C++ exception that "signals" the Python
> >>> exception from passing
> >>> through the C parts.
> >>
> >> How does the library handle callbacks? An event loop in a separate
> >> thread? Do you have to explicitly call some blocking function to run
the
> >> event loop?
> >
> > Yes. There's a separate thread that schedules events to a queue being
> > dispatch in the main loop, in the main thread.
> > And yes, there's a blocking call to a dispatch method with the
possibility
> > of a timeout or alternatively a non-blocking poll call (we make
> sure to properly
> > release&  reacquire the Python GIL during blocking).
> >
> >> If it's a C lib likely the callbacks are just function pointers. Being
> >> called inside a C object I'd say you assumption is correct: no C++
> >> exceptions to be
> >> raised inside callbacks (the lib is gcc-compiled, it has no knowledge
of
> >> exceptions).
> >
> > Correct, the callbacks are function pointers from the C libs point of
view.
> >
> >> If you could recompile with g++ the exception would raise from the
> >> event loop,
> >> unless catched while calling the callback function pointer.
> >
> > While I do have the C++ sources (to be able to recompile for different
C++
> > compilers)
> > I don't have the C sources so I unfortunately I can't recompile the
C-lib
> > parts with
> > exceptions support.
> > Sidenote: For Oracle/Sun Solaris Studio compilers this isn't a problem
as
> > you basically can't
> > and don't need to switch the exception support of the compiler for
mixing C
> > and C++ code
> > (http://www.oracle.com/technetwork/articles/servers-storage-dev/
> mixingcandcpluspluscode-305840.html)
>
> I have found a couple of references.
> http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html (see static-libgcc)
> http://gcc.gnu.org/wiki/Visibility

Thanks, I'll need to look into these.

> The proprietary lib is shared, right? linked to? shared? static?

Shared C lib, we compile a shared C++ lib linked to the C lib from the
vendor
C++ sources, which we shared-link the (shared) Boost.Python wrapper to.

> >> Sidenote: how does the C++ exception mechanism work under the hood?
What
> >> happens if it's called inside a C compiled function?
> >
> > Not sure if I understand your question correctly, but:
> > - Solaris Studio compilers: An exception raised in a C++ compiled
function
> > that got called
> > from a C compiled function called from a C++ main will properly
propagate
> > to the main caller
> > - GCC: An exception raised in a C++ compiled function that got called
> > from a C compiled function called from a C++ main will
> >- segfault if the C compiled function hasn't been compiled
withexception
> > support (-fexceptions)
> >- properly propagate to the main caller if the C compiled function
has
> > been compiled with exception support
>
> Well, I was thinking about ASM level :-)

No clue whatsoever.

Regards
Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] question on boost.python exception mechanisms

2013-04-10 Thread Holger Joukl
Hi,

"Cplusplus-sig" 
wrote on 09.04.2013 03:04:33:

> From: "Niall Douglas" 

> On 8 Apr 2013 at 14:11, Holger Joukl wrote:
>
> > > I have found a couple of references.
> > > http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html (see
static-libgcc)
> > > http://gcc.gnu.org/wiki/Visibility
> >
> > Thanks, I'll need to look into these.
>
> I wrote the second one. Really not sure how that helps you.

At the very least I'll definitely learn something :-)

> Look into capturing the exception before it enters the C code using
> std::exception_ptr, and then rethrowing it on reentry to C++.

In a similar approach I'm trying out I currently catch
bp::error_already_set before entering
C Code and on reentry to C++ call bp::throw_error_already_set() iff
PyErr_Occurred().
So I basically make use of Python's global-per-thread exception indicator
to "suppress"
the exception for the C code and detect the need to re-raise before
returning from C++
to Python.

I guess that will work just fine unless some non-Python related exception
creeps
in, either raised from within Boost.Python or in my custom code.

> If you don't have C++11 in your C++, Boost provides an okay partial
> implementation of C++11 exception support.

I'll look into this. This would then mean instrumenting some object with a
place
to store the caught exception to re-raise upon reentry from C to C++.
I take it this would then do much the same as my approach sketched above
but
"safer and sounder".

Thanks,
Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] question on boost.python exception mechanisms

2013-04-17 Thread Holger Joukl
Hi,

Giuseppe Corbelli  wrote on 09.04.2013
09:09:14:

> On 08/04/2013 14:11, Holger Joukl wrote:
> >> I have found a couple of references.
> >> http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html (see
static-libgcc)
> >> http://gcc.gnu.org/wiki/Visibility
> >
> > Thanks, I'll need to look into these.
> >
> >> The proprietary lib is shared, right? linked to? shared? static?
> >
> > Shared C lib, we compile a shared C++ lib linked to the C lib from the
> > vendor
> > C++ sources, which we shared-link the (shared) Boost.Python wrapper to.
>
> Quoting from the manual:
> There are several situations in which an application should use the
shared
> libgcc instead of the static version. The most common of these is when
the
> application wishes to throw and catch exceptions across different shared
> libraries. In that case, each of the libraries as well as the application

> itself should use the shared libgcc.

Both the shared libboost_python.so and the extension module I'm building
link against
the shared libgcc_s.so.

> However, if a library or main executable is supposed to throw or catch
> exceptions, you must link it using the G++ or GCJ driver, as appropriate
for
> the languages used in the program, or using the option -shared-libgcc,
such
> that it is linked with the shared libgcc.
>
> Likely the C_lib.so is not linked to libgcc_s.so. Don't know if
it'spossible
> to "extract" the objects from the shared .so. Maybe playing dirty
> with LD_PRELOAD?

While the shared lib is indeed not linked to libgcc_s.so I now don't think
this does
make any difference for the problem at hand:

Experimenting with this simple test lib:

0 $ cat dispatch.h
// File: dispatch.h

#ifdef __cplusplus
extern "C" {
#endif


typedef char const *cb_arg_t;
typedef void (*callback_func_ptr_t)(cb_arg_t);

void invoke(callback_func_ptr_t cb, cb_arg_t arg);


#ifdef __cplusplus
}
#endif



0  $ cat dispatch.c
// File: dispatch.c

#include 
#include "dispatch.h"

void invoke(callback_func_ptr_t cb, cb_arg_t arg) {
printf("--> invoke(%d, %s)\n", &(*cb), arg);
(*cb)(arg);
printf("<-- invoke(%d, %s)\n", &(*cb), arg);
}

$ cat dispatch_main.cpp
// File: dispatch_main.cpp

#include 
#include 
#include "dispatch.h"

void callback(cb_arg_t arg) {
printf("--> CPP callback(%s)\n", arg);
printf("<-- CPP callback(%s)\n", arg);
}


void callback_with_exception(cb_arg_t arg) {
printf("--> CPP exception-throwing callback(%s)\n", arg);
throw std::runtime_error("throwing up");
printf("<-- CPP exception-throwing callback(%s)\n", arg);
}


int main(void) {
std::cout << "--> CPP main" << std::endl;
cb_arg_t s = "CPP main callback argument";
invoke(&callback, s);
try {
invoke(&callback_with_exception, s);
} catch (const std::exception& exc) {
std::cout << "caught callback exception: " << exc.what() <<
std::endl;
}
std::cout << "<-- CPP main" << std::endl;
return 0;
}

I've found that:
(1) linking the C lib dynamically or statically against libgcc does not
make any difference wrt exception segfaulting.

I.e. lib compiled with
 - gcc -static-libgcc -o libdispatch.so -shared -fPIC dispatch.c:
$ ldd libdispatch.so
libc.so.1 => /lib/libc.so.1
libm.so.2 => /lib/libm.so.2
/platform/SUNW,Sun-Fire-V490/lib/libc_psr.so.1
 - gcc -o libdispatch.so -shared -fPIC dispatch.c
$ ldd libdispatch.so
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1
libc.so.1 => /lib/libc.so.1
libm.so.2 => /lib/libm.so.2
/platform/SUNW,Sun-Fire-V490/lib/libc_psr.so.1

will not make any difference when running the main program:
0 $ g++ -I. -L. -R. -ldispatch dispatch_main.cpp
0 $ ./a.out
--> CPP main
--> invoke(68316, CPP main callback argument)
--> CPP callback(CPP main callback argument)
<-- CPP callback(CPP main callback argument)
<-- invoke(68316, CPP main callback argument)
--> invoke(68372, CPP main callback argument)
--> CPP exception-throwing callback(CPP main callback argument)
terminate called after throwing an instance of 'std::runtime_error'
  what():  throwing up
Abort (core dumped)

(2) Compiling the C lib with exception support i.e. -fexceptions will make
the segfault disappear:

0 $ gcc -static-libgcc -fexceptions -o libdispatch.so -shared -fPIC
dispatch.c
0 $ ./a.out
--> CPP main
--> invoke(68720, CPP main callback argument)
--> CPP callback(CPP main callback argument)
<-- CPP callback(CPP main callback argument)
<-- invoke(68720, CPP main callback argument)
--> invoke(68776, C

Re: [C++-sig] question on boost.python exception mechanisms

2013-04-17 Thread Holger Joukl
Hi,

> From: "Niall Douglas" 
> On 10 Apr 2013 at 13:48, Holger Joukl wrote:
>
> > > If you don't have C++11 in your C++, Boost provides an okay partial
> > > implementation of C++11 exception support.

I'm currently using gcc 4.6.1 which supports the necessary features using
-std=c++0x but also Solaris Studio 12.2 which doesn't so I'd need the
Boost implementation.

> > I'll look into this. This would then mean instrumenting some object
with a
> > place
> > to store the caught exception to re-raise upon reentry from C to C++.
> > I take it this would then do much the same as my approach sketched
above
> > but
> > "safer and sounder".
>
> There is always the trick of keeping a hash table keyed on thread id
> and call function depth. In fact it could even be made lock free and
> wait free with Boost v1.53's new lock and wait free queue
> implementations.

A bit of a simplified example version using Boost's partial C++11 exception
support
would then be s.th. like:

0 $ cat dispatch_main_exception_map.cpp
// File: dispatch_main_exception_map.cpp

#include 
#include 
#include 
#include 
// header-only:
#include 
// header-only:
#include 
#include "dispatch.h"


// the global per-thread exception storage
boost::unordered_map exception_map;


void callback(cb_arg_t arg) {
std::cout << "--> CPP callback" << arg << std::endl;
std::cout << "<-- CPP callback" << arg << std::endl;
}


// this callback raises an exception
void callback_with_exception(cb_arg_t arg) {
std::cout << "--> exception-throwing CPP callback" << arg << std::endl;
throw std::runtime_error("throwing up");
std::cout << "<-- exception-throwing CPP callback" << arg << std::endl;
}


// this callback raises an exception, catches it and stores it in the
// global (thread, exception)-map
void guarded_callback_with_exception(cb_arg_t arg) {
std::cout << "--> guarded exception-throwing CPP callback" << arg <<
std::endl;
try {
throw std::runtime_error("throwing up");
} catch (...) {
std::cout << "storing exception in exception map" << std::endl;
pthread_t current_thread = pthread_self();
exception_map[current_thread] = boost::current_exception();
exception_map.erase(current_thread);
//global_exception_holder = boost::current_exception();
}
std::cout << "<-- guarded exception-throwing CPP callback" << arg <<
std::endl;
}


int main(void) {
std::cout << "--> CPP main" << std::endl;
cb_arg_t s = "CPP main callback argument";

std::cout << std::endl;
invoke(&callback, s);

std::cout << std::endl;
invoke(&guarded_callback_with_exception, s);
pthread_t current_thread = pthread_self();
if (exception_map.find(current_thread) != exception_map.end()) {
try {
std::cout << "rethrowing exception from exception map" <<
std::endl;
boost::rethrow_exception(exception_map[current_thread]);
} catch (const std::exception& exc) {
std::cout << "caught callback exception: " << exc.what() <<
std::endl;
}
}

std::cout << std::endl;
try {
invoke(&callback_with_exception, s);
} catch (const std::exception& exc) {
std::cout << "caught callback exception: " << exc.what() <<
std::endl;
}

std::cout << std::endl;
std::cout << "<-- CPP main" << std::endl;
return 0;
}

Which doesn't respect call function depth (how would I do that?)
and doesn't use a queue; I suppose you mean using the lockfree queue for
threadsafe
access to the hash table.

I think I don't even need that for my use case as I basically
- call dispatch on a Boost.Python wrapped object
- which invokes the C libs dispatcher function
- which invokes the registered callbacks (these will usually be implemented
in Python)

i.e. the same thread that produced the exception will need to handle it.

So what I have to make sure is that
- no exception can propagate back to the C lib
- I recognize an exception has happened, in the initial dispatch method in
the same
thread, to re-raise it and let Boost.Python translate it back to Python

It looks like getting at the thread ID is also not too portable. This is
something that
the simple solution of using (abusing?) the Python per-thread exception
indicator would
avoid.

Thanks for the valuable hints!

Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] question on boost.python exception mechanisms

2013-04-18 Thread Holger Joukl
Before trying out Niall's wealth of suggestions, just to fix up my own
erroneous example:

> From: Holger Joukl 
> A bit of a simplified example version using Boost's partial C++11
exception
> support
> would then be s.th. like:
>
> 0 $ cat dispatch_main_exception_map.cpp
> // File: dispatch_main_exception_map.cpp
>
> #include 
> [...]
> // this callback raises an exception, catches it and stores it in the
> // global (thread, exception)-map
> void guarded_callback_with_exception(cb_arg_t arg) {
> std::cout << "--> guarded exception-throwing CPP callback" << arg <<
> std::endl;
> try {
> throw std::runtime_error("throwing up");
> } catch (...) {
> std::cout << "storing exception in exception map" << std::endl;
> pthread_t current_thread = pthread_self();
> exception_map[current_thread] = boost::current_exception();
> exception_map.erase(current_thread);
> [...]
  ^^^
  |
This defeats the purpose, of course, and rather needs to be put where the
re-throw takes place.
Shouldn't make late additions and then overlook the missing output.

$ cat dispatch_main_exception_map.cpp
// File: dispatch_main_exception_map.cpp

#include 
#include 
#include 
#include 
// header-only:
#include 
// header-only:
#include 
#include "dispatch.h"


// the global per-thread exception storage
boost::unordered_map exception_map;


void callback(cb_arg_t arg) {
std::cout << "--> CPP callback" << arg << std::endl;
std::cout << "<-- CPP callback" << arg << std::endl;
}

// this callback raises an exception
void callback_with_exception(cb_arg_t arg) {
std::cout << "--> exception-throwing CPP callback" << arg << std::endl;
throw std::runtime_error("throwing up");
std::cout << "<-- exception-throwing CPP callback" << arg << std::endl;
}


// this callback raises an exception, catches it and stores it in the
// global (thread, exception)-map
void guarded_callback_with_exception(cb_arg_t arg) {
std::cout << "--> guarded exception-throwing CPP callback" << arg <<
std::endl;
try {
throw std::runtime_error("throwing up");
} catch (...) {
std::cout << "storing exception in exception map" << std::endl;
pthread_t current_thread = pthread_self();
exception_map[current_thread] = boost::current_exception();
}
std::cout << "<-- guarded exception-throwing CPP callback" << arg <<
std::endl;
}


int main(void) {
std::cout << "--> CPP main" << std::endl;
cb_arg_t s = "CPP main callback argument";

std::cout << std::endl;
invoke(&callback, s);

std::cout << std::endl;
invoke(&guarded_callback_with_exception, s);
pthread_t current_thread = pthread_self();
if (exception_map.find(current_thread) != exception_map.end()) {
try {
std::cout << "rethrowing exception from exception map" <<
std::endl;
boost::exception_ptr current_exception(exception_map
[current_thread]);
exception_map.erase(current_thread);
boost::rethrow_exception(current_exception);
} catch (const std::exception& exc) {
std::cout << "caught callback exception: " << exc.what() <<
std::endl;
}
}

std::cout << std::endl;
try {
invoke(&callback_with_exception, s);
} catch (const std::exception& exc) {
std::cout << "caught callback exception: " << exc.what() <<
std::endl;
}

std::cout << std::endl;
std::cout << "<-- CPP main" << std::endl;
return 0;
}
0 $ ./a.out
--> CPP main

--> invoke(136888, CPP main callback argument)
--> CPP callbackCPP main callback argument
<-- CPP callbackCPP main callback argument
<-- invoke(136888, CPP main callback argument)

--> invoke(137608, CPP main callback argument)
--> guarded exception-throwing CPP callbackCPP main callback argument
storing exception in exception map
<-- guarded exception-throwing CPP callbackCPP main callback argument
<-- invoke(137608, CPP main callback argument)
rethrowing exception from exception map
caught callback exception: throwing up

--> invoke(137112, CPP main callback argument)
--> exception-throwing CPP callbackCPP main callback argument
caught callback exception: throwing up

<-- CPP main

Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] question on boost.python exception mechanisms

2013-04-29 Thread Holger Joukl
Hi,

> From: "Niall Douglas" 
> On 17 Apr 2013 at 17:13, Holger Joukl wrote:
>
> > // the global per-thread exception storage
> > boost::unordered_map exception_map;
>
> You can't assume pthread_t is of integral type. You can a thread_t
> (from C11) I believe. You may not care on your supported platforms
> though.

I see. If it isn't an integral type I suppose I'd need to supply a custom
hash implementation to be able to use unordered_map.

> > throw std::runtime_error("throwing up");
>
> If you're going to use Boost's exception_ptr implementation, you
> really ought to throw using Boost's exception throw macro. Otherwise
> stuff become unreliable.

Right. This should then rather be

throw boost::enable_current_exception(std::runtime_error("throwing
up"));

Looks like unfortunately Boost.Python does not use this itself so a
packaged_task/future will throw unknown_exception for the deferred
invocation of a boost::python::error_already_set-throwing call.
I could work around this in my case by wrapping the original call in
try-catch and re-raise like

try {
 this->get_override("onMsg")(bp::ptr(listener), boost::ref(msg));
} catch (const bp::error_already_set& e) {
// enable support for cloning the current exception, to avoid
having
// a packaged_task/future throw an unknown_exception
boost::enable_current_exception(bp::error_already_set());
}

> > [...]
>
> If you're just going to do this, I'd suggest you save yourself some
> hassle and look into packaged_task which is a std::function combined
> with a std::future. It takes care of the exception trapping and
> management for you. Do bear in mind there is absolutely no reason you
> can't use a future within a single thread to traverse some state over
> third party binary blob code, indeed I do this in my own code at
> times e.g. if Qt, which doesn't like exceptions, stands between my
> exception throwing code at the end of a Qt signal and my code which
> called Qt.
>
> > [...]
>
> Why not using thread local storage?

Using thread local storage of a queue of deferred futures might then look
s.th. like this:

$ cat dispatch_main_packaged_task_tls_queue.cpp
// File: dispatch_main_packaged_task_tls_queue.cpp

#include 
#include 
#include 
#include 
#include  // header-only
#include   // header-only
#include   // header-only
#include 
#include "dispatch.h"


// global thread local store of void-returning task results
// (per-thread queue of futures)
class CURRENT_THREAD_STATE {
public:
typedef boost::unique_future unique_future_t;
typedef boost::shared_ptr unique_future_ptr_t;
typedef boost::lockfree::spsc_queue<
unique_future_ptr_t, boost::lockfree::capacity<10> >
future_queue_t;
typedef boost::thread_specific_ptr< future_queue_t > tls_t;

private:
// the internal per-thread futures queue storage
static tls_t _current_thread_tls;

public:
// package a task and defer it
// (to a thread-local queue of of void-returning futures)
template 
static void deferred(Fn func, A0 const & arg1) {
// need a nullary function object as an arg to packaged_task so
// use boost::bind
boost::packaged_task pt(boost::bind(func, arg1));
unique_future_t fut = pt.get_future();
future_queue_t * queue_ptr = _current_thread_tls.get();

if (queue_ptr == NULL) {
 queue_ptr = new future_queue_t;
 _current_thread_tls.reset(queue_ptr);
}

unique_future_ptr_t fut_ptr(new unique_future_t(boost::move(fut)));
queue_ptr->push(fut_ptr);
pt();
}

// retrieve the deferred task results
static void get_deferred(void) {
future_queue_t * queue_ptr = _current_thread_tls.get();
if (queue_ptr != NULL) {
unique_future_ptr_t fut_ptr;
if (queue_ptr->pop(fut_ptr)) {
if (fut_ptr) {
fut_ptr->get();
}
}
}

}
};

// don't forget the definition of the static member variable
CURRENT_THREAD_STATE::tls_t CURRENT_THREAD_STATE::_current_thread_tls;


void callback(cb_arg_t arg) {
std::cout << "--> CPP callback arg=" << arg << std::endl;
std::cout << "<-- CPP callback arg=" << arg << std::endl;
}


// this callback raises an exception
void callback_with_exception(cb_arg_t arg) {
std::cout << "--> exception-throwing CPP callback arg=" << arg <<
std::endl;
std::string errormsg("throwing up ");
errormsg += arg;
std::cout << "errormsg=" << errormsg << std::endl;
throw std::runtime_erro

Re: [C++-sig] boost python wrapping boost message queue problem

2015-01-09 Thread Holger Joukl
Hi,

> I wrapped the boost ipc message queue into Python using Boost.Python.
> Everything goes fine except I found that
>
> 1. the try_receive / try_send will block python when the mq is empty /
full.
> 2. when I use the wrapped message queue in one Python thread, any
> other Python thread would be blocked and won't execute.

I don't know about the boost ipc message queue but my guess is try_receive
(...) and
try_send(...) are blocking calls(?) and you'll need to allow Python threads
to
run while blocking.

I.e. you'd need to release Python's global interpreter lock (GIL) before
the blocking call and reacquire it when the call returns by using the
Py_BEGIN_ALLOW_THREADS / Py_END_ALLOW_THREADS macros.

Looks to me like you could do so in your message_queue class's methods,
something similar to

boost::python::str message_queue::try_receive(size_t m_size) {
  char* buffer = new char[m_size];
  bi::message_queue::size_type recvd_size;
  unsigned int priority;
  Py_BEGIN_ALLOW_THREADS;
  p_message_queue->try_receive(buffer, m_size, recvd_size, priority);
  Py_END_ALLOW_THREADS;
  return boost::python::str(buffer, m_size);
}

(fully untested code!)

Note that there might be additional intricacies with regard to waking up
the
blocking call when a message arrives in the queue and/or signal handling,
e.g. making
the program interruptible while in the blocking call.
This depends on the queue implementation and your requirements (play well
with
signal handlers registered on the Python side, )

The snippets below are samples from our wrapping of a message queue of the
commercial
messaging middleware TIB/Rendezvous - it's old code and could be improved
but works for us and might just give you an idea plus some documentation.

Hope it helps,
Holger


// file helpers/debug_config.hpp
#ifndef DEBUG_CONFIG_HPP
#define DEBUG_CONFIG_HPP

// __GNUC__ is defined for both C and C++
#if defined(__GNUC__)
#define __PRETTY_FUNCTION__ __PRETTY_FUNCTION__
#elif (defined(__SUNPRO_C) || defined(__SUNPRO_CC))
#define __PRETTY_FUNCTION__ __func__
#else
#define __PRETTY_FUNCTION__ __func__
#endif // if defined(__GNUC__)

#include 


// See proposed solution by Graham Dumpleton here for debug macros:
// http://www.velocityreviews.com/forums/t280342-debugging-macros.html
// IMHO this has 2 advantages:
// - integrates much nicer with code formatting than #ifdef DEBUG ...
#endif
// - gets compiled even if DEBUG is unset so the debug code gets checked
//   by the compiler (and optimized away, then, hopefully :)
//FIXME: Does this *really* get optimized away? For gcc (4.6.1) the unused
//FIXME: output code is left out (checked using the strings cmd), but for
//FIXME: Solaris studio i can grep the debug code in the resulting object
//FIXME: file in a simple example program... Must we care?


// DEBUG switches on all debugging output
#ifdef DEBUG
#define DEBUG_TRACE
#define DEBUG_FUNC
#define DEBUG_CTOR
#define DEBUG_DTOR
#define DEBUG_MODULES
#endif


// use these switches to switch on specific debug tracing
#ifdef DEBUG_TRACE
#define DEBUGTRACER_TRACE if (0) ; else std::cout
#define DEBUGTRACER_CONDITIONAL if (0) ; else
#else
#define DEBUGTRACER_TRACE if (1) ; else std::cout
#define DEBUGTRACER_CONDITIONAL if (1) ; else
#endif

#ifdef DEBUG_FUNC
#define DEBUGTRACER_FUNC if (0) ; else std::cout
#else
#define DEBUGTRACER_FUNC if (1) ; else std::cout
#endif

#ifdef DEBUG_CTOR
#define DEBUGTRACER_CTOR if (0) ; else std::cout
#else
#define DEBUGTRACER_CTOR if (1) ; else std::cout
#endif

#ifdef DEBUG_DTOR
#define DEBUGTRACER_DTOR if (0) ; else std::cout
#else
#define DEBUGTRACER_DTOR if (1) ; else std::cout
#endif

#ifdef DEBUG_MODULES
#define DEBUGTRACER_MODULES if (0) ; else std::cout
#else
#define DEBUGTRACER_MODULES if (1) ; else std::cout
#endif

#endif //DEBUG_CONFIG_HPP




// file tibrvqueue.hpp
// See tibrvque.cpp for extensive background documentation

#ifndef _ThreadedTibrvQueue_hpp
#define _ThreadedTibrvQueue_hpp

#include 
#include 
#include 
#include 

#include "helpers/debug_config.hpp"

class ThreadedTibrvQueue : public TibrvQueue
{
public:
ThreadedTibrvQueue();
void waitEvent();
bool waitEvent(double timeout);

TibrvStatus destroy();
TibrvStatus destroy(TibrvQueueOnComplete* completeCB, const void*
closure = NULL);

private:
static void _myHook(tibrvQueue eventQueue, void* closure);
static void sighandler(int);
static void installSignalHandlers();
static void removeSignalHandlers();
private:
pthread_cond_t m_cond;
pthread_mutex_t m_mutex;
typedef std::list instance_list;
static instance_list m_instances;
static pthread_mutex_t m_instances_mutex;
static int m_waiting;
typedef void (*sighandler_t)(int);
static sighandler_t m_sighandler[NSIG];
};

#endif



// file tibrvqueue.cpp
// ThreadedTibrvQueue: A TibrvQueue subclass to enable multithreaded python
// programs with Rendezvous
//

Re: [C++-sig] [Boost Python] Cannot call base method from within python extended class method

2015-01-13 Thread Holger Joukl
Hi,

> For ElementWrap::get_float, try:
> float get_float() { return this->get_override("get_float")(); }
>
> Binding to Python of that function should then be:
> .def("get_float", pure_virtual(&Element::get_float))
>
> See also:
> http://www.boost.org/doc/libs/1_57_0/libs/python/doc/tutorial/doc/
> html/python/exposing.html#python.class_virtual_functions
>
> With regards,
>
>  Paul

Doesn't solve this problem:

$ cat m1_py.cpp
// m1_py.cpp
#include "boost/python.hpp"
#include 
#include "m1.hpp"



class ElementWrap : public Element, public boost::python::wrapper
{
public:
// Element::get_float is pure virtual so no need for default
implementation
// if no python override found
virtual float get_float() {
boost::python::override py_override = this->get_override
("get_float");
if (!py_override) {
// want a nice error message if no Python override of the
// pure virtual method has been found
boost::python::detail::pure_virtual_called();
}
return py_override();
}
};



void set_element(Owner& owner, std::auto_ptr e)
{
owner.set_element(e.get());
e.release();
}


BOOST_PYTHON_MODULE(m1) {

boost::python::class_,
  boost::noncopyable>(
  "Element",
   boost::python::init<>())
.def("get_int", &Element::get_int)
.def("get_float", boost::python::pure_virtual(&Element::get_float))
;


boost::python::class_("Owner", boost::python::init<>())
.def("set_element", &set_element)
.def("get_element", &Owner::get_element,
boost::python::return_internal_reference<>())
;
}
0 $ cat m2.py
# m2.py

import m1

class SubElement(m1.Element):

def get_float(self):
return 4.5678 + self.get_int()

element = SubElement()
print "element:", element
owner = m1.Owner()
print "element.get_int():",
print element.get_int()
print "owner.set_element(element)..."
owner.set_element(element)
print "element:", element
try:
print "element.get_int():",
print element.get_int()
except Exception as e:
print "*** Exception caught:"
print e
print "element = owner.get_element(element)..."
element = owner.get_element()
print "element:", element

# ops!
print (element.get_float())

0 $ PYTHONPATH=./bin/gcc-4.6.1/debug/ python2.7 m2.py
element: <__main__.SubElement object at 0x7fef49783100>
element.get_int(): -1
owner.set_element(element)...
element: <__main__.SubElement object at 0x7fef49783100>
element.get_int(): *** Exception caught:
Python argument types in
Element.get_int(SubElement)
did not match C++ signature:
get_int(Element {lvalue})
element = owner.get_element(element)...
element: <__main__.SubElement object at 0x7fef49783100>
Traceback (most recent call last):
  File "m2.py", line 29, in 
print (element.get_float())
  File "m2.py", line 8, in get_float
return 4.5678 + self.get_int()
Boost.Python.ArgumentError: Python argument types in
Element.get_int(SubElement)
did not match C++ signature:
get_int(Element {lvalue})


We don't even get to the code to invoke a Python override here.

Note how after owner.set_element() the SubElement instance becomes
"inoperational".

I don't quite understand the boost.python inner workings but the call to
void set_element(Owner& owner, std::auto_ptr e)
transfers ownership to the local auto_ptr e, so the auto_ptr held from
the Python side gets modified (released ownership, now pointing to null).

Much the same result as with the original implementation (although I seem
to get the same object id for the get_element() return value here but that
might be coincidence).

Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
https://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] [Boost Python] Cannot call base method from within python extended class method

2015-01-13 Thread Holger Joukl
> > > For ElementWrap::get_float, try:
> > > float get_float() { return this->get_override("get_float")(); }
> > >
> > > Binding to Python of that function should then be:
> > > .def("get_float", pure_virtual(&Element::get_float))
> > >
> > > See also:
> > > http://www.boost.org/doc/libs/1_57_0/libs/python/doc/tutorial/doc/
> > > html/python/exposing.html#python.class_virtual_functions
> > >
> > > With regards,
> > >
> > >  Paul
> >
> > Doesn't solve this problem:
>
> I confirm what Holger said. Paul's reply doesn't solve the problem.
> In fact, if I change the ElementWrap::get_float to:
> virtual float get_float() { return this->get_override("get_float")(); }
>
> I get in python:
> Traceback (most recent call last):
>   File "m2.py", line 18, in 
> print (element.get_float())
> TypeError: 'NoneType' object is not callable

Is your element object actually a SubElement instance or a m1.Element
instance here?
You should normally get this only when calling the get_float method of an
m1.Element
instance. This is basically a call to a pure virtual method which is really
only
possible because the original C++ element class is represented to Python by
the derived ElementWrap class, which overrides the pure virtual to make
callbacks from C++ to Python possible.

I put the
boost::python::detail::pure_virtual_called();
line into my example code to have a nicer error message for this case.

No step closer to solving your actual problem, though...

Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
https://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] Wrapping virtual method returning void

2015-02-22 Thread Holger Joukl

Hi,

not boost.python- but C/C++ syntax-related.
You never reach the Base class call in your wrapper class:

 > struct SongWrapper :  Song, bp::wrapper
> {
> void chorus()
> {
> if (bp::override chorus = this->get_override("chorus"))
> chorus();
> return;< Called unconditionally
> Song::chorus();
> return;
> }
>
> void default_chorus(){  this->Song::chorus(); }
> };

I suggest using proper {} brackets and indentation with if-else constructs
for readability.

Your int-returning member function doesn't suffer from this problem:

>
> struct AnotherSongWrapper :  AnotherSong, bp::wrapper
> {
> int chorus()
> {
> if (bp::override chorus = this->get_override("chorus"))
> return chorus();
> return AnotherSong::chorus();
> }
>
> int default_chorus()   {  return this->AnotherSong::chorus(); }
> };

Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
https://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] Subclassing C++ classes in Python

2015-03-16 Thread Holger Joukl

Hi Ernie,

>   When I tries to use class exposed as ’wrapper’ as substitute for C
> ++ original class i am getting a segfault error (see example below).
> Is there is something wrong with a way i create a wrapper-class or
> it is not intended to work as substitute for a base class?

I haven't tried your code sample but you'd normally just expose the
wrapper class *instead* of the original class, with the name of "A".

Python users don't need to know about the wrapper class intricacies.

If you expose a non-pure-virtual method you should also add the
default implementation, just as you cited from
http://www.boost.org/doc/libs/1_57_0/libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions
(necessary to avoid infinite recursion if your Python override
implementation calls the
C++ base class method)

I.e. something like (untested! Stick closely to the tutorial if in doubt)

#include 
#include 

class A
{
public:
virtual ~A() { std::cout << "A destructor for object: " << this <<
   std::endl; }

virtual void info() { std::cout << "C++ A info for object" << this
<< std::endl; }
};


struct A_Wrapper : A, boost::python::wrapper
{
void info(
{
if (override info_override = this->get_override("info")) {
return info_override();
}
return A::info();
}

void default_info() { return this->A::info(); }
};


BOOST_PYTHON_MODULE(subclass)
{
boost::python::class_("A",
    boost::python::init <>() )
   .def("info", &A::info, &A_Wrapper::default_info)
;
}

So the wrapper class provides you with the callback-ability to Python and
this is the one to expose.

As per the segfault you get: I guess that this might stem from your not
calling the boost::python::wrapper base class constructor in your
A_Wapper
constructor (note how I didn't provide a constructor for the wrapper
class):

A_Wrapper() : A() {} // <-- not calling all base constructors here

Again, haven't actually tried it.

Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart
___
Cplusplus-sig mailing list
[email protected]
https://mail.python.org/mailman/listinfo/cplusplus-sig

Re: [C++-sig] Boost python exposing abstract class , function returning boost::shared_ptr

2015-03-27 Thread Holger Joukl
Hi,

> [...]
>  // expose to python
> BOOST_PYTHON_MODULE(grids)
>  {
> class_ , boost::noncopyable >("A2")
>.def("ret",pure_virtual(&A2::ret));
>
> class_,bases>("B2");
> def("f1",f1);
>  }
>
>
> I get the following result on execution :
>
> >import grids
> >>> a = grids.f1()
>
> Traceback (most recent call last):
>
> File "", line 1, in 
> TypeError: No to_python (by-value) converter found for C++ type:
> boost::shared_ptr

What happens if you expose like this:

 class_ , boost::noncopyable >("A2")
^^
|- original class here, not the callback-wrapper class

?

Holger


Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
https://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] Boost python exposing abstract class , function returning boost::shared_ptr

2015-03-30 Thread Holger Joukl
Hi,

> Thank you for the reply.
> It compiles but same error on execution.

If I change the A2 exposure to

bp::class_, boost::noncopyable>("A2",
bp::no_init)
...

then f1() successfully returns a B2 object. But of course we then lose
the Python-callback abilities provided by the wrapper class.

Looking into the Boost.Python tests i stumbled across shared_ptr.cpp
which contains:
...
// This is the ugliness required to register a to-python converter
// for shared_ptr.
objects::class_value_wrapper<
shared_ptr
  , objects::make_ptr_instance,A> >
>();
...


So, giving this a try - looks like the following seems to be a working
version for your sample
(note that I changed the extension module name to shared_ptr_hierarchy
in my code):


C++ (wrapper) code:
==

#include 

namespace bp = boost::python;


struct A2
{
virtual ~A2(){}
virtual int ret() =0;
};


struct B2: public A2
{
virtual ~B2(){}
int ret() { return 1; }
};


// wrapper
struct  A2Wrap : A2, bp::wrapper
{
inline int ret()
{
return this->get_override("ret")();
}
};


// To the best of my knowledge we need to add callback support
// through a wrapper class at every level of the hierarchy, so
// a bit of code duplication going on. This is due to the fact
// that B2 has no inheritance relation whatsoever to A2Wrap.
// I haven't so far found an elegant/short solution for this
// (e.g. using templates or macros)
struct  B2Wrap : B2, bp::wrapper
{
inline int ret()
{
if (bp::override py_override = this->get_override("ret")) {
return py_override();
}
return B2::ret();
}

inline int default_ret()
{
return B2::ret();
}
};


// function to map
boost::shared_ptr f1()
{
return  boost::shared_ptr(new B2());
}


// invoke overridden virtual from C++ side (check callback-ability)
int invoke_ret(A2 & a2)
{
return a2.ret();
}


// expose to python
BOOST_PYTHON_MODULE(shared_ptr_hierarchy)
{

bp::class_, boost::noncopyable>("A2")
.def("ret", bp::pure_virtual(&A2::ret))
;

// taken from boost.python libs/python/test/shared_ptr.cpp:
// This is the ugliness required to register a to-python converter
// for shared_ptr.
bp::objects::class_value_wrapper<
boost::shared_ptr
  , bp::objects::make_ptr_instance,A2> >
>();

bp::class_, bp::bases,
boost::noncopyable >("B2")
.def("ret", &B2::ret, &B2Wrap::default_ret)
;

bp::def("f1", f1);

bp::def("invoke_ret", &invoke_ret, (bp::arg("a2")));
}


Python test code:
=

import shared_ptr_hierarchy


class PyB2(shared_ptr_hierarchy.A2):
def ret(self):
print "PyB2 Python class", self
return 5

class PyC2(shared_ptr_hierarchy.B2):
def ret(self):
print "PyC2 Python class", self
return 6


def invoke(factory):
print "\nfactory:", factory
obj = factory()
print "obj =", obj
print "obj.ret() ->", obj.ret()
if hasattr(shared_ptr_hierarchy, 'invoke_ret'):
print "shared_ptr_hierarchy.invoke_ret(obj) ->", \
  shared_ptr_hierarchy.invoke_ret(obj)

try:
invoke(shared_ptr_hierarchy.A2)
except Exception as e:
print "Exception:", e
invoke(shared_ptr_hierarchy.B2)
invoke(shared_ptr_hierarchy.f1)
invoke(PyB2)
invoke(PyC2)


Test code output:
=

factory: 
obj = 
obj.ret() -> Exception: Pure virtual function called

factory: 
obj = 
obj.ret() -> 1
shared_ptr_hierarchy.invoke_ret(obj) -> 1

factory: 
obj = 
obj.ret() -> 1
shared_ptr_hierarchy.invoke_ret(obj) -> 1

factory: 
obj = <__main__.PyB2 object at 0x17cb628>
obj.ret() -> PyB2 Python class <__main__.PyB2 object at 0x17cb628>
5
shared_ptr_hierarchy.invoke_ret(obj) -> PyB2 Python class <__main__.PyB2
object at 0x17cb628>
5

factory: 
obj = <__main__.PyC2 object at 0x17cb628>
obj.ret() -> PyC2 Python class <__main__.PyC2 object at 0x17cb628>
6
shared_ptr_hierarchy.invoke_ret(obj) -> PyC2 Python class <__main__.PyC2
object at 0x17cb628>
6


I can't really say that I understand why that's needed, but alas...

Open issues:
- Would be nice to have the abstract class A2 not being initializable from
Python,
but we can't use bp::no_init and inherit from A2 in Python because the
Python-derived
needs to call the (A2) base class constructor


Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
https://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] Returning values to Python in C++ reference arguments

2015-05-26 Thread Holger Joukl

> Von: Jason Addison
>
> How can results be returned in function arguments?
>
> I've include my example C++ extension and Python code below.
>
> I've tried, what I think, are some obvious approaches (Python objects,
> ctypes), though none have worked.
>
> It seems like this should be doable.

As already mentioned, you can use helper functions and return tuples.

Or you could expose custom "ref-object" classes to Python, s.th. along the
lines of:

// ref_object.hpp
#if !defined REF_OBJECT
#define REF_OBJECT


#include 
#include 


namespace bp = boost::python;

namespace refob {


// Basic RefObject
template
struct RefObject {
public:
T t;

RefObject();
// callable operator
T operator()();

// conversion functions: implicit castability
operator T&() { return t; }
};


// RefObject for handling C-style arrays
// This provides an operator() that allows access to
// a list of values.
// NOTE: If numElements > the actual stored number of elements then
// THIS WILL CRASH! It is essential to correctly apply set_num() after
// this has been used as a function argument, in some thin wrappers
// There is only some very rudimentary safety in that _numElements is
// initialized to 0
// I really don't see a better way to make this safer
template
struct RefObject {
T const * t;

RefObject();
// callable operator
bp::list operator()(unsigned int numElements=0);

// conversion functions: implicit castability
operator T const *&() { return t; }

void set_num(unsigned int const & numElements);

private:
unsigned int _numElements;
};


// RefObject specialization for void*
template<>
struct RefObject {
void* t;

RefObject();
// callable operator
void* operator()();
};


// RefObject specialization for void const* (where we cast away const for
the
// operator() call result to make boost work automagically
template<>
struct RefObject {
void const * t;

RefObject();
// callable operator
void* operator()();
};


// RefObject specialization for char const* which boost.python will
automatically
// handle as a python string (necessary to distingish from the C-style
array
// handling RefObject, see above
template<>
struct RefObject {
char const * t;

RefObject();
// callable operator
char const* operator()();
};


// Is inlining the way to go to avoid multiply defined symbols here?
// Note: Remember that
//  * a specialization is not a template but a concrete (member function in
// this case)
//  * as ref_object.hpp are
//#included from every module there will be multiple definitions (one
//in each compilation unit)
//  ==> linker chokes
// Using inline this can be avoided
// See
// http://msdn.microsoft.com/en-us/magazine/cc163769.aspx
// http://www.parashift.com/c++-faq-lite/inline-functions.html
// for background

template 
RefObject::RefObject(): t() {
//std::cout << "RefObject<" << typeid(T).name() << ">::RefObject()" <<
std::endl;
}


template 
RefObject::RefObject(): t(), _numElements(0) {
//std::cout << "RefObject<" << typeid(T).name() << " const
*>::RefObject()" << std::endl;
}


inline RefObject::RefObject(): t() {
//std::cout << "RefObject::RefObject()" << std::endl;
}


inline RefObject::RefObject(): t() {
//std::cout << "RefObject::RefObject()" << std::endl;
}


inline RefObject::RefObject(): t() {
//std::cout << "RefObject::RefObject()" << std::endl;
}


template 
T RefObject::operator()()
{
// Do we need to care about pointer data issues here?
return t;
}


template
bp::list RefObject::operator()(unsigned int numElements)
{
bp::list list_object;

unsigned int maxElements = std::min(numElements, _numElements);
for (unsigned int i=0; i < maxElements; i++) {
bp::object item(*t);
list_object.append(item);
}
return list_object;
}


inline void* RefObject::operator()()
{
void* non_const_ptr = const_cast(t);
//std::cout << "returning non-const void* t" << std::endl;
return non_const_ptr;
}


inline void* RefObject::operator()()
{
return t;
}


inline char const* RefObject::operator()()
{
return t;
}


template
void RefObject::set_num(unsigned int const & numElements)
{
_numElements = numElements;
}


} // namespace refob

#endif // #if !defined REF_OBJECT


And you might expose those to Python:

// ref_object.cpp
#include 
#include "ref_object.hpp"


namespace bp = boost::python;


namespace refob
{


// dummy function, expose this to force creation of void* converters in
boost registry
void* void_ptr_from_void_ptr(void* void_ptr) {
return void_ptr;
}


void export_reference_type_classes()
{

// // dummy function registration to force creation of void* converters
// // (not necessary if there is an exposed function returning void*)
// bp::def("void_ptr_from_void_ptr", &void_ptr_from_void_ptr,
// bp::return_value_policy());

// const-pointer types

// 1. char

// 1.1: const char*
b

Re: [C++-sig] Returning values to Python in C++ reference arguments

2015-05-26 Thread Holger Joukl
Hi,

> Von: Jason Addison
> You can return results via function arguments from C to Python (see
> code below).
>
> Why is something similar impossible with Boost Python?
>
> my_module2.c
> 
> /*
> clang -c -I/usr/include/python2.7 my_module2.c
> clang -dynamiclib -o my_module2.so -lpython2.7 my_module2.o
>  */
>
> void foo_bar(int *a, double *b) {
> *a = 12;
> *b = 6.2832;
> }
> 
>
> byref2.py
> 
> from ctypes import *
> my_module2 = CDLL('my_module2.so')
>

Because you don't create Python built-in int or float objects here:

> x = c_int(0)
> y = c_double(0)

What does type(x) and type(y) give you?

> my_module2.foo_bar(byref(x), byref(y))
>
> assert(x.value == 12)
> assert(y.value == 6.2832)
> 

(unrelated sidenote: it's probably not the best idea to test float/double
equality)

Best regards
Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
https://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] boost python exposing const*

2015-09-09 Thread Holger Joukl

Hi,

> I have a c++ class T that I succesfully expose via:
>
> class_ ...
>
> later on, I have
>
> struct S {
>   const T* underlying;
> };
>
> class_("S").
>     .def_readonly("underlying", &S::underlying)
> ;
>
> From python, when I call:
>
> s.underlying
>
> where s is a python instance of S, i get the following error:
>
> TypeError: No to_python (by-value) converter found for C++ type: T const*
>
> Do I need another converter for T const* in particular? or for both
> T* and T const*?
> Does the class_ above only expose T itself, not pointers to it?

Using add_property() instead should be your friend, to be able to use a
call policy.

E.g.:

#include 

namespace bp = boost::python;


// classes to expose
struct A
{
};


struct B
{
B() : underlying(NULL)  { }
A const * underlying;
};


// expose to python
BOOST_PYTHON_MODULE(properties)
{

bp::class_("A")
;

bp::class_("B")
// Won't work: "No to_python (by-value) converter found...
//.def_readonly("underlying", &B::underlying)
.add_property("underlying", bp::make_getter(&B::underlying,
bp::return_internal_reference<>()))
;
}


See FAQ entry also:
http://www.boost.org/doc/libs/1_59_0/libs/python/doc/v2/faq.html#topythonconversionfailed

Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
https://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] Boost Python Question - Multiple Classes and Modules not appearing as attribute

2016-09-09 Thread Holger Joukl
Hi,

"Cplusplus-sig" 
schrieb am 09.09.2016 02:33:57:

> Hi,
>
> And here is yet another person who seems to encounter the same issue:
> http://stackoverflow.com/questions/9140572/c-boost-python-2-problems
>
> -Jon

Python expects an init function for extension modules named initNAME
where NAME is the name of the extension module, i.e. NAME.so.
(see https://docs.python.org/2/extending/extending.html)

BOOST_PYTHON_MODULE is boost.python's macro for automagically giving you
such
an init function.

So in the directives
- in the boost.python wrapper code: BOOST_PYTHON_MODULE(NAME)
- in the Jamroot file: python-extension NAME
(or maybe if you compile without bjam, in your g++ link step the -o
Parameter:
g++ -shared -oNAME.so -Wl,-h -Wl,NAME.so ...
# don't know if the SONAME setting (-Wl,-h -Wl,NAME.so) must also match as
# Python dlopen()s the extension)

NAME must be consistent.

Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
https://mail.python.org/mailman/listinfo/cplusplus-sig