The Python generate() call is creating a Python TestExtendedFactory object, which is derived from the Python wrapper for BasicFactory, so it contains a C++ BasicFactory. Does it contain a C++ Factory object? not unless BasicFactory is derived from Factory and, from Boost.Python's POV, not unless its class_ names Factory as one of its bases<...>. You didn't show the declaration of BasicFactory, so it's hard to say much about it.
A lack of bases was indeed the problem. I generated the source with a patched and updated version of Pyste that has new-style polymorphism and handles wrapped classes that have holders, and had an incorrect test that resulted in the bases not being included. Thanks! That has led me to a question on what is required in terms of implicit conversion calls to handle classes in the same hierarchy that are wrapped with wrapper<> and held by smart pointers. I can't seem to find a combination to allow derivation from both Factory and BasicFactory. If I have a python class that derives from Factory, held by a smart pointer, I need the implicit conversion defined below in Factory.cpp for it to work. If I have a python class that derives from BasicFactory (which itself derives from Factory), also held by a smart pointer, I need the implicit conversions in BasicFactory for that to work. However if I have both, a python class derived from BasicFactory will segfault. My guess is that that's because there's two converters between classes in the same hierarchy to a smart_ptr<Factory>, and it's looping in trying to resolve that. Am I doing something wrong in how I'm setting up the implicit conversions? Or should only the base class have the holder specificied, with derived classes getting it automatically (although I tried this and couldn't make it work)? As a side note the Factory and BasicFactory classes are exported in separate modules. I'm not sure that that's relevant though. Below is the boost python code for Factory/BasicFactory, the C++ for the example Runner class to show how the factory is used, and python to show the usage. I've also added some gdb output to show the loop and the initial entry into it. Apologies if this is too verbose. Thanks in advance for any help. Scott ------ Factory.cpp namespace { struct Factory_Wrapper: Factory, wrapper< Factory > { Factory_Wrapper(const Factory& p0): Factory(p0) {} Factory_Wrapper(): Factory() {} Factory& generate(SourceGroup& p0) { if (override f = this->get_override("generate")) return call< Factory& >( f.ptr(), boost::ref(p0)); return Factory::generate(boost::ref(p0)); } Factory& default_generate(SourceGroup& p0) { return Factory::generate(boost::ref(p0)); } }; }// namespace void Export_Factory() { class_< Factory_Wrapper, smart_ptr< Factory_Wrapper > >("Factory", init< >()) .def("generate", &Factory::generate, &Factory_Wrapper::default_generate, return_self<>()) .def(init< const Factory& >()) ; implicitly_convertible< smart_ptr< Factory_Wrapper >, smart_ptr< Factory > >(); implicitly_convertible< smart_ptr< Factory >, smart_ptr< Factory_Wrapper > >(); } ---- BasicFactory namespace { struct BasicFactory_Wrapper: BasicFactory, wrapper< BasicFactory > { BasicFactory_Wrapper(const BasicFactory& p0): BasicFactory(p0) {} BasicFactory_Wrapper(): BasicFactory() {} Factory& generate(SourceGroup& p0) { if (override f = this->get_override("generate")) return call< Factory& >( f.ptr(), boost::ref(p0)); return BasicFactory::generate(boost::ref(p0)); } Factory& default_generate(SourceGroup& p0) { return BasicFactory::generate(boost::ref(p0)); } }; }// namespace void Export_BasicFactory() { class_< BasicFactory_Wrapper, bases< Factory > , smart_ptr< BasicFactory_Wrapper > >("BasicFactory", init< >()) .def("generate", (Factory& (BasicFactory::*)(SourceGroup&) )&BasicFactory::generate, (Factory& (BasicFactory_Wrapper::*)(SourceGroup&))&BasicFactory_Wrapper::default_generate, return_self<>()) .def(init< const BasicFactory& >()) ; implicitly_convertible< smart_ptr< BasicFactory_Wrapper >, smart_ptr< Factory > >(); implicitly_convertible< smart_ptr< Factory >, smart_ptr< BasicFactory_Wrapper > >(); } ----- Dummy class to show how we use it: class Runner { SourceGroup _docs; smart_ptr<Factory> _factory; public: Runner() {} void setFactory( const smart_ptr<Factory> &factory ) { _factory = factory; } void run() { _factory->generate( _docs ); std::cout << "Generated: " << _docs.size() << " docs.\n"; } }; ------- Python usage example: class TestExtendedFactory( X.BasicFactory ): def __init__( self ): # call init of parent to setup smart pointers correctly super( TestExtendedFactory, self ).__init__() def generate( self, output ): super( TestExtendedFactory, self ).generate( output ) return self def main(): runner = X.Runner() myFactory = TestExtendedFactory() runner.setFactory( myFactory ) runner.run() #3564 0x0e3aaa10 in boost::python::converter::extract_rvalue<smart_ptr<Factory>
::operator() (this=0xdfe34180) at extract.hpp:175 #3565 0x0e3aa381 in boost::python::converter::implicit<smart_ptr<Factory>, smart_ptr<(anonymous namespace)::Factory_Wrapper> >::construct (obj=0xe1c25a4, data=0xdfe34234) at implicit.hpp:33 #3566 0x0e3b9f51 in boost::python::converter::rvalue_from_python_stage2 (source=0xe1c25a4, data=@0xdfe34234, converters=@0x81a3cd0) at boost/build-1.32.0/boost_1_32_0/libs/python/build/../src/converter/from_python.cpp:112 #3567 0x0e3aa8b2 in boost::python::converter::extract_rvalue<smart_ptr<(anonymous namespace)::Factory_Wrapper> >::operator() (this=0xdfe34230) at extract.hpp:175 #3568 0x0e3aa1cd in boost::python::converter::implicit<smart_ptr<(anonymous namespace)::Factory_Wrapper>, smart_ptr<Factory> >::construct (obj=0xe1c25a4, data=0xdfe342e4) at implicit.hpp:33 #3569 0x0e3b9f51 in boost::python::converter::rvalue_from_python_stage2 (source=0xe1c25a4, data=@0xdfe342e4, converters=@0x81a3be0) at boost/build-1.32.0/boost_1_32_0/libs/python/build/../src/converter/from_python.cpp:112 #3570 0x0e3aaa10 in boost::python::converter::extract_rvalue<smart_ptr<Factory> ::operator() (this=0xdfe342e0) at extract.hpp:175 #3571 0x0e3aa381 in boost::python::converter::implicit<smart_ptr<Factory>, smart_ptr<(anonymous namespace)::Factory_Wrapper> >::construct (obj=0xe1c25a4, data=0xdfe34394) at implicit.hpp:33 #3572 0x0e3b9f51 in boost::python::converter::rvalue_from_python_stage2 (source=0xe1c25a4, data=@0xdfe34394, converters=@0x81a3cd0) at boost/build-1.32.0/boost_1_32_0/libs/python/build/../src/converter/from_python.cpp:112 #3573 0x0e3aa8b2 in boost::python::converter::extract_rvalue<smart_ptr<(anonymous namespace)::Factory_Wrapper> >::operator() (this=0xdfe34390) at extract.hpp:175 #3574 0x0e3aa1cd in boost::python::converter::implicit<smart_ptr<(anonymous namespace)::Factory_Wrapper>, smart_ptr<Factory> >::construct (obj=0xe1c25a4, data=0xdfe34444) at implicit.hpp:33 #3575 0x0e3b9f51 in boost::python::converter::rvalue_from_python_stage2 (source=0xe1c25a4, data=@0xdfe34444, converters=@0x81a3be0) at boost/build-1.32.0/boost_1_32_0/libs/python/build/../src/converter/from_python.cpp:112
.... #35422 0x0e3aa8b2 in boost::python::converter::extract_rvalue<smart_ptr<(anonymous namespace)::Factory_Wrapper> >::operator() (this=0xdfffc570) at extract.hpp:175 #35423 0x0e3aa1cd in boost::python::converter::implicit<smart_ptr<(anonymous namespace)::Factory_Wrapper>, smart_ptr<Factory> >::construct (obj=0xe1c2644, data=0xdfffc630) at implicit.hpp:33 #35424 0x0e3b9a93 in boost::python::converter::arg_rvalue_from_python<smart_ptr<Factory> const&>::operator() (this=0xdfffc630) at arg_from_python.hpp:321 #35425 0x0e3b9705 in boost::python::detail::invoke<int, void (Runner::*)(smart_ptr<Factory> const&), boost::python::arg_from_python<Runner&>, boost::python::arg_from_python<smart_ptr<Factory> const&> > (f=@0x81a576c, tc=@0xdfffc648, ac0=@0xdfffc630) at invoke.hpp:94 #35426 0x0e3b9258 in boost::python::detail::caller_arity<2u>::impl<void (Runner::*)(smart_ptr<Factory> const&), boost::python::default_call_policies, boost::mpl::vector3<void, Runner&, smart_ptr<Factory> const&> >::operator() (this=0x81a576c, args_=0xe1bff8c) at caller.hpp:199 #35427 0x0e3b8d5e in boost::python::objects::caller_py_function_impl<boost::python::detail::caller<void (Runner::*)(smart_ptr<Factory> const&), boost::python::default_call_policies, boost::mpl::vector3<void, Runner&, smart_ptr<Factory> const&> > >::operator() (this=0x81a5768, args=0xe1bff8c, kw=0x0) at py_function.hpp:38 #35428 0x0e3c2df5 in boost::python::objects::py_function::operator() (this=0x81a5780, args=0xe1bff8c, kw=0x0) at py_function.hpp:139 #35429 0x0e3c189c in boost::python::objects::function::call (this=0x81a5778, args=0xe1bff8c, keywords=0x0) at boost/build-1.32.0/boost_1_32_0/libs/python/build/../src/object/function.cpp:212 #35430 0x0e3c4bae in boost::python::objects::(anonymous namespace)::bind_return::operator() (this=0xdfffc830) at boost/build-1.32.0/boost_1_32_0/libs/python/build/../src/object/function.cpp:505