Define class in 2 scopes without re-exposing

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Define class in 2 scopes without re-exposing

John Reid-3
Hi,

If I want to define the same class (Inner) in 2 different scopes (Outer1
and Outer 2), I can do it like this:

#include <boost/python.hpp>

struct Outer1 {};
struct Outer2 {};
struct Inner {};

BOOST_PYTHON_MODULE( _sandbox )
{
     namespace bp = ::boost::python;
     {
         bp::scope scope = bp::class_< Outer1 >( "Outer1" );
         bp::class_< Inner >( "Inner" );
     }

     {
         bp::scope scope = bp::class_< Outer2 >( "Outer2" );
         bp::class_< Inner >( "Inner" );
     }
}


Unfortunately when I import the _sandbox module I get the standard error:

RuntimeWarning: to-Python converter for Inner already registered; second
conversion method ignored.

and in debug build the second Inner registration asserts.

Is there any way to test if Inner is already registered and if so just
place it in the correct scope? Perhaps replacing the second scoped block
with something like this:

     {
         bp::object class_Outer2 = bp::class_< Outer2 >( "Outer2" );
         bp::type_info info = boost::python::type_id< Inner >();
         const bp::converter::registration * reg =
bp::converter::registry::query( info );
         if( NULL == reg ) {
             bp::class_< Inner >( "Inner" );
         } else {
             // Some magic here!
         }
     }

Also I should say that the 2 scoped blocks of code aren't adjacent in my
library so I don't really want to pass objects between them. I'm hoping
for a solution that just extracts info from the boost.python registry.

Thanks for any help,
John.

_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Define class in 2 scopes without re-exposing

Dave Abrahams

on Fri Apr 13 2012, John Reid <j.reid-AT-mail.cryst.bbk.ac.uk> wrote:

> Hi,
>
> If I want to define the same class (Inner) in 2 different scopes
> (Outer1 and Outer 2), I can do it like this:
>
> #include <boost/python.hpp>
>
> struct Outer1 {};
> struct Outer2 {};
> struct Inner {};
>
> BOOST_PYTHON_MODULE( _sandbox )
> {
>     namespace bp = ::boost::python;
>     {
>         bp::scope scope = bp::class_< Outer1 >( "Outer1" );
>         bp::class_< Inner >( "Inner" );
>     }
>
>     {
>         bp::scope scope = bp::class_< Outer2 >( "Outer2" );
>         bp::class_< Inner >( "Inner" );
>     }
> }
>
> Unfortunately when I import the _sandbox module I get the standard error:
>
> RuntimeWarning: to-Python converter for Inner already registered;
> second conversion method ignored.
>
> and in debug build the second Inner registration asserts.

You can't do this; don't even try.  Each C++ class has to have a unique
Python identity.  If you just want to refer to the same class by a
different name, you can of course:

BOOST_PYTHON_MODULE( _sandbox )
{
    namespace bp = ::boost::python;
    object inner;
    {
        bp::scope scope = bp::class_< Outer1 >( "Outer1" );
        inner = bp::class_< Inner >( "Inner" );
    }

    {
        object outer2 = bp::class_< Outer2 >( "Outer2" );
        outer2.attr("Inner") = inner;
    }
}

> Is there any way to test if Inner is already registered and if so just
> place it in the correct scope? Perhaps replacing the second scoped
> block with something like this:
>
>     {
>         bp::object class_Outer2 = bp::class_< Outer2 >( "Outer2" );
>         bp::type_info info = boost::python::type_id< Inner >();
>         const bp::converter::registration * reg =
> bp::converter::registry::query( info );
>         if( NULL == reg ) {
>             bp::class_< Inner >( "Inner" );
>         } else {
>             // Some magic here!
>         }
>     }
>
> Also I should say that the 2 scoped blocks of code aren't adjacent in
> my library so I don't really want to pass objects between them. I'm
> hoping for a solution that just extracts info from the boost.python
> registry.

BOOST_PYTHON_MODULE( _sandbox )
{
    namespace bp = ::boost::python;
    {
        bp::scope scope = bp::class_< Outer1 >( "Outer1" );
        bp::class_< Inner >( "Inner" );
    }

    {
        object outer2 = bp::class_< Outer2 >( "Outer2" );
        outer2.attr("Inner") = scope().attr("Outer1").attr("Inner");
    }
}

HTH-ly y'rs,

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Define class in 2 scopes without re-exposing

John Reid-3


On 15/04/12 03:23, Dave Abrahams wrote:

>
> You can't do this; don't even try.  Each C++ class has to have a unique
> Python identity.  If you just want to refer to the same class by a
> different name, you can of course:
>
> BOOST_PYTHON_MODULE( _sandbox )
> {
>      namespace bp = ::boost::python;
>      object inner;
>      {
>          bp::scope scope = bp::class_<  Outer1>( "Outer1" );
>          inner = bp::class_<  Inner>( "Inner" );
>      }
>
>      {
>          object outer2 = bp::class_<  Outer2>( "Outer2" );
>          outer2.attr("Inner") = inner;
>      }
> }
>

I didn't know you could do that and it is useful but it is not quite
what I had in mind. I would rather not pass the inner object around all
the parts of my code that might need it. Is it possible to get it out of
the registry in the second block? I'm guessing it must be in there
somewhere as I get exactly the same behaviour (plus the warning message)
if I just register the class in both blocks.

Thanks,
John.

_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Define class in 2 scopes without re-exposing

Jim Bosch-2
On 04/16/2012 03:15 AM, John Reid wrote:

>
>
> On 15/04/12 03:23, Dave Abrahams wrote:
>>
>> You can't do this; don't even try. Each C++ class has to have a unique
>> Python identity. If you just want to refer to the same class by a
>> different name, you can of course:
>>
>> BOOST_PYTHON_MODULE( _sandbox )
>> {
>> namespace bp = ::boost::python;
>> object inner;
>> {
>> bp::scope scope = bp::class_< Outer1>( "Outer1" );
>> inner = bp::class_< Inner>( "Inner" );
>> }
>>
>> {
>> object outer2 = bp::class_< Outer2>( "Outer2" );
>> outer2.attr("Inner") = inner;
>> }
>> }
>>
>
> I didn't know you could do that and it is useful but it is not quite
> what I had in mind. I would rather not pass the inner object around all
> the parts of my code that might need it. Is it possible to get it out of
> the registry in the second block? I'm guessing it must be in there
> somewhere as I get exactly the same behaviour (plus the warning message)
> if I just register the class in both blocks.
>

You can get it from the registry (see below), but it requires relying on
what I'd consider implementation details of the library.

If you can, I'd recommend just importing the module that contains outer1
and doing the above trick with that:

bp::object mod1 = bp::import("module1");
bp::object outer2 = bp::class_< Outer2 >("Outer2");
outer2.attr("Inner") = mod1.attr("Outer1").attr("Inner");

If you do really want to use the registry, I think you want something
like this:

bp::converter::registration const * reg =
     bp::converter::registry::query(bp::type_id<Inner>());
assert(reg); // 0 if you haven't wrapped Inner yet
bp::object inner(bp::handle<>(bp::borrowed(
     reinterpret_cast<PyObject*>(reg.get_class_object())
)));



Jim
_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Define class in 2 scopes without re-exposing

Dave Abrahams
In reply to this post by John Reid-3

on Mon Apr 16 2012, John Reid <j.reid-AT-mail.cryst.bbk.ac.uk> wrote:

> On 15/04/12 03:23, Dave Abrahams wrote:
>>
>> You can't do this; don't even try.  Each C++ class has to have a unique
>> Python identity.  If you just want to refer to the same class by a
>> different name, you can of course:
>>
>
>> BOOST_PYTHON_MODULE( _sandbox )
>> {
>>      namespace bp = ::boost::python;
>>      object inner;
>>      {
>>          bp::scope scope = bp::class_<  Outer1>( "Outer1" );
>>          inner = bp::class_<  Inner>( "Inner" );
>>      }
>>
>>      {
>>          object outer2 = bp::class_<  Outer2>( "Outer2" );
>>          outer2.attr("Inner") = inner;
>>      }
>> }
>>
>
> I didn't know you could do that and it is useful but it is not quite
> what I had in mind. I would rather not pass the inner object around
> all the parts of my code that might need it. Is it possible to get it
> out of the registry in the second block?

Why don't you read to the end of my posting?  The answer's there at the
bottom :-)

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Define class in 2 scopes without re-exposing

John Reid-3


On 16/04/12 19:13, Dave Abrahams wrote:

>
> on Mon Apr 16 2012, John Reid <j.reid-AT-mail.cryst.bbk.ac.uk> wrote:
>
>> On 15/04/12 03:23, Dave Abrahams wrote:
>>>
>>> You can't do this; don't even try.  Each C++ class has to have a unique
>>> Python identity.  If you just want to refer to the same class by a
>>> different name, you can of course:
>>>
>>
>>> BOOST_PYTHON_MODULE( _sandbox )
>>> {
>>>      namespace bp = ::boost::python;
>>>      object inner;
>>>      {
>>>          bp::scope scope = bp::class_<  Outer1>( "Outer1" );
>>>          inner = bp::class_<  Inner>( "Inner" );
>>>      }
>>>
>>>      {
>>>          object outer2 = bp::class_<  Outer2>( "Outer2" );
>>>          outer2.attr("Inner") = inner;
>>>      }
>>> }
>>>
>>
>> I didn't know you could do that and it is useful but it is not quite
>> what I had in mind. I would rather not pass the inner object around
>> all the parts of my code that might need it. Is it possible to get it
>> out of the registry in the second block?
>
> Why don't you read to the end of my posting?  The answer's there at the
> bottom :-)
>

Thanks! I was guilty of reading your post too quickly. And thx to Jim
too for what looks like a similar method.

John.

_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Loading...