Wrapping a function that takes class type, such as type_info

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Wrapping a function that takes class type, such as type_info

Adam Preble
I am using Boost 1.47

I have these class methods:

void Remove(const std::type_info &type);
void Remove(const boost::python::type_info type);

I tried wrapping them both in Boost.Python:

void (Entity::*Remove1)(const std::type_info&) = &Foo::Remove;
void (Entity::*Remove2)(const boost::python::type_info) = & Foo::Remove;

class_< Foo , boost::noncopyable, shared_ptr< Foo > >(" Foo", init<>())
...
.def("Remove", Remove1)
.def("Remove", Remove2)
...

(I just tried type_info of both namespaces to be comprehensive here...)

It'll compile and and I'll get that Remove method fine.  Except I can't seem to cram something into it when I try to actually execute the subroutine.  Say I have class Bar wrapped in Python too, and I have been using it fine and dandy.  How do I get Remove() to accept the type of Bar as an argument?

Say:

foo = Foo()
foo.Remove(Bar)...            
foo.Remove(type(Bar))...    

I just can't get any love here:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
    foo.Remove(Foo, type)
did not match C++ signature:
    Remove(class game::Entity {lvalue}, struct boost::python::type_info)
    Remove(class game::Entity {lvalue}, class type_info)



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

Re: Wrapping a function that takes class type, such as type_info

Adam Preble
I think I need to ask a better question here, so I'm coming back here with an adjusted situation.  I've found I can't get Python to bind up to prototypes for stuff taking std::type_info or boost::type_info.  I suppose I should be surprised if it actually did.  I'm thinking--what if I have a Python implementation of an interface I defined in C++?  It would be really odd if that would even be compatible with type_info in any way.  I am thinking type_info is not the way to go, but I see some code in Boost dealing with PyType.

I figure what I need instead is a method that types something else than type_info, but what I need is a mystery.  For giggles, I just tried to take a PyObject* and pass in whatever.  if I give it from Python type(Foo) then I think I get a PyType.  I see some stuff in Boost source code about working with these.  I'm wondering, is there any helpers for this?  Or any idea at all what to do?

I suppose the overall situation is this: imagine I have a container of pointers referencing some interface.  The container contains potentially both C++ and Python implementations.  All implementations are exposed in Python.  Is there a way I could pass in some kind of type information and be able to positively identify if something in that container matches the type?

On Tue, Feb 21, 2012 at 2:03 AM, Adam Preble <[hidden email]> wrote:
It'll compile and and I'll get that Remove method fine.  Except I can't seem to cram something into it when I try to actually execute the subroutine.  Say I have class Bar wrapped in Python too, and I have been using it fine and dandy.  How do I get Remove() to accept the type of Bar as an argument?


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

Re: Wrapping a function that takes class type, such as type_info

Jim Bosch-2
On 02/23/2012 02:31 AM, Adam Preble wrote:
> I think I need to ask a better question here, so I'm coming back here with
> an adjusted situation.  I've found I can't get Python to bind up to
> prototypes for stuff taking std::type_info or boost::type_info.  I suppose
> I should be surprised if it actually did.  I'm thinking--what if I have a
> Python implementation of an interface I defined in C++?  It would be really
> odd if that would even be compatible with type_info in any way.  I am
> thinking type_info is not the way to go, but I see some code in Boost
> dealing with PyType.
>

Glad you sent this; I was about to reply to your last with something
that probably wouldn't have been very helpful, for the reasons you've
already noted yourself.

> I figure what I need instead is a method that types something else than
> type_info, but what I need is a mystery.  For giggles, I just tried to take
> a PyObject* and pass in whatever.  if I give it from Python type(Foo) then
> I think I get a PyType.  I see some stuff in Boost source code about
> working with these.  I'm wondering, is there any helpers for this?  Or any
> idea at all what to do?
>

You can probably find out a lot from just looking at the Python C API
reference documentation for type objects.  You'll need to use that
directly for a lot of your interaction with them, because there's no
Boost.Python wrapper (like there is for, say, tuple or str).

The main place you'll see them in Boost.Python is that this is actually
what a boost::python::class_ object holds under the hood; you can assign
that to a boost::python::object to get the type object without having to
carry around all the template parameters.

> I suppose the overall situation is this: imagine I have a container of
> pointers referencing some interface.  The container contains potentially
> both C++ and Python implementations.  All implementations are exposed in
> Python.  Is there a way I could pass in some kind of type information and
> be able to positively identify if something in that container matches the
> type?
>

Yes, as long as:

- You can do the checking with a Python function that operates on type
objects, like isinstance and issubclass (or their C API equivalents,
PyObject_IsInstance and PyObject_IsSubclass).

- You are content with looking up a PyTypeObject* given a C++ type_info,
and not the other way around; you can use
boost::python::converter::registry::lookup to find the PyTypeObject for
a Boost.Python-wrapped class.  That's deep in the bowels of
Boost.Python's internals - see converter/registry.hpp and
converter/registration.hpp to learn more - but it's quite usable.



Jim

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

Re: Wrapping a function that takes class type, such as type_info

Adam Preble
Jim,

I'll top post since I think this might get messy nice and fast otherwise.  I found I couldn't get to a method wrapped to type a PyTypeObject* and only PyObject* would do.  Despite all this, I managed to twist your advice around just enough to birth this abomination:

bool ContainsImplementables::Has(PyObject* noIdea)
{
for(std::list<boost::shared_ptr<Implementable> >::iterator i = implementables.begin(); i != implementables.end(); ++i)
{
Implementable* imp = (*i).get();
boost::python::converter::registration registration = boost::python::converter::registry::lookup(boost::python::type_info(typeid(*imp)));
PyTypeObject* internal_type = const_cast<PyTypeObject*>(registration.to_python_target_type());      // const_cast heresy
if(internal_type != NULL)
{
if(PyObject_IsInstance((PyObject*) internal_type, noIdea) == 1)
{
return true;
}
}
}

return false;
}

Well, it doesn't crash!  I really don't know if I'm getting all the right things in order, but I know in the debugger the stuff doesn't look like complete garbage, and  internal_type isn't NULL.  The PyObject_IsInstance() is never working when I pass in a class to Has() and it's always claiming true if I pass type(class) to the Has() method there, regardless if the particular class in question is actually contained inside there.  I tried to step into that particular code and it was pretty rough on the eyes; I couldn't figure out anything.

So to be more explicit about what happens:

cont = ContainsImplementables()
cont.Add(CImplementation())
cont.Add(PythonImplementation())

cont.Has(CImplementation) # False
cont.Has(type(CImplementation)) # True
cont.Has(PythonImplementation) # False
cont.Has(type( Python Implementation)) # True
cont.Has(AnotherPythonImplementation) # False
cont.Has(type(AnotherPythonImplementation)) # True

Am I anywhere near close on this? 

On Thu, Feb 23, 2012 at 10:03 AM, Jim Bosch <[hidden email]> wrote:

You can probably find out a lot from just looking at the Python C API reference documentation for type objects.  You'll need to use that directly for a lot of your interaction with them, because there's no Boost.Python wrapper (like there is for, say, tuple or str).

The main place you'll see them in Boost.Python is that this is actually what a boost::python::class_ object holds under the hood; you can assign that to a boost::python::object to get the type object without having to carry around all the template parameters.


I suppose the overall situation is this: imagine I have a container of
pointers referencing some interface.  The container contains potentially
both C++ and Python implementations.  All implementations are exposed in
Python.  Is there a way I could pass in some kind of type information and
be able to positively identify if something in that container matches the
type?


Yes, as long as:

- You can do the checking with a Python function that operates on type objects, like isinstance and issubclass (or their C API equivalents, PyObject_IsInstance and PyObject_IsSubclass).

- You are content with looking up a PyTypeObject* given a C++ type_info, and not the other way around; you can use boost::python::converter::registry::lookup to find the PyTypeObject for a Boost.Python-wrapped class.  That's deep in the bowels of Boost.Python's internals - see converter/registry.hpp and converter/registration.hpp to learn more - but it's quite usable.



Jim

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


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

Re: Wrapping a function that takes class type, such as type_info

Jim Bosch-2
On 02/24/2012 02:31 AM, Adam Preble wrote:
> Jim,
>
> I'll top post since I think this might get messy nice and fast
> otherwise.  I found I couldn't get to a method wrapped to type a
> PyTypeObject* and only PyObject* would do.

Yeah, that's not surprising.  You can also have it take a
boost::python::object; that's essentially a smart pointer for PyObject*.

> if(PyObject_IsInstance((PyObject*) internal_type, noIdea) == 1)

I think this is the only line that needs to change; you just need to use
PyObject_IsSubClass instead of PyObject_IsInstance.

Right now you're asking whether "internal_type" is an instance of
"noIdea", so the answer is only True when "noIdea" is "type".

I think you want to ask whether "internal_type" is a subclass of
"noIdea".  And that's just:

if (PyObject_IsInstance((PyObject*)internal_type, noIdea) == 1)



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

Re: Wrapping a function that takes class type, such as type_info

Adam Preble
It looks like PyObject_IsSubClass is working (!), but I wanted to follow up on the boost::python::object stuff:

On Fri, Feb 24, 2012 at 9:56 PM, Jim Bosch <[hidden email]> wrote:
On 02/24/2012 02:31 AM, Adam Preble wrote:
Jim,

I'll top post since I think this might get messy nice and fast
otherwise.  I found I couldn't get to a method wrapped to type a
PyTypeObject* and only PyObject* would do.

Yeah, that's not surprising.  You can also have it take a boost::python::object; that's essentially a smart pointer for PyObject*.

I couldn't get that to work.  I can't pass it directly into PyObject_IsSubclass, which isn't surprising.  However, I couldn't do a get or find anything else to extract the PyObject* out of it.  Is there a trick to this?  I would wonder--is there a particular reason I should use that instead?  In my case, I'm not trying to sit on the pointer outside of the class to Has().  The list I'm using has shared_ptr's of the underlying type already.  So I assume in my particular case I wouldn't have to worry about it.
 
 

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

Re: Wrapping a function that takes class type, such as type_info

Jim Bosch-2
On 02/25/2012 09:25 AM, Adam Preble wrote:

> It looks like PyObject_IsSubClass is working (!), but I wanted to follow up
> on the boost::python::object stuff:
>
> On Fri, Feb 24, 2012 at 9:56 PM, Jim Bosch<[hidden email]>  wrote:
>
>> On 02/24/2012 02:31 AM, Adam Preble wrote:
>>
>>> Jim,
>>>
>>> I'll top post since I think this might get messy nice and fast
>>> otherwise.  I found I couldn't get to a method wrapped to type a
>>> PyTypeObject* and only PyObject* would do.
>>>
>>
>> Yeah, that's not surprising.  You can also have it take a
>> boost::python::object; that's essentially a smart pointer for PyObject*.
>>
>
> I couldn't get that to work.  I can't pass it directly into
> PyObject_IsSubclass, which isn't surprising.  However, I couldn't do a get
> or find anything else to extract the PyObject* out of it.  Is there a trick
> to this?  I would wonder--is there a particular reason I should use that
> instead?  In my case, I'm not trying to sit on the pointer outside of the
> class to Has().  The list I'm using has shared_ptr's of the underlying type
> already.  So I assume in my particular case I wouldn't have to worry about
> it.
>

It's - probably unfortunately - just a totally non-standard accessor:
".ptr()".

But you're basically right - there's really no need to worry about
managing the pointer lifetime in this case, so PyObject * is just fine.

Jim

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