Discussion:
[C++-sig] Why Python for C++ programmers
David Abrahams
2002-12-05 20:36:34 UTC
Permalink
Hi All,

I'm starting work on some articles and talks about Boost.Python. Some
of these are primarily for a "C++ audience", and I'll have to at least
briefly make the case for why a C++ programmer should care about
Python. Some of the answers are obvious to me, but I thought I should
get additional feedback from a group who must have their own
well-thought-out reasons.

Here are some things I've thought of.

In broad strokes, they're complimentary because:

* C++ is hard. Python is easy

* C++ is fast. Python is small

* C++ is "dangerous" (easy to crash). Python is "safe"

* C++ is rigorous. Python is loose.

* C++ is compiled. Python is interactive.

* C++ has a deep and focused standard library. Python has broad
libraries

* C++ has limited introspection capability. Everything in Python is
introspectable

* C++ is supported to varying degrees on different platforms. The
latest Python really does run ``everywhere''.

Other thoughts?
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Nicodemus
2002-12-05 22:26:46 UTC
Permalink
Hi,

Some more from the top of my head.

* Even though python is interpreted, therefore slower, it can be
extended with other languages (like C++).

* Python code is very readable

* Python is fun

Best Regards,
Nicodemus.
Post by David Abrahams
Hi All,
I'm starting work on some articles and talks about Boost.Python. Some
of these are primarily for a "C++ audience", and I'll have to at least
briefly make the case for why a C++ programmer should care about
Python. Some of the answers are obvious to me, but I thought I should
get additional feedback from a group who must have their own
well-thought-out reasons.
Here are some things I've thought of.
* C++ is hard. Python is easy
* C++ is fast. Python is small
* C++ is "dangerous" (easy to crash). Python is "safe"
* C++ is rigorous. Python is loose.
* C++ is compiled. Python is interactive.
* C++ has a deep and focused standard library. Python has broad
libraries
* C++ has limited introspection capability. Everything in Python is
introspectable
* C++ is supported to varying degrees on different platforms. The
latest Python really does run ``everywhere''.
Other thoughts?
Stefan Franke
2002-12-05 23:31:27 UTC
Permalink
My favourite, albeit often quoted point is this:

Python's runtime polymorphism along with its built-in powerful
data types make it an ideal rapid development language.

Its dynamic, nonetheless strict typing consumes much less
brain cycles during prototypical development which are better
spend on developing better algorithms and overall architecture.

C++ OTOH is a typical "big design first" language because things
are much harder to change afterwards.

C++ excessive static typing enables you to implement data structures
with optimal performance generically. However, its polymorphism is
limited to compile time type information, which makes it often hard
to implement an extensible, self-reflecting framework and top level
logic for your programs.

This is where a combination of both can truly excel.
-----Original Message-----
From: c++-sig-admin at python.org [mailto:c++-sig-admin at python.org]On
Behalf Of David Abrahams
Sent: Thursday, December 05, 2002 9:37 PM
To: pysig
Cc: Andy Koenig
Subject: [C++-sig] Why Python for C++ programmers
Hi All,
I'm starting work on some articles and talks about Boost.Python. Some
of these are primarily for a "C++ audience", and I'll have to at least
briefly make the case for why a C++ programmer should care about
Python. Some of the answers are obvious to me, but I thought I should
get additional feedback from a group who must have their own
well-thought-out reasons.
Here are some things I've thought of.
* C++ is hard. Python is easy
* C++ is fast. Python is small
* C++ is "dangerous" (easy to crash). Python is "safe"
* C++ is rigorous. Python is loose.
* C++ is compiled. Python is interactive.
* C++ has a deep and focused standard library. Python has broad
libraries
* C++ has limited introspection capability. Everything in Python is
introspectable
* C++ is supported to varying degrees on different platforms. The
latest Python really does run ``everywhere''.
Other thoughts?
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
_______________________________________________
C++-sig mailing list
C++-sig at python.org
http://mail.python.org/mailman/listinfo/c++-sig
Dirk Gerrits
2002-12-05 23:44:48 UTC
Permalink
Post by David Abrahams
Other thoughts?
* Programming in Python is much faster than programming in C++: great
for prototyping.

* Functions are at best second class citizens in C++, not so in Python.

* Many APIs have C and Python bindings but not C++ bindings. So in
Python you can use those APIs taking full advantage of the language,
while in C++ you can only communicate with the API through a subset of
the language. (You could of course communicate with the API in C++ using
Boost.Python though. ;))

Just my two eurocents,

Dirk Gerrits
Ralf W. Grosse-Kunstleve
2002-12-06 05:29:08 UTC
Permalink
Post by David Abrahams
Other thoughts?
Others mentioned "rapid prototyping" already. I see this as one of the
strongest points.

I also find that debugging/testing my C++ algorithms is a lot faster if I
expose the new classes to Python from where they can easily be exercised with
different inputs. Almost all regression tests for my C++ algorithms are written
in Python.

Ralf


__________________________________________________
Do you Yahoo!?
Yahoo! Mail Plus - Powerful. Affordable. Sign up now.
http://mailplus.yahoo.com
Toon Knapen
2002-12-06 08:13:44 UTC
Permalink
Post by Ralf W. Grosse-Kunstleve
Post by David Abrahams
Other thoughts?
Others mentioned "rapid prototyping" already. I see this as one of the
strongest points.
And that's why the combination C++ Python is gaining a lot of momentum in
performance / scientific / simulation software. C++ is a robust language to
offer good performance, Python can offer some kind of Matlab-like experience.

toon
David Abrahams
2002-12-10 22:59:29 UTC
Permalink
Post by Ralf W. Grosse-Kunstleve
I also find that debugging/testing my C++ algorithms is a lot faster if I
expose the new classes to Python from where they can easily be exercised with
different inputs. Almost all regression tests for my C++ algorithms are written
in Python.
Why is it easier to excercise your C++ from Python than from C++?

Surely the Python binding layer hides some of the variations on
possible C++ inputs (e.g. const vs. non-const), making it impossible
to fully-exercise some C++ interfaces?

Even discounting this issue, it's not obvious to me why it would be
easier to write a Python binding layer just to test your C++ code.

Thanks for your patience,
Dave
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Paul F. Kunz
2002-12-11 04:29:18 UTC
Permalink
Post by David Abrahams
Post by Ralf W. Grosse-Kunstleve
I also find that debugging/testing my C++ algorithms is a lot
faster if I expose the new classes to Python from where they can
easily be exercised with different inputs. Almost all regression
tests for my C++ algorithms are written in Python.
Why is it easier to excercise your C++ from Python than from C++?
Ralf answered quite completely. Let me say, if he hadn't I would
have said more or less the same sort of things.
Scott A. Smith
2002-12-06 14:46:51 UTC
Permalink
I have a quick question on avoiding error C1204 when using
BP and MSVC++ V6. I break up my code into separate files to
avoid the problem as directed in

http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/*checkout*/boost/boost/libs/p
ython/doc/v2/faq.html#c1204

Works great. But when it comes to doing so in a class I don't
see how to get an instance of my class into the module definition.
If I have my BP module (following along with the FAQ)

BOOST_PYTHON_MODULE(my_module)
{
def("foo", foo);
...
class_<my_class>("my_class", init<>())
...
;
more_of_my_class(x); <======= ???
}

void more_of_my_class(class<my_class>& x)
{
x
.def("baz", baz)
.add_property("xx", &my_class::get_xx, &my_class::set_xx)
;
...
}

How to I get an reference to an instance of my_class?
That is, where do I get the x for the line "more_of_my_class(x);"
assuming this is the correct means of breaking up the class?

Thanks, Scott
Nicodemus
2002-12-06 15:55:21 UTC
Permalink
Post by Scott A. Smith
Works great. But when it comes to doing so in a class I don't
see how to get an instance of my class into the module definition.
If I have my BP module (following along with the FAQ)
BOOST_PYTHON_MODULE(my_module)
{
def("foo", foo);
...
class_<my_class>("my_class", init<>())
...
;
more_of_my_class(x); <======= ???
}
void more_of_my_class(class<my_class>& x)
{
x
.def("baz", baz)
.add_property("xx", &my_class::get_xx, &my_class::set_xx)
;
...
}
How to I get an reference to an instance of my_class?
Just use:

BOOST_PYTHON_MODULE(my_module)
{
def("foo", foo);
...
class_<my_class> x ("my_class", init<>())
^^^
...
;
more_of_my_class(x); <======= ???
}


Regards,
Nicodemus.
Post by Scott A. Smith
Thanks, Scott
_______________________________________________
C++-sig mailing list
C++-sig at python.org
http://mail.python.org/mailman/listinfo/c++-sig
.
David Abrahams
2002-12-06 14:47:39 UTC
Permalink
Post by Scott A. Smith
I have a quick question on avoiding error C1204 when using
BP and MSVC++ V6. I break up my code into separate files to
avoid the problem as directed in
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/*checkout*/boost/boost/libs/p
ython/doc/v2/faq.html#c1204
Works great. But when it comes to doing so in a class I don't
see how to get an instance of my class into the module definition.
If I have my BP module (following along with the FAQ)
BOOST_PYTHON_MODULE(my_module)
{
def("foo", foo);
...
class_<my_class>("my_class", init<>())
...
;
more_of_my_class(x); <======= ???
}
void more_of_my_class(class<my_class>& x)
{
x
.def("baz", baz)
.add_property("xx", &my_class::get_xx, &my_class::set_xx)
;
...
}
How to I get an reference to an instance of my_class?
That is, where do I get the x for the line "more_of_my_class(x);"
assuming this is the correct means of breaking up the class?
option 1:

BOOST_PYTHON_MODULE(my_module)
{
def("foo", foo);
...
class_<my_class> x("my_class", init<>())

x
.def(...)
...
;

more_of_my_class(x);
}

option 2:

BOOST_PYTHON_MODULE(my_module)
{
def("foo", foo);
...

more_of_my_class(
class_<my_class>("my_class", init<>())
.def(...)
...

);
}

It's just regular C++.
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Brett Calcott
2002-12-07 00:05:24 UTC
Permalink
Post by David Abrahams
Hi All,
I'm starting work on some articles and talks about Boost.Python. Some
of these are primarily for a "C++ audience", and I'll have to at least
briefly make the case for why a C++ programmer should care about
Python. Some of the answers are obvious to me, but I thought I should
get additional feedback from a group who must have their own
well-thought-out reasons.
Here are some things I've thought of.
* C++ is hard. Python is easy
* C++ is fast. Python is small
* C++ is "dangerous" (easy to crash). Python is "safe"
* C++ is rigorous. Python is loose.
* C++ is compiled. Python is interactive.
* C++ has a deep and focused standard library. Python has broad
libraries
* C++ has limited introspection capability. Everything in Python is
introspectable
* C++ is supported to varying degrees on different platforms. The
latest Python really does run ``everywhere''.
Other thoughts?
All of these things combine to make a programming experience where the
majority of the time is spent on the problem, not the intricacies of the
language you are working in. I think Eric Raymond summed it up nicely
whilst talking about his first python project:

"... I noticed I was generating working code nearly as fast as I could
type. When I realized this, I was quite startled. An important measure
of effort in coding is the frequency with which you write something that
doesn't actually match your mental representation of the problem, and
have to backtrack on realizing that what you just typed won't actually
tell the language to do what you're thinking. An important measure of
good language design is how rapidly the percentage of missteps of this
kind falls as you gain experience with the language."

http://www.linuxjournal.com/article.php?sid=3882
Paul F. Kunz
2002-12-07 19:47:58 UTC
Permalink
I have some widgets which inherit from Qt and made them as Python
extension module using boost.python (v2). Now another group wants to
use them in their application built with PyQt which uses SIP to make
the Python extension modules. At first glance, it looks like this
wouldn't work. A simple test program cause Segmentation fault.

Is it known that use of boost.python and SIP together doesn't work?
If they can be made to work, what is the magic?

I can provide more details if any body thinks they can help.
David Abrahams
2002-12-07 20:02:53 UTC
Permalink
Post by Paul F. Kunz
I have some widgets which inherit from Qt and made them as Python
extension module using boost.python (v2).
So, in Python they're represented as Boost.Python extension instances
containing instances of your widget classes (?)
Post by Paul F. Kunz
Now another group wants to use them in their application built with
PyQt which uses SIP to make the Python extension modules. At first
glance, it looks like this wouldn't work.
If I understand you correctly, whether it would work or not depends on
how sophisticated SIP can be about unwrapping a Boost.Python extension
instance and retrieving the underlying C++ object. I doubt SIP has
this ability built-in, but it may be possible for you to add it.
Post by Paul F. Kunz
A simple test program cause Segmentation fault.
That doesn't prove much of course. Most simple test programs cause
Segmentation faults ;-)
Post by Paul F. Kunz
Is it known that use of boost.python and SIP together doesn't work?
I have no such knowledge.
Post by Paul F. Kunz
If they can be made to work, what is the magic?
Hard to say without knowing a lot more about SIP.

It seems like there are two obvious approaches:

1. Get Boost.Python to wrap your objects in a way that SIP already
undertstands

2. Get SIP to understand the way Boost.Python already wraps objects
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Paul F. Kunz
2002-12-07 20:22:11 UTC
Permalink
Post by David Abrahams
Post by Paul F. Kunz
I have some widgets which inherit from Qt and made them as Python
extension module using boost.python (v2).
So, in Python they're represented as Boost.Python extension
instances containing instances of your widget classes (?)
Yes. My C++ objects are wrap by Boost.Python
Post by David Abrahams
Post by Paul F. Kunz
Now another group wants to use them in their application built with
PyQt which uses SIP to make the Python extension modules. At first
glance, it looks like this wouldn't work.
If I understand you correctly, whether it would work or not depends
on how sophisticated SIP can be about unwrapping a Boost.Python
extension instance and retrieving the underlying C++ object. I doubt
SIP has this ability built-in, but it may be possible for you to add
it.
I don't see why SIP needs to know my objects are wrapped by
Boost.Python. But let me show you some Python code

a = QApplication(sys.argv)
clock = DigitalClock()
clock.resize(170,80)
a.setMainWidget(clock)
clock.show()
# the above are Python objects wrapped with SIP
# below are my objects wrapped with Boost.Pythoin
wc = WindowController()
cw = wc.newCanvas()

a.exec_loop()
Post by David Abrahams
1. Get Boost.Python to wrap your objects in a way that SIP already
undertstands
2. Get SIP to understand the way Boost.Python already wraps objects
Why should SIP need to know about my objects or vica versa?

I've trace the point of a problem a bit further. Steping down the
call stack, I see...

#6 0x0807705e in eval_frame (f=0x811a974) at Python/ceval.c:1784
(gdb)
#5 0x08056794 in PyObject_GetAttr (v=0x82cc4cc, name=0x815a8e0)
at Objects/object.c:1108
(gdb)
#4 0x401afa43 in instanceGetAttr ()
from /usr/local/lib/python2.2/site-packages/libsip.so

Note the function is in libsip.so. The line in PyObject_GetAttr()
that got us there appears to be...

if (tp->tp_getattro != NULL)
return (*tp->tp_getattro)(v, name);

Perhaps SIP depends on overriding something in Python in order to
interact with it's extension modules.
David Abrahams
2002-12-07 21:13:52 UTC
Permalink
Post by Paul F. Kunz
Post by David Abrahams
Post by Paul F. Kunz
I have some widgets which inherit from Qt and made them as Python
extension module using boost.python (v2).
So, in Python they're represented as Boost.Python extension
instances containing instances of your widget classes (?)
Yes. My C++ objects are wrap by Boost.Python
Post by David Abrahams
Post by Paul F. Kunz
Now another group wants to use them in their application built with
PyQt which uses SIP to make the Python extension modules. At first
glance, it looks like this wouldn't work.
If I understand you correctly, whether it would work or not depends
on how sophisticated SIP can be about unwrapping a Boost.Python
extension instance and retrieving the underlying C++ object. I doubt
SIP has this ability built-in, but it may be possible for you to add
it.
I don't see why SIP needs to know my objects are wrapped by
Boost.Python. But let me show you some Python code
a = QApplication(sys.argv)
clock = DigitalClock()
clock.resize(170,80)
a.setMainWidget(clock)
clock.show()
# the above are Python objects wrapped with SIP
# below are my objects wrapped with Boost.Pythoin
wc = WindowController()
cw = wc.newCanvas()
a.exec_loop()
Oh, I see that there's no interaction on the C++ side.

In that case, I agree with you. There's no reason Boost.Python and SIP
should have to interact in any way.
Post by Paul F. Kunz
Post by David Abrahams
1. Get Boost.Python to wrap your objects in a way that SIP already
undertstands
2. Get SIP to understand the way Boost.Python already wraps objects
Why should SIP need to know about my objects or vica versa?
I assumed that because you cited a problem, there must be one, and the
only kind of issue I can imagine arises when the C++ code wrapped with
SIP needs to use a type which you've wrapped with Boost.Python, or
vice-versa.
Post by Paul F. Kunz
I've trace the point of a problem a bit further. Steping down the
call stack, I see...
#6 0x0807705e in eval_frame (f=0x811a974) at Python/ceval.c:1784
(gdb)
#5 0x08056794 in PyObject_GetAttr (v=0x82cc4cc, name=0x815a8e0)
at Objects/object.c:1108
(gdb)
#4 0x401afa43 in instanceGetAttr ()
from /usr/local/lib/python2.2/site-packages/libsip.so
Note the function is in libsip.so. The line in PyObject_GetAttr()
that got us there appears to be...
if (tp->tp_getattro != NULL)
return (*tp->tp_getattro)(v, name);
Perhaps SIP depends on overriding something in Python in order to
interact with it's extension modules.
I don't know, but this certainly appears to be a SIP problem. I don't
think this has anything to do with Boost.Python.
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Paul F. Kunz
2002-12-07 21:28:37 UTC
Permalink
Post by David Abrahams
Note the function is in libsip.so. The line in PyObject_GetAttr()
that got us there appears to be...
if (tp->tp_getattro != NULL) return (*tp->tp_getattro)(v, name);
Perhaps SIP depends on overriding something in Python in order to
interact with it's extension modules.
I don't know, but this certainly appears to be a SIP problem. I
don't think this has anything to do with Boost.Python.
I think I agree with you, unfortunately. Maybe it is fixable if I
supply as an attribute, what ever SIP is looking for. Currently, I
don't define any attributes. My Boost.Python interface is just...


class_ < CanvasWindow > ( "CanvasWindow" )
.def ( "fileNew", &CanvasWindow::fileNew )
;

class_ < WindowController > ( "WindowController" )
.def ( "instance", &WindowController::instance,
return_value_policy < reference_existing_object > () )
.def ( "newCanvas",
( CanvasWindow * ( WindowController::* ) // function pointer
(void) ) // arguments
&WindowController::newCanvas,
return_value_policy < reference_existing_object > () )
;

and to recall the Python code that uses it...

wc = WindowController()
cw = wc.newCanvas()

The first line doesn't cause any problem. The second line attempts
to bring up two windows, one of which is a CanvasWindow.
David Abrahams
2002-12-07 21:58:05 UTC
Permalink
Post by Paul F. Kunz
Post by David Abrahams
Note the function is in libsip.so. The line in PyObject_GetAttr()
that got us there appears to be...
if (tp->tp_getattro != NULL) return (*tp->tp_getattro)(v, name);
Perhaps SIP depends on overriding something in Python in order to
interact with it's extension modules.
I don't know, but this certainly appears to be a SIP problem. I
don't think this has anything to do with Boost.Python.
I think I agree with you, unfortunately. Maybe it is fixable if I
supply as an attribute, what ever SIP is looking for.
I don't think so. It's not looking for an attribute on a Boost.Python
object, but on a SIP object (which explains this stack frame):

#4 0x401afa43 in instanceGetAttr ()
from /usr/local/lib/python2.2/site-packages/libsip.so
Post by Paul F. Kunz
Currently, I
don't define any attributes. My Boost.Python interface is just...
class_ < CanvasWindow > ( "CanvasWindow" )
.def ( "fileNew", &CanvasWindow::fileNew )
;
class_ < WindowController > ( "WindowController" )
.def ( "instance", &WindowController::instance,
return_value_policy < reference_existing_object > () )
.def ( "newCanvas",
( CanvasWindow * ( WindowController::* ) // function pointer
(void) ) // arguments
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Are you certain the above cast is valid?

You could check by writing:

CanvasWindow* (WindowController::*f)() = &WindowController::newCanvas;
Post by Paul F. Kunz
&WindowController::newCanvas,
return_value_policy < reference_existing_object > () )
Ummm... this looks very wrong to me. I presume newCanvas allocates a
new object? Why are you using reference_existing_object for that? It
will be leaked if you do it that way... though that shouldn't cause
the crash you're seeing, of course.
Post by Paul F. Kunz
;
and to recall the Python code that uses it...
wc = WindowController()
cw = wc.newCanvas()
The first line doesn't cause any problem. The second line attempts
to bring up two windows, one of which is a CanvasWindow.
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Paul F. Kunz
2002-12-07 22:26:40 UTC
Permalink
Post by David Abrahams
the above cast is valid?
Yes, it works from Python (when used without the SIP application).
Post by David Abrahams
Ummm... this looks very wrong to me. I presume newCanvas allocates a
new object? Why are you using reference_existing_object for that? It
will be leaked if you do it that way... though that shouldn't cause
the crash you're seeing, of course.
The WindowController owns all CanvasWindows. The calling object
may add objects into the window and make enquires.

Thanks for all your help today.
David Abrahams
2002-12-07 22:48:52 UTC
Permalink
Post by Paul F. Kunz
Post by David Abrahams
the above cast is valid?
Yes, it works from Python (when used without the SIP application).
Post by David Abrahams
Ummm... this looks very wrong to me. I presume newCanvas allocates a
new object? Why are you using reference_existing_object for that? It
will be leaked if you do it that way... though that shouldn't cause
the crash you're seeing, of course.
The WindowController owns all CanvasWindows. The calling object
may add objects into the window and make enquires.
You might consider return_internal_reference, then.
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Paul F. Kunz
2002-12-07 23:54:45 UTC
Permalink
Post by David Abrahams
You might consider return_internal_reference, then.
Ok. I found this part of the document confusing, so I didn't know
what to do.
Paul F. Kunz
2002-12-08 02:46:47 UTC
Permalink
Here is some response I got from the PyQt mailing list. I joined
the list in hope to resolve my problems. Note that the author of PyQt
responsing at 2 am in the morning his time.

---
On Sun, 08 Dec 2002 01:29:27 +0000, Phil Thompson
I don't think it's a known problem because I'd be surprised if
anybody had tried it before.
Further investigation of my problem shows that SIP is doing
something strange to Python. Stepping forward in the trace back of
my segmentation fault, I find...
#6 0x0807705e in eval_frame (f=0x811a974) at Python/ceval.c:1784
(gdb)
#5 0x08056794 in PyObject_GetAttr (v=0x82cc4cc, name=0x815a8e0)
at Objects/object.c:1108
(gdb)
#4 0x401afa43 in instanceGetAttr ()
from /usr/local/lib/python2.2/site-packages/libsip.so
Current directory is /usr/local/bin/
This is caused by the second line in The following Python code that is
using PyQt...
wc = WindowController()
cw = wc.newCanvas()
The WindowController class is C++ class wrapped with Boost.Python.
In the second line, it is trying to return another C++ class wrapped
with Boost.Python that creates two Windows created by C++ classes
derived from Qt.
If these classes are using Boost.Python, then why does Python call a
function in libsip.so on them? The offending line in
PyObject_GetAttr function appears to be...
if (tp->tp_getattro != NULL)
return (*tp->tp_getattro)(v, name);
This returns something that is an error, and when python attempts to
report the error messge, its thread state is null.
SIP takes over the class and instance getattr functions - it patches the class
and instance type objects. It does this to implement a "lazy" getattr so that
the Python object wrapping a C++ method is only created when that method is
referenced. PyQt contains over 5000 methods - if this technique wasn't used
then both the startup time of a PyQt application, and the memory it consumed,
would make it unusable.
The obvious workaround is to re-wrap your widgets using SIP.
I've already learned on way to expose my C++ to Python, why do I
need to learn another way. SIP should not be doing things to Python
that is incompatible with other Python extension modules. Or is
Boost.Python producing something incompatible with other Python
extension modules? Or is there something I'm doing wrong? This is
really hard to decyipher
The real problem is that SWIG/Boost/SIP have to agree on how they are going to
represent a pointer to a C++ object - or at least you have to provide code
that converts between the different representations.

Also, I don't believe (although I'd be happy to be proved wrong) that you can
produce production quality bindings for Qt derived classes using anything
other than SIP. For example, how do you handle object ownership issues?

Phil

---
David Abrahams
2002-12-08 14:52:07 UTC
Permalink
Hi Phil,
Post by Paul F. Kunz
Here is some response I got from the PyQt mailing list. I joined
the list in hope to resolve my problems. Note that the author of PyQt
responsing at 2 am in the morning his time.
---
On Sun, 08 Dec 2002 01:29:27 +0000, Phil Thompson
SIP takes over the class and instance getattr functions - it patches the class
and instance type objects. It does this to implement a "lazy" getattr so that
the Python object wrapping a C++ method is only created when that method is
referenced. PyQt contains over 5000 methods - if this technique wasn't used
then both the startup time of a PyQt application, and the memory it consumed,
would make it unusable.
Firstly, Boost.Python doesn't use class and/or instance. It's using
only new-style objects. We have a metatype derived from 'type' and a
type derived from PyBaseObject_Type. But I guess that you must be
patching those base types (or their bases) somehow, because if you
were only patching class and/or instance it should have no effect on
Boost.Python.

If you /are/ in fact patching some of our base types, it seems
unneccessary to me. Situations like this are why Guido created the
new-style type system: you can just use subtypes with overridden
getattr functions. It even seems unneccessary if you're patching class
and instance. The first version of Boost.Python used its own class and
instance types which were clones of the ones built into Python, before
the new-style type system allowed us to eliminate all that code. We
had our ouwn getattr behavior; it worked perfectly.

I don't see how any patch to the Python core which changes its
behavior could avoid breaking other things. Is this really the first
problem it's caused?
Post by Paul F. Kunz
The obvious workaround is to re-wrap your widgets using SIP.
No comment ;->
Post by Paul F. Kunz
I've already learned on way to expose my C++ to Python, why do I
need to learn another way. SIP should not be doing things to Python
that is incompatible with other Python extension modules. Or is
Boost.Python producing something incompatible with other Python
extension modules? Or is there something I'm doing wrong? This is
really hard to decyipher
The real problem is that SWIG/Boost/SIP have to agree on how they are going to
represent a pointer to a C++ object - or at least you have to provide code
that converts between the different representations.
I don't think that should be neccessary in this case. At first, I too
thought that was Paul's problem. However, the SIP-wrapped C++ code is
not directly touching the C++ type he's exposing, and the
Boost.Python-wrapped C++ code is not directly touching any types
wrapped by SIP, AFAICT.
Post by Paul F. Kunz
Also, I don't believe (although I'd be happy to be proved wrong)
that you can produce production quality bindings for Qt derived
classes using anything other than SIP. For example, how do you
handle object ownership issues?
Boost.Python has a suite of policies designed for handling object
ownership issues. It may need to be extended to work optimally with Qt
objects, but since Boost.Python is a framework, that should be no
problem.

http://www.boost.org/libs/python/doc/v2/reference.html#models_of_call_policies
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Phil Thompson
2002-12-08 16:25:38 UTC
Permalink
Post by David Abrahams
Hi Phil,
Post by Paul F. Kunz
Here is some response I got from the PyQt mailing list. I joined
the list in hope to resolve my problems. Note that the author of PyQt
responsing at 2 am in the morning his time.
I'd just finished the washing up after a dinner party.
Post by David Abrahams
Post by Paul F. Kunz
On Sun, 08 Dec 2002 01:29:27 +0000, Phil Thompson
SIP takes over the class and instance getattr functions - it patches the
class and instance type objects. It does this to implement a "lazy"
getattr so that the Python object wrapping a C++ method is only created
when that method is referenced. PyQt contains over 5000 methods - if this
technique wasn't used then both the startup time of a PyQt application,
and the memory it consumed, would make it unusable.
Firstly, Boost.Python doesn't use class and/or instance. It's using
only new-style objects. We have a metatype derived from 'type' and a
type derived from PyBaseObject_Type. But I guess that you must be
patching those base types (or their bases) somehow, because if you
were only patching class and/or instance it should have no effect on
Boost.Python.
SIP patches PyClass_Type.tp_getattro and PyInstance_Type.tp_getattro.
Post by David Abrahams
If you /are/ in fact patching some of our base types, it seems
unneccessary to me. Situations like this are why Guido created the
new-style type system: you can just use subtypes with overridden
getattr functions. It even seems unneccessary if you're patching class
and instance. The first version of Boost.Python used its own class and
instance types which were clones of the ones built into Python, before
the new-style type system allowed us to eliminate all that code. We
had our ouwn getattr behavior; it worked perfectly.
SIP generated code is intended to work with any version of Python from 1.5.2
onwards.
Post by David Abrahams
I don't see how any patch to the Python core which changes its
behavior could avoid breaking other things. Is this really the first
problem it's caused?
It doesn't change the behaviour. The "new" code first calls the old getattro
code. If a particular exception has been raised it then searches SIP
generated data structures to see if the name refers to a SIP wrapped method.
If it does then the appropriate Python objects are created and returned in
place of the exception.

Note that the patching is only done to enhance performance - required for PyQt
because it has so many classes and methods.

Phil
David Abrahams
2002-12-08 17:15:23 UTC
Permalink
Post by Phil Thompson
Post by David Abrahams
Hi Phil,
Firstly, Boost.Python doesn't use class and/or instance. It's using
only new-style objects. We have a metatype derived from 'type' and a
type derived from PyBaseObject_Type. But I guess that you must be
patching those base types (or their bases) somehow, because if you
were only patching class and/or instance it should have no effect on
Boost.Python.
SIP patches PyClass_Type.tp_getattro and PyInstance_Type.tp_getattro.
In that case, the only thing I can imagine is that the attribute
access in question is not actually the one induced by "wc.newCanvas",
but something that happens when "wc.newCanvas()" is invoked. In other
words, something in Paul's WindowController class calls back into
Python.

Of course, the only way I'd be able to know for sure would be to see
more of the stack trace, and some of the variable values (e.g. the
attribute name) wouldn't hurt...
Post by Phil Thompson
Post by David Abrahams
If you /are/ in fact patching some of our base types, it seems
unneccessary to me. Situations like this are why Guido created the
new-style type system: you can just use subtypes with overridden
getattr functions. It even seems unneccessary if you're patching class
and instance. The first version of Boost.Python used its own class and
instance types which were clones of the ones built into Python, before
the new-style type system allowed us to eliminate all that code. We
had our ouwn getattr behavior; it worked perfectly.
SIP generated code is intended to work with any version of Python from 1.5.2
onwards.
That's fine; Boost.Python v1 worked with 1.5.2. It isn't that hard to
create your own clones of the builtin 'class' and 'instance'.
Post by Phil Thompson
Post by David Abrahams
I don't see how any patch to the Python core which changes its
behavior could avoid breaking other things. Is this really the
first problem it's caused?
It doesn't change the behaviour. The "new" code first calls the old getattro
code. If a particular exception has been raised
Is this a SIP-specific exception or just the usual AttributeError?
Post by Phil Thompson
it then searches SIP generated data structures to see if the name
refers to a SIP wrapped method. If it does then the appropriate
Python objects are created and returned in place of the exception.
Aha. Well, as long as "particular exception" is specific to SIP, that
sounds like it is probably harmless... though it makes me uneasy.
Post by Phil Thompson
Note that the patching is only done to enhance performance -
required for PyQt because it has so many classes and methods.
I understand why a performance enhancement might be needed, but it
still seems unlikely to me that patching is actually required.
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Paul F. Kunz
2002-12-08 19:18:34 UTC
Permalink
Post by David Abrahams
In that case, the only thing I can imagine is that the attribute
access in question is not actually the one induced by
"wc.newCanvas", but something that happens when "wc.newCanvas()" is
invoked. In other words, something in Paul's WindowController class
calls back into Python.
Nothing in my class calls back to Python. The returned Python
object wraps a C++ class derived from Qt's QMainWindow, and another
object is created that is derived from Qt's QDialog. None of my C++
code calls Python, I don't even know how (yet).

Doesn't mean that there isn't still some fault in my code, of
course.
Post by David Abrahams
Of course, the only way I'd be able to know for sure would be to see
more of the stack trace, and some of the variable values (e.g. the
attribute name) wouldn't hurt...
I'll try to provide that later today.
Paul F. Kunz
2002-12-08 19:48:36 UTC
Permalink
Post by David Abrahams
Of course, the only way I'd be able to know for sure would be to see
more of the stack trace, and some of the variable values (e.g. the
attribute name) wouldn't hurt...
(gdb) run
Starting program: /usr/local/bin/python /home/pfkeb/hippodraw-BUILD/testsuite/dclock.py
[New Thread 1024 (LWP 17399)]

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 1024 (LWP 17399)]
PyErr_SetObject (exception=0x81103c4, value=0x82c3db0) at Python/errors.c:39
(gdb)

gdb is pointing to this line

oldtype = tstate->curexc_type;

(gdb) p tstate
$1 = (PyThreadState *) 0x0

(gdb) bt
#0 PyErr_SetObject (exception=0x81103c4, value=0x82c3db0)
at Python/errors.c:39
#1 0x0808827b in PyErr_SetString (exception=0x81103c4,
string=0x80d1641 "tuple index out of range") at Python/errors.c:70
#2 0x0805ea1c in tupleitem (a=0x810598c, i=1) at Objects/tupleobject.c:283
#3 0x080ade3c in PySequence_GetItem (s=0x810598c, i=1)
at Objects/abstract.c:1106
#4 0x080c0df0 in iter_iternext (iterator=0x82d0760) at Objects/iterobject.c:75
#5 0x080ad396 in PyIter_Next (iter=0x82d0760) at Objects/abstract.c:2092
#6 0x080ac23b in PySequence_List (v=0x810598c) at Objects/abstract.c:1401
#7 0x0805f841 in mro_implementation (type=0x40ca2460)
at Objects/typeobject.c:756
#8 0x0805f8ce in mro_internal (type=0x40ca2460) at Objects/typeobject.c:792
#9 0x08061d0c in PyType_Ready (type=0x40ca2460) at Objects/typeobject.c:2170
#10 0x40c83ade in boost::python::objects::make_nurse_and_patient ()
from /usr/local/boost/libboost_python.so.1.29.0
#11 0x0815e304 in ?? ()
Cannot access memory at address 0x2

Hmmm. This is different from yesterday. No sign of going thru
libsip.so, for example. The only change in my code was to follow
David's suggestion of `return_internal_reference<>'.

Its beginning to look like there is really something wrong with my
code or my Boost.Python wrapping. :-(
David Abrahams
2002-12-08 21:37:14 UTC
Permalink
Post by Paul F. Kunz
Hmmm. This is different from yesterday. No sign of going thru
libsip.so, for example. The only change in my code was to follow
David's suggestion of `return_internal_reference<>'.
Its beginning to look like there is really something wrong with my
code or my Boost.Python wrapping. :-(
Or the way you've built your extension module. Are you embedding
Python in a C++ application? It looks a bit like Python was never
initialized.

Does this code still fail when you don't exercise any SIP-wrapped code
beforehand?
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Paul F. Kunz
2002-12-08 22:20:08 UTC
Permalink
Post by David Abrahams
Hmmm. This is different from yesterday. No sign of going thru
libsip.so, for example. The only change in my code was to follow
David's suggestion of `return_internal_reference<>'.
Its beginning to look like there is really something wrong with my
code or my Boost.Python wrapping. :-(
Or the way you've built your extension module. Are you embedding
Python in a C++ application? It looks a bit like Python was never
initialized.
Python in not embedded. I start Python from a UNIX shell.
Post by David Abrahams
Does this code still fail when you don't exercise any SIP-wrapped
code beforehand?
i've moved somethings around, and now can make it fail...

[pfkeb at Kunz-pbdsl1 python]$ python
Python 2.2.2 (#1, Oct 15 2002, 07:42:56)
[GCC 2.95.3 20010315 (release)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
Post by David Abrahams
from hippo import *
wc = WCFactory()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
IndexError: tuple index out of range
This looks like the same error that didn't get a chance to printout
when run with PyQt.

Relavent code is...

WindowController * WCFactory ()
{
WindowController * controller = WindowController::instance ();
return controller;
}

def ( "WCFactory", WCFactory, return_internal_reference<> () );

WindowController is a singleton, so the first call to instance() will
create one via the default constructor, or return an existing one.

WindowController::WindowController ( )
: m_active_window ( 0 ),
m_inspector ( 0 )
{
s_instance = this;
}
WindowController * WindowController::instance ()
{
if ( s_instance == 0 ) {
s_instance = new WindowController ();
}

return s_instance;
}

Are we getting close to understanding it?
David Abrahams
2002-12-08 23:04:37 UTC
Permalink
Post by Paul F. Kunz
i've moved somethings around, and now can make it fail...
[pfkeb at Kunz-pbdsl1 python]$ python
Python 2.2.2 (#1, Oct 15 2002, 07:42:56)
[GCC 2.95.3 20010315 (release)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
from hippo import *
wc = WCFactory()
File "<stdin>", line 1, in ?
IndexError: tuple index out of range
This looks like the same error that didn't get a chance to printout
when run with PyQt.
Relavent code is...
WindowController * WCFactory ()
{
WindowController * controller = WindowController::instance ();
return controller;
}
def ( "WCFactory", WCFactory, return_internal_reference<> () );
Err, Paul: when I suggested that you use return_internal_reference<>
for your newCanvas call, I didn't mean that you should blindly
substitute it for reference_existing_object everywhere!

You probably shouldn't be using call policies until you understand
what these things do. What is unclear when you RTFM? I mean, in
particular, the 3 sections starting here:
http://www.boost.org/libs/python/doc/v2/reference.html#models_of_call_policies

It's not surprising that you're getting an exception in this case,
since the zeroth element of the argument tuple (which is going to be
the ward object in the relationship established by
return_internal_reference<>) doesn't exist.

I suppose I should add some compile-time checks to prevent users from
using return_internal_reference<> with a custodian object index that
is greater than the wrapped function's arity... though I'm not sure
that's possible without changing the CallPolicies interface.
Post by Paul F. Kunz
WindowController is a singleton, so the first call to instance() will
create one via the default constructor, or return an existing one.
WindowController::WindowController ( )
: m_active_window ( 0 ),
m_inspector ( 0 )
{
s_instance = this;
}
WindowController * WindowController::instance ()
{
if ( s_instance == 0 ) {
s_instance = new WindowController ();
}
return s_instance;
}
Are we getting close to understanding it?
No, this pretty much has nothing to do with whatever crash you were
seeing before.
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Paul F. Kunz
2002-12-08 23:59:28 UTC
Permalink
Post by David Abrahams
Err, Paul: when I suggested that you use return_internal_reference<>
for your newCanvas call, I didn't mean that you should blindly
substitute it for reference_existing_object everywhere!
Sorry.
Post by David Abrahams
You probably shouldn't be using call policies until you understand
what these things do. What is unclear when you RTFM? I mean, in
http://www.boost.org/libs/python/doc/v2/reference.html#models_of_call_policies
Upon reading them again, I'm not sure. But...

- the example for `return_internal_reference' looked like my case, but
now I realize it is for a member function not a global function.
My mistake.

- The example for `reference_existing_object' seems to be in error.
it is not a template argument for `return_value_policy'.

Ok, so now I have...

def ( "WCFactory", WCFactory,
return_value_policy < reference_existing_object > () );

class_ <WindowController> ( "WindowController" )
.def ( "newCanvas",
( CanvasWindow * ( WindowController::* ) // function pointer
(void) ) // arguments
&WindowController::newCanvas,
return_internal_reference <> () )
;

So if I understand it, the *this, ie the WindowController object owns
the returned CanvasWindow, which is what I want.

I think the problem is not in Boost.Python incompatiblity, but in
my code. I think my Window is trying to do something before the Qt
application object is running. I'll have write some more code to
test that.

Thanks again for all your help, David and Phil.
David Abrahams
2002-12-09 00:31:53 UTC
Permalink
Post by Paul F. Kunz
Post by David Abrahams
Err, Paul: when I suggested that you use return_internal_reference<>
for your newCanvas call, I didn't mean that you should blindly
substitute it for reference_existing_object everywhere!
Sorry.
Post by David Abrahams
You probably shouldn't be using call policies until you understand
what these things do. What is unclear when you RTFM? I mean, in
http://www.boost.org/libs/python/doc/v2/reference.html#models_of_call_policies
Upon reading them again, I'm not sure. But...
- the example for `return_internal_reference' looked like my case, but
now I realize it is for a member function not a global function.
My mistake.
Did you read
http://www.boost.org/libs/python/doc/v2/return_internal_reference.html#introduction
or did you just look at the example usage?
Post by Paul F. Kunz
- The example for `reference_existing_object' seems to be in error.
it is not a template argument for `return_value_policy'.
Yes, that's been fixed in CVS for quite some time:

http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/*checkout*/boost/boost/libs/python/doc/v2/reference_existing_object.html#examples
Post by Paul F. Kunz
Ok, so now I have...
def ( "WCFactory", WCFactory,
return_value_policy < reference_existing_object > () );
class_ <WindowController> ( "WindowController" )
.def ( "newCanvas",
( CanvasWindow * ( WindowController::* ) // function pointer
(void) ) // arguments
&WindowController::newCanvas,
return_internal_reference <> () )
;
So if I understand it, the *this, ie the WindowController object owns
the returned CanvasWindow, which is what I want.
Actually, the returned CanvasWindow Python object owns the
WindowController, which is what you want ;-)

It's a little counterintuitive, but that's correct.
Post by Paul F. Kunz
I think the problem is not in Boost.Python incompatiblity, but in
my code. I think my Window is trying to do something before the Qt
application object is running. I'll have write some more code to
test that.
Thanks again for all your help, David and Phil.
My pleasure.
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Paul F. Kunz
2002-12-09 00:54:21 UTC
Permalink
Post by David Abrahams
Did you read
http://www.boost.org/libs/python/doc/v2/return_internal_reference.html#introduction
or did you just look at the example usage?
I read it. But had to look at the example to understand it. I
think it would help if there were statement of example in the
descriptive text.
Post by David Abrahams
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/*checkout*/boost/boost/libs/python/doc/v2/reference_existing_object.html#examples
Maybe I better use the Web documentation instead of what came with
the distribution.
Post by David Abrahams
Actually, the returned CanvasWindow Python object owns the
WindowController, which is what you want ;-)
It's a little counterintuitive, but that's correct.
Yes, now I'm event more confused.

In the meantime, I've increased the number of exposed method of my
code to try an example like dclock.py. And I can see that there is
something wrong with my code. I don't know what yet. But Python
doesn't crash, things just don't work right.
David Abrahams
2002-12-09 02:23:46 UTC
Permalink
Post by Paul F. Kunz
Post by David Abrahams
Did you read
http://www.boost.org/libs/python/doc/v2/return_internal_reference.html#introduction
or did you just look at the example usage?
I read it. But had to look at the example to understand it. I
think it would help if there were statement of example in the
descriptive text.
I don't understand what you mean. Patches welcome.
Post by Paul F. Kunz
Maybe I better use the Web documentation instead of what came with
the distribution.
Probably. There are some small feature changes as well, but there are
more corrections than new features.
Post by Paul F. Kunz
Post by David Abrahams
Actually, the returned CanvasWindow Python object owns the
WindowController, which is what you want ;-)
It's a little counterintuitive, but that's correct.
Yes, now I'm event more confused.
The CanvasWindow Python object only contains a (non-owning) pointer to
the CanvasWindow C++ object, which is owned by the WindowController
C++ object, which is owned by the WindowController Python object.

I think you can figure the rest out from here... ;-)
Post by Paul F. Kunz
In the meantime, I've increased the number of exposed method of
my code to try an example like dclock.py. And I can see that there
is something wrong with my code. I don't know what yet. But Python
doesn't crash, things just don't work right.
Happens to the best of us. Good luck,
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Paul F. Kunz
2002-12-08 00:38:22 UTC
Permalink
I didn't see my response for this show up in the archives, so I'll
repeat it. Sorry if it is indeed a duplication...
Post by David Abrahams
Hi All,
* C++ is hard. Python is easy
If you are talking to a C++ audience, it doesn't seem like a way to
make friends :-)
Post by David Abrahams
Other thoughts?
Your view of "complimentary" seems to focus on language. My view
is how Python and C++ can work together rather than trying to force
everything into one language or the other. Some examples...

- Many C++ applications needs some set of parameters to intialize the
application before executing some simulation or analysis. So some
initialization file with a particular syntax is invented. This
file has to be parsed with C++. But Python is much better at
parsing, so if you expose the appropriate `setXXX' methods in the
C++ code to Python, one can use Python to parse the file.

- One expand upon the above one better. Eliminate the initialization
file and just tell people to write Python code. This has the
advantage that one can use Python as a programing language to set
parameters. For example, if a simulation has 100 layers of
something, set at certain distances, a Python for loop can be use.
If one only had a static initialization file, one would have to type
in the number corresponding to each layer.

- If the above has been done, then one gets for free the ability to
change the parameters of the program interactively. Also read back
results and do something useful with them, instead of writing to a
file and having to run another program to parse that file.

- If one has two C++ programs, written independently, perhaps by
different organization, it is often quite difficult to take the
output of one and feed it to the next. But if both have the the
appropriate parts exposed to Python, then python can be the glue
between them.

Hope you might find this useful.
David Abrahams
2002-12-08 15:23:49 UTC
Permalink
Post by Paul F. Kunz
I didn't see my response for this show up in the archives, so I'll
repeat it. Sorry if it is indeed a duplication...
Post by David Abrahams
Hi All,
* C++ is hard. Python is easy
If you are talking to a C++ audience, it doesn't seem like a way to
make friends :-)
No, and I don't like the way the tone was coming out here.
However, even as a C++ jock, I have to admit it's true.
Post by Paul F. Kunz
Post by David Abrahams
Other thoughts?
Your view of "complimentary" seems to focus on language. My view
is how Python and C++ can work together rather than trying to force
everything into one language or the other.
Very nice, this is what I want to talk about.
Post by Paul F. Kunz
Some examples...
- Many C++ applications needs some set of parameters to intialize the
application before executing some simulation or analysis. So some
initialization file with a particular syntax is invented. This
file has to be parsed with C++. But Python is much better at
parsing,
I think Joel de Guzman of the Spirit parser framework might argue with
you about that... but I take your point.
Post by Paul F. Kunz
so if you expose the appropriate `setXXX' methods in the
C++ code to Python, one can use Python to parse the file.
- One expand upon the above one better. Eliminate the initialization
file and just tell people to write Python code. This has the
advantage that one can use Python as a programing language to set
parameters. For example, if a simulation has 100 layers of
something, set at certain distances, a Python for loop can be use.
If one only had a static initialization file, one would have to type
in the number corresponding to each layer.
Yes, I agree. Python literals are extremely powerful and expressive.
Post by Paul F. Kunz
- If the above has been done, then one gets for free the ability to
change the parameters of the program interactively. Also read back
results and do something useful with them, instead of writing to a
file and having to run another program to parse that file.
- If one has two C++ programs, written independently, perhaps by
different organization, it is often quite difficult to take the
output of one and feed it to the next. But if both have the the
appropriate parts exposed to Python, then python can be the glue
between them.
Hope you might find this useful.
very much, thanks.
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Joel de Guzman
2002-12-08 23:31:59 UTC
Permalink
----- Original Message -----
From: "David Abrahams" <dave at boost-consulting.com>
Post by David Abrahams
Post by Paul F. Kunz
- Many C++ applications needs some set of parameters to intialize the
application before executing some simulation or analysis. So some
initialization file with a particular syntax is invented. This
file has to be parsed with C++. But Python is much better at
parsing,
I think Joel de Guzman of the Spirit parser framework might argue with
you about that... but I take your point.
Hmmm, I'm not sure. I haven't done any parsing in Python :-)

Ok, here's my take, FWIW....

C++ is strongly typed, Python is dynamically typed. You get the best of
both worlds when you marry the two. I like the safety of strongly typed
C++ in that you catch many typing mistakes at compile time. On the
other hand, I also like the flexibility of dynamic typing of Python where
dynamic polymorphism shines in its glory.

2c-w...

Cheers,
Joel de Guzman
joel at boost-consulting.com
http://www.boost-consulting.com
Achim Domma
2002-12-08 15:52:16 UTC
Permalink
Hi Dave,

here's my opinion, why Python is important for C++ developers:

There are many languages which all have pros and cons. So you could learn
many languages, to solve every problem with it's specialized language, but
these languages are usually very different and not very easy to combine. The
other extreme would be something like Java, which tries to solve everything
(but nothing right, in my opinion).
For me, C++/Python is the perfect middleway, because you can easy mix fast
and native code with dynamic runtime magic, and have to use/learn only two
languages. Thanks to boost.python there is only a minimal overhead to
combine both, what is the most important point. There are JNI or COM of
course, but I have written some JNI and COM wrappers, which have been more
work than the wrapped library. ;-)

Hope this was understandable, but philosphical discussions are hard for non
native speakers. ;-)

regards,
Achim
Paul F. Kunz
2002-12-09 19:31:35 UTC
Permalink
Still having trouble with my Boost.Python wrapping of classes derived
from Qt. If one recalls I have

def ( "WCFactory", WCFactory,
return_value_policy < reference_existing_object > () );

class_ <WindowController> ( "WindowController" )
.def ( "newCanvas",
( CanvasWindow * ( WindowController::* ) // function pointer
(void) ) // arguments
&WindowController::newCanvas,
return_internal_reference <> () )
;

Do I have to anything special when exposing CanvasWindow? Currently
I have

class_ < CanvasWindow > ( "CanvasWindow" )
.def ( "show", &CanvasWindow::show )
.def ( "fileNew", &CanvasWindow::fileNew )
;
David Abrahams
2002-12-09 19:38:45 UTC
Permalink
Post by Paul F. Kunz
Still having trouble with my Boost.Python wrapping of classes derived
from Qt. If one recalls I have
def ( "WCFactory", WCFactory,
return_value_policy < reference_existing_object > () );
class_ <WindowController> ( "WindowController" )
.def ( "newCanvas",
( CanvasWindow * ( WindowController::* ) // function pointer
(void) ) // arguments
You may remember that I warned you that the previous line could be
unsafe...

Avoid casts if possible, especially C-style casts.
Post by Paul F. Kunz
&WindowController::newCanvas,
return_internal_reference <> () )
;
Do I have to anything special when exposing CanvasWindow? Currently
I have
class_ < CanvasWindow > ( "CanvasWindow" )
.def ( "show", &CanvasWindow::show )
.def ( "fileNew", &CanvasWindow::fileNew )
;
How would anyone know? We can't see CanvasWindow.
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Paul F. Kunz
2002-12-09 20:10:37 UTC
Permalink
Post by David Abrahams
class_ <WindowController> ( "WindowController" ) .def (
"newCanvas", ( CanvasWindow * ( WindowController::* ) // function
pointer (void) ) // arguments
You may remember that I warned you that the previous line could be
unsafe...
Avoid casts if possible, especially C-style casts.
I have to, there's another method with the same name that takes a
const std::string & as argument.
Post by David Abrahams
How would anyone know? We can't see CanvasWindow.
class CanvasWindow : public CanvasWindowBase
{
private:

/* members not shown */

public:
CanvasWindow ();

CanvasWindow ( const CanvasWindow & );

virtual ~CanvasWindow();

/*other members not shown*/
};
David Abrahams
2002-12-09 21:01:50 UTC
Permalink
Post by Paul F. Kunz
Post by David Abrahams
class_ <WindowController> ( "WindowController" ) .def (
"newCanvas", ( CanvasWindow * ( WindowController::* ) // function
pointer (void) ) // arguments
You may remember that I warned you that the previous line could be
unsafe...
Avoid casts if possible, especially C-style casts.
I have to, there's another method with the same name that takes a
const std::string & as argument.
You don't have to. You can declare a variable of that type and assign
to that first, or you can use the following function template, soon to
be in Boost:

template <class U> implicit_cast(U x) { return x; }

as:

implicit_cast<CanvasWindow * ( WindowController::* )()>(
&WindowController::newCanvas )
Post by Paul F. Kunz
Post by David Abrahams
How would anyone know? We can't see CanvasWindow.
class CanvasWindow : public CanvasWindowBase
{
/* members not shown */
CanvasWindow ();
CanvasWindow ( const CanvasWindow & );
virtual ~CanvasWindow();
/*other members not shown*/
};
There's nothing obviously amiss here.
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Paul F. Kunz
2002-12-10 01:21:54 UTC
Permalink
Its me again. This time, I've got my Python extension modules
working completely with Boost.Python wrapped alone. That is...

[pfkeb at Kunz-pbdsl1 testsuite]$ python
Python 2.2.2 (#1, Oct 15 2002, 07:42:56)
[GCC 2.95.3 20010315 (release)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
from hippo import *
app = HDApp(1)
cw = CanvasWindow()
cw.show()
app.exec_loop()
works fine. In the above, `HDApp' is not derived from
QApplication, but delegates to a class which does. CanvasWindow
wraps a C++ class which derives from QMainWindow.

Now I modify the dclock.py example that comes with PyQt to...

a = QApplication(sys.argv)
clock = DigitalClock()
clock.resize(170,80)
a.setMainWidget(clock)
clock.show()

cw = CanvasWindow() # added
cw.show() # added

a.exec_loop()

and get ...

Starting program: /usr/local/bin/python /home/pfkeb/hippodraw-BUILD/testsuite/dclock.py
[New Thread 1024 (LWP 5948)]

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 1024 (LWP 5948)]
PyErr_SetObject (exception=0x8108a8c, value=0x81ab208) at Python/errors.c:39
(gdb) bt
#0 PyErr_SetObject (exception=0x8108a8c, value=0x81ab208)
at Python/errors.c:39
#1 0x08087ac7 in PyErr_Format (exception=0x8108a8c,
format=0x80df620 "%.50s instance has no attribute '%.400s'")
at Python/errors.c:408
#2 0x080b0467 in instance_getattr1 (inst=0x82c5654, name=0x8154558)
at Objects/classobject.c:678
#3 0x080b3e35 in instance_getattr (inst=0x82c5654, name=0x8154558)
at Objects/classobject.c:715
#4 0x40cd2a43 in instanceGetAttr ()
from /usr/local/lib/python2.2/site-packages/libsip.so
#5 0x08056794 in PyObject_GetAttr (v=0x82c5654, name=0x8154558)
at Objects/object.c:1108
#6 0x0807705e in eval_frame (f=0x811a974) at Python/ceval.c:1784
#7 0x0807866e in PyEval_EvalCodeEx (co=0x8161de0, globals=0x81139b4,
locals=0x81139b4, args=0x0, argcount=0, kws=0x0, kwcount=0, defs=0x0,
defcount=0, closure=0x0) at Python/ceval.c:2595
#8 0x0807a700 in PyEval_EvalCode (co=0x8161de0, globals=0x81139b4,
locals=0x81139b4) at Python/ceval.c:481
#9 0x080950b1 in run_node (n=0x81263b8,
filename=0xbffffca2 "/home/pfkeb/hippodraw-BUILD/testsuite/dclock.py",
globals=0x81139b4, locals=0x81139b4, flags=0xbffffac4)
at Python/pythonrun.c:1079
#10 0x08095062 in run_err_node (n=0x81263b8,
filename=0xbffffca2 "/home/pfkeb/hippodraw-BUILD/testsuite/dclock.py",
globals=0x81139b4, locals=0x81139b4, flags=0xbffffac4)
at Python/pythonrun.c:1066
#11 0x08094ccb in PyRun_FileExFlags (fp=0x8104038,
filename=0xbffffca2 "/home/pfkeb/hippodraw-BUILD/testsuite/dclock.py",
start=257, globals=0x81139b4, locals=0x81139b4, closeit=1,
flags=0xbffffac4) at Python/pythonrun.c:1057
#12 0x080938b1 in PyRun_SimpleFileExFlags (fp=0x8104038,
filename=0xbffffca2 "/home/pfkeb/hippodraw-BUILD/testsuite/dclock.py",
closeit=1, flags=0xbffffac4) at Python/pythonrun.c:685
#13 0x0809481f in PyRun_AnyFileExFlags (fp=0x8104038,
filename=0xbffffca2 "/home/pfkeb/hippodraw-BUILD/testsuite/dclock.py",
closeit=1, flags=0xbffffac4) at Python/pythonrun.c:495
#14 0x08053632 in Py_Main (argc=2, argv=0xbffffb54) at Modules/main.c:364
#15 0x08052ee6 in main (argc=2, argv=0xbffffb54) at Modules/python.c:10
#16 0x40088627 in __libc_start_main (main=0x8052ed0 <main>, argc=2,
ubp_av=0xbffffb54, init=0x80522d4 <_init>, fini=0x80cf610 <_fini>,
rtld_fini=0x4000dcd4 <_dl_fini>, stack_end=0xbffffb4c)
at ../sysdeps/generic/libc-start.c:129
(gdb)

On the line of the error

oldtype = tstate->curexc_type;

(gdb) p tstate
$1 = (PyThreadState *) 0x0
(gdb)

It really appears to me that Boost.Python extensions and SIP Python
extensions are incompatible with each other. Or there is still
something that I'm doing wrong.

Any suggestions on how to proceed?
David Abrahams
2002-12-10 04:03:31 UTC
Permalink
Post by Paul F. Kunz
Its me again. This time, I've got my Python extension modules
working completely with Boost.Python wrapped alone. That is...
[pfkeb at Kunz-pbdsl1 testsuite]$ python
Python 2.2.2 (#1, Oct 15 2002, 07:42:56)
[GCC 2.95.3 20010315 (release)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
from hippo import *
app = HDApp(1)
cw = CanvasWindow()
cw.show()
app.exec_loop()
works fine. In the above, `HDApp' is not derived from
QApplication, but delegates to a class which does. CanvasWindow
wraps a C++ class which derives from QMainWindow.
Now I modify the dclock.py example that comes with PyQt to...
Hmm, does dclock.py by any chance use threads?
Post by Paul F. Kunz
a = QApplication(sys.argv)
clock = DigitalClock()
clock.resize(170,80)
a.setMainWidget(clock)
clock.show()
cw = CanvasWindow() # added
cw.show() # added
a.exec_loop()
and get ...
Starting program: /usr/local/bin/python /home/pfkeb/hippodraw-BUILD/testsuite/dclock.py
[New Thread 1024 (LWP 5948)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 1024 (LWP 5948)]
PyErr_SetObject (exception=0x8108a8c, value=0x81ab208) at Python/errors.c:39
(gdb) bt
<snip>
Post by Paul F. Kunz
(gdb)
On the line of the error
oldtype = tstate->curexc_type;
(gdb) p tstate
$1 = (PyThreadState *) 0x0
(gdb)
Well, the thread state is NULL. I don't know what this means, but I
think it's premature to conclude that SIP and Boost.Python are
incompatible with one another. As far as I can tell, they should not
interact in any particular way, any more than Boost.Python should
interact with, say, the CPickle extension module which comes with
Python's standard library.

I know relatively little about Python threading, except that only one
thread may be executing core Python code at any given time. That means
that if your C++ code is being called from multiple threads it must
acquire something called the global interpreter lock (GIL) before it
touches any Python objects. If you have any virtual function
dispatching back to Python going on in your C++ objects (i.e. using
call_method), you could easily be running into this issue.
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Paul F. Kunz
2002-12-10 15:25:07 UTC
Permalink
Post by David Abrahams
Hmm, does dclock.py by any chance use threads?
No, but it does use timer. Maybe that's it.
Post by David Abrahams
If you have any virtual
function dispatching back to Python going on in your C++ objects
(i.e. using call_method), you could easily be running into this
issue.
No call backs to Python from my code.

I better try another example without a timer.
Phil Thompson
2002-12-10 09:53:53 UTC
Permalink
Post by Paul F. Kunz
Its me again. This time, I've got my Python extension modules
working completely with Boost.Python wrapped alone. That is...
[pfkeb at Kunz-pbdsl1 testsuite]$ python
Python 2.2.2 (#1, Oct 15 2002, 07:42:56)
[GCC 2.95.3 20010315 (release)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
from hippo import *
app = HDApp(1)
cw = CanvasWindow()
cw.show()
app.exec_loop()
works fine. In the above, `HDApp' is not derived from
QApplication, but delegates to a class which does. CanvasWindow
wraps a C++ class which derives from QMainWindow.
Now I modify the dclock.py example that comes with PyQt to...
a = QApplication(sys.argv)
clock = DigitalClock()
clock.resize(170,80)
a.setMainWidget(clock)
clock.show()
cw = CanvasWindow() # added
cw.show() # added
a.exec_loop()
and get ...
Starting program: /usr/local/bin/python
/home/pfkeb/hippodraw-BUILD/testsuite/dclock.py [New Thread 1024 (LWP
5948)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 1024 (LWP 5948)]
PyErr_SetObject (exception=0x8108a8c, value=0x81ab208) at
Python/errors.c:39 (gdb) bt
#0 PyErr_SetObject (exception=0x8108a8c, value=0x81ab208)
at Python/errors.c:39
#1 0x08087ac7 in PyErr_Format (exception=0x8108a8c,
format=0x80df620 "%.50s instance has no attribute '%.400s'")
at Python/errors.c:408
#2 0x080b0467 in instance_getattr1 (inst=0x82c5654, name=0x8154558)
at Objects/classobject.c:678
#3 0x080b3e35 in instance_getattr (inst=0x82c5654, name=0x8154558)
at Objects/classobject.c:715
#4 0x40cd2a43 in instanceGetAttr ()
from /usr/local/lib/python2.2/site-packages/libsip.so
#5 0x08056794 in PyObject_GetAttr (v=0x82c5654, name=0x8154558)
at Objects/object.c:1108
#6 0x0807705e in eval_frame (f=0x811a974) at Python/ceval.c:1784
#7 0x0807866e in PyEval_EvalCodeEx (co=0x8161de0, globals=0x81139b4,
locals=0x81139b4, args=0x0, argcount=0, kws=0x0, kwcount=0, defs=0x0,
defcount=0, closure=0x0) at Python/ceval.c:2595
#8 0x0807a700 in PyEval_EvalCode (co=0x8161de0, globals=0x81139b4,
locals=0x81139b4) at Python/ceval.c:481
#9 0x080950b1 in run_node (n=0x81263b8,
filename=0xbffffca2 "/home/pfkeb/hippodraw-BUILD/testsuite/dclock.py",
globals=0x81139b4, locals=0x81139b4, flags=0xbffffac4)
at Python/pythonrun.c:1079
#10 0x08095062 in run_err_node (n=0x81263b8,
filename=0xbffffca2 "/home/pfkeb/hippodraw-BUILD/testsuite/dclock.py",
globals=0x81139b4, locals=0x81139b4, flags=0xbffffac4)
at Python/pythonrun.c:1066
#11 0x08094ccb in PyRun_FileExFlags (fp=0x8104038,
filename=0xbffffca2 "/home/pfkeb/hippodraw-BUILD/testsuite/dclock.py",
start=257, globals=0x81139b4, locals=0x81139b4, closeit=1,
flags=0xbffffac4) at Python/pythonrun.c:1057
#12 0x080938b1 in PyRun_SimpleFileExFlags (fp=0x8104038,
filename=0xbffffca2 "/home/pfkeb/hippodraw-BUILD/testsuite/dclock.py",
closeit=1, flags=0xbffffac4) at Python/pythonrun.c:685
#13 0x0809481f in PyRun_AnyFileExFlags (fp=0x8104038,
filename=0xbffffca2 "/home/pfkeb/hippodraw-BUILD/testsuite/dclock.py",
closeit=1, flags=0xbffffac4) at Python/pythonrun.c:495
#14 0x08053632 in Py_Main (argc=2, argv=0xbffffb54) at Modules/main.c:364
#15 0x08052ee6 in main (argc=2, argv=0xbffffb54) at Modules/python.c:10
#16 0x40088627 in __libc_start_main (main=0x8052ed0 <main>, argc=2,
ubp_av=0xbffffb54, init=0x80522d4 <_init>, fini=0x80cf610 <_fini>,
rtld_fini=0x4000dcd4 <_dl_fini>, stack_end=0xbffffb4c)
at ../sysdeps/generic/libc-start.c:129
(gdb)
On the line of the error
oldtype = tstate->curexc_type;
(gdb) p tstate
$1 = (PyThreadState *) 0x0
(gdb)
It really appears to me that Boost.Python extensions and SIP Python
extensions are incompatible with each other. Or there is still
something that I'm doing wrong.
The only area of possible conflict I can think of is threads, the following is
from the PyQt docs...

"PyQt implements the full set of Qt's thread classes. Python, of course, also
has its own thread extension modules. It is possible to use either of the
APIs so long as you follow some simple rules.

If you use the Qt API then the very first import of one of the PyQt modules
must be done from the main thread.

If you use the Python API then all calls to PyQt (including any imports must
be done from one thread only. Therefore, if you want to make calls to PyQt
from several threads then you must use the Qt API.

If you want to use both APIs in the same application then all calls to PyQt
must be done from threads created using the Qt API."

Another possible conflict, perhaps more likely, is the two modules fighting
over the Qt API.

Phil
David Abrahams
2002-12-10 10:47:57 UTC
Permalink
Post by Phil Thompson
Another possible conflict, perhaps more likely, is the two modules
fighting over the Qt API.
Could you be a little more specific about what this might mean?

Thanks,
Dave
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Phil Thompson
2002-12-10 13:28:58 UTC
Permalink
Post by David Abrahams
Post by Phil Thompson
Another possible conflict, perhaps more likely, is the two modules
fighting over the Qt API.
Could you be a little more specific about what this might mean?
Not really - just an uncomfortable feeling about events being dispatched from
an object wrapped by one module to an object wrapped by another module that
calls a virtual re-implemented in the first module etc, etc.

BTW, dclock.py doesn't use threads explicitly, but any SIP generated code will
cooperate with the Python thread infrastructure and the GIL.

Phil
Paul F. Kunz
2002-12-10 15:38:43 UTC
Permalink
Post by Phil Thompson
Phil Thompson <phil at river-bank.demon.co.uk> writes: > Another
possible conflict, perhaps more likely, is the two modules >
fighting over the Qt API.
Could you be a little more specific about what this might mean?
Not really - just an uncomfortable feeling about events being
dispatched from an object wrapped by one module to an object wrapped
by another module that calls a virtual re-implemented in the first
module etc, etc.
In Boost.Python terms, my CanvasWindow module is

class_ < CanvasWindow > ( "CanvasWindow" )
.def ( "show", &CanvasWindow::show )
.def ( "fileNew", &CanvasWindow::fileNew )
;

In SIP terms that's
class CanvasWindow
{
public:
CanvasWindow ();
void show();
void fileNew ( const std::string & );
};

In C++, CanvasWindow inherits from CanvasWindowBase created by Qt
Designer which inherits from QMainWindow. All the above member
functions are virtual.
Paul F. Kunz
2002-12-11 18:31:01 UTC
Permalink
Me again, one final time on this topic.

I built a Python extension module for my C++ CanvasWindow class using
SIP. Now the following works...

[pfkeb at Kunz-pbdsl1 sip]$ python
Python 2.2.2 (#1, Oct 15 2002, 07:42:56)
[GCC 2.95.3 20010315 (release)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
import sys
from qt import *
app = QApplication ( sys.argv)
from sihippo import *
cw = CanvasWindow()
cw.show()
app.exec_loop()
So it appears that SIP and Boost.Python modules can not work
together if they are both interfacing to Qt.
David Abrahams
2002-12-11 19:15:17 UTC
Permalink
Post by Paul F. Kunz
Me again, one final time on this topic.
I built a Python extension module for my C++ CanvasWindow class using
SIP. Now the following works...
[pfkeb at Kunz-pbdsl1 sip]$ python
Python 2.2.2 (#1, Oct 15 2002, 07:42:56)
[GCC 2.95.3 20010315 (release)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
import sys
from qt import *
app = QApplication ( sys.argv)
from sihippo import *
cw = CanvasWindow()
cw.show()
app.exec_loop()
So it appears that SIP and Boost.Python modules can not work
together if they are both interfacing to Qt.
I don't think that's really the right conclusion... or at least, it
masks something much deeper. I would very much appreciate it if
someone could get me a simple test case I where can easily reproduce
this problem (preferably, but not neccessarily on a Windows machine).

Thanks,
Dave
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Paul F. Kunz
2002-12-11 20:04:13 UTC
Permalink
Post by David Abrahams
I don't think that's really the right conclusion... or at least, it
masks something much deeper. I would very much appreciate it if
someone could get me a simple test case I where can easily reproduce
this problem (preferably, but not neccessarily on a Windows
machine).
I'd like to help, but this problem has delayed me a week. After I
get the other half of my group going with a minimal interface using
SIP, I'll come back and work up a simple example for you.
Paul F. Kunz
2002-12-13 17:40:53 UTC
Permalink
Post by David Abrahams
I don't think that's really the right conclusion... or at least, it
masks something much deeper.
You might be right here. Although I got my Qt Window to work with
PyQt by using SIP under Linux, I'm still having trouble under
Windows. It is not Python crash however, it is something about
QPainter being used on a device which already has a QPainter.
Post by David Abrahams
I would very much appreciate it if
someone could get me a simple test case I where can easily reproduce
this problem (preferably, but not neccessarily on a Windows
machine).
I think I'll try to proceed by cutting down my code to try isolate
the problem. This may lead to simple test case you would like to
see.
greg Landrum
2002-12-10 13:47:56 UTC
Permalink
Post by Paul F. Kunz
It really appears to me that Boost.Python extensions and SIP Python
extensions are incompatible with each other. Or there is still
something that I'm doing wrong.
Any suggestions on how to proceed?
I'm afraid I don't have any helpful suggestions, but I can provide the data
point that I use Boost.Python modules from within PyQt apps all the time
without any problems.

-greg
Paul F. Kunz
2002-12-10 15:29:35 UTC
Permalink
Post by greg Landrum
Post by Paul F. Kunz
It really appears to me that Boost.Python extensions and SIP Python
extensions are incompatible with each other. Or there is still
something that I'm doing wrong.
Any suggestions on how to proceed?
I'm afraid I don't have any helpful suggestions, but I can provide
the data point that I use Boost.Python modules from within PyQt apps
all the time without any problems.
Do any of your Boost.Python modules use Qt directly?
greg Landrum
2002-12-10 19:03:15 UTC
Permalink
Post by Paul F. Kunz
Do any of your Boost.Python modules use Qt directly?
Ah, no. I didn't realize that you were doing this... guess I should have
read the rest of the thread more carefully.

-greg
Ralf W. Grosse-Kunstleve
2002-12-11 00:27:49 UTC
Permalink
Post by Ralf W. Grosse-Kunstleve
Post by Ralf W. Grosse-Kunstleve
I also find that debugging/testing my C++ algorithms is a lot faster if I
^^^^^^^^^^
Post by Ralf W. Grosse-Kunstleve
Post by Ralf W. Grosse-Kunstleve
expose the new classes to Python from where they can easily be exercised
with
Post by Ralf W. Grosse-Kunstleve
different inputs. Almost all regression tests for my C++ algorithms are
written
Post by Ralf W. Grosse-Kunstleve
in Python.
Surely the Python binding layer hides some of the variations on
possible C++ inputs (e.g. const vs. non-const), making it impossible
to fully-exercise some C++ interfaces?
^^^^^^^^^^

I find it easier to debug my /algorithms/ from Python. This is very different
from exercising interfaces.

- Most of my algorithms require very complex inputs. It would take a lot of
time to write C++ code for generating these inputs.

- If things go wrong it is easy to insert print statements in Python to narrow
down the problem. This is much more time-consuming in C++ because of the
compilation/linking overhead.

- From Python I can easily try different inputs without inventing file formats
or recompiling. Being able to quickly change inputs or to systematically try a
range of inputs often is the key to finding out which of the many parts of a
complex algorithm is not functioning properly.
Post by Ralf W. Grosse-Kunstleve
Even discounting this issue, it's not obvious to me why it would be
easier to write a Python binding layer just to test your C++ code.
Agreed. But of course I want the Python bindings anyway because this is the
most efficient way of putting together a large system. -- I realize my
arguments are a bit circular. Maybe it just comes down to: since I have a
hybrid system anyway I am free to choose how I implement the regression tests.
In practice I find it almost always more efficient to use Python for this
purpose.

Ralf


__________________________________________________
Do you Yahoo!?
Yahoo! Mail Plus - Powerful. Affordable. Sign up now.
http://mailplus.yahoo.com
David Abrahams
2002-12-11 13:19:57 UTC
Permalink
Post by David Abrahams
Post by Ralf W. Grosse-Kunstleve
Post by Ralf W. Grosse-Kunstleve
I also find that debugging/testing my C++ algorithms is a lot faster if I
^^^^^^^^^^
Post by Ralf W. Grosse-Kunstleve
Post by Ralf W. Grosse-Kunstleve
expose the new classes to Python from where they can easily be exercised
with
Post by Ralf W. Grosse-Kunstleve
different inputs. Almost all regression tests for my C++ algorithms are
written
Post by Ralf W. Grosse-Kunstleve
in Python.
Surely the Python binding layer hides some of the variations on
possible C++ inputs (e.g. const vs. non-const), making it impossible
to fully-exercise some C++ interfaces?
^^^^^^^^^^
I find it easier to debug my /algorithms/ from Python. This is very different
from exercising interfaces.
- Most of my algorithms require very complex inputs. It would take a lot of
time to write C++ code for generating these inputs.
- If things go wrong it is easy to insert print statements in Python to narrow
down the problem. This is much more time-consuming in C++ because of the
compilation/linking overhead.
- From Python I can easily try different inputs without inventing file formats
or recompiling. Being able to quickly change inputs or to systematically try a
range of inputs often is the key to finding out which of the many parts of a
complex algorithm is not functioning properly.
Does this all come down to the fact that Python has extremely powerful
literal expressions which allow you to easily build up new composite
objects, and you don't have to recompile it to build new ones?
--
David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution
Ralf W. Grosse-Kunstleve
2002-12-11 17:41:02 UTC
Permalink
Post by David Abrahams
Does this all come down to the fact that Python has extremely powerful
literal expressions which allow you to easily build up new composite
objects, and you don't have to recompile it to build new ones?
Maybe. But Python is more than the sum of the pieces.
Ralf


__________________________________________________
Do you Yahoo!?
Yahoo! Mail Plus - Powerful. Affordable. Sign up now.
http://mailplus.yahoo.com
Marcelo A. Camelo
2002-12-13 17:23:38 UTC
Permalink
I've also had some problems related to Win32 message queue. The
WindowProc message for my own Window Classes is being called from the
Qt main event loop. If I dispatch those messages and generate events
to python code that calls back to my C++ library, bang!!! In this
case, I don't know if the crash only occurs when making win32 API
calls.
Marcelo,
Anything you can give me which would help me reproduce this problem
would be hugely appreciated. I'm willing to install Qt if neccessary.
Dave,

I'm in the same situation as Paul. I'm in the hurry of releasing
my product before December 19th and, although I'm on schedule, It's a
very tight schedule. The problem is that I'm going on vacations on the
21st, and I will be 23 days at hundred miles away from the nearest
phone booth. ;-)

If things get a bit easier before my departure, I will be able to send
you something. Before that, maybe I can help you reproducing the same
behavior. And yes, I think you will need to install Qt (and maybe
PyQt) to work on it.

Cheers,

Camelo
Jim Bublitz
2002-12-13 18:24:46 UTC
Permalink
Post by Paul F. Kunz
Post by David Abrahams
On Wed, 11 Dec 2002 14:15:17 -0500, David Abrahams
I don't think that's really the right conclusion... or at least,
it masks something much deeper.
You might be right here. Although I got my Qt Window to work
with PyQt by using SIP under Linux, I'm still having trouble
under Windows. It is not Python crash however, it is something
about QPainter being used on a device which already has a
QPainter.
Are you sure that you only have a single QApplication instance and
that both Boost.Python and PyQt are referencing the same
QApplication instance? That's QPainter related somewhat (if you try
to instantiate a QWidget with no QApplication instance, the error
will be from QPainter, for example).

QApplication also sets up the event loop (there should be only one
of those too).

Jim
Paul F. Kunz
2002-12-13 19:46:41 UTC
Permalink
Post by Jim Bublitz
Are you sure that you only have a single QApplication instance and
that both Boost.Python and PyQt are referencing the same
QApplication instance?
Yes. Create QApplication with PyQt (SIP) and try to create my
derived class of QMainWindow with boost.python, or vica versa.
Post by Jim Bublitz
That's QPainter related somewhat (if you try
to instantiate a QWidget with no QApplication instance, the error
will be from QPainter, for example).
Yes, I've seen that error. Tells you to create a QApplication.
That's not the error I'm getting under Windows now. The error I'm
getting now is after I do app.exec_loop().
Post by Jim Bublitz
QApplication also sets up the event loop (there should be only one
of those too).
I've seen the affect of making that mistake. I'm not making it
now.

Thanks for trying to help.

Loading...