diff options
Diffstat (limited to 'libs/python/doc/v2/faq.html')
-rw-r--r-- | libs/python/doc/v2/faq.html | 861 |
1 files changed, 861 insertions, 0 deletions
diff --git a/libs/python/doc/v2/faq.html b/libs/python/doc/v2/faq.html new file mode 100644 index 000000000..75283d77c --- /dev/null +++ b/libs/python/doc/v2/faq.html @@ -0,0 +1,861 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "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> + </head> + + <body link="#0000ff" vlink="#800080"> + <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="../../../../boost.png" 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> + </td> + </tr> + </table> + <hr> + + <dl class="page-index"> + + <dt><a href="#funcptr">How can I wrap a function which takes a + function pointer as an argument?</a><dd> + + <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> + + <dt><a href="#slow_compilation">Compilation takes too much time and eats too much memory! + What can I do to make it faster?</a></dt> + + <dt><a href="#packages">How do I create sub-packages using Boost.Python?</a></dt> + + <dt><a href="#msvcthrowbug" + >error C2064: term does not evaluate to a function taking 2 arguments</a> + </dt> + + <dt><a href="#custom_string" + >How can I automatically convert my custom string type to + and from a Python string?</a></dt> + + <dt><a href="#topythonconversionfailed">Why is my automatic to-python conversion not being + found?</a></dt> + + <dt><a href="#threadsupport">Is Boost.Python thread-aware/compatible with multiple interpreters?</a></dt> + </dl> + <hr> + + <h2><a name="funcptr">How can I wrap a function which takes a + function pointer as an argument?</a></h2> + + If what you're trying to do is something like this: +<pre> +typedef boost::function<void (string s) > funcptr; + +void foo(funcptr fp) +{ + fp("hello,world!"); +} + +BOOST_PYTHON_MODULE(test) +{ + def("foo",foo) ; +} +</pre> + +And then: + +<pre> +>>> def hello(s): +... print s +... +>>> foo(hello) +hello, world! +</pre> + + The short answer is: "you can't". This is not a + Boost.Python limitation so much as a limitation of C++. The + problem is that a Python function is actually data, and the only + way of associating data with a C++ function pointer is to store it + in a static variable of the function. The problem with that is + that you can only associate one piece of data with every C++ + function, and we have no way of compiling a new C++ function + on-the-fly for every Python function you decide to pass + to <code>foo</code>. In other words, this could work if the C++ + function is always going to invoke the <em>same</em> Python + function, but you probably don't want that. + + <p>If you have the luxury of changing the C++ code you're + wrapping, pass it an <code>object</code> instead and call that; + the overloaded function call operator will invoke the Python + function you pass it behind the <code>object</code>. + + <p>For more perspective on the issue, see <a + href="http://aspn.activestate.com/ASPN/Mail/Message/1554837">this + posting</a>. + + <hr> + + <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& get_floating_frequency() const +{ + return boost::python::call_method<period const&>( + 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> + </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& to + this object is returned by a member function of another class. From the + viewpoint of using the returned object in Python I do not care if I get + a copy or a reference to the returned object. In Boost.Python Version 2 + I have the choice of using copy_const_reference or + 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> + </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> + + <ol> + <li> + Using the regular <code>class_<></code> wrapper: +<pre> +class_<std::vector<double> >("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 + + <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<> instantiations. + + <p>This type of C++/Python binding is most suitable for containers + that may contain a large number of elements (>10000).</p> + </li> + + <li> + Using custom rvalue converters. Boost.Python "rvalue converters" + match function signatures such as: +<pre> +void foo(std::vector<double> const& array); // pass by const-reference +void foo(std::vector<double> array); // pass by value +</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<> or std::list<> 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 <-> 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 + 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<> <-> 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<double>& array) +{ + for(std::size_t i=0;i<array.size();i++) { + array[i] *= 2; + } +} +</pre> + Python: +<pre> +>>> l = [1, 2, 3] +>>> foo(l) +>>> 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> +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> + + <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> + + <ol> + <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> +... +void more_of_my_module(); +BOOST_PYTHON_MODULE(my_module) +{ + def("foo", foo); + def("bar", bar); + ... + more_of_my_module(); +} +</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><...></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<my_class>& x) +{ + x + .def("baz", baz) + .add_property("xx", &my_class::get_xx, &my_class::set_xx) + ; + + ... +} +</pre> + </li> + </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> + + <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 + reasons for wrapping the library in python. An expected side-effect or + benefit of using BPL is that debugging should be isolated to the c++ + library that is under test, given that python code is minimal and + 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> +(gdb) target exec python +(gdb) run + >>> from my_ext import * + >>> [C-c] +(gdb) break MyClass::MyBuggyFunction +(gdb) cont + >>> pyobj = MyClass() + >>> pyobj.MyBuggyFunction() +Breakpoint 1, MyClass::MyBuggyFunction ... +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>Raoul Gough has provided the following for gdb on Windows:</p> + + <blockquote> + + <p>gdb support for Windows DLLs has improved lately, so it is + now possible to debug Python extensions using a few + tricks. Firstly, you will need an up-to-date gdb with support + for minimal symbol extraction from a DLL. Any gdb from version 6 + onwards, or Cygwin gdb-20030214-1 and onwards should do. A + suitable release will have a section in the gdb.info file under + Configuration – Native – Cygwin Native – + Non-debug DLL symbols. Refer to that info section for more + details of the procedures outlined here.</p> + + <p>Secondly, it seems necessary to set a breakpoint in the + Python interpreter, rather than using ^C to break execution. A + good place to set this breakpoint is PyOS_Readline, which will + stop execution immediately before reading each interactive + Python command. You have to let Python start once under the + debugger, so that it loads its own DLL, before you can set the + breakpoint:</p> + +<p> +<pre> +$ gdb python +GNU gdb 2003-09-02-cvs (cygwin-special) +[...] + +(gdb) run +Starting program: /cygdrive/c/Python22/python.exe +Python 2.2.2 (#37, Oct 14 2002, 17:02:34) [MSC 32 bit (Intel)] on win32 +Type "help", "copyright", "credits" or "license" for more information. +>>> ^Z + + +Program exited normally. +(gdb) break *&PyOS_Readline +Breakpoint 1 at 0x1e04eff0 +(gdb) run +Starting program: /cygdrive/c/Python22/python.exe +Python 2.2.2 (#37, Oct 14 2002, 17:02:34) [MSC 32 bit (Intel)] on win32 +Type "help", "copyright", "credits" or "license" for more information. + +Breakpoint 1, 0x1e04eff0 in python22!PyOS_Readline () + from /cygdrive/c/WINNT/system32/python22.dll +(gdb) cont +Continuing. +>>> from my_ext import * + +Breakpoint 1, 0x1e04eff0 in python22!PyOS_Readline () + from /cygdrive/c/WINNT/system32/python22.dll +(gdb) # my_ext now loaded (with any debugging symbols it contains) +</pre> + </blockquote> + + <h3>Debugging extensions through Boost.Build</h3> + If you are launching your extension module tests with <a href= + "../../../../tools/build/v1/build_system.htm">Boost.Build</a> using the + <code>boost-python-runtest</code> rule, you can ask it to launch your + debugger for you by adding "--debugger=<i>debugger</i>" to your bjam + command-line: +<pre> +bjam -sTOOLS=vc7.1 "--debugger=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. + <hr> + + <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> + <i>operator. It always tells me "can't multiply sequence with non int + 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> +>>> class X(object): +... def __imul__(self, x): +... print 'imul' +... +>>> x = X() +>>> x *= 1 +</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> + + It is known to work under 10.2.8 and 10.3 using + Apple's gcc 3.3 compiler: + <pre>gcc (GCC) 3.3 20030304 (Apple Computer, Inc. build 1493)</pre> + Under 10.2.8 get the August 2003 gcc update (free at + <a href="http://connect.apple.com/">http://connect.apple.com/</a>). + Under 10.3 get the Xcode Tools v1.0 (also free). + <p> + Python 2.3 is required. The Python that ships with 10.3 is + fine. Under 10.2.8 use these commands to install Python + as a framework: + <pre>./configure --enable-framework +make +make frameworkinstall</pre> + The last command requires root privileges because the target + directory is + <tt>/Library/Frameworks/Python.framework/Versions/2.3</tt>. + However, the installation does not interfere with the Python + version that ships with 10.2.8. + <p> + It is also crucial to increase the <tt>stacksize</tt> before + starting compilations, e.g.: + <pre>limit stacksize 8192k</pre> + If the <tt>stacksize</tt> is too small the build might crash with + internal compiler errors. + <p> + Sometimes Apple's compiler exhibits a bug by printing an error + like the following while compiling a + <tt>boost::python::class_<your_type></tt> + template instantiation: + <pre>.../inheritance.hpp:44: error: cannot + dynamic_cast `p' (of type `struct cctbx::boost_python::<unnamed>::add_pair* + ') to type `void*' (source type is not polymorphic)</pre> + + We do not know a general workaround, but if the definition of + <tt>your_type</tt> can be modified the following was found + to work in all cases encountered so far:<pre>struct your_type +{ + // before defining any member data +#if defined(__MACH__) && defined(__APPLE_CC__) && __APPLE_CC__ == 1493 + bool dummy_; +#endif + // now your member data, e.g. + double x; + int j; + // etc. +};</pre> + + <hr> + <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> +class X { X(int); virtual ~X(); ... }; +X* f(); // known to return Xs that are managed by Python objects + + +// wrapping code + +struct X_wrap : X +{ + X_wrap(PyObject* self, int v) : self(self), X(v) {} + PyObject* self; +}; + +handle<> f_wrap() +{ + X_wrap* xw = dynamic_cast<X_wrap*>(f()); + assert(xw != 0); + return handle<>(borrowed(xw->self)); +} + +... + +def("f", f_wrap()); +class_<X,X_wrap,boost::noncopyable>("X", init<int>()) + ... + ; +</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<X></code> is + converted from Python, the shared_ptr actually manages a reference to the + containing Python object. When a shared_ptr<X> 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> + + <hr> + + <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> +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> +a = mod.A() +b = mod.B() +b.add( a ) +del a +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> +class_<A, std::auto_ptr<A> >("A") + ... + ; +</pre> + Then make a thin wrapper function which takes an auto_ptr parameter: +<pre> +void b_insert(B& b, std::auto_ptr<A> 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. + + <hr> + <h2><a name="slow_compilation">Compilation takes too much time and eats too + much memory! What can I do to make it faster?</a></h2> + <p> + Please refer to the <a href="../tutorial/doc/html/python/techniques.html#python.reducing_compiling_time" + >Reducing Compiling Time</a> section in the tutorial. + </p> + + <hr> + <h2><a name="packages">How do I create sub-packages using Boost.Python?</a></h2> + <p> + Please refer to the <a href="../tutorial/doc/html/python/techniques.html#python.creating_packages" + >Creating Packages</a> section in the tutorial. + </p> + + <hr> + <h2><a name="msvcthrowbug"></a>error C2064: term does + not evaluate to a function taking 2 arguments</h2> + <font size="-1"><i>Niall Douglas provides these notes:</i></font><p> + If you see Microsoft Visual C++ 7.1 (MS Visual Studio .NET 2003) issue + an error message like the following it is most likely due to a bug + in the compiler: + <pre>boost\boost\python\detail\invoke.hpp(76): +error C2064: term does not evaluate to a function taking 2 arguments"</pre> + This message is triggered by code like the following: +<pre>#include <boost/python.hpp> + +using namespace boost::python; + +class FXThread +{ +public: + bool setAutoDelete(bool doso) throw(); +}; + +void Export_FXThread() +{ + class_< FXThread >("FXThread") + .def("setAutoDelete", &FXThread::setAutoDelete) + ; +} + </pre> + The bug is related to the <code>throw()</code> modifier. + As a workaround cast off the modifier. E.g.: +<pre> + .def("setAutoDelete", (bool (FXThread::*)(bool)) &FXThread::setAutoDelete)</pre> + <p>(The bug has been reported to Microsoft.)</p> + + <hr> + <h2><a name="custom_string"></a>How can I automatically + convert my custom string type to and from a Python string?</h2> + <font size="-1"><i>Ralf W. Grosse-Kunstleve provides these + notes:</i></font><p> + Below is a small, self-contained demo extension module that shows + how to do this. Here is the corresponding trivial test: + <pre>import custom_string +assert custom_string.hello() == "Hello world." +assert custom_string.size("california") == 10</pre> + + If you look at the code you will find: + + <ul> + <li>A custom <tt>to_python</tt> converter (easy): + <tt>custom_string_to_python_str</tt> + + <li>A custom lvalue converter (needs more code): + <tt>custom_string_from_python_str</tt> + </ul> + + The custom converters are registered in the global Boost.Python + registry near the top of the module initialization function. Once + flow control has passed through the registration code the automatic + conversions from and to Python strings will work in any module + imported in the same process. + +<pre>#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/to_python_converter.hpp> + +namespace sandbox { namespace { + + class custom_string + { + public: + custom_string() {} + custom_string(std::string const& value) : value_(value) {} + std::string const& value() const { return value_; } + private: + std::string value_; + }; + + struct custom_string_to_python_str + { + static PyObject* convert(custom_string const& s) + { + return boost::python::incref(boost::python::object(s.value()).ptr()); + } + }; + + struct custom_string_from_python_str + { + custom_string_from_python_str() + { + boost::python::converter::registry::push_back( + &convertible, + &construct, + boost::python::type_id<custom_string>()); + } + + static void* convertible(PyObject* obj_ptr) + { + if (!PyString_Check(obj_ptr)) return 0; + return obj_ptr; + } + + static void construct( + PyObject* obj_ptr, + boost::python::converter::rvalue_from_python_stage1_data* data) + { + const char* value = PyString_AsString(obj_ptr); + if (value == 0) boost::python::throw_error_already_set(); + void* storage = ( + (boost::python::converter::rvalue_from_python_storage<custom_string>*) + data)->storage.bytes; + new (storage) custom_string(value); + data->convertible = storage; + } + }; + + custom_string hello() { return custom_string("Hello world."); } + + std::size_t size(custom_string const& s) { return s.value().size(); } + + void init_module() + { + using namespace boost::python; + + boost::python::to_python_converter< + custom_string, + custom_string_to_python_str>(); + + custom_string_from_python_str(); + + def("hello", hello); + def("size", size); + } + +}} // namespace sandbox::<anonymous> + +BOOST_PYTHON_MODULE(custom_string) +{ + sandbox::init_module(); +}</pre> + + <hr> + <h2><a name="topythonconversionfailed"></a + >Why is my automatic to-python conversion not being found?</h2> + <font size="-1"><i>Niall Douglas provides these notes:</i></font><p> + If you define custom converters similar to the ones + shown above the <tt>def_readonly()</tt> and <tt>def_readwrite()</tt> + member functions provided by <tt>boost::python::class_</tt> for + direct access to your member data will not work as expected. + This is because <tt>def_readonly("bar", &foo::bar)</tt> is + equivalent to: + +<pre>.add_property("bar", make_getter(&foo::bar, return_internal_reference()))</pre> + + Similarly, <tt>def_readwrite("bar", &foo::bar)</tt> is + equivalent to: + +<pre>.add_property("bar", make_getter(&foo::bar, return_internal_reference()), + make_setter(&foo::bar, return_internal_reference())</pre> + + In order to define return value policies compatible with the + custom conversions replace <tt>def_readonly()</tt> and + <tt>def_readwrite()</tt> by <tt>add_property()</tt>. E.g.: + +<pre>.add_property("bar", make_getter(&foo::bar, return_value_policy<return_by_value>()), + make_setter(&foo::bar, return_value_policy<return_by_value>()))</pre> + + <hr> + <h2><a name="threadsupport"></a + >Is Boost.Python thread-aware/compatible with multiple interpreters?</h2> + <font size="-1"><i>Niall Douglas provides these notes:</i></font><p> + The quick answer to this is: no.</p> + <p> + The longer answer is that it can be patched to be so, but it's + complex. You will need to add custom lock/unlock wrapping of every + time your code enters Boost.Python (particularly every virtual + function override) plus heavily modify + <tt>boost/python/detail/invoke.hpp</tt> with custom unlock/lock + wrapping of every time Boost.Python enters your code. You must + furthermore take care to <i>not</i> unlock/lock when Boost.Python + is invoking iterator changes via <tt>invoke.hpp</tt>.</p> + <p> + There is a patched <tt>invoke.hpp</tt> posted on the C++-SIG + mailing list archives and you can find a real implementation of all + the machinery necessary to fully implement this in the TnFOX + project at <a href="http://sourceforge.net/projects/tnfox/"> this + SourceForge project location</a>.</p> + + <hr> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 12 March, 2006 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002-2006.</i></p> + </body> +</html> |