Re: [C++-sig] PyEval_EvalCode

2008-11-12 Thread Alan Baljeu
My question probably derives from ignorance of the Python way.  I kind of 
assumed people would advocate defining classes and methods, and then calling 
those methods.  You apparently see things otherwise.  One thing I'm considering 
is to make one layer of abstraction, and define a Python function which takes a 
dictionary and a script file name.  I think this level would make the code more 
instrumentable than with all the stuff in C++.

 Alan Baljeu




- Original Message 
From: Stefan Seefeld <[EMAIL PROTECTED]>
To: Development of Python/C++ integration 
Sent: Tuesday, November 11, 2008 4:25:00 PM
Subject: Re: [C++-sig] PyEval_EvalCode

Alan Baljeu wrote:
> I was reading some legacy code we have here, and discovered an unexpected 
> idiom.  Starting from C++, we create a dictionary, store a few named 
> constants in there, and then call PyEval_EvalCode passing in the dictionary.  
> The code it calls is a bunch of python files generated from a CAD model, with 
> no function definitions.  It works of course.  Question is, what do you think 
> of this approach?  What is a more typical idiom?
>  

I don't quite understand the question. What I think of this approach depends a 
lot on what you use it for. Typical for what ?

Having a C++ application run some python script that has access to some of the 
application state (i.e., whatever you expose through the dictionary) is 
certainly a fine way to make your application scriptable.
(FWIW, boost.python offers 'exec()' and 'eval()' for this.)

Regards,
  Stefan

-- 
 ...ich hab' noch einen Koffer in Berlin...

___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig



  __
Looking for the perfect gift? Give the gift of Flickr! 

http://www.flickr.com/gift/
___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] PyEval_EvalCode

2008-11-12 Thread Stefan Seefeld

Alan Baljeu wrote:

My question probably derives from ignorance of the Python way.  I kind of 
assumed people would advocate defining classes and methods, and then calling 
those methods.  You apparently see things otherwise.


Not really. I just see it as an orthogonal problem to the question you 
asked in your previous mail.



  One thing I'm considering is to make one layer of abstraction, and define a 
Python function which takes a dictionary and a script file name.  I think this 
level would make the code more instrumentable than with all the stuff in C++.
  


Again, without at last a little bit of context (what is your application 
doing, and what part of that would you like to control via python 
scripts) it's very hard to have a meaningful discussion. Also, I'm not 
sure whether your question is really specific to 'eval', or whether you 
also include 'exec' into this discussion (eval evaluates an expression 
and returns the result, while exec runs code, not necessarily returning 
anything).


It seems your question is all about the boundary / interface between the 
(C++) application and the script that gets invoked: What should the 
content of the dictionary be, and what is the script expected to do with 
it ?
In the most trivial case such a script could simply store named values 
(numbers, strings) into the dictionary, which then get evaluated

by the application. The script thus becomes a mere configuration file.
Alternatively, you can inject functions or even objects into the 
dictionary, which the script is expected to interact with. How much 
'Object-Orientedness' makes sense really depends on your needs, which 
you haven't talked about yet.


Regards,
  Stefan

--

 ...ich hab' noch einen Koffer in Berlin...

___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] PyEval_EvalCode

2008-11-12 Thread Alan Baljeu
>It seems your question is all about the boundary / interface between the (C++) 
>application and the script that gets invoked: What should the content of the 
>dictionary be, and what is the script expected to do with it ?
>In the most trivial case such a script could simply store named values 
>(numbers, strings) into the dictionary, which then get evaluated
>by the application. The script thus becomes a mere configuration file.
>Alternatively, you can inject functions or even objects into the dictionary, 
>which the script is expected to interact with. How much 'Object-Orientedness' 
>makes sense really depends on your needs, which you haven't >talked about yet.
>
>Regards,
>  Stefan

Okay I'll try.  I'm growing a CAD plug-in DLL.  I have decided that the 
edit/compile/run/test cycle is too slow both because C++ is a bear, and because 
both compile and run steps are extremely slow in my environment.  

To solve this, I intend to write as much Python as possible, to drive C++ 
objects, so I won't have to recompile, or restart my environment.  (Previous 
use of python had a slightly different goal: use Python minimally for a dynamic 
modeling problem)  So Python code will consist of interactive and 
non-interactive scripts.  These scripts receive objects, work with them, and 
return other objects.  There are no persistent Python objects.  There are 
probably Python classes designed as temporary wrappers of C++ classes.

Steps 
1) Embed Python in this C++ plug-in. [Done.]
2) Expose C++ objects (functions and/or data) defined by the plugin to Python.
3) Write code in Python to create and manipulate those objects.  (exec, not 
eval)
4) Write code in C++, but only when required to make (2) easy.  (Abundant 
existing code may hinder my goals, and force more C++)
5) Develop a library of unittest methods.


  __
Yahoo! Canada Toolbar: Search from anywhere on the web, and bookmark your 
favourite sites. Download it now at
http://ca.toolbar.yahoo.com.
___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] PyEval_EvalCode

2008-11-12 Thread Stefan Seefeld

Alan Baljeu wrote:
To solve this, I intend to write as much Python as possible, to drive 
C++ objects, so I won't have to recompile, or restart my environment. 
(Previous use of python had a slightly different goal: use Python 
minimally for a dynamic modeling problem) So Python code will consist 
of interactive and non-interactive scripts. These scripts receive 
objects, work with them, and return other objects. There are no 
persistent Python objects. There are probably Python classes designed 
as temporary wrappers of C++ classes.
Steps 
1) Embed Python in this C++ plug-in. [Done.]

2) Expose C++ objects (functions and/or data) defined by the plugin to Python.
3) Write code in Python to create and manipulate those objects.  (exec, not 
eval)
4) Write code in C++, but only when required to make (2) easy.  (Abundant 
existing code may hinder my goals, and force more C++)
5) Develop a library of unittest methods.

  


This sounds perfectly reasonable to me, FWIW.
An interesting question then is how you embed your interactive Python 
shell into the application's main event loop. But that's mainly an 
implementation detail. :-)


Regards,
  Stefan

--

 ...ich hab' noch einen Koffer in Berlin...

___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] PyEval_EvalCode

2008-11-12 Thread Alan Baljeu
>This sounds perfectly reasonable to me, FWIW.
>An interesting question then is how you embed your interactive Python shell 
>into the application's main event loop. But that's mainly an implementation 
>detail. :-)
>
>Regards,
 > Stefan

Well, rendering is on a separate thread, so no issue there.  My plan is:
1) create a console
2) type text into the console
3) ask you guys how to get the interactive Python shell to respond to that text.

If there's another option besides a console window, I'm interested.


  __
Be smarter than spam. See how smart SpamGuard is at giving junk email the boot 
with the All-new Yahoo! Mail.  Click on Options in Mail and switch to New Mail 
today or register for free at http://mail.yahoo.ca
___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] PyEval_EvalCode

2008-11-12 Thread David Abrahams

on Wed Nov 12 2008, Alan Baljeu  wrote:

>>This sounds perfectly reasonable to me, FWIW.
>>An interesting question then is how you embed your interactive Python shell 
>>into the
> application's main event loop. But that's mainly an implementation detail. :-)
>>
>>Regards,
>  > Stefan
>
> Well, rendering is on a separate thread, so no issue there.  My plan is:
> 1) create a console
> 2) type text into the console
> 3) ask you guys how to get the interactive Python shell to respond to that 
> text.

That looks like a question someone on the regular Python (non-C++) list
would likely be better at answering. 

> If there's another option besides a console window, I'm interested.

And that one too.

-- 
Dave Abrahams
BoostPro Computing
http://www.boostpro.com
___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig


[C++-sig] c++ object deleted

2008-11-12 Thread Renato Araujo
Hi all,

Is possible in boost::python create a exception when the c++ object is
deleted internal, and you try use the python object. Because here I
got a core when I try do this.

BR

-- 
Renato Araujo Oliveira Filho
___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] c++ object deleted

2008-11-12 Thread Stefan Seefeld

Renato Araujo wrote:

Hi all,

Is possible in boost::python create a exception when the c++ object is
deleted internal, and you try use the python object. Because here I
got a core when I try do this.
  


I'm not sure whether it's technically possible, but I do believe this is 
a bad idea: Exceptions are just the wrong tool to deal with programming 
errors. Instead, you need to figure out what the expected lifetime of 
your object is and why it got deleted before. Once you understand this, 
modify your boost.python wrappers to use the appropriate return-value 
(or call) policies so this doesn't happen again.


Regards,
  Stefan

--

 ...ich hab' noch einen Koffer in Berlin...

___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] Manage new object return policy (was Re: new to python; old to C++)

2008-11-12 Thread Paul Melis
David Abrahams wrote:
> on Mon Nov 10 2008, Paul Melis  wrote:
>
>   
>> The FAQ entry on this doesn't really help, so perhaps I'm not using the 
>> return policy
>> correctly or missing something else. The full test code (which is actually 
>> quite
>> small) is attached.
>> 
>
> Please reduce it to its absolute minimum.  Remove every single thing you
> don't need in order to produce the result.  If the problem isn't
> glaringly obvious to you then, I will help.
>   
Well, I tried reducing in several different ways. The bottom line is
that I can't seem to produce this without using the wrapper class (or
perhaps I missed the right combination of return policies).

Simplest test case (see below for the rest of the files):

#!/usr/bin/env python
from boost import *
 
class MyCallback(Callback):
 
def __init__(self):
Callback.__init__(self)
 
def __call__(self):
return Value()
 
cb = MyCallback()
 
r = go(cb)


Storing a reference to the Value instance returned in __call__ keeps the
instance alive, so the dangling pointer is caused by the Value instance
that is returned getting destructed. But this only happens when the
instance is passed through go() as its return value. When calling cb
directly the Value is not destructed (as I would expect). What I don't
understand is why it is destructed when it *is* passed through go(),
shouldn't the manage_new_object policy keep it alive?

Regards,
Paul

// classes.h

#ifndef CLASSES_H
#define CLASSES_H

#include 

class Value
{
public:
Value() { printf("Value::Value()\n"); }
Value(const Value& v)   { printf("Value::Value(const Value& v)\n"); }
~Value(){ printf("Value::~Value()\n"); }
};

class Callback
{
public:
Callback()  {}
Callback(const Callback& cb){}
virtual ~Callback() {}
// Returns new Value instance
virtual Value* operator()() { return new Value(); }
};

Value *go(Callback *cb)
{
return (*cb)();
};

#endif


// boost.cpp

// g++ -shared -fPIC -O3 -o boost.so -I/usr/include/python2.5 boost.cpp
-lboost_python -lpython2.5

#include 
#include "classes.h"

namespace bp = boost::python;

struct CallbackWrap : Callback, bp::wrapper
{
virtual Value *operator()()
{
printf("CallbackWrap::operator()\n");

if (bp::override call = this->get_override("__call__"))
{
printf("Have override for __call__, calling it\n");
return call();
}

return Callback::operator()();
}

Value *default_call()
{
printf("CallbackWrap::default_call()\n");
return this->Callback::operator()();
}
};


BOOST_PYTHON_MODULE(boost)
{
bp::class_< Value >("Value");

bp::class_< CallbackWrap, boost::noncopyable >("Callback")
.def("__call__", &Callback::operator(),
&CallbackWrap::default_call,
bp::return_value_policy());

bp::def("go", &go, bp::return_value_policy());
}



___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] Manage new object return policy (was Re: new to python; old to C++)

2008-11-12 Thread David Abrahams

on Wed Nov 12 2008, Paul Melis  wrote:

> David Abrahams wrote:
>> on Mon Nov 10 2008, Paul Melis  wrote:
>>
>>   
>>> The FAQ entry on this doesn't really help, so perhaps I'm not using the 
>>> return
> policy
>>> correctly or missing something else. The full test code (which is actually 
>>> quite
>>> small) is attached.
>>> 
>>
>> Please reduce it to its absolute minimum.  Remove every single thing you
>> don't need in order to produce the result.  If the problem isn't
>> glaringly obvious to you then, I will help.
>>   
> Well, I tried reducing in several different ways. The bottom line is
> that I can't seem to produce this without using the wrapper class (or
> perhaps I missed the right combination of return policies).

This is a classic example of the FAQ entry.  See below.

> Simplest test case (see below for the rest of the files):
>
> #!/usr/bin/env python
> from boost import *
>  
> class MyCallback(Callback):
>  
> def __init__(self):
> Callback.__init__(self)
>  
> def __call__(self):
> return Value()

A new C++ Value instance is created here, managed by a Python Value
instance.  When this function returns, its caller's stack frame will own
the only reference to Value.  When this is invoked from C++ as an
override of a C++ virtual function, its caller is a function in
Boost.Python.

>  
> cb = MyCallback()
>  
> r = go(cb)
>
>
> Storing a reference to the Value instance returned in __call__ keeps the
> instance alive, so the dangling pointer is caused by the Value instance
> that is returned getting destructed. But this only happens when the
> instance is passed through go() as its return value. When calling cb
> directly the Value is not destructed (as I would expect). What I don't
> understand is why it is destructed when it *is* passed through go(),
> shouldn't the manage_new_object policy keep it alive?

I hope the other things I've written above and below answer the first
question.  As for the second one, manage_new_object says to manage a new
C++ object's lifetime, and the problem you have is that a Python object
already owns the C++ object, and that object will go away.

I might have a hunch about how to fix some of these problems
using a Python WeakPtr, but unfortunately I don't have any time right
now to work on it.  Best I can do is suggest you open a Trac ticket
referencing this thread.

> Regards,
> Paul
>
> // classes.h
>
> #ifndef CLASSES_H
> #define CLASSES_H
>
> #include 
>
> class Value
> {
> public:
> Value() { printf("Value::Value()\n"); }
> Value(const Value& v)   { printf("Value::Value(const Value& v)\n"); }
> ~Value(){ printf("Value::~Value()\n"); }
> };
>
> class Callback
> {
> public:
> Callback()  {}
> Callback(const Callback& cb){}
> virtual ~Callback() {}
> // Returns new Value instance
> virtual Value* operator()() { return new Value(); }

This one doesn't get executed; it's been overridden by CallbackWrap.

> };
>
> Value *go(Callback *cb)
> {
> return (*cb)();
> };
>
> #endif
>
>
> // boost.cpp
>
> // g++ -shared -fPIC -O3 -o boost.so -I/usr/include/python2.5 boost.cpp
> -lboost_python -lpython2.5
>
> #include 
> #include "classes.h"
>
> namespace bp = boost::python;
>
> struct CallbackWrap : Callback, bp::wrapper
> {
> virtual Value *operator()()
> {
> printf("CallbackWrap::operator()\n");
>
> if (bp::override call = this->get_override("__call__"))
> {

A python override has been found here

> printf("Have override for __call__, calling it\n");
> return call();

It is invoked in the line above. To return control to you, Boost.Python
will reach into the Python Value object to pull out a pointer to the C++
Value object it manages.  However, in your case, the reference count on
the Python object is 1, and the C++ object will have been deleted by its
owner Python object by the time the library returns.

> }
>
> return Callback::operator()();
> }
>
> Value *default_call()
> {
> printf("CallbackWrap::default_call()\n");
> return this->Callback::operator()();
> }
> };
>
>
> BOOST_PYTHON_MODULE(boost)
> {
> bp::class_< Value >("Value");
>
> bp::class_< CallbackWrap, boost::noncopyable >("Callback")
> .def("__call__", &Callback::operator(),
> &CallbackWrap::default_call,
> bp::return_value_policy());
>
> bp::def("go", &go, bp::return_value_policy());
> }
>
>
>
> ___
> Cplusplus-sig mailing list
> Cplusplus-sig@python.org
> http://mail.python.org/mailman/listinfo/cplusplus-sig
>

-- 
Dave Abrahams
BoostPro Computing
http://www.boostpro.com
___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] c++ object deleted

2008-11-12 Thread Renato Araujo
The main problem here is my parent control.

My object life is controlled by the parent life time:

somethin like that:

struct object
{
  object(object *parent)
  { parent.add_child(this); }

  ~object()

}



On Wed, Nov 12, 2008 at 2:14 PM, Stefan Seefeld <[EMAIL PROTECTED]> wrote:
> Renato Araujo wrote:
>>
>> Hi all,
>>
>> Is possible in boost::python create a exception when the c++ object is
>> deleted internal, and you try use the python object. Because here I
>> got a core when I try do this.
>>
>
> I'm not sure whether it's technically possible, but I do believe this is a
> bad idea: Exceptions are just the wrong tool to deal with programming
> errors. Instead, you need to figure out what the expected lifetime of your
> object is and why it got deleted before. Once you understand this, modify
> your boost.python wrappers to use the appropriate return-value (or call)
> policies so this doesn't happen again.
>
> Regards,
>  Stefan
>
> --
>
> ...ich hab' noch einen Koffer in Berlin...
>
> ___
> Cplusplus-sig mailing list
> Cplusplus-sig@python.org
> http://mail.python.org/mailman/listinfo/cplusplus-sig
>



-- 
Renato Araujo Oliveira Filho
___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig