2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-23 05:42:30 +00:00

Added dangling_reference FAQ

Various idiomatic MPL cleanups in indirect_traits.hpp
raw_function support
Patches for CWPro7.2
Patches to pass tests under Python 2.3 with the new bool type.
Tests for member operators returning const objects
Fixes for testing Boost.Python under Cygwin


[SVN r17777]
This commit is contained in:
Dave Abrahams
2003-03-08 03:53:19 +00:00
parent e042228f45
commit a870ce20fc
17 changed files with 618 additions and 474 deletions

View File

@@ -3,7 +3,7 @@
<html>
<head>
<meta name="generator" content=
"HTML Tidy for Windows (vers 1st August 2002), see www.w3.org">
"HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="../boost.css">
@@ -75,6 +75,12 @@ void def(char const* name, Fn fn, A1 const&amp;, A2 const&amp;, A3 const&amp;);
<dd>
<ul>
<li>If <code>Fn</code> is [derived from] <code><a href=
"object.html#object-spec">object</a></code>, it will be added to
the current scope as a single overload. To be useful,
<code>fn</code> should be <a href=
"http://www.python.org/doc/current/lib/built-in-funcs.html#l2h-6">callable</a>.</li>
<li>
If <code>a1</code> is the result of an <a href=
"overloads.html#overload-dispatch-expression"><em>overload-dispatch-expression</em></a>,
@@ -104,67 +110,52 @@ void def(char const* name, Fn fn, A1 const&amp;, A2 const&amp;, A3 const&amp;);
</dl>
</li>
<li>
Otherwise, a single function overload built around fn (which must
not be null) is added to the <a href="scope.html">current
scope</a>:
<ul>
<li>If fn is a function or member function pointer,
<code>a1</code>-<code>a3</code> (if supplied) may be selected
in any order from the table below.</li>
<li>Otherwise, <code>Fn</code> must be [derived from] <code><a
href="object.html#object-spec">object</a></code>, and
<code>a1-a2</code> (if supplied) may be selcted in any order
from the first two rows of the table below. To be useful,
<code>fn</code> should be <a href=
"http://www.python.org/doc/current/lib/built-in-funcs.html#l2h-6">
callable</a>.</li>
</ul>
<table border="1" summary="def() optional arguments">
<tr>
<th>Memnonic Name</th>
<th>Requirements/Type properties</th>
<th>Effects</th>
</tr>
<tr>
<td>docstring</td>
<td>Any <a href="definitions.html#ntbs">ntbs</a>.</td>
<td>Value will be bound to the <code>__doc__</code> attribute
of the resulting method overload.</td>
</tr>
<tr>
<td>policies</td>
<td>A model of <a href=
"CallPolicies.html">CallPolicies</a></td>
<td>A copy will be used as the call policies of the resulting
method overload.</td>
</tr>
<tr>
<td>keywords</td>
<td>The result of a <a href=
"args.html#keyword-expression"><em>keyword-expression</em></a>
specifying no more arguments than the <a href=
"definitions.html#arity">arity</a> of <code>fn</code>.</td>
<td>A copy will be used as the call policies of the resulting
method overload.</td>
</tr>
</table>
</li>
<li>Otherwise, fn must be a non-null function or member function
pointer, and a single function overload built around fn is added to
the <a href="scope.html">current scope</a>. If any of
<code>a1</code>-<code>a3</code> are supplied, they may be selected
in any order from the table below.</li>
</ul>
<table border="1" summary="def() optional arguments">
<tr>
<th>Memnonic Name</th>
<th>Requirements/Type properties</th>
<th>Effects</th>
</tr>
<tr>
<td>docstring</td>
<td>Any <a href="definitions.html#ntbs">ntbs</a>.</td>
<td>Value will be bound to the <code>__doc__</code> attribute of
the resulting method overload.</td>
</tr>
<tr>
<td>policies</td>
<td>A model of <a href="CallPolicies.html">CallPolicies</a></td>
<td>A copy will be used as the call policies of the resulting
method overload.</td>
</tr>
<tr>
<td>keywords</td>
<td>The result of a <a href=
"args.html#keyword-expression"><em>keyword-expression</em></a>
specifying no more arguments than the <a href=
"definitions.html#arity">arity</a> of <code>fn</code>.</td>
<td>A copy will be used as the call policies of the resulting
method overload.</td>
</tr>
</table>
</dd>
</dl>
@@ -174,6 +165,8 @@ void def(char const* name, Fn fn, A1 const&amp;, A2 const&amp;, A3 const&amp;);
#include &lt;boost/python/module.hpp&gt;
#include &lt;boost/python/args.hpp&gt;
using namespace boost::python;
char const* foo(int x, int y) { return "foo"; }
BOOST_PYTHON_MODULE(def_test)
@@ -184,8 +177,8 @@ BOOST_PYTHON_MODULE(def_test)
<p>
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
13 November, 2002
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
7 March, 2003
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href=

View File

@@ -1,70 +1,95 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta name="generator" content=
"HTML Tidy for Cygwin (vers 1st February 2003), see www.w3.org">
"HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org">
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<link rel="stylesheet" type="text/css" href="../boost.css">
<title>
Boost.Python - FAQ
</title>
<title>Boost.Python - FAQ</title>
</head>
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%"
summary="header">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<h3>
<a href="../../../../index.htm"><img height="86" width="277"
alt="C++ Boost" src="../../../../c++boost.gif" border=
"0"></a>
</h3>
<h3><a href="../../../../index.htm"><img height="86" width="277"
alt="C++ Boost" src="../../../../c++boost.gif" border="0"></a></h3>
</td>
<td valign="top">
<h1 align="center">
<a href="../index.html">Boost.Python</a>
</h1>
<h2 align="center">
Frequently Asked Questions (FAQs)
</h2>
<h1 align="center"><a href="../index.html">Boost.Python</a></h1>
<h2 align="center">Frequently Asked Questions (FAQs)</h2>
</td>
</tr>
</table>
<hr>
<dl class="page-index">
<dt>
<a href="#question1">Is return_internal_reference efficient?</a>
</dt>
<dt>
<a href="#question2">How can I wrap functions which take C++
containers as arguments?</a>
</dt>
<dt>
<a href="#c1204">fatal error C1204:Compiler limit:internal structure
overflow</a>
</dt>
<dt>
<a href="#debugging">How do I debug my Python extensions?</a>
</dt>
<dt>
<a href="#imul">Why doesn't my <code>*=</code> operator work?</a>
</dt>
<dt>
<a href="#macosx">Does Boost.Python work with Mac OS X?</a>
</dt>
<dt>
<a href="#xref">How can I find the existing PyObject that holds a C++
object?</a>
</dt>
<dt>
<a href="#ownership">How can I wrap a function which needs to take
ownership of a raw pointer?</a>
</dt>
<dt><a href="#dangling">I'm getting the "attempt to return dangling
reference" error. What am I doing wrong?</a></dt>
<dt><a href="#question1">Is return_internal_reference
efficient?</a></dt>
<dt><a href="#question2">How can I wrap functions which take C++
containers as arguments?</a></dt>
<dt><a href="#c1204">fatal error C1204:Compiler limit:internal
structure overflow</a></dt>
<dt><a href="#debugging">How do I debug my Python extensions?</a></dt>
<dt><a href="#imul">Why doesn't my <code>*=</code> operator
work?</a></dt>
<dt><a href="#macosx">Does Boost.Python work with Mac OS X?</a></dt>
<dt><a href="#xref">How can I find the existing PyObject that holds a
C++ object?</a></dt>
<dt><a href="#ownership">How can I wrap a function which needs to take
ownership of a raw pointer?</a></dt>
</dl>
<hr>
<h2>
<a name="question1"></a>Is return_internal_reference efficient?
</h2>
<h2><a name="dangling">I'm getting the "attempt to return dangling
reference" error. What am I doing wrong?</a></h2>
That exception is protecting you from causing a nasty crash. It usually
happens in response to some code like this:
<pre>
period const&amp; get_floating_frequency() const
{
return boost::python::call_method&lt;period const&amp;&gt;(
m_self,"get_floating_frequency");
}
</pre>
And you get:
<pre>
ReferenceError: Attempt to return dangling reference to object of type:
class period
</pre>
<p>In this case, the Python method invoked by <code>call_method</code>
constructs a new Python object. You're trying to return a reference to a
C++ object (an instance of <code>class period</code>) contained within
and owned by that Python object. Because the called method handed back a
brand new object, the only reference to it is held for the duration of
<code>get_floating_frequency()</code> above. When the function returns,
the Python object will be destroyed, destroying the instance of
<code>class period</code>, and leaving the returned reference dangling.
That's already undefined behavior, and if you try to do anything with
that reference you're likely to cause a crash. Boost.Python detects this
situation at runtime and helpfully throws an exception instead of letting
you do that.<br>
&nbsp;</p>
<hr>
<h2><a name="question1"></a>Is return_internal_reference efficient?</h2>
<blockquote>
<b>Q:</b> <i>I have an object composed of 12 doubles. A const&amp; to
this object is returned by a member function of another class. From the
@@ -74,126 +99,129 @@
return_internal_reference. Are there considerations that would lead me
to prefer one over the other, such as size of generated code or memory
overhead?</i>
<p>
<b>A:</b> copy_const_reference will make an instance with storage for
one of your objects, size = base_size + 12 * sizeof(double).
return_internal_reference will make an instance with storage for a
pointer to one of your objects, size = base_size + sizeof(void*).
However, it will also create a weak reference object which goes in
the source object's weakreflist and a special callback object to
manage the lifetime of the internally-referenced object. My guess?
copy_const_reference is your friend here, resulting in less overall
memory use and less fragmentation, also probably fewer total cycles.
</p>
<p><b>A:</b> copy_const_reference will make an instance with storage
for one of your objects, size = base_size + 12 * sizeof(double).
return_internal_reference will make an instance with storage for a
pointer to one of your objects, size = base_size + sizeof(void*).
However, it will also create a weak reference object which goes in the
source object's weakreflist and a special callback object to manage the
lifetime of the internally-referenced object. My guess?
copy_const_reference is your friend here, resulting in less overall
memory use and less fragmentation, also probably fewer total
cycles.</p>
</blockquote>
<hr>
<h2>
<a name="question2"></a>How can I wrap functions which take C++
containers as arguments?
</h2>
<p>
Ralf W. Grosse-Kunstleve provides these notes:
</p>
<h2><a name="question2"></a>How can I wrap functions which take C++
containers as arguments?</h2>
<p>Ralf W. Grosse-Kunstleve provides these notes:</p>
<ol>
<li>
Using the regular <code>class_&lt;&gt;</code> wrapper:
<pre>
<pre>
class_&lt;std::vector&lt;double&gt; &gt;("std_vector_double")
.def(...)
...
;
</pre>This can be moved to a template so that several types (double, int,
long, etc.) can be wrapped with the same code. This technique is used in the
file
</pre>
This can be moved to a template so that several types (double, int,
long, etc.) can be wrapped with the same code. This technique is used
in the file
<blockquote>
scitbx/include/scitbx/array_family/boost_python/flex_wrapper.h
</blockquote>in the "scitbx" package. The file could easily be
modified for wrapping std::vector&lt;&gt; instantiations.
<p>
This type of C++/Python binding is most suitable for containers
that may contain a large number of elements (&gt;10000).
</p>
</blockquote>
in the "scitbx" package. The file could easily be modified for
wrapping std::vector&lt;&gt; instantiations.
<p>This type of C++/Python binding is most suitable for containers
that may contain a large number of elements (&gt;10000).</p>
</li>
<li>
Using custom rvalue converters. Boost.Python "rvalue converters"
match function signatures such as:
<pre>
<pre>
void foo(std::vector&lt;double&gt; const&amp; array); // pass by const-reference
void foo(std::vector&lt;double&gt; array); // pass by value
</pre>Some custom rvalue converters are implemented in the file
</pre>
Some custom rvalue converters are implemented in the file
<blockquote>
scitbx/include/scitbx/boost_python/container_conversions.h
</blockquote>This code can be used to convert from C++ container
types such as std::vector&lt;&gt; or std::list&lt;&gt; to Python
tuples and vice versa. A few simple examples can be found in the file
</blockquote>
This code can be used to convert from C++ container types such as
std::vector&lt;&gt; or std::list&lt;&gt; to Python tuples and vice
versa. A few simple examples can be found in the file
<blockquote>
scitbx/array_family/boost_python/regression_test_module.cpp
</blockquote>Automatic C++ container &lt;-&gt; Python tuple
conversions are most suitable for containers of moderate size. These
converters generate significantly less object code compared to
alternative 1 above.
</blockquote>
Automatic C++ container &lt;-&gt; Python tuple conversions are most
suitable for containers of moderate size. These converters generate
significantly less object code compared to alternative 1 above.
</li>
</ol>A disadvantage of using alternative 2 is that operators such as
</ol>
A disadvantage of using alternative 2 is that operators such as
arithmetic +,-,*,/,% are not available. It would be useful to have custom
rvalue converters that convert to a "math_array" type instead of tuples.
This is currently not implemented but is possible within the framework of
Boost.Python V2 as it will be released in the next couple of weeks. [ed.:
this was posted on 2002/03/10]
<p>
It would also be useful to also have "custom lvalue converters" such as
std::vector&lt;&gt; &lt;-&gt; Python list. These converters would
support the modification of the Python list from C++. For example:
</p>
<p>
C++:
</p>
<pre>
<p>It would also be useful to also have "custom lvalue converters" such
as std::vector&lt;&gt; &lt;-&gt; Python list. These converters would
support the modification of the Python list from C++. For example:</p>
<p>C++:</p>
<pre>
void foo(std::vector&lt;double&gt;&amp; array)
{
for(std::size_t i=0;i&lt;array.size();i++) {
array[i] *= 2;
}
}
</pre>Python:
<pre>
</pre>
Python:
<pre>
&gt;&gt;&gt; l = [1, 2, 3]
&gt;&gt;&gt; foo(l)
&gt;&gt;&gt; print l
[2, 4, 6]
</pre>Custom lvalue converters require changes to the Boost.Python core
library and are currently not available.
<p>
P.S.:
</p>
<p>
The "scitbx" files referenced above are available via anonymous CVS:
</p>
<pre>
</pre>
Custom lvalue converters require changes to the Boost.Python core library
and are currently not available.
<p>P.S.:</p>
<p>The "scitbx" files referenced above are available via anonymous
CVS:</p>
<pre>
cvs -d:pserver:anonymous@cvs.cctbx.sourceforge.net:/cvsroot/cctbx login
cvs -d:pserver:anonymous@cvs.cctbx.sourceforge.net:/cvsroot/cctbx co scitbx
</pre>
<hr>
<h2>
<a name="c1204"></a>fatal error C1204:Compiler limit:internal structure
overflow
</h2>
<h2><a name="c1204"></a>fatal error C1204:Compiler limit:internal
structure overflow</h2>
<blockquote>
<b>Q:</b> <i>I get this error message when compiling a large source
file. What can I do?</i>
<p>
<b>A:</b> You have two choices:
</p>
<p><b>A:</b> You have two choices:</p>
<ol>
<li>
Upgrade your compiler (preferred)
</li>
<li>Upgrade your compiler (preferred)</li>
<li>
Break your source file up into multiple translation units.
<p>
<code><b>my_module.cpp</b></code>:
</p>
<pre>
<p><code><b>my_module.cpp</b></code>:</p>
<pre>
...
void more_of_my_module();
BOOST_PYTHON_MODULE(my_module)
@@ -203,23 +231,25 @@ BOOST_PYTHON_MODULE(my_module)
...
more_of_my_module();
}
</pre><code><b>more_of_my_module.cpp</b></code>:
<pre>
</pre>
<code><b>more_of_my_module.cpp</b></code>:
<pre>
void more_of_my_module()
{
def("baz", baz);
...
}
</pre>If you find that a <code><a href=
"class.html#class_-spec">class_</a>&lt;...&gt;</code> declaration can't fit
in a single source file without triggering the error, you can always pass a
reference to the <code>class_</code> object to a function in another source
file, and call some of its member functions (e.g. <code>.def(...)</code>) in
the auxilliary source file:
<p>
<code><b>more_of_my_class.cpp</b></code>:
</p>
<pre>
</pre>
If you find that a <code><a href=
"class.html#class_-spec">class_</a>&lt;...&gt;</code> declaration
can't fit in a single source file without triggering the error, you
can always pass a reference to the <code>class_</code> object to a
function in another source file, and call some of its member
functions (e.g. <code>.def(...)</code>) in the auxilliary source
file:
<p><code><b>more_of_my_class.cpp</b></code>:</p>
<pre>
void more_of_my_class(class&lt;my_class&gt;&amp; x)
{
x
@@ -234,12 +264,11 @@ void more_of_my_class(class&lt;my_class&gt;&amp; x)
</ol>
</blockquote>
<hr>
<h2>
<a name="debugging"></a>How do I debug my Python extensions?
</h2>
<p>
Greg Burley gives the following answer for Unix GCC users:
</p>
<h2><a name="debugging"></a>How do I debug my Python extensions?</h2>
<p>Greg Burley gives the following answer for Unix GCC users:</p>
<blockquote>
Once you have created a boost python extension for your c++ library or
class, you may need to debug the code. Afterall this is one of the
@@ -249,13 +278,12 @@ void more_of_my_class(class&lt;my_class&gt;&amp; x)
boost::python either works or it doesn't. (ie. While errors can occur
when the wrapping method is invalid, most errors are caught by the
compiler ;-).
<p>
The basic steps required to initiate a gdb session to debug a c++
library via python are shown here. Note, however that you should
start the gdb session in the directory that contains your BPL
my_ext.so module.
</p>
<pre>
<p>The basic steps required to initiate a gdb session to debug a c++
library via python are shown here. Note, however that you should start
the gdb session in the directory that contains your BPL my_ext.so
module.</p>
<pre>
(gdb) target exec python
(gdb) run
&gt;&gt;&gt; from my_ext import *
@@ -269,44 +297,43 @@ Current language: auto; currently c++
(gdb) do debugging stuff
</pre>
</blockquote>
<p>
Greg's approach works even better using Emacs' "<code>gdb</code>"
command, since it will show you each line of source as you step through
it.
</p>
<p>
On <b>Windows</b>, my favorite debugging solution is the debugger that
comes with Microsoft Visual C++ 7. This debugger seems to work with
code generated by all versions of Microsoft and Metrowerks toolsets;
it's rock solid and "just works" without requiring any special tricks
from the user.
</p>
<p>
Unfortunately for Cygwin and MinGW users, as of this writing gdb on
Windows has a very hard time dealing with shared libraries, which could
make Greg's approach next to useless for you. My best advice for you is
to use Metrowerks C++ for compiler conformance and Microsoft Visual
Studio as a debugger when you need one.
</p>
<h3>
Debugging extensions through Boost.Build
</h3>If you are launching your extension module tests with <a href=
<p>Greg's approach works even better using Emacs' "<code>gdb</code>"
command, since it will show you each line of source as you step through
it.</p>
<p>On <b>Windows</b>, my favorite debugging solution is the debugger that
comes with Microsoft Visual C++ 7. This debugger seems to work with code
generated by all versions of Microsoft and Metrowerks toolsets; it's rock
solid and "just works" without requiring any special tricks from the
user.</p>
<p>Unfortunately for Cygwin and MinGW users, as of this writing gdb on
Windows has a very hard time dealing with shared libraries, which could
make Greg's approach next to useless for you. My best advice for you is
to use Metrowerks C++ for compiler conformance and Microsoft Visual
Studio as a debugger when you need one.</p>
<h3>Debugging extensions through Boost.Build</h3>
If you are launching your extension module tests with <a href=
"../../../tools/build">Boost.Build</a> using the
<code>boost-python-runtest</code> rule, you can ask it to launch your
debugger for you by adding "-sPYTHON_LAUNCH=<i>debugger</i>" to your bjam
command-line:
<pre>
<pre>
bjam -sTOOLS=metrowerks "-sPYTHON_LAUNCH=devenv /debugexe" test
bjam -sTOOLS=gcc -sPYTHON_LAUNCH=gdb test
</pre>It can also be extremely useful to add the <code>-d+2</code> option
when you run your test, because Boost.Build will then show you the exact
commands it uses to invoke it. This will invariably involve setting up
PYTHONPATH and other important environment variables such as LD_LIBRARY_PATH
which may be needed by your debugger in order to get things to work right.
</pre>
It can also be extremely useful to add the <code>-d+2</code> option when
you run your test, because Boost.Build will then show you the exact
commands it uses to invoke it. This will invariably involve setting up
PYTHONPATH and other important environment variables such as
LD_LIBRARY_PATH which may be needed by your debugger in order to get
things to work right.
<hr>
<h2>
<a name="imul"></a>Why doesn't my <code>*=</code> operator work?
</h2>
<h2><a name="imul"></a>Why doesn't my <code>*=</code> operator work?</h2>
<blockquote>
<b>Q:</b> <i>I have exported my class to python, with many overloaded
operators. it works fine for me except the</i> <code>*=</code>
@@ -314,60 +341,57 @@ which may be needed by your debugger in order to get things to work right.
type". If I use</i> <code>p1.__imul__(p2)</code> <i>instead of</i>
<code>p1 *= p2</code><i>, it successfully executes my code. What's
wrong with me?</i>
<p>
<b>A:</b> There's nothing wrong with you. This is a bug in Python
2.2. You can see the same effect in Pure Python (you can learn a lot
about what's happening in Boost.Python by playing with new-style
classes in Pure Python).
</p>
<pre>
<p><b>A:</b> There's nothing wrong with you. This is a bug in Python
2.2. You can see the same effect in Pure Python (you can learn a lot
about what's happening in Boost.Python by playing with new-style
classes in Pure Python).</p>
<pre>
&gt;&gt;&gt; class X(object):
... def __imul__(self, x):
... print 'imul'
...
&gt;&gt;&gt; x = X()
&gt;&gt;&gt; x *= 1
</pre>To cure this problem, all you need to do is upgrade your Python to
version 2.2.1 or later.
</pre>
To cure this problem, all you need to do is upgrade your Python to
version 2.2.1 or later.
</blockquote>
<hr>
<h2>
<a name="macosx"></a>Does Boost.Python work with Mac OS X?
</h2>
<h2><a name="macosx"></a>Does Boost.Python work with Mac OS X?</h2>
<blockquote>
<p>
The short answer: as of January 2003, unfortunately not.
</p>
<p>
The longer answer: using Mac OS 10.2.3 with the December Developer's
Kit, Python 2.3a1, and bjam's darwin-tools.jam, Boost.Python compiles
fine, including the examples. However, there are problems at runtime
(see <a href=
"http://mail.python.org/pipermail/c++-sig/2003-January/003267.html">http://mail.python.org/pipermail/c++-sig/2003-January/003267.html</a>).
Solutions are currently unknown.
</p>
<p>
It is known that under certain circumstances objects are
double-destructed. See <a href=
"http://mail.python.org/pipermail/c++-sig/2003-January/003278.html">http://mail.python.org/pipermail/c++-sig/2003-January/003278.html</a>
for details. It is not clear however if this problem is related to
the Boost.Python runtime issues.
</p>
<p>The short answer: as of January 2003, unfortunately not.</p>
<p>The longer answer: using Mac OS 10.2.3 with the December Developer's
Kit, Python 2.3a1, and bjam's darwin-tools.jam, Boost.Python compiles
fine, including the examples. However, there are problems at runtime
(see <a href=
"http://mail.python.org/pipermail/c++-sig/2003-January/003267.html">http://mail.python.org/pipermail/c++-sig/2003-January/003267.html</a>).
Solutions are currently unknown.</p>
<p>It is known that under certain circumstances objects are
double-destructed. See <a href=
"http://mail.python.org/pipermail/c++-sig/2003-January/003278.html">http://mail.python.org/pipermail/c++-sig/2003-January/003278.html</a>
for details. It is not clear however if this problem is related to the
Boost.Python runtime issues.</p>
</blockquote>
<hr>
<h2>
<a name="xref">How can I find the existing PyObject that holds a C++
object?</a>
</h2>
<h2><a name="xref">How can I find the existing PyObject that holds a C++
object?</a></h2>
<blockquote>
"I am wrapping a function that always returns a pointer to an
already-held C++ object."
</blockquote>One way to do that is to hijack the mechanisms used for
wrapping a class with virtual functions. If you make a wrapper class with
an initial PyObject* constructor argument and store that PyObject* as
"self", you can get back to it by casting down to that wrapper type in a
thin wrapper function. For example:
<pre>
</blockquote>
One way to do that is to hijack the mechanisms used for wrapping a class
with virtual functions. If you make a wrapper class with an initial
PyObject* constructor argument and store that PyObject* as "self", you
can get back to it by casting down to that wrapper type in a thin wrapper
function. For example:
<pre>
class X { X(int); virtual ~X(); ... };
X* f(); // known to return Xs that are managed by Python objects
@@ -393,44 +417,43 @@ def("f", f_wrap());
class_&lt;X,X_wrap&gt;("X", init&lt;int&gt;())
...
;
</pre>Of course, if X has no virtual functions you'll have to use
<code>static_cast</code> instead of <code>dynamic_cast</code> with no runtime
check that it's valid. This approach also only works if the <code>X</code>
object was constructed from Python, because <code>X</code>s constructed from
C++ are of course never <code>X_wrap</code> objects.
<p>
Another approach to this requires some work on Boost.Python, but it's
work we've been meaning to get to anyway. Currently, when a
<code>shared_ptr&lt;X&gt;</code> is converted from Python, the
shared_ptr actually manages a reference to the containing Python
object. I plan to make it so that when a shared_ptr&lt;X&gt; is
converted back to Python, the library checks to see if it's one of
those "Python object managers" and if so just returns the original
Python object. To exploit this you'd have to be able to change the C++
code you're wrapping so that it deals with shared_ptr instead of raw
pointers.
</p>
<p>
There are other approaches too. The functions that receive the Python
object that you eventually want to return could be wrapped with a thin
wrapper that records the correspondence between the object address and
its containing Python object, and you could have your f_wrap function
look in that mapping to get the Python object out.
</p>
<h2>
<a name="ownership">How can I wrap a function which needs to take
ownership of a raw pointer?</a>
</h2>
</pre>
Of course, if X has no virtual functions you'll have to use
<code>static_cast</code> instead of <code>dynamic_cast</code> with no
runtime check that it's valid. This approach also only works if the
<code>X</code> object was constructed from Python, because
<code>X</code>s constructed from C++ are of course never
<code>X_wrap</code> objects.
<p>Another approach to this requires you to change your C++ code a bit;
if that's an option for you it might be a better way to go. work we've
been meaning to get to anyway. When a <code>shared_ptr&lt;X&gt;</code> is
converted from Python, the shared_ptr actually manages a reference to the
containing Python object. When a shared_ptr&lt;X&gt; is converted back to
Python, the library checks to see if it's one of those "Python object
managers" and if so just returns the original Python object. So you could
just write <code>object(p)</code> to get the Python object back. To
exploit this you'd have to be able to change the C++ code you're wrapping
so that it deals with shared_ptr instead of raw pointers.</p>
<p>There are other approaches too. The functions that receive the Python
object that you eventually want to return could be wrapped with a thin
wrapper that records the correspondence between the object address and
its containing Python object, and you could have your f_wrap function
look in that mapping to get the Python object out.</p>
<h2><a name="ownership">How can I wrap a function which needs to take
ownership of a raw pointer?</a></h2>
<blockquote>
<i>Part of an API that I'm wrapping goes something like this:</i>
<pre>
<pre>
struct A {}; struct B { void add( A* ); }
where B::add() takes ownership of the pointer passed to it.
</pre>
<p>
<i>However:</i>
</p>
<pre>
<p><i>However:</i></p>
<pre>
a = mod.A()
b = mod.B()
b.add( a )
@@ -439,41 +462,43 @@ del b
# python interpreter crashes
# later due to memory corruption.
</pre>
<p>
<i>Even binding the lifetime of a</i> to b via
with_custodian_and_ward doesn't prevent the python object a from
ultimately trying to delete the object it's pointing to. Is there a
way to accomplish a 'transfer-of-ownership' of a wrapped C++ object?
</p>
<p>
<i>--Bruce Lowery</i>
</p>
</blockquote>Yes: Make sure the C++ object is held by auto_ptr:
<pre>
<p><i>Even binding the lifetime of a</i> to b via
with_custodian_and_ward doesn't prevent the python object a from
ultimately trying to delete the object it's pointing to. Is there a way
to accomplish a 'transfer-of-ownership' of a wrapped C++ object?</p>
<p><i>--Bruce Lowery</i></p>
</blockquote>
Yes: Make sure the C++ object is held by auto_ptr:
<pre>
class_&lt;A, std::auto_ptr&lt;A&gt; &gt;("A")
...
;
</pre>Then make a thin wrapper function which takes an auto_ptr parameter:
<pre>
</pre>
Then make a thin wrapper function which takes an auto_ptr parameter:
<pre>
void b_insert(B&amp; b, std::auto_ptr&lt;A&gt; a)
{
b.insert(a.get());
a.release();
}
</pre>Wrap that as B.add. Note that pointers returned via
<code><a href="manage_new_object.html#manage_new_object-spec">manage_new_object</a></code>
will also be held by <code>auto_ptr</code>, so this
transfer-of-ownership will also work correctly.
</pre>
Wrap that as B.add. Note that pointers returned via <code><a href=
"manage_new_object.html#manage_new_object-spec">manage_new_object</a></code>
will also be held by <code>auto_ptr</code>, so this transfer-of-ownership
will also work correctly.
<hr>
<p>
Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
23 January, 2003
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p>
<i>&copy; Copyright <a href="../../../../people/dave_abrahams.htm">Dave
Abrahams</a> 2002-2003. All Rights Reserved.</i>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
23 January, 2003
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href=
"../../../../people/dave_abrahams.htm">Dave Abrahams</a> 2002-2003. All
Rights Reserved.</i></p>
</body>
</html>

View File

@@ -3,7 +3,7 @@
<html>
<head>
<meta name="generator" content=
"HTML Tidy for Windows (vers 1st August 2002), see www.w3.org">
"HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="../boost.css">
@@ -13,7 +13,7 @@
p.c3 {font-style: italic}
h2.c2 {text-align: center}
h1.c1 {text-align: center}
</style>
</style>
</head>
<body>
@@ -527,6 +527,24 @@
</dl>
</dd>
</dl>
</dd>
<dt><a href="raw_function.html">raw_function.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="raw_function.html#functions">Functions</a></dt>
<dd>
<dl class="page-index">
<dt><a href=
"raw_function.html#raw_function-spec">raw_function</a></dt>
</dl>
</dd>
</dl>
</dd>
<dd>
<a name="models_of_call_policies"></a>
<h3>Models of CallPolicies</h3>
@@ -913,8 +931,8 @@
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
13 November, 2002
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
7 March, 2003
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p class="c3">&copy; Copyright <a href=

View File

@@ -132,7 +132,9 @@ namespace detail
must_be_derived_class_member(Default const&)
{
typedef typename assertion<mpl::not_<is_same<Default,Fn> > >::failed test0;
# if !BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
typedef typename assertion<is_polymorphic<T> >::failed test1;
# endif
typedef typename assertion<is_member_function_pointer<Fn> >::failed test2;
not_a_derived_class_member<Default>(Fn());
}

View File

@@ -76,12 +76,17 @@ namespace detail
detail::define_with_defaults(
name, stubs, current, detail::get_signature(sig));
}
template <class T>
object make_function1(T fn, ...) { return make_function(fn); }
object make_function1(object const& x, object const*) { return x; }
}
template <class Fn>
void def(char const* name, Fn fn)
{
detail::scope_setattr_doc(name, boost::python::make_function(fn), 0);
detail::scope_setattr_doc(name, detail::make_function1(fn, &fn), 0);
}
template <class Arg1T, class Arg2T>

View File

@@ -6,7 +6,6 @@
#ifndef INDIRECT_TRAITS_DWA2002131_HPP
# define INDIRECT_TRAITS_DWA2002131_HPP
# include <boost/type_traits/is_function.hpp>
# include <boost/type_traits/detail/ice_and.hpp>
# include <boost/type_traits/is_reference.hpp>
# include <boost/type_traits/is_pointer.hpp>
# include <boost/type_traits/is_class.hpp>
@@ -16,8 +15,18 @@
# include <boost/type_traits/remove_cv.hpp>
# include <boost/type_traits/remove_reference.hpp>
# include <boost/type_traits/remove_pointer.hpp>
# include <boost/type_traits/detail/ice_and.hpp>
# include <boost/detail/workaround.hpp>
# if 0 && BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
# include <boost/type_traits/is_enum.hpp>
# endif
# include <boost/mpl/if.hpp>
# include <boost/mpl/bool.hpp>
# include <boost/mpl/and.hpp>
# include <boost/mpl/not.hpp>
# include <boost/mpl/aux_/lambda_support.hpp>
# ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
@@ -28,27 +37,24 @@ namespace boost { namespace python { namespace detail {
# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
template <class T>
struct is_reference_to_const
struct is_reference_to_const : mpl::false_
{
BOOST_STATIC_CONSTANT(bool, value = false);
};
template <class T>
struct is_reference_to_const<T const&>
struct is_reference_to_const<T const&> : mpl::true_
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
# if defined(BOOST_MSVC) && _MSC_FULL_VER <= 13102140 // vc7.01 alpha workaround
template<class T>
struct is_reference_to_const<T const volatile&>
struct is_reference_to_const<T const volatile&> : mpl::true_
{
static const bool value = true;
};
# endif
template <class T>
struct is_reference_to_function : mpl::bool_<false>
struct is_reference_to_function : mpl::false_
{
};
@@ -58,9 +64,8 @@ struct is_reference_to_function<T&> : is_function<T>
};
template <class T>
struct is_pointer_to_function : mpl::bool_<false>
struct is_pointer_to_function : mpl::false_
{
BOOST_STATIC_CONSTANT(bool, value = false);
};
// There's no such thing as a pointer-to-cv-function, so we don't need
@@ -71,7 +76,7 @@ struct is_pointer_to_function<T*> : is_function<T>
};
template <class T>
struct is_reference_to_member_function_pointer_impl : mpl::bool_<false>
struct is_reference_to_member_function_pointer_impl : mpl::false_
{
};
@@ -91,23 +96,23 @@ struct is_reference_to_member_function_pointer
template <class T>
struct is_reference_to_function_pointer_aux
: mpl::and_<
is_reference<T>
, is_pointer_to_function<
typename remove_cv<
typename remove_reference<T>::type
>::type
>
>
{
// There's no such thing as a pointer-to-cv-function, so we don't need specializations for those
BOOST_STATIC_CONSTANT(bool, value = (
is_reference<T>::value
& is_pointer_to_function<
typename remove_cv<
typename remove_reference<T>::type
>::type
>::value));
typedef mpl::bool_<value> type;
};
template <class T>
struct is_reference_to_function_pointer
: mpl::if_c<
is_reference_to_function<T>::value
, mpl::bool_<false>
: mpl::if_<
is_reference_to_function<T>
, mpl::false_
, is_reference_to_function_pointer_aux<T>
>::type
{
@@ -115,70 +120,60 @@ struct is_reference_to_function_pointer
template <class T>
struct is_reference_to_non_const
: mpl::and_<
is_reference<T>
, mpl::not_<
is_reference_to_const<T>
>
>
{
BOOST_STATIC_CONSTANT(
bool, value = (
::boost::type_traits::ice_and<
::boost::is_reference<T>::value
, ::boost::type_traits::ice_not<
::boost::python::detail::is_reference_to_const<T>::value>::value
>::value)
);
};
template <class T>
struct is_reference_to_volatile
struct is_reference_to_volatile : mpl::false_
{
BOOST_STATIC_CONSTANT(bool, value = false);
};
template <class T>
struct is_reference_to_volatile<T volatile&>
struct is_reference_to_volatile<T volatile&> : mpl::true_
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
# if defined(BOOST_MSVC) && _MSC_FULL_VER <= 13102140 // vc7.01 alpha workaround
template <class T>
struct is_reference_to_volatile<T const volatile&>
struct is_reference_to_volatile<T const volatile&> : mpl::true_
{
static const bool value = true;
};
# endif
template <class T>
struct is_reference_to_pointer
struct is_reference_to_pointer : mpl::false_
{
BOOST_STATIC_CONSTANT(bool, value = false);
};
template <class T>
struct is_reference_to_pointer<T*&>
struct is_reference_to_pointer<T*&> : mpl::true_
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template <class T>
struct is_reference_to_pointer<T* const&>
struct is_reference_to_pointer<T* const&> : mpl::true_
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template <class T>
struct is_reference_to_pointer<T* volatile&>
struct is_reference_to_pointer<T* volatile&> : mpl::true_
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template <class T>
struct is_reference_to_pointer<T* const volatile&>
struct is_reference_to_pointer<T* const volatile&> : mpl::true_
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template <class T>
struct is_reference_to_class
struct is_reference_to_classx
{
BOOST_STATIC_CONSTANT(
bool, value
@@ -196,19 +191,47 @@ struct is_reference_to_class
};
template <class T>
struct is_pointer_to_class
struct is_reference_to_class
: mpl::and_<
is_reference<T>
# if 0 && BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
, mpl::not_<
is_enum<
typename remove_cv<
typename remove_reference<T>::type
>::type
>
>
# endif
, is_class<
typename remove_cv<
typename remove_reference<T>::type
>::type
>
>
{
};
template <class T>
struct is_pointer_to_class
: mpl::and_<
is_pointer<T>
# if 0 && BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
, mpl::not_<
is_enum<
typename remove_cv<
typename remove_pointer<T>::type
>::type
>
>
# endif
, is_class<
typename remove_cv<
typename remove_pointer<T>::type
>::type
>
>
{
BOOST_STATIC_CONSTANT(
bool, value
= (boost::type_traits::ice_and<
is_pointer<T>::value
, is_class<
typename remove_cv<
typename remove_pointer<T>::type
>::type
>::value
>::value)
);
};
# else
@@ -220,8 +243,8 @@ typedef char (&outer_no_type)[1];
template <typename V>
struct is_const_help
{
typedef typename mpl::if_c<
is_const<V>::value
typedef typename mpl::if_<
is_const<V>
, inner_yes_type
, inner_no_type
>::type type;
@@ -230,8 +253,8 @@ struct is_const_help
template <typename V>
struct is_volatile_help
{
typedef typename mpl::if_c<
is_volatile<V>::value
typedef typename mpl::if_<
is_volatile<V>
, inner_yes_type
, inner_no_type
>::type type;
@@ -240,8 +263,8 @@ struct is_volatile_help
template <typename V>
struct is_pointer_help
{
typedef typename mpl::if_c<
is_pointer<V>::value
typedef typename mpl::if_<
is_pointer<V>
, inner_yes_type
, inner_no_type
>::type type;
@@ -250,8 +273,8 @@ struct is_pointer_help
template <typename V>
struct is_class_help
{
typedef typename mpl::if_c<
is_class<V>::value
typedef typename mpl::if_<
is_class<V>
, inner_yes_type
, inner_no_type
>::type type;

View File

@@ -315,7 +315,10 @@ namespace detail
, mpl::push_front<>
>::type args;
typedef typename ClassT::holder_selector::type selector_t;
typedef typename ClassT::holder_selector holder_selector_t;
# if !BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
typedef typename holder_selector_t::type selector_t;
# endif
typedef typename ClassT::held_type held_type_t;
cl.def(

View File

@@ -11,6 +11,7 @@
# include <boost/mpl/if.hpp>
# include <boost/type_traits/object_traits.hpp>
# include <boost/type_traits/is_polymorphic.hpp>
# include <boost/detail/workaround.hpp>
namespace boost { namespace python { namespace objects {
@@ -108,16 +109,20 @@ struct implicit_cast_generator
template <class Source, class Target>
struct cast_generator
{
// CWPro7 will return false sometimes, but that's OK since we can
// always cast up with dynamic_cast<>
// It's OK to return false, since we can always cast up with
// dynamic_cast<> if neccessary.
# if BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
BOOST_STATIC_CONSTANT(bool, is_upcast = false);
# else
BOOST_STATIC_CONSTANT(
bool, is_upcast = (
is_base_and_derived<Target,Source>::value
));
# endif
typedef typename mpl::if_c<
is_upcast
# if defined(__MWERKS__) && __MWERKS__ <= 0x2406
# if BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
// grab a few more implicit_cast cases for CodeWarrior
|| !is_polymorphic<Source>::value
|| !is_polymorphic<Target>::value

View File

@@ -48,8 +48,14 @@ struct make_ptr_instance
}
template <class U>
static inline PyTypeObject* get_derived_class_object(mpl::false_, U*)
static inline PyTypeObject* get_derived_class_object(mpl::false_, U* x)
{
# if BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
if (typeid(*x) != typeid(U))
return get_derived_class_object(mpl::true_(), x);
# else
(void)x;
# endif
return 0;
}
};

View File

@@ -39,10 +39,15 @@ function::function(
unsigned keyword_offset
= m_max_arity > num_keywords ? m_max_arity - num_keywords : 0;
m_arg_names = object(handle<>(PyTuple_New(m_max_arity)));
for (unsigned j = 0; j < keyword_offset; ++j)
PyTuple_SET_ITEM(m_arg_names.ptr(), j, incref(Py_None));
unsigned tuple_size = num_keywords ? m_max_arity : 0;
m_arg_names = object(handle<>(PyTuple_New(tuple_size)));
if (num_keywords != 0)
{
for (unsigned j = 0; j < keyword_offset; ++j)
PyTuple_SET_ITEM(m_arg_names.ptr(), j, incref(Py_None));
}
for (unsigned i = 0; i < num_keywords; ++i)
{
@@ -68,7 +73,7 @@ function::function(
function::~function()
{
}
PyObject* function::call(PyObject* args, PyObject* keywords) const
{
std::size_t nargs = PyTuple_GET_SIZE(args);
@@ -76,47 +81,68 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const
std::size_t total_args = nargs + nkeywords;
function const* f = this;
// Try overloads looking for a match
do
{
// Check for a plausible number of arguments
if (total_args >= f->m_min_arity && total_args <= f->m_max_arity)
{
// This will be the args that actually get passed
handle<> args2(allow_null(borrowed(args)));
if (nkeywords > 0)
if (nkeywords > 0) // Keyword arguments were supplied
{
if (!f->m_arg_names
|| static_cast<std::size_t>(PyTuple_Size(f->m_arg_names.ptr())) < total_args)
if (f->m_arg_names.ptr() == Py_None) // this overload doesn't accept keywords
{
args2 = handle<>(); // signal failure
}
else
{
// build a new arg tuple
args2 = handle<>(PyTuple_New(total_args));
std::size_t max_args
= static_cast<std::size_t>(PyTuple_Size(f->m_arg_names.ptr()));
// Fill in the positional arguments
for (std::size_t i = 0; i < nargs; ++i)
PyTuple_SET_ITEM(args2.get(), i, incref(PyTuple_GET_ITEM(args, i)));
// Grab remaining arguments by name from the keyword dictionary
for (std::size_t j = nargs; j < total_args; ++j)
// "all keywords are none" is a special case
// indicating we will accept any number of keyword
// arguments
if (max_args == 0)
{
PyObject* value = PyDict_GetItem(
keywords, PyTuple_GET_ITEM(f->m_arg_names.ptr(), j));
if (!value)
// no argument preprocessing
}
else if (max_args < total_args)
{
args2 = handle<>();
}
else
{
// build a new arg tuple
args2 = handle<>(PyTuple_New(total_args));
// Fill in the positional arguments
for (std::size_t i = 0; i < nargs; ++i)
PyTuple_SET_ITEM(args2.get(), i, incref(PyTuple_GET_ITEM(args, i)));
// Grab remaining arguments by name from the keyword dictionary
for (std::size_t j = nargs; j < total_args; ++j)
{
PyErr_Clear();
args2 = handle<>();
break;
PyObject* value = PyDict_GetItem(
keywords, PyTuple_GET_ITEM(f->m_arg_names.ptr(), j));
if (!value)
{
PyErr_Clear();
args2 = handle<>();
break;
}
PyTuple_SET_ITEM(args2.get(), j, incref(value));
}
PyTuple_SET_ITEM(args2.get(), j, incref(value));
}
}
}
// Call the function
PyObject* result = args2 ? f->m_fn(args2.get(), 0) : 0;
// Call the function. Pass keywords in case it's a
// function accepting any number of keywords
PyObject* result = args2 ? f->m_fn(args2.get(), keywords) : 0;
// If the result is NULL but no error was set, m_fn failed
// the argument-matching test.
@@ -482,4 +508,20 @@ handle<> function_handle_impl(py_function const& f, unsigned min_arity, unsigned
new function(f, min_arity, max_arity, 0, 0)));
}
}}} // namespace boost::python::objects
}
namespace detail
{
object BOOST_PYTHON_DECL make_raw_function(objects::py_function f, std::size_t min_args)
{
static keyword k;
return objects::function_object(
f
, min_args
, std::numeric_limits<std::size_t>::max()
, keyword_range(&k,&k));
}
}
}} // namespace boost::python::objects

View File

@@ -9,6 +9,7 @@
#include <boost/python/tuple.hpp>
#include <boost/python/class.hpp>
#include <boost/python/overloads.hpp>
#include <boost/python/raw_function.hpp>
#include <boost/python/return_internal_reference.hpp>
#include "test_class.hpp"
@@ -39,12 +40,20 @@ struct X
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_f_overloads, X::f, 0, 3)
tuple raw_func(tuple args, dict kw)
{
return make_tuple(args, kw);
}
BOOST_PYTHON_MODULE(args_ext)
{
def("f", f, args("x", "y", "z")
, "This is f's docstring"
);
def("raw", raw_function(raw_func));
#if defined(BOOST_MSVC) && BOOST_MSVC <= 1200
// MSVC6 gives a fatal error LNK1179: invalid or corrupt file:
// duplicate comdat error if we try to re-use the exact type of f
@@ -57,6 +66,7 @@ BOOST_PYTHON_MODULE(args_ext)
class_<Y>("Y", init<int>(args("value"), "Y's docstring"))
.def("value", &Y::value)
.def("raw", raw_function(raw_func))
;
class_<X>("X", "This is X's docstring")

View File

@@ -1,6 +1,9 @@
"""
>>> from args_ext import *
>>> raw(3, 4, foo = 'bar', baz = 42)
((3, 4), {'foo': 'bar', 'baz': 42})
>>> f(x= 1, y = 3, z = 'hello')
(1, 3.0, 'hello')
@@ -101,6 +104,11 @@
>>> inner(n = 1, self = q).value()
1
>>> y = Y(value = 33)
>>> y.raw(this = 1, that = 'the other')[1]
{'this': 1, 'that': 'the other'}
"""
def run(args = None):
import sys

View File

@@ -10,8 +10,7 @@
>>> z2 = copy_Z(z)
>>> x_instances()
4
>>> y_identity(y) is y
1
>>> assert y_identity(y) is y
>>> y_equality(y, y)
1
'''

View File

@@ -7,11 +7,21 @@
#include <boost/python/def.hpp>
#include <boost/python/module.hpp>
#include <boost/python/class.hpp>
#if BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
# include <boost/type_traits/is_enum.hpp>
# include <boost/mpl/bool.hpp>
#endif
using namespace boost::python;
enum color { red = 1, green = 2, blue = 4 };
#if BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
namespace boost // Pro7 has a hard time detecting enums
{
template <> struct is_enum<color> : boost::mpl::true_ {};
}
#endif
color identity_(color x) { return x; }
struct colorized {

View File

@@ -21,7 +21,13 @@
using namespace boost::python;
typedef test_class<> X;
struct X : test_class<>
{
typedef test_class<> base_t;
X(int x) : base_t(x) {}
X const operator+(X const& r) const { return X(value() + r.value()); }
};
X operator-(X const& l, X const& r) { return X(l.value() - r.value()); }
X operator-(int l, X const& r) { return X(l - r.value()); }
@@ -39,17 +45,17 @@ X abs(X x) { return X(x.value() < 0 ? -x.value() : x.value()); }
X pow(X x, int y)
{
return X(int(pow(double(x.value()), y)));
return X(int(pow(double(x.value()), double(y))));
}
X pow(X x, X y)
{
return X(int(pow(double(x.value()), y.value())));
return X(int(pow(double(x.value()), double(y.value()))));
}
int pow(int x, X y)
{
return int(pow(double(x), y.value()));
return int(pow(double(x), double(y.value())));
}
std::ostream& operator<<(std::ostream& s, X const& x)
@@ -61,6 +67,7 @@ BOOST_PYTHON_MODULE(operators_ext)
{
class_<X>("X", init<int>())
.def("value", &X::value)
.def(self + self)
.def(self - self)
.def(self - int())
.def(other<int>() - self)

View File

@@ -61,19 +61,15 @@ r"""
... else: print 'expected an OverflowError!'
>>> abs(rewrap_value_float(4.2) - 4.2) < .000001
1
>>> assert abs(rewrap_value_float(4.2) - 4.2) < .000001
>>> rewrap_value_double(4.2) - 4.2
0.0
>>> rewrap_value_long_double(4.2) - 4.2
0.0
>>> abs(rewrap_value_complex_float(4+.2j) - (4+.2j)) < .000001
1
>>> abs(rewrap_value_complex_double(4+.2j) - (4+.2j)) < .000001
1
>>> abs(rewrap_value_complex_long_double(4+.2j) - (4+.2j)) < .000001
1
>>> assert abs(rewrap_value_complex_float(4+.2j) - (4+.2j)) < .000001
>>> assert abs(rewrap_value_complex_double(4+.2j) - (4+.2j)) < .000001
>>> assert abs(rewrap_value_complex_long_double(4+.2j) - (4+.2j)) < .000001
>>> rewrap_value_cstring('hello, world')
'hello, world'
@@ -136,19 +132,15 @@ r"""
42L
>>> abs(rewrap_const_reference_float(4.2) - 4.2) < .000001
1
>>> assert abs(rewrap_const_reference_float(4.2) - 4.2) < .000001
>>> rewrap_const_reference_double(4.2) - 4.2
0.0
>>> rewrap_const_reference_long_double(4.2) - 4.2
0.0
>>> abs(rewrap_const_reference_complex_float(4+.2j) - (4+.2j)) < .000001
1
>>> abs(rewrap_const_reference_complex_double(4+.2j) - (4+.2j)) < .000001
1
>>> abs(rewrap_const_reference_complex_long_double(4+.2j) - (4+.2j)) < .000001
1
>>> assert abs(rewrap_const_reference_complex_float(4+.2j) - (4+.2j)) < .000001
>>> assert abs(rewrap_const_reference_complex_double(4+.2j) - (4+.2j)) < .000001
>>> assert abs(rewrap_const_reference_complex_long_double(4+.2j) - (4+.2j)) < .000001
>>> rewrap_const_reference_cstring('hello, world')
'hello, world'
@@ -221,11 +213,9 @@ Check that classic classes also work
... else: print 'expected a TypeError exception'
# show that arbitrary handle<T> instantiations can be returned
>>> get_type(1) is type(1)
1
>>> assert get_type(1) is type(1)
>>> return_null_handle() is None
1
>>> assert return_null_handle() is None
"""
def run(args = None):

View File

@@ -70,11 +70,9 @@ Test call policies for constructors here
>>> num_a_instances()
0
>>> as_A(create('dynalloc')) is None
0
>>> assert as_A(create('dynalloc')) is not None
>>> base = Base()
>>> as_A(base) is None
1
>>> assert as_A(base) is None
"""
def run(args = None):
import sys