Boost C++ Libraries: Ticket #2049: extracting c++ pointer from python object with multiple parents https://svn.boost.org/trac10/ticket/2049 <p> Extracting a C++ pointer from a python object which inherited two base classes form C++ doesn't work correctly. Only the first base can be extracted, the second cannot be extracted under all circumstances. The script runs within an embedded python interpreter. </p> <p> CPP code: </p> <pre class="wiki">#define BOOST_PYTHON_STATIC_LIB #include &lt;boost/python.hpp&gt; using namespace boost::python; class Base1 { public: virtual ~Base1() {} }; class Base2 { public: virtual ~Base2() {} }; void extractBase1( boost::python::object&amp; obj) { Base1* ex1 = extract&lt;Base1*&gt;(obj) BOOST_EXTRACT_WORKAROUND; Base1&amp; ex2 = extract&lt;Base1&amp;&gt;(obj) BOOST_EXTRACT_WORKAROUND; } void extractBase2( boost::python::object&amp; obj) { Base2* ex1 = extract&lt;Base2*&gt;(obj) BOOST_EXTRACT_WORKAROUND; Base2&amp; ex2 = extract&lt;Base2&amp;&gt;(obj) BOOST_EXTRACT_WORKAROUND; } BOOST_PYTHON_MODULE(Test_ext) { class_&lt;Base1, boost::noncopyable&gt;("Base1"); class_&lt;Base2, boost::noncopyable&gt;("Base2"); def("extractBase1", extractBase1); def("extractBase2", extractBase2); } int main(int, char **) { try { Py_Initialize(); initTest_ext(); object main = import("__main__"); object dictionary(main.attr("__dict__")); object result = exec_file("test.py", dictionary, dictionary ); } catch (error_already_set) { PyErr_Print(); } return 0; } </pre><p> test.py: </p> <pre class="wiki"> from Test_ext import * class both1(Base1, Base2): def foo(self): print "foo!" class both2(Base2, Base1): def foo(self): print "foo2!" obj1 = both1() extractBase1(obj1) extractBase2(obj1) # doesn't work obj2 = both() extractBase1(obj2) # doesn't work extractBase2(obj2) </pre> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/2049 Trac 1.4.3 Dave Abrahams Wed, 25 Jun 2008 16:38:24 GMT <link>https://svn.boost.org/trac10/ticket/2049#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/2049#comment:1</guid> <description> <p> Does this fail even when the dtors are non-virtual? </p> </description> <category>Ticket</category> </item> <item> <author>bloodyfanatic@…</author> <pubDate>Wed, 25 Jun 2008 16:48:15 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/2049#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/2049#comment:2</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/2049#comment:1" title="Comment 1">dave</a>: </p> <blockquote class="citation"> <p> Does this fail even when the dtors are non-virtual? </p> </blockquote> <p> yes it does, with the same error as always: </p> <pre class="wiki">Traceback (most recent call last): File "test.py", line 15, in &lt;module&gt; extractBase2(obj1) # doesn't work TypeError: No registered converter was able to extract a C++ pointer to type class Base2 from this Python object of type both1 </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>Dave Abrahams</dc:creator> <pubDate>Thu, 26 Jun 2008 14:27:58 GMT</pubDate> <title>status changed; cc, resolution set https://svn.boost.org/trac10/ticket/2049#comment:3 https://svn.boost.org/trac10/ticket/2049#comment:3 <ul> <li><strong>cc</strong> <span class="trac-author">Stefan Seefeld</span> added </li> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">invalid</span> </li> </ul> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/2049#comment:2" title="Comment 2">bloodyfanatic@gmx.de</a>: </p> <blockquote class="citation"> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/2049#comment:1" title="Comment 1">dave</a>: </p> <blockquote class="citation"> <p> Does this fail even when the dtors are non-virtual? </p> </blockquote> <p> yes it does, with the same error as always: </p> </blockquote> <p> In that case, please post the <em>fully reduced</em> test case </p> <p> Also, you need an <span class="underline">init</span> method in both1 and both2 that initializes *both* bases or this can never work, because a wrapped class' <span class="underline">init</span> function is what actually constructs the C++ base object. Without it, there is no base object to which a pointer can be returned from <code>extract</code>: </p> <pre class="wiki"> def __init__(self): Base1.__init__(self) Base2.__init__(self) </pre><p> I don't know how to do this properly with super (the technique Stefan was suggesting), but his suggestion as written didn't take care of both bases, as the following demonstrates: </p> <div class="wiki-code"><div class="code"><pre><span class="o">&gt;&gt;&gt;</span> <span class="k">class</span> <span class="nc">X</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="o">...</span> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="o">...</span> <span class="k">print</span> <span class="s1">&#39;X&#39;</span> <span class="o">...</span> <span class="o">&gt;&gt;&gt;</span> <span class="k">class</span> <span class="nc">Y</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="o">...</span> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="o">...</span> <span class="k">print</span> <span class="s1">&#39;Y&#39;</span> <span class="o">...</span> <span class="o">&gt;&gt;&gt;</span> <span class="k">class</span> <span class="nc">Z</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="n">Y</span><span class="p">):</span> <span class="k">pass</span> <span class="c1"># essentially what you posted</span> <span class="o">...</span> <span class="o">&gt;&gt;&gt;</span> <span class="n">z</span> <span class="o">=</span> <span class="n">Z</span><span class="p">()</span> <span class="n">X</span> <span class="o">&gt;&gt;&gt;</span> <span class="k">class</span> <span class="nc">Z</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="n">Y</span><span class="p">):</span> <span class="o">...</span> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="o">...</span> <span class="nb">super</span><span class="p">(</span><span class="n">Z</span><span class="p">,</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span> <span class="c1"># Stefan&#39;s suggestion</span> <span class="o">...</span> <span class="o">&gt;&gt;&gt;</span> <span class="n">z</span> <span class="o">=</span> <span class="n">Z</span><span class="p">()</span> <span class="n">X</span> <span class="o">&gt;&gt;&gt;</span> <span class="k">class</span> <span class="nc">Z</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="n">Y</span><span class="p">):</span> <span class="o">...</span> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="o">...</span> <span class="n">X</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">...</span> <span class="n">Y</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">...</span> <span class="o">&gt;&gt;&gt;</span> <span class="n">z</span> <span class="o">=</span> <span class="n">Z</span><span class="p">()</span> <span class="n">X</span> <span class="n">Y</span> <span class="o">&gt;&gt;&gt;</span> </pre></div></div><p> I'm pretty sure this solves your problem so I'm closing the ticket, but if it doesn't, please re-open it. </p> Ticket anonymous Thu, 26 Jun 2008 14:56:34 GMT <link>https://svn.boost.org/trac10/ticket/2049#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/2049#comment:4</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/2049#comment:3" title="Comment 3">dave</a>: </p> <blockquote class="citation"> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/2049#comment:2" title="Comment 2">bloodyfanatic@gmx.de</a>: </p> <blockquote class="citation"> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/2049#comment:1" title="Comment 1">dave</a>: </p> <blockquote class="citation"> <p> Does this fail even when the dtors are non-virtual? </p> </blockquote> <p> yes it does, with the same error as always: </p> </blockquote> <p> In that case, please post the <em>fully reduced</em> test case </p> <p> Also, you need an <span class="underline">init</span> method in both1 and both2 that initializes *both* bases or this can never work, because a wrapped class' <span class="underline">init</span> function is what actually constructs the C++ base object. Without it, there is no base object to which a pointer can be returned from <code>extract</code>: </p> <pre class="wiki"> def __init__(self): Base1.__init__(self) Base2.__init__(self) </pre><p> I don't know how to do this properly with super (the technique Stefan was suggesting), but his suggestion as written didn't take care of both bases, as the following demonstrates: </p> <div class="wiki-code"><div class="code"><pre><span class="o">&gt;&gt;&gt;</span> <span class="k">class</span> <span class="nc">X</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="o">...</span> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="o">...</span> <span class="k">print</span> <span class="s1">&#39;X&#39;</span> <span class="o">...</span> <span class="o">&gt;&gt;&gt;</span> <span class="k">class</span> <span class="nc">Y</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="o">...</span> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="o">...</span> <span class="k">print</span> <span class="s1">&#39;Y&#39;</span> <span class="o">...</span> <span class="o">&gt;&gt;&gt;</span> <span class="k">class</span> <span class="nc">Z</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="n">Y</span><span class="p">):</span> <span class="k">pass</span> <span class="c1"># essentially what you posted</span> <span class="o">...</span> <span class="o">&gt;&gt;&gt;</span> <span class="n">z</span> <span class="o">=</span> <span class="n">Z</span><span class="p">()</span> <span class="n">X</span> <span class="o">&gt;&gt;&gt;</span> <span class="k">class</span> <span class="nc">Z</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="n">Y</span><span class="p">):</span> <span class="o">...</span> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="o">...</span> <span class="nb">super</span><span class="p">(</span><span class="n">Z</span><span class="p">,</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span> <span class="c1"># Stefan&#39;s suggestion</span> <span class="o">...</span> <span class="o">&gt;&gt;&gt;</span> <span class="n">z</span> <span class="o">=</span> <span class="n">Z</span><span class="p">()</span> <span class="n">X</span> <span class="o">&gt;&gt;&gt;</span> <span class="k">class</span> <span class="nc">Z</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="n">Y</span><span class="p">):</span> <span class="o">...</span> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="o">...</span> <span class="n">X</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">...</span> <span class="n">Y</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">...</span> <span class="o">&gt;&gt;&gt;</span> <span class="n">z</span> <span class="o">=</span> <span class="n">Z</span><span class="p">()</span> <span class="n">X</span> <span class="n">Y</span> <span class="o">&gt;&gt;&gt;</span> </pre></div></div><p> I'm pretty sure this solves your problem so I'm closing the ticket, but if it doesn't, please re-open it. </p> </blockquote> <p> just tested that and it works. Thank you very much :) </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Stefan Seefeld</dc:creator> <pubDate>Thu, 26 Jun 2008 15:02:03 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/2049#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/2049#comment:5</guid> <description> <p> Dave, </p> <p> The use of 'super' with <span class="underline">init</span> does in fact work, as long as all classes use it: </p> <pre class="wiki">class A(object): def __init__(self): super(A, self).__init__() print 'A' class B(object): def __init__(self): super(B, self).__init__() print 'B' class C(A, B): def __init__(self): super(C, self).__init__() print 'C' c = C() # prints A B C </pre><p> The reason for this is pretty well explained in <a class="ext-link" href="http://fuhm.net/super-harmful/"><span class="icon">​</span>http://fuhm.net/super-harmful/</a>. In a nutshell: super() doesn't (necessarily) invoke the superclass method itself, but the next one in the MRO chain. If you omit super in one case, you break out of this chain. </p> <p> FWIW. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Dave Abrahams</dc:creator> <pubDate>Thu, 26 Jun 2008 16:27:52 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/2049#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/2049#comment:6</guid> <description> <p> I knew that once ;-) thanks for the reminder. </p> </description> <category>Ticket</category> </item> <item> <pubDate>Mon, 03 Nov 2008 14:20:34 GMT</pubDate> <title>milestone deleted https://svn.boost.org/trac10/ticket/2049#comment:7 https://svn.boost.org/trac10/ticket/2049#comment:7 <ul> <li><strong>milestone</strong> <span class="trac-field-deleted">Boost 1.35.1</span> </li> </ul> <p> Milestone Boost 1.35.1 deleted </p> Ticket