From 04cad679a59712bcb6feb61b1d2305cbddcac956 Mon Sep 17 00:00:00 2001 From: Stefan Seefeld Date: Wed, 29 Jul 2015 17:43:42 -0400 Subject: [PATCH] Convert docs to QuickBook. --- doc/Jamfile | 56 +- doc/building.qbk | 563 ++++++ doc/building.rst | 680 ------- doc/configuration.qbk | 83 + doc/faq.qbk | 737 +++++++ doc/glossary.qbk | 37 + doc/html/boost.css | 66 + doc/html/boostbook.css | 700 +++++++ doc/html/images/alert.png | Bin 0 -> 603 bytes doc/html/images/blank.png | Bin 0 -> 374 bytes doc/html/images/boost.png | Bin 0 -> 6308 bytes doc/html/images/callouts/1.png | Bin 0 -> 391 bytes doc/html/images/callouts/1.svg | 15 + doc/html/images/callouts/10.png | Bin 0 -> 485 bytes doc/html/images/callouts/10.svg | 18 + doc/html/images/callouts/11.png | Bin 0 -> 410 bytes doc/html/images/callouts/11.svg | 16 + doc/html/images/callouts/12.png | Bin 0 -> 488 bytes doc/html/images/callouts/12.svg | 18 + doc/html/images/callouts/13.png | Bin 0 -> 509 bytes doc/html/images/callouts/13.svg | 20 + doc/html/images/callouts/14.png | Bin 0 -> 499 bytes doc/html/images/callouts/14.svg | 17 + doc/html/images/callouts/15.png | Bin 0 -> 507 bytes doc/html/images/callouts/15.svg | 19 + doc/html/images/callouts/16.svg | 20 + doc/html/images/callouts/17.svg | 17 + doc/html/images/callouts/18.svg | 21 + doc/html/images/callouts/19.svg | 20 + doc/html/images/callouts/2.png | Bin 0 -> 446 bytes doc/html/images/callouts/2.svg | 17 + doc/html/images/callouts/20.svg | 20 + doc/html/images/callouts/21.svg | 18 + doc/html/images/callouts/22.svg | 20 + doc/html/images/callouts/23.svg | 22 + doc/html/images/callouts/24.svg | 19 + doc/html/images/callouts/25.svg | 21 + doc/html/images/callouts/26.svg | 22 + doc/html/images/callouts/27.svg | 19 + doc/html/images/callouts/28.svg | 23 + doc/html/images/callouts/29.svg | 22 + doc/html/images/callouts/3.png | Bin 0 -> 431 bytes doc/html/images/callouts/3.svg | 19 + doc/html/images/callouts/30.svg | 22 + doc/html/images/callouts/4.png | Bin 0 -> 441 bytes doc/html/images/callouts/4.svg | 16 + doc/html/images/callouts/5.png | Bin 0 -> 423 bytes doc/html/images/callouts/5.svg | 18 + doc/html/images/callouts/6.png | Bin 0 -> 431 bytes doc/html/images/callouts/6.svg | 19 + doc/html/images/callouts/7.png | Bin 0 -> 397 bytes doc/html/images/callouts/7.svg | 16 + doc/html/images/callouts/8.png | Bin 0 -> 434 bytes doc/html/images/callouts/8.svg | 20 + doc/html/images/callouts/9.png | Bin 0 -> 420 bytes doc/html/images/callouts/9.svg | 19 + doc/html/images/caution.png | Bin 0 -> 1250 bytes doc/html/images/caution.svg | 68 + doc/html/images/draft.png | Bin 0 -> 17454 bytes doc/html/images/home.png | Bin 0 -> 358 bytes doc/html/images/home.svg | 26 + doc/html/images/important.png | Bin 0 -> 722 bytes doc/html/images/important.svg | 25 + doc/html/images/jam.png | Bin 0 -> 3884 bytes doc/html/images/next.png | Bin 0 -> 336 bytes doc/html/images/next.svg | 19 + doc/html/images/next_disabled.png | Bin 0 -> 1110 bytes doc/html/images/note.png | Bin 0 -> 490 bytes doc/html/images/note.svg | 33 + doc/html/images/prev.png | Bin 0 -> 334 bytes doc/html/images/prev.svg | 19 + doc/html/images/prev_disabled.png | Bin 0 -> 1109 bytes doc/html/images/smiley.png | Bin 0 -> 867 bytes doc/html/images/tip.png | Bin 0 -> 449 bytes doc/html/images/tip.svg | 84 + doc/html/images/toc-blank.png | Bin 0 -> 318 bytes doc/html/images/toc-minus.png | Bin 0 -> 259 bytes doc/html/images/toc-plus.png | Bin 0 -> 264 bytes doc/html/images/up.png | Bin 0 -> 370 bytes doc/html/images/up.svg | 19 + doc/html/images/up_disabled.png | Bin 0 -> 1115 bytes doc/html/images/warning.png | Bin 0 -> 1241 bytes doc/html/images/warning.svg | 23 + doc/index.qbk | 19 + doc/preface.qbk | 26 + doc/python.qbk | 61 + doc/reference.qbk | 25 + doc/reference/args.qbk | 64 + doc/reference/call.qbk | 26 + doc/reference/call_method.qbk | 80 + doc/reference/calling.qbk | 65 + doc/reference/class.qbk | 300 +++ doc/reference/components.qbk | 18 + doc/reference/concepts.qbk | 134 ++ doc/reference/conversion.qbk | 10 + doc/reference/copy_const_reference.qbk | 58 + doc/reference/copy_non_const_reference.qbk | 58 + doc/reference/data_members.qbk | 98 + doc/reference/def.qbk | 54 + doc/reference/def_visitor.qbk | 61 + doc/reference/default_call_policies.qbk | 58 + doc/reference/dict.qbk | 71 + doc/reference/docstring_options.qbk | 214 ++ doc/reference/embedding.qbk | 6 + doc/reference/enum.qbk | 107 + doc/reference/errors.qbk | 142 ++ doc/reference/exception_translator.qbk | 51 + doc/reference/exec.qbk | 84 + doc/reference/extract.qbk | 99 + doc/reference/function_doc_signature.qbk | 129 ++ doc/reference/functions.qbk | 35 + doc/reference/handle.qbk | 190 ++ doc/reference/has_back_reference.qbk | 115 ++ doc/reference/implicit.qbk | 69 + doc/reference/import.qbk | 31 + doc/reference/indexing.qbk | 279 +++ doc/reference/init.qbk | 91 + doc/reference/instance_holder.qbk | 92 + doc/reference/iterator.qbk | 111 ++ doc/reference/list.qbk | 60 + doc/reference/long.qbk | 38 + doc/reference/lvalue_from_pytype.qbk | 120 ++ doc/reference/make_function.qbk | 83 + doc/reference/manage_new_object.qbk | 56 + doc/reference/module.qbk | 41 + doc/reference/numeric.qbk | 153 ++ doc/reference/object.qbk | 574 ++++++ doc/reference/objects.qbk | 12 + doc/reference/opaque_pointer_converter.qbk | 30 + doc/reference/operators.qbk | 257 +++ doc/reference/overloads.qbk | 97 + doc/reference/pickle.qbk | 159 ++ doc/reference/pointee.qbk | 47 + doc/reference/ptr.qbk | 118 ++ doc/reference/pytype_function.qbk | 194 ++ doc/reference/raw_function.qbk | 44 + doc/reference/reference_existing_object.qbk | 75 + doc/reference/register_ptr_to_python.qbk | 88 + doc/reference/return_arg.qbk | 91 + doc/reference/return_by_value.qbk | 62 + doc/reference/return_internal_reference.qbk | 88 + doc/reference/return_opaque_pointer.qbk | 95 + doc/reference/return_value_policy.qbk | 59 + doc/reference/scope.qbk | 83 + doc/reference/slice.qbk | 136 ++ doc/reference/ssize_t.qbk | 27 + doc/reference/stl_iterator.qbk | 108 + doc/reference/str.qbk | 153 ++ doc/reference/to_python_converter.qbk | 90 + doc/reference/to_python_indirect.qbk | 65 + doc/reference/to_python_value.qbk | 34 + doc/reference/topics.qbk | 7 + doc/reference/tuple.qbk | 52 + doc/reference/type_id.qbk | 76 + doc/reference/utility.qbk | 10 + doc/reference/with_custodian_and_ward.qbk | 72 + doc/reference/wrapper.qbk | 117 ++ doc/tutorial.qbk | 1982 +++++++++++++++++++ 158 files changed, 11896 insertions(+), 699 deletions(-) create mode 100644 doc/building.qbk delete mode 100644 doc/building.rst create mode 100644 doc/configuration.qbk create mode 100644 doc/faq.qbk create mode 100644 doc/glossary.qbk create mode 100644 doc/html/boost.css create mode 100644 doc/html/boostbook.css create mode 100644 doc/html/images/alert.png create mode 100644 doc/html/images/blank.png create mode 100644 doc/html/images/boost.png create mode 100644 doc/html/images/callouts/1.png create mode 100644 doc/html/images/callouts/1.svg create mode 100644 doc/html/images/callouts/10.png create mode 100644 doc/html/images/callouts/10.svg create mode 100644 doc/html/images/callouts/11.png create mode 100644 doc/html/images/callouts/11.svg create mode 100644 doc/html/images/callouts/12.png create mode 100644 doc/html/images/callouts/12.svg create mode 100644 doc/html/images/callouts/13.png create mode 100644 doc/html/images/callouts/13.svg create mode 100644 doc/html/images/callouts/14.png create mode 100644 doc/html/images/callouts/14.svg create mode 100644 doc/html/images/callouts/15.png create mode 100644 doc/html/images/callouts/15.svg create mode 100644 doc/html/images/callouts/16.svg create mode 100644 doc/html/images/callouts/17.svg create mode 100644 doc/html/images/callouts/18.svg create mode 100644 doc/html/images/callouts/19.svg create mode 100644 doc/html/images/callouts/2.png create mode 100644 doc/html/images/callouts/2.svg create mode 100644 doc/html/images/callouts/20.svg create mode 100644 doc/html/images/callouts/21.svg create mode 100644 doc/html/images/callouts/22.svg create mode 100644 doc/html/images/callouts/23.svg create mode 100644 doc/html/images/callouts/24.svg create mode 100644 doc/html/images/callouts/25.svg create mode 100644 doc/html/images/callouts/26.svg create mode 100644 doc/html/images/callouts/27.svg create mode 100644 doc/html/images/callouts/28.svg create mode 100644 doc/html/images/callouts/29.svg create mode 100644 doc/html/images/callouts/3.png create mode 100644 doc/html/images/callouts/3.svg create mode 100644 doc/html/images/callouts/30.svg create mode 100644 doc/html/images/callouts/4.png create mode 100644 doc/html/images/callouts/4.svg create mode 100644 doc/html/images/callouts/5.png create mode 100644 doc/html/images/callouts/5.svg create mode 100644 doc/html/images/callouts/6.png create mode 100644 doc/html/images/callouts/6.svg create mode 100644 doc/html/images/callouts/7.png create mode 100644 doc/html/images/callouts/7.svg create mode 100644 doc/html/images/callouts/8.png create mode 100644 doc/html/images/callouts/8.svg create mode 100644 doc/html/images/callouts/9.png create mode 100644 doc/html/images/callouts/9.svg create mode 100644 doc/html/images/caution.png create mode 100644 doc/html/images/caution.svg create mode 100644 doc/html/images/draft.png create mode 100644 doc/html/images/home.png create mode 100644 doc/html/images/home.svg create mode 100644 doc/html/images/important.png create mode 100644 doc/html/images/important.svg create mode 100644 doc/html/images/jam.png create mode 100644 doc/html/images/next.png create mode 100644 doc/html/images/next.svg create mode 100644 doc/html/images/next_disabled.png create mode 100644 doc/html/images/note.png create mode 100644 doc/html/images/note.svg create mode 100644 doc/html/images/prev.png create mode 100644 doc/html/images/prev.svg create mode 100644 doc/html/images/prev_disabled.png create mode 100644 doc/html/images/smiley.png create mode 100644 doc/html/images/tip.png create mode 100644 doc/html/images/tip.svg create mode 100644 doc/html/images/toc-blank.png create mode 100644 doc/html/images/toc-minus.png create mode 100644 doc/html/images/toc-plus.png create mode 100644 doc/html/images/up.png create mode 100644 doc/html/images/up.svg create mode 100644 doc/html/images/up_disabled.png create mode 100644 doc/html/images/warning.png create mode 100644 doc/html/images/warning.svg create mode 100644 doc/index.qbk create mode 100644 doc/preface.qbk create mode 100644 doc/python.qbk create mode 100644 doc/reference.qbk create mode 100644 doc/reference/args.qbk create mode 100644 doc/reference/call.qbk create mode 100644 doc/reference/call_method.qbk create mode 100644 doc/reference/calling.qbk create mode 100644 doc/reference/class.qbk create mode 100644 doc/reference/components.qbk create mode 100644 doc/reference/concepts.qbk create mode 100644 doc/reference/conversion.qbk create mode 100644 doc/reference/copy_const_reference.qbk create mode 100644 doc/reference/copy_non_const_reference.qbk create mode 100644 doc/reference/data_members.qbk create mode 100644 doc/reference/def.qbk create mode 100644 doc/reference/def_visitor.qbk create mode 100644 doc/reference/default_call_policies.qbk create mode 100644 doc/reference/dict.qbk create mode 100644 doc/reference/docstring_options.qbk create mode 100644 doc/reference/embedding.qbk create mode 100644 doc/reference/enum.qbk create mode 100644 doc/reference/errors.qbk create mode 100644 doc/reference/exception_translator.qbk create mode 100644 doc/reference/exec.qbk create mode 100644 doc/reference/extract.qbk create mode 100644 doc/reference/function_doc_signature.qbk create mode 100644 doc/reference/functions.qbk create mode 100644 doc/reference/handle.qbk create mode 100644 doc/reference/has_back_reference.qbk create mode 100644 doc/reference/implicit.qbk create mode 100644 doc/reference/import.qbk create mode 100644 doc/reference/indexing.qbk create mode 100644 doc/reference/init.qbk create mode 100644 doc/reference/instance_holder.qbk create mode 100644 doc/reference/iterator.qbk create mode 100644 doc/reference/list.qbk create mode 100644 doc/reference/long.qbk create mode 100644 doc/reference/lvalue_from_pytype.qbk create mode 100644 doc/reference/make_function.qbk create mode 100644 doc/reference/manage_new_object.qbk create mode 100644 doc/reference/module.qbk create mode 100644 doc/reference/numeric.qbk create mode 100644 doc/reference/object.qbk create mode 100644 doc/reference/objects.qbk create mode 100644 doc/reference/opaque_pointer_converter.qbk create mode 100644 doc/reference/operators.qbk create mode 100644 doc/reference/overloads.qbk create mode 100644 doc/reference/pickle.qbk create mode 100644 doc/reference/pointee.qbk create mode 100644 doc/reference/ptr.qbk create mode 100644 doc/reference/pytype_function.qbk create mode 100644 doc/reference/raw_function.qbk create mode 100644 doc/reference/reference_existing_object.qbk create mode 100644 doc/reference/register_ptr_to_python.qbk create mode 100644 doc/reference/return_arg.qbk create mode 100644 doc/reference/return_by_value.qbk create mode 100644 doc/reference/return_internal_reference.qbk create mode 100644 doc/reference/return_opaque_pointer.qbk create mode 100644 doc/reference/return_value_policy.qbk create mode 100644 doc/reference/scope.qbk create mode 100644 doc/reference/slice.qbk create mode 100644 doc/reference/ssize_t.qbk create mode 100644 doc/reference/stl_iterator.qbk create mode 100644 doc/reference/str.qbk create mode 100644 doc/reference/to_python_converter.qbk create mode 100644 doc/reference/to_python_indirect.qbk create mode 100644 doc/reference/to_python_value.qbk create mode 100644 doc/reference/topics.qbk create mode 100644 doc/reference/tuple.qbk create mode 100644 doc/reference/type_id.qbk create mode 100644 doc/reference/utility.qbk create mode 100644 doc/reference/with_custodian_and_ward.qbk create mode 100644 doc/reference/wrapper.qbk create mode 100644 doc/tutorial.qbk diff --git a/doc/Jamfile b/doc/Jamfile index 9b7c8841..94296899 100644 --- a/doc/Jamfile +++ b/doc/Jamfile @@ -1,23 +1,41 @@ -# Copyright David Abrahams 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying +# Copyright (c) 2006 Joel de Guzman +# Copyright (c) 2015 Stefan Seefeld +# +# 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) -import docutils ; -import path ; -sources = building.rst ; -bases = $(sources:S=) ; - -# This is a path relative to the html/ subdirectory where the -# generated output will eventually be moved. -stylesheet = "--stylesheet=../../../rst.css" ; +path-constant here : . ; +path-constant images : html/images ; -for local b in $(bases) -{ - html $(b) : $(b).rst : - - "-gdt --source-url="./$(b).rst" --link-stylesheet --traceback --trim-footnote-reference-space --footnote-references=superscript "$(stylesheet) - ; -} -alias htmls : $(bases) ; -stage . : $(bases) ; +project python/doc + : requirements html:boost.defaults=Boost + html:toc.max.depth=3 + html:toc.section.depth=3 + html:chunk.section.depth=3 + ; + +import boostbook ; +import quickbook ; + +boostbook python : python.qbk + : html:$(here)/html + html:generate.toc="library nop; chapter toc; section toc;" + html:html.stylesheet=boostbook.css + html:boost.image.src=images/boost.png + html:boost.graphics.root=images/ + ; + +boostbook tutorial : tutorial.qbk + : html:$(here)/html/tutorial + html:html.stylesheet=../boostbook.css + html:boost.image.src=../images/boost.png + html:boost.graphics.root=../images/ + ; + +boostbook reference : reference.qbk + : html:$(here)/html/reference + html:html.stylesheet=../boostbook.css + html:boost.image.src=../images/boost.png + html:boost.graphics.root=../images/ + ; diff --git a/doc/building.qbk b/doc/building.qbk new file mode 100644 index 00000000..70bd9f59 --- /dev/null +++ b/doc/building.qbk @@ -0,0 +1,563 @@ +[chapter Building and Testing + [quickbook 1.7] + [authors [Abrahams, David]] + [copyright 2002 - 2015 David Abrahams, Stefan Seefeld] + [id building] +] +[/ 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) + /] + +[section Requirements] + +Boost.Python requires [@http://www.python.org/2.2 Python 2.2] +[footnote Note that although we tested earlier versions of Boost.Python + with Python 2.2, and we don't *think* we've done anything to break + compatibility, this release of Boost.Python may not have been tested + with versions of Python earlier than 2.4, so we're not 100% sure that + python 2.2 and 2.3 are supported.] *or* [@http://www.python.org newer]. + +[endsect] +[section Background] + +There are two basic models for combining C++ and Python: + +* [@http://www.python.org/doc/current/ext/intro.html extending], + in which the end-user launches the Python interpreter + executable and imports Python “extension modules” written in C++. + Think of taking a library written in C++ and giving it a Python + interface so Python programmers can use it. From Python, these + modules look just like regular Python modules. + +* [@http://www.python.org/doc/current/ext/embedding.html embedding], + in which the end-user launches a program written + in C++ that in turn invokes the Python interpreter as a library + subroutine. Think of adding scriptability to an existing + application. + +The key distinction between extending and embedding is the location +of the C++ `main()` function: in the Python interpreter executable, +or in some other program, respectively. Note that even when +embedding Python in another program, [@http://www.python.org/doc/current/ext/extending-with-embedding.html extension modules are often +the best way to make C/C++ functionality accessible to Python +code], so the use of extension modules is really at the heart of +both models. + +Except in rare cases, extension modules are built as +dynamically-loaded libraries with a single entry point, which means +you can change them without rebuilding either the other extension +modules or the executable containing `main()`. + +[endsect] +[section No-Install Quickstart] + +There is no need to “install Boost” in order to get started using +Boost.Python. These instructions use [@http://boost.org/build] projects, +which will build those binaries as soon as they're needed. Your +first tests may take a little longer while you wait for +Boost.Python to build, but doing things this way will save you from +worrying about build intricacies like which library binaries to use +for a specific compiler configuration and figuring out the right +compiler options to use yourself. + +[note Of course it's possible to use other build systems to + build Boost.Python and its extensions, but they are not + officially supported by Boost. Moreover *99% of all “I can't + build Boost.Python” problems come from trying to use another + build system* without first following these instructions. + + If you want to use another system anyway, we suggest that you + follow these instructions, and then invoke ``bjam`` with the + + `-a -o`\ *filename* + + options to dump the build commands it executes to a file, so + you can see what your alternate build system needs to do.] + +[section Basic Procedure] + +1. Get Boost; see sections 1 and 2 of the _gsg_. + +2. Get the `bjam` build driver. See section 5 of the _gsg_. + +3. cd into the `example/quickstart/` directory of your + Boost.Python installation, which contains a small example project. + +4. Invoke `bjam`. Replace the “\ `stage`\ “ argument from the + example invocation from section 5 of the _gsg_ with “\ `test`\ ,“ to + build all the test targets. Also add the argument “\ `--verbose-test`\ ” + to see the output generated by the tests when they are run. + On Windows, your `bjam` invocation might look something like: + `` + C:\\boost_1_34_0\\...\\quickstart> bjam toolset=msvc --verbose-test test + `` + and on Unix variants, perhaps, + `` + ~/boost_1_34_0/.../quickstart$ bjam toolset=gcc --verbose-test test + `` + +[note For the sake of concision, the rest of this guide will use + unix-style forward slashes in pathnames instead of the + backslashes with which Windows users may be more familiar. The forward + slashes should work everywhere except in + [@http://www.boost.org/more/getting_started/windows.html#command-prompt Command Prompt windows], + where you should use backslashes.] + +If you followed this procedure successfully, you will have built an +extension module called `extending` and tested it by running a +Python script called `test_extending.py`. You will also have +built and run a simple application called `embedding` that embeds +python. + +[endsect] +[section In Case of Trouble] + +If you're seeing lots of compiler and/or linker error messages, +it's probably because Boost.Build is having trouble finding your +Python installation. You might want to pass the +`--debug-configuration` option to `bjam` the first few times +you invoke it, to make sure that Boost.Build is correctly locating +all the parts of your Python installation. If it isn't, consider +[link building.configuring_boost_build Configuring Boost.Build] +as detailed below. + +If you're still having trouble, Someone on one of the following +mailing lists may be able to help: + +* The _bb_list_ for issues related to Boost.Build +* The _bp_list_ for issues specifically related to Boost.Python + +[endsect] +[section In Case Everything Seemed to Work] + +Rejoice! If you're new to Boost.Python, at this point it might be +a good idea to ignore build issues for a while and concentrate on +learning the library by going through the _tutorial_ and perhaps +some of the _reference_, trying out what you've +learned about the API by modifying the quickstart project. + +[endsect] +[section Modifying the Example Project] + +If you're content to keep your extension module forever in one +source file called `extending.cpp`, inside your Boost.Python +distribution, and import it forever as `extending`, then you can +stop here. However, it's likely that you will want to make a few +changes. There are a few things you can do without having to learn +_bb_ in depth. + +The project you just built is specified in two files in the current +directory: `boost-build.jam`, which tells `bjam` where it can +find the interpreted code of the Boost build system, and +`Jamroot`, which describes the targets you just built. These +files are heavily commented, so they should be easy to modify. +Take care, however, to preserve whitespace. Punctuation such as +`;` will not be recognized as intended by `bjam` if it is not +surrounded by whitespace. + +[section Relocate the Project] + +You'll probably want to copy this project elsewhere so you can +change it without modifying your Boost distribution. To do that, +simply + +a. copy the entire `example/quickstart/` directory + into a new directory. + +b. In the new copies of `boost-build.jam` and `Jamroot`, locate + the relative path near the top of the file that is clearly + marked by a comment, and edit that path so that it refers to the + same directory your Boost distribution as it referred to when + the file was in its original location in the + `example/quickstart/` directory. + +For example, if you moved the project from +`/home/dave/boost_1_34_0/libs/python/example/quickstart` to +`/home/dave/my-project`, you could change the first path in +`boost-build.jam` from +`` + ../../../../tools/build/v2 +`` +to +`` + /home/dave/boost_1_34_0/tools/build/v2 +`` +and change the first path in `Jamroot` from +`` + ../../../.. +`` +to +`` + /home/dave/boost_1_34_0 +`` + +[endsect] +[section Add New or Change Names of Existing Source Files] + +The names of additional source files involved in building your +extension module or embedding application can be listed in +`Jamroot` right alongside `extending.cpp` or `embedding.cpp` +respectively. Just be sure to leave whitespace around each +filename: +`` + … file1.cpp file2.cpp file3.cpp … +`` +Naturally, if you want to change the name of a source file you can +tell Boost.Build about it by editing the name in `Jamroot`. + +[endsect] +[section Change the Name of your Extension Module] + +The name of the extension module is determined by two things: + +1. the name in `Jamroot` immediately following `python-extension`, and +2. the name passed to ``BOOST_PYTHON_MODULE`` in `extending.cpp`. + +To change the name of the extension module from `extending` to +`hello`, you'd edit `Jamroot`, changing +`` + python-extension extending : extending.cpp ; +`` +to +`` + python-extension hello : extending.cpp ; +`` +and you'd edit extending.cpp, changing + +`` + BOOST_PYTHON_MODULE(extending) +`` +to +`` + BOOST_PYTHON_MODULE(hello) +`` +[endsect] +[endsect] +[section Installing Boost.Python on your System] + +Since Boost.Python is a separately-compiled (as opposed to +`header-only`) library, its user relies on the services of a +Boost.Python library binary. + +If you need a regular installation of the Boost.Python library +binaries on your system, the _gsg_ will +walk you through the steps of creating one. If building binaries +from source, you might want to supply the `--with-python` +argument to `bjam` (or the `--with-libraries=python` argument +to `configure`), so only the Boost.Python binary will be built, +rather than all the Boost binaries. + +[endsect] +[section Configuring Boost.Build] + +As described in the _reference_, a file called +`user-config.jam` in your home directory is used to +specify the tools and libraries available to the build system. You +may need to create or edit `user-config.jam` to tell Boost.Build +how to invoke Python, `#include` its headers, and link with its +libraries. + +[note If you are using a unix-variant OS and you ran Boost's + `configure` script, it may have generated a + `user-config.jam` for you. [footnote `configure` overwrites the existing + `user-config.jam` in your home directory (if any) after making a backup of + the old version.] If your `configure`\ /\ `make` sequence was successful and + Boost.Python binaries were built, your `user-config.jam` file is probably already + correct.] + +If you have one fairly “standard” python installation for your +platform, you might not need to do anything special to describe it. If +you haven't configured python in `user-config.jam` (and you don't +specify `--without-python` on the Boost.Build command line), +Boost.Build will automatically execute the equivalent of + +`` + import toolset : using ; + using python ; +`` +which automatically looks for Python in the most likely places. +However, that only happens when using the Boost.Python project file +(e.g. when referred to by another project as in the quickstart +method). If instead you are linking against separately-compiled +Boost.Python binaries, you should set up a `user-config.jam` file +with at least the minimal incantation above. + +[endsect] +[section Python Configuration Parameters] + +If you have several versions of Python installed, or Python is +installed in an unusual way, you may want to supply any or all of +the following optional parameters to `using python`. + +* *version* + + the version of Python to use. Should be in Major.Minor + format, for example, `2.3`. Do not include the subminor + version (i.e. *not* `2.5.1`). If you have multiple Python + versions installed, the version will usually be the only + configuration argument required. + +* *cmd-or-prefix* + + preferably, a command that invokes a Python interpreter. + Alternatively, the installation prefix for Python libraries and + header files. Only use the alternative formulation if there is + no appropriate Python executable available. + +* *includes* + + the `#include` paths for Python headers. Normally the correct + path(s) will be automatically deduced from `version` and/or + `cmd-or-prefix`. + +* *libraries* + + the path to Python library binaries. On MacOS/Darwin, + you can also pass the path of the Python framework. Normally the + correct path(s) will be automatically deduced from `version` + and/or `cmd-or-prefix`. + +* *condition* + + if specified, should be a set of Boost.Build + properties that are matched against the build configuration when + Boost.Build selects a Python configuration to use. See examples + below for details. + +* *extension-suffix* + + A string to append to the name of extension + modules before the true filename extension. You almost certainly + don't need to use this. Usually this suffix is only used when + targeting a Windows debug build of Python, and will be set + automatically for you based on the value of the + |python-debugging|_ feature. However, at least one Linux + distribution (Ubuntu Feisty Fawn) has a specially configured + [@https://wiki.ubuntu.com/PyDbgBuilds ] package + that claims to use such a suffix. + +[endsect] +[section Examples] + +Note that in the examples below, case and *especially whitespace* are +significant. + +* If you have both python 2.5 and python 2.4 installed, + `user-config.jam` might contain + + `` + using python : 2.5 ; # Make both versions of Python available + using python : 2.4 ; # To build with python 2.4, add python=2.4 + # to your command line. + `` + The first version configured (2.5) becomes the default. To build + against python 2.4, add `python=2.4` to the `bjam` command line. + +* If you have python installed in an unusual location, you might + supply the path to the interpreter in the `cmd-or-prefix` + parameter: + + `` + using python : : /usr/local/python-2.6-beta/bin/python ; + `` + +* If you have a separate build of Python for use with a particular + toolset, you might supply that toolset in the `condition` + parameter: + + `` + using python ; # use for most toolsets + + # Use with Intel C++ toolset + using python + : # version + : c:\\Devel\\Python-2.5-IntelBuild\\PCBuild\\python # cmd-or-prefix + : # includes + : # libraries + : intel # condition + ; + `` + +* If you have downloaded the Python sources and built both the + normal and the “\ `python debugging`_\ ” builds from source on + Windows, you might see: + + `` + using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python ; + using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python_d + : # includes + : # libs + : on ; + `` +* You can set up your user-config.jam so a bjam built under Windows + can build/test both Windows and Cygwin_ python extensions. Just pass + `cygwin` in the `condition` parameter + for the cygwin python installation: + + `` + # windows installation + using python ; + + # cygwin installation + using python : : c:\\cygwin\\bin\\python2.5 : : : cygwin ; + `` + when you put target-os=cygwin in your build request, it should build + with the cygwin version of python: [#flavor]_ + + `` + bjam target-os=cygwin toolset=gcc + `` + This is supposed to work the other way, too (targeting windows + python with a [@http://cygwin.com Cygwin] bjam) but it seems as though the support in + Boost.Build's toolsets for building that way is broken at the + time of this writing. + +* Note that because of [@http://zigzag.cs.msu.su/boost.build/wiki/AlternativeSelection + the way Boost.Build currently selects target alternatives], you might have be very + explicit in your build requests. For example, given: + + `` + using python : 2.5 ; # a regular windows build + using python : 2.4 : : : : cygwin ; + `` + building with + `` + bjam target-os=cygwin + `` + + will yield an error. Instead, you'll need to write + + `` + bjam target-os=cygwin/python=2.4 + `` + +[endsect] +[endsect] +[section Choosing a Boost.Python Library Binary] + +If—instead of letting Boost.Build construct and link with the right +libraries automatically—you choose to use a pre-built Boost.Python +library, you'll need to think about which one to link with. The +Boost.Python binary comes in both static and dynamic flavors. Take +care to choose the right flavor for your application. [footnote +Information about how to identify the static and dynamic builds of Boost.Python on +[@http://boost.org/getting_started/windows.html#library-naming Windows] / +[@http://boost.org/getting_started/unix-variants.html#library-naming Unix variants]] + +[section The Dynamic Binary] + +The dynamic library is the safest and most-versatile choice: + +* A single copy of the library code is used by all extension + modules built with a given toolset. [footnote Because of the way most \*nix platforms + share symbols among dynamically-loaded objects, I'm not certain + that extension modules built with different compiler toolsets + will always use different copies of the Boost.Python library + when loaded into the same Python instance. Not using different + libraries could be a good thing if the compilers have compatible + ABIs, because extension modules built with the two libraries + would be interoperable. Otherwise, it could spell disaster, + since an extension module and the Boost.Python library would + have different ideas of such things as class layout. I would + appreciate someone doing the experiment to find out what + happens.] + +* The library contains a type conversion registry. Because one + registry is shared among all extension modules, instances of a + class exposed to Python in one dynamically-loaded extension + module can be passed to functions exposed in another such module. + +[endsect] +[section The Static Binary] + +It might be appropriate to use the static Boost.Python library in +any of the following cases: + +* You are extending python and the types exposed in your + dynamically-loaded extension module don't need to be used by any + other Boost.Python extension modules, and you don't care if the + core library code is duplicated among them. + +* You are embedding python in your application and either: + + * You are targeting a Unix variant OS other than MacOS or AIX, + where the dynamically-loaded extension modules can “see” the + Boost.Python library symbols that are part of the executable. + + * Or, you have statically linked some Boost.Python extension + modules into your application and you don't care if any + dynamically-loaded Boost.Python extension modules are able to + use the types exposed by your statically-linked extension + modules (and vice-versa). + +[endsect] +[endsect] +[section `#include` Issues] + +1. If you should ever have occasion to `#include "python.h"` + directly in a translation unit of a program using Boost.Python, + use `#include "boost/python/detail/wrap_python.hpp"` instead. + It handles several issues necessary for use with Boost.Python, + one of which is mentioned in the next section. + +2. Be sure not to `#include` any system headers before + `wrap_python.hpp`. This restriction is actually imposed by + Python, or more properly, by Python's interaction with your + operating system. See + http://docs.python.org/ext/simpleExample.html for details. + +[endsect] +[section Python Debugging Builds] + +Python can be built in a special “python debugging” configuration +that adds extra checks and instrumentation that can be very useful +for developers of extension modules. The data structures used by +the debugging configuration contain additional members, so *a +Python executable built with python debugging enabled cannot be +used with an extension module or library compiled without it, and +vice-versa.* + +Since pre-built “python debugging” versions of the Python +executable and libraries are not supplied with most distributions +of Python, [#get-debug-build]_ and we didn't want to force our users +to build them, Boost.Build does not automatically enable python +debugging in its `debug` build variant (which is the default). +Instead there is a special build property called +`python-debugging` that, when used as a build property, will +define the right preprocessor symbols and select the right +libraries to link with. + +On unix-variant platforms, the debugging versions of Python's data +structures will only be used if the symbol `Py_DEBUG` is defined. +On many windows compilers, when extension modules are built with +the preprocessor symbol `_DEBUG`, Python defaults to force +linking with a special debugging version of the Python DLL. Since +that symbol is very commonly used even when Python is not present, +Boost.Python temporarily undefines _DEBUG when Python.h +is #included from `boost/python/detail/wrap_python.hpp` - unless +`BOOST_DEBUG_PYTHON` is defined. The upshot is that if you want +“python debugging”and you aren't using Boost.Build, you should make +sure `BOOST_DEBUG_PYTHON` is defined, or python debugging will be +suppressed. + +[endsect] +[section Testing Boost.Python] + +To run the full test suite for Boost.Python, invoke `bjam` in the +`test` subdirectory of your Boost.Python distribution. + +[endsect] +[section Notes for MinGW (and Cygwin with -mno-cygwin) GCC Users] + +If you are using a version of Python prior to 2.4.1 with a MinGW +prior to 3.0.0 (with binutils-2.13.90-20030111-1), you will need to +create a MinGW-compatible version of the Python library; the one +shipped with Python will only work with a Microsoft-compatible +linker. Follow the instructions in the “Non-Microsoft” section of +the “Building Extensions: Tips And Tricks” chapter in [@http://www.python.org/doc/current/inst/index.html Installing Python Modules] to create `libpythonXX.a`, where `XX` +corresponds to the major and minor version numbers of your Python +installation. + +[endsect] diff --git a/doc/building.rst b/doc/building.rst deleted file mode 100644 index 1e2c7d42..00000000 --- a/doc/building.rst +++ /dev/null @@ -1,680 +0,0 @@ -.. 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) - -============================================== - |(logo)|__ Boost.Python Build and Test HOWTO -============================================== - -.. |(logo)| image:: ../../../boost.png - :alt: Boost C++ Libraries: - :class: boost-logo - -__ ../index.html - - -.. section-numbering:: - :depth: 2 - -.. contents:: Contents - :depth: 2 - :class: sidebar small - -.. |newer| replace:: *newer* - -Requirements -============ - -Boost.Python requires `Python 2.2`_ [#2.2]_ *or* |newer|__. - -.. _Python 2.2: http://www.python.org/2.2 -__ http://www.python.org - -Background -========== - -There are two basic models for combining C++ and Python: - -- extending_, in which the end-user launches the Python interpreter - executable and imports Python “extension modules” written in C++. - Think of taking a library written in C++ and giving it a Python - interface so Python programmers can use it. From Python, these - modules look just like regular Python modules. - -- embedding_, in which the end-user launches a program written - in C++ that in turn invokes the Python interpreter as a library - subroutine. Think of adding scriptability to an existing - application. - -.. _extending: http://www.python.org/doc/current/ext/intro.html -.. _embedding: http://www.python.org/doc/current/ext/embedding.html - -The key distinction between extending and embedding is the location -of the C++ ``main()`` function: in the Python interpreter executable, -or in some other program, respectively. Note that even when -embedding Python in another program, `extension modules are often -the best way to make C/C++ functionality accessible to Python -code`__, so the use of extension modules is really at the heart of -both models. - -__ http://www.python.org/doc/current/ext/extending-with-embedding.html - -Except in rare cases, extension modules are built as -dynamically-loaded libraries with a single entry point, which means -you can change them without rebuilding either the other extension -modules or the executable containing ``main()``. - -.. _quickstart: - -No-Install Quickstart -===================== - -There is no need to “install Boost” in order to get started using -Boost.Python. These instructions use Boost.Build_ projects, -which will build those binaries as soon as they're needed. Your -first tests may take a little longer while you wait for -Boost.Python to build, but doing things this way will save you from -worrying about build intricacies like which library binaries to use -for a specific compiler configuration and figuring out the right -compiler options to use yourself. - -.. .. raw:: html - -
- -.. Note:: Of course it's possible to use other build systems to - build Boost.Python and its extensions, but they are not - officially supported by Boost. Moreover **99% of all “I can't - build Boost.Python” problems come from trying to use another - build system** without first following these instructions. - - If you want to use another system anyway, we suggest that you - follow these instructions, and then invoke ``bjam`` with the - - .. parsed-literal:: - - ``-a -o``\ *filename* - - options to dump the build commands it executes to a file, so - you can see what your alternate build system needs to do. - -.. .. raw:: html - -
- -.. _Boost.Build: ../../../tools/build/index.html - -Basic Procedure ---------------- - -1. Get Boost; see sections 1 and 2 [`Unix/Linux`__, `Windows`__\ ] of the - Boost `Getting Started Guide`_. - - __ ../../../more/getting_started/unix-variants.html#get-boost - __ ../../../more/getting_started/windows.html#get-boost - -2. Get the ``bjam`` build driver. See section 5 [`Unix/Linux`__, - `Windows`__\ ] of the Boost `Getting Started Guide`_. - - __ ../../../more/getting_started/unix-variants.html#prepare-to-use-a-boost-library-binary - __ ../../../more/getting_started/windows.html#prepare-to-use-a-boost-library-binary - - -3. cd into the ``libs/python/example/quickstart/`` directory of your - Boost installation, which contains a small example project. - -4. Invoke ``bjam``. Replace the “\ ``stage``\ “ argument from the - example invocation from section 5 of the `Getting Started - Guide`_ with “\ ``test``\ ,“ to build all the test targets. Also add - the argument “\ ``--verbose-test``\ ” to see the output generated by - the tests when they are run. - - On Windows, your ``bjam`` invocation might look something like: - - .. parsed-literal:: - - C:\\boost_1_34_0\\…\\quickstart> **bjam toolset=msvc --verbose-test test** - - and on Unix variants, perhaps, - - .. parsed-literal:: - - ~/boost_1_34_0/…/quickstart$ **bjam toolset=gcc --verbose-test test** - -.. Admonition:: Note to Windows Users - - For the sake of concision, the rest of this guide will use - unix-style forward slashes in pathnames instead of the - backslashes with which you may be more familiar. The forward - slashes should work everywhere except in `Command Prompt`_ - windows, where you should use backslashes. - - .. _Command Prompt: ../../../more/getting_started/windows.html#command-prompt - -If you followed this procedure successfully, you will have built an -extension module called ``extending`` and tested it by running a -Python script called ``test_extending.py``. You will also have -built and run a simple application called ``embedding`` that embeds -python. - -.. _Getting Started Guide: ../../../more/getting_started/index.html - -In Case of Trouble ------------------- - -If you're seeing lots of compiler and/or linker error messages, -it's probably because Boost.Build is having trouble finding your -Python installation. You might want to pass the -``--debug-configuration`` option to ``bjam`` the first few times -you invoke it, to make sure that Boost.Build is correctly locating -all the parts of your Python installation. If it isn't, consider -`Configuring Boost.Build`_ as detailed below. - -If you're still having trouble, Someone on one of the following -mailing lists may be able to help: - -* The `Boost.Build mailing list`__ for issues related to Boost.Build -* The Python `C++ Sig`__ for issues specifically related to Boost.Python - -__ http://www.boost.org/more/mailing_lists.htm#jamboost -__ http://www.boost.org/more/mailing_lists.htm#cplussig - -In Case Everything Seemed to Work ---------------------------------- - -Rejoice! If you're new to Boost.Python, at this point it might be -a good idea to ignore build issues for a while and concentrate on -learning the library by going through the tutorial_ and perhaps -some of the `reference documentation`_, trying out what you've -learned about the API by modifying the quickstart project. - -.. _reference documentation: v2/reference.html -.. _tutorial: tutorial/index.html - -Modifying the Example Project ------------------------------ - -If you're content to keep your extension module forever in one -source file called |extending.cpp|_, inside your Boost -distribution, and import it forever as ``extending``, then you can -stop here. However, it's likely that you will want to make a few -changes. There are a few things you can do without having to learn -Boost.Build_ in depth. - -The project you just built is specified in two files in the current -directory: |boost-build.jam|_, which tells ``bjam`` where it can -find the interpreted code of the Boost build system, and -|Jamroot|_, which describes the targets you just built. These -files are heavily commented, so they should be easy to modify. -Take care, however, to preserve whitespace. Punctuation such as -``;`` will not be recognized as intended by ``bjam`` if it is not -surrounded by whitespace. - -.. |boost-build.jam| replace:: ``boost-build.jam`` -.. _boost-build.jam: ../example/quickstart/boost-build.jam - -.. |Jamroot| replace:: ``Jamroot`` -.. _Jamroot: ../example/quickstart/Jamroot - -.. |extending.cpp| replace:: ``extending.cpp`` -.. _extending.cpp: ../example/quickstart/extending.cpp - -Relocate the Project -.................... - -You'll probably want to copy this project elsewhere so you can -change it without modifying your Boost distribution. To do that, -simply - -a. copy the entire ``libs/python/example/quickstart/`` directory - into a new directory. - -b. In the new copies of |boost-build.jam|_ and |Jamroot|_, locate - the relative path near the top of the file that is clearly - marked by a comment, and edit that path so that it refers to the - same directory your Boost distribution as it referred to when - the file was in its original location in the - ``libs/python/example/quickstart/`` directory. - -For example, if you moved the project from -``/home/dave/boost_1_34_0/libs/python/example/quickstart`` to -``/home/dave/my-project``, you could change the first path in -|boost-build.jam|_ from - -.. parsed-literal:: - - **../../../..**\ /tools/build/v2 - -to - -.. parsed-literal:: - - **/home/dave/boost_1_34_0**\ /tools/build/v2 - -and change the first path in |Jamroot|_ from - -.. parsed-literal:: - - **../../../..** - -to - -.. parsed-literal:: - - **/home/dave/boost_1_34_0** - -Add New or Change Names of Existing Source Files -................................................ - -The names of additional source files involved in building your -extension module or embedding application can be listed in -|Jamroot|_ right alongside ``extending.cpp`` or ``embedding.cpp`` -respectively. Just be sure to leave whitespace around each -filename:: - - … file1.cpp file2.cpp file3.cpp … - -Naturally, if you want to change the name of a source file you can -tell Boost.Build about it by editing the name in |Jamroot|_. - -Change the Name of your Extension Module -........................................ - -The name of the extension module is determined by two things: - -1. the name in |Jamroot|_ immediately following ``python-extension``, and -2. the name passed to ``BOOST_PYTHON_MODULE`` in |extending.cpp|_. - -To change the name of the extension module from ``extending`` to -``hello``, you'd edit |Jamroot|_, changing - -.. parsed-literal:: - - python-extension **extending** : extending.cpp ; - -to - -.. parsed-literal:: - - python-extension **hello** : extending.cpp ; - -and you'd edit extending.cpp, changing - -.. parsed-literal:: - - BOOST_PYTHON_MODULE(\ **extending**\ ) - -to - -.. parsed-literal:: - - BOOST_PYTHON_MODULE(\ **hello**\ ) - -Installing Boost.Python on your System -====================================== - -Since Boost.Python is a separately-compiled (as opposed to -`header-only`_) library, its user relies on the services of a -Boost.Python library binary. - -.. _header-only: ../../../more/getting_started/windows.html#header-only-libraries - -If you need a regular installation of the Boost.Python library -binaries on your system, the Boost `Getting Started Guide`_ will -walk you through the steps of creating one. If building binaries -from source, you might want to supply the ``--with-python`` -argument to ``bjam`` (or the ``--with-libraries=python`` argument -to ``configure``), so only the Boost.Python binary will be built, -rather than all the Boost binaries. - - -Configuring Boost.Build -======================= - -As described in the `Boost.Build reference manual`__, a file called -``user-config.jam`` in your home directory [#home-dir]_ is used to -specify the tools and libraries available to the build system. You -may need to create or edit ``user-config.jam`` to tell Boost.Build -how to invoke Python, ``#include`` its headers, and link with its -libraries. - -__ http://www.boost.orgdoc/html/bbv2/advanced.html#bbv2.advanced.configuration - -.. Admonition:: Users of Unix-Variant OSes - - If you are using a unix-variant OS and you ran Boost's - ``configure`` script, it may have generated a - ``user-config.jam`` for you. [#overwrite]_ If your ``configure``\ - /\ ``make`` sequence was successful and Boost.Python binaries - were built, your ``user-config.jam`` file is probably already - correct. - -If you have one fairly “standard” python installation for your -platform, you might not need to do anything special to describe it. If -you haven't configured python in ``user-config.jam`` (and you don't -specify ``--without-python`` on the Boost.Build command line), -Boost.Build will automatically execute the equivalent of :: - - import toolset : using ; - using python ; - -which automatically looks for Python in the most likely places. -However, that only happens when using the Boost.Python project file -(e.g. when referred to by another project as in the quickstart_ -method). If instead you are linking against separately-compiled -Boost.Python binaries, you should set up a ``user-config.jam`` file -with at least the minimal incantation above. - -Python Configuration Parameters -------------------------------- - -If you have several versions of Python installed, or Python is -installed in an unusual way, you may want to supply any or all of -the following optional parameters to ``using python``. - -version - the version of Python to use. Should be in Major.Minor - format, for example, ``2.3``. Do not include the subminor - version (i.e. *not* ``2.5.1``). If you have multiple Python - versions installed, the version will usually be the only - configuration argument required. - -cmd-or-prefix - preferably, a command that invokes a Python interpreter. - Alternatively, the installation prefix for Python libraries and - header files. Only use the alternative formulation if there is - no appropriate Python executable available. - -includes - the ``#include`` paths for Python headers. Normally the correct - path(s) will be automatically deduced from ``version`` and/or - ``cmd-or-prefix``. - -libraries - the path to Python library binaries. On MacOS/Darwin, - you can also pass the path of the Python framework. Normally the - correct path(s) will be automatically deduced from ``version`` - and/or ``cmd-or-prefix``. - -condition - if specified, should be a set of Boost.Build - properties that are matched against the build configuration when - Boost.Build selects a Python configuration to use. See examples - below for details. - -extension-suffix - A string to append to the name of extension - modules before the true filename extension. You almost certainly - don't need to use this. Usually this suffix is only used when - targeting a Windows debug build of Python, and will be set - automatically for you based on the value of the - |python-debugging|_ feature. However, at least one Linux - distribution (Ubuntu Feisty Fawn) has a specially configured - `python-dbg`__ package that claims to use such a suffix. - -.. |python-debugging| replace:: ```` - -__ https://wiki.ubuntu.com/PyDbgBuilds - - -Examples --------- - -Note that in the examples below, case and *especially whitespace* are -significant. - -- If you have both python 2.5 and python 2.4 installed, - ``user-config.jam`` might contain:: - - using python : 2.5 ; # Make both versions of Python available - - using python : 2.4 ; # To build with python 2.4, add python=2.4 - # to your command line. - - The first version configured (2.5) becomes the default. To build - against python 2.4, add ``python=2.4`` to the ``bjam`` command line. - -- If you have python installed in an unusual location, you might - supply the path to the interpreter in the ``cmd-or-prefix`` - parameter:: - - using python : : /usr/local/python-2.6-beta/bin/python ; - -- If you have a separate build of Python for use with a particular - toolset, you might supply that toolset in the ``condition`` - parameter:: - - using python ; # use for most toolsets - - # Use with Intel C++ toolset - using python - : # version - : c:\\Devel\\Python-2.5-IntelBuild\\PCBuild\\python # cmd-or-prefix - : # includes - : # libraries - : intel # condition - ; - - -- If you have downloaded the Python sources and built both the - normal and the “\ `python debugging`_\ ” builds from source on - Windows, you might see:: - - using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python ; - using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python_d - : # includes - : # libs - : on ; - -- You can set up your user-config.jam so a bjam built under Windows - can build/test both Windows and Cygwin_ python extensions. Just pass - ``cygwin`` in the ``condition`` parameter - for the cygwin python installation:: - - # windows installation - using python ; - - # cygwin installation - using python : : c:\\cygwin\\bin\\python2.5 : : : cygwin ; - - when you put target-os=cygwin in your build request, it should build - with the cygwin version of python: [#flavor]_ - - bjam target-os=cygwin toolset=gcc - - This is supposed to work the other way, too (targeting windows - python with a Cygwin_ bjam) but it seems as though the support in - Boost.Build's toolsets for building that way is broken at the - time of this writing. - -- Note that because of `the way Boost.Build currently selects target - alternatives`__, you might have be very explicit in your build - requests. For example, given:: - - using python : 2.5 ; # a regular windows build - using python : 2.4 : : : : cygwin ; - - building with :: - - bjam target-os=cygwin - - will yield an error. Instead, you'll need to write:: - - bjam target-os=cygwin/python=2.4 - -.. _Cygwin: http://cygwin.com - -__ http://zigzag.cs.msu.su/boost.build/wiki/AlternativeSelection - -Choosing a Boost.Python Library Binary -====================================== - -If—instead of letting Boost.Build construct and link with the right -libraries automatically—you choose to use a pre-built Boost.Python -library, you'll need to think about which one to link with. The -Boost.Python binary comes in both static and dynamic flavors. Take -care to choose the right flavor for your application. [#naming]_ - -The Dynamic Binary ------------------- - -The dynamic library is the safest and most-versatile choice: - -- A single copy of the library code is used by all extension - modules built with a given toolset. [#toolset-specific]_ - -- The library contains a type conversion registry. Because one - registry is shared among all extension modules, instances of a - class exposed to Python in one dynamically-loaded extension - module can be passed to functions exposed in another such module. - -The Static Binary ------------------ - -It might be appropriate to use the static Boost.Python library in -any of the following cases: - -- You are extending_ python and the types exposed in your - dynamically-loaded extension module don't need to be used by any - other Boost.Python extension modules, and you don't care if the - core library code is duplicated among them. - -- You are embedding_ python in your application and either: - - - You are targeting a Unix variant OS other than MacOS or AIX, - where the dynamically-loaded extension modules can “see” the - Boost.Python library symbols that are part of the executable. - - - Or, you have statically linked some Boost.Python extension - modules into your application and you don't care if any - dynamically-loaded Boost.Python extension modules are able to - use the types exposed by your statically-linked extension - modules (and vice-versa). - -``#include`` Issues -=================== - -1. If you should ever have occasion to ``#include "python.h"`` - directly in a translation unit of a program using Boost.Python, - use ``#include "boost/python/detail/wrap_python.hpp"`` instead. - It handles several issues necessary for use with Boost.Python, - one of which is mentioned in the next section. - -2. Be sure not to ``#include`` any system headers before - ``wrap_python.hpp``. This restriction is actually imposed by - Python, or more properly, by Python's interaction with your - operating system. See - http://docs.python.org/ext/simpleExample.html for details. - -.. _python-debugging: -.. _python debugging: - -Python Debugging Builds -======================= - -Python can be built in a special “python debugging” configuration -that adds extra checks and instrumentation that can be very useful -for developers of extension modules. The data structures used by -the debugging configuration contain additional members, so **a -Python executable built with python debugging enabled cannot be -used with an extension module or library compiled without it, and -vice-versa.** - -Since pre-built “python debugging” versions of the Python -executable and libraries are not supplied with most distributions -of Python, [#get-debug-build]_ and we didn't want to force our users -to build them, Boost.Build does not automatically enable python -debugging in its ``debug`` build variant (which is the default). -Instead there is a special build property called -``python-debugging`` that, when used as a build property, will -define the right preprocessor symbols and select the right -libraries to link with. - -On unix-variant platforms, the debugging versions of Python's data -structures will only be used if the symbol ``Py_DEBUG`` is defined. -On many windows compilers, when extension modules are built with -the preprocessor symbol ``_DEBUG``, Python defaults to force -linking with a special debugging version of the Python DLL. Since -that symbol is very commonly used even when Python is not present, -Boost.Python temporarily undefines _DEBUG when Python.h -is #included from ``boost/python/detail/wrap_python.hpp`` - unless -``BOOST_DEBUG_PYTHON`` is defined. The upshot is that if you want -“python debugging”and you aren't using Boost.Build, you should make -sure ``BOOST_DEBUG_PYTHON`` is defined, or python debugging will be -suppressed. - -Testing Boost.Python -==================== - -To run the full test suite for Boost.Python, invoke ``bjam`` in the -``libs/python/test`` subdirectory of your Boost distribution. - -Notes for MinGW (and Cygwin with -mno-cygwin) GCC Users -======================================================= - -If you are using a version of Python prior to 2.4.1 with a MinGW -prior to 3.0.0 (with binutils-2.13.90-20030111-1), you will need to -create a MinGW-compatible version of the Python library; the one -shipped with Python will only work with a Microsoft-compatible -linker. Follow the instructions in the “Non-Microsoft” section of -the “Building Extensions: Tips And Tricks” chapter in `Installing -Python Modules`__ to create ``libpythonXX.a``, where ``XX`` -corresponds to the major and minor version numbers of your Python -installation. - -__ http://www.python.org/doc/current/inst/index.html - ------------------------------ - -.. [#2.2] Note that although we tested earlier versions of - Boost.Python with Python 2.2, and we don't *think* we've done - anything to break compatibility, this release of Boost.Python - may not have been tested with versions of Python earlier than - 2.4, so we're not 100% sure that python 2.2 and 2.3 are - supported. - -.. [#naming] Information about how to identify the - static and dynamic builds of Boost.Python: - - * `on Windows`__ - * `on Unix variants`__ - - __ ../../../more/getting_started/windows.html#library-naming - __ ../../../more/getting_started/unix-variants.html#library-naming - -.. [#toolset-specific] Because of the way most \*nix platforms - share symbols among dynamically-loaded objects, I'm not certain - that extension modules built with different compiler toolsets - will always use different copies of the Boost.Python library - when loaded into the same Python instance. Not using different - libraries could be a good thing if the compilers have compatible - ABIs, because extension modules built with the two libraries - would be interoperable. Otherwise, it could spell disaster, - since an extension module and the Boost.Python library would - have different ideas of such things as class layout. I would - appreciate someone doing the experiment to find out what - happens. - -.. [#overwrite] ``configure`` overwrites the existing - ``user-config.jam`` in your home directory - (if any) after making a backup of the old version. - -.. [#flavor] Note that the ``cygwin`` feature is - different from the ``cygwin`` subfeature of the ``gcc`` - toolset, and you might need handle both explicitly if you also - have a MinGW GCC installed. - -.. [#home-dir] Windows users, your home directory can be - found by typing:: - - ECHO %HOMEDRIVE%%HOMEPATH% - - into a `command prompt`_ window. - -.. [#get-debug-build] On Unix and similar platforms, a debugging - python and associated libraries are built by adding - ``--with-pydebug`` when configuring the Python build. On - Windows, the debugging version of Python is generated by - the "Win32 Debug" target of the Visual Studio project in the - PCBuild subdirectory of a full Python source code distribution. diff --git a/doc/configuration.qbk b/doc/configuration.qbk new file mode 100644 index 00000000..518a0b6d --- /dev/null +++ b/doc/configuration.qbk @@ -0,0 +1,83 @@ +[chapter Configuration + [quickbook 1.7] + [authors [Abrahams, David]] + [copyright 2002 - 2015 David Abrahams, Stefan Seefeld] + [id configuration] +] + + +[section Configuration] + +[section Introduction] +*Boost.Python* uses several configuration macros in ``, as well as configuration macros meant to be supplied by the application. These macros are documented here. + +[endsect] +[section Application Defined Macros] + +These are the macros that may be defined by an application using Boost.Python. Note that if you extend a strict interpretation of the C++ standard to cover dynamic libraries, using different values of these macros when compiling different libraries (including extension modules and the Boost.Python library itself) is a violation of the ODR. However, we know of no C++ implementations on which this particular violation is detectable or causes any problems. + +[table + [[Macro][Default][Meaning]] + [[BOOST_PYTHON_MAX_ARITY] + [15] + [The maximum arity of any function, member function, + or constructor to be wrapped, invocation of a + Boost.Python function wich is specified as taking + arguments x1, x2,...Xn. This includes, in particular, + callback mechanisms such as object::operator()(...) or call_method(... ).]] + [[BOOST_PYTHON_MAX_BASES][10] + [The maximum number of template arguments to the + `bases<...>` class template, which is used to specify + the bases of a wrapped C++ class..]] + [[BOOST_PYTHON_STATIC_MODULE] + [ /not defined/ ] + [If defined, prevents your module initialization + function from being treated as an exported symbol + on platforms which support that distinction in-code]] + [[BOOST_PYTHON_ENABLE_CDECL] + [ /not defined/ ] + [If defined, allows functions using the `__cdecl` + calling convention to be wrapped.]] + [[BOOST_PYTHON_ENABLE_STDCALL] + [ /not defined/ ] + [If defined, allows functions using the `__stdcall` + calling convention to be wrapped.]] + [[BOOST_PYTHON_ENABLE_FASTCALL] + [ /not defined/ ] + [If defined, allows functions using the `__fastcall` + calling convention to be wrapped.]] +] +[endsect] +[section Library Defined Defined Macros] + +[table + [[Macro][Default][Meaning]] + [[BOOST_PYTHON_TYPE_ID_NAME][ /not defined/ ] + [If defined, this indicates that the type_info comparison across + shared library boundaries does not work on this platform. + In other words, if shared-lib-1 passes `typeid(T)` to a function + in shared-lib-2 which compares it to `typeid(T)`, that comparison + may return `false`. If this macro is #defined, Boost.Python uses + and compares `typeid(T).name()` instead of using and comparing + the `std::type_info` objects directly.]] + [[BOOST_PYTHON_NO_PY_SIGNATURES][ /not defined/ ] + [If defined for a module no pythonic signatures are generated for + the docstrings of the module functions, and no python type is + associated with any of the converters registered by the module. + This also reduces the binary size of the module by about 14% + (gcc compiled). + If defined for the boost_python runtime library, the default for + the `docstring_options.enable_py_signatures()` is set to `false`.]] + [[BOOST_PYTHON_SUPPORTS_PY_SIGNATURES] + [ /defined/ if `BOOST_PYTHON_NO_PY_SIGNATURES` is /undefined/ ] + [This macro is defined to enable a smooth transition from older + Boost.Python versions which do not support pythonic signatures. + For example usage see here.]] + [[BOOST_PYTHON_PY_SIGNATURES_PROPER_INIT_SELF_TYPE][ /not defined/ ] + [If defined the python type of `__init__` method "self" parameters + is properly generated, otherwise object is used. It is undefined by + default because it increases the binary size of the module by about + 14% (gcc compiled).]] +] +[endsect] +[endsect] diff --git a/doc/faq.qbk b/doc/faq.qbk new file mode 100644 index 00000000..a5d4f8a8 --- /dev/null +++ b/doc/faq.qbk @@ -0,0 +1,737 @@ +[chapter FAQ + [quickbook 1.7] + [id faq] +] + +[section How can I wrap a function which takes a function pointer as an argument?] + +If what you're trying to do is something like this: +`` + typedef boost::function funcptr; + + void foo(funcptr fp) + { + fp("hello,world!"); + } + + BOOST_PYTHON_MODULE(test) + { + def("foo",foo); + } +`` + +And then: + +`` +>>> def hello(s): +... print s +... +>>> foo(hello) +hello, world! +`` +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 `foo`. In other words, this could work if the C++ +function is always going to invoke the /same/ Python +function, but you probably don't want that. + +If you have the luxury of changing the C++ code you're +wrapping, pass it an `object` instead and call that; +the overloaded function call operator will invoke the Python +function you pass it behind the `object`. + +[endsect] +[section I'm getting the "attempt to return dangling reference" error. + What am I doing wrong?] + +That exception is protecting you from causing a nasty crash. It usually +happens in response to some code like this: +`` + period const &get_floating_frequency() const + { + return boost::python::call_method( + m_self,"get_floating_frequency"); + } +`` +And you get: +`` + ReferenceError: Attempt to return dangling reference to object of type: + class period +`` + +In this case, the Python method invoked by `call_method` +constructs a new Python object. You're trying to return a reference to a +C++ object (an instance of `class period`) 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 +`get_floating_frequency()` above. When the function returns, +the Python object will be destroyed, destroying the instance of +`class period`, 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. + +[endsect] +[section Is return_internal_reference efficient?] + +[*Q:] /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?/ + +[*A:] `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. + +[endsect] +[section How can I wrap functions which take C++ containers as arguments?] + +Ralf W. Grosse-Kunstleve provides these notes: + +# Using the regular `class_<>` wrapper: + `` + class_ >("std_vector_double") + .def(...) + ... + ; + `` + 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 `scitbx/include/scitbx/array_family/boost_python/flex_wrapper.h` + in the "scitbx" package. The file could easily be modified for + wrapping `std::vector<>` instantiations. + This type of C++/Python binding is most suitable for containers + that may contain a large number of elements (>10000). + +# Using custom rvalue converters. Boost.Python "rvalue converters" + match function signatures such as: + `` + void foo(std::vector const &array); // pass by const-reference + void foo(std::vector array); // pass by value + `` + Some custom rvalue converters are implemented in the file + `scitbx/include/scitbx/boost_python/container_conversions.h` + 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 + `scitbx/array_family/boost_python/regression_test_module.cpp` + 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. + +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] + +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: + +C++: +`` + void foo(std::vector &array) + { + for(std::size_t i=0;i<array.size();i++) { + array[i] *= 2; + } + } +`` +Python: +`` + >>> l = [1, 2, 3] + >>> foo(l) + >>> print l + [2, 4, 6] +`` +Custom lvalue converters require changes to the Boost.Python core library +and are currently not available. + +P.S.: + +The "scitbx" files referenced above are available via anonymous +CVS: +`` + cvs -d:pserver:anonymous@cvs.cctbx.sourceforge.net:/cvsroot/cctbx login + cvs -d:pserver:anonymous@cvs.cctbx.sourceforge.net:/cvsroot/cctbx co scitbx +`` + +[endsect] +[section fatal error C1204:Compiler limit:internal structure overflow] + +[*Q:] /I get this error message when compiling a large source file. What can I do?/ + +[*A:] You have two choices: + +# Upgrade your compiler (preferred) + +# Break your source file up into multiple translation units. + + `my_module.cpp`: + + `` + ... + void more_of_my_module(); + BOOST_PYTHON_MODULE(my_module) + { + def("foo", foo); + def("bar", bar); + ... + more_of_my_module(); + } + `` + `more_of_my_module.cpp`: + `` + void more_of_my_module() + { + def("baz", baz); + ... + } + `` + If you find that a [link reference.class-spec class_]<...> declaration + can't fit in a single source file without triggering the error, you + can always pass a reference to the `class_` object to a + function in another source file, and call some of its member + functions (e.g. `.def(...)`) in the auxilliary source + file: + + `more_of_my_class.cpp`: + `` + void more_of_my_class(class<my_class>& x) + { + x + .def("baz", baz) + .add_property("xx", &my_class::get_xx, &my_class::set_xx) + ; + ... + } + `` + +[endsect] +[section How do I debug my Python extensions?] + +Greg Burley gives the following answer for Unix GCC users: + +[: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 ;-). + + 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. + + `` + (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 + `` +] + +Greg's approach works even better using Emacs' "gdb" +command, since it will show you each line of source as you step through it. + +On *Windows*, 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. + +Raoul Gough has provided the following for gdb on Windows: + +[: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. + + 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: + + `` + $ 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) + `` +] + +[h2 Debugging extensions through Boost.Build] + +If you are launching your extension module tests with _bb_ using the +`boost-python-runtest` rule, you can ask it to launch your +debugger for you by adding "--debugger=/debugger/" to your bjam +command-line: +`` + bjam -sTOOLS=vc7.1 "--debugger=devenv /debugexe" test + bjam -sTOOLS=gcc -sPYTHON_LAUNCH=gdb test +`` +It can also be extremely useful to add the `-d+2` 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. + +[endsect] +[section Why doesn't my `*=` operator work?] + +[*Q:] ['I have exported my class to python, with many overloaded +operators. it works fine for me except the `*=` +operator. It always tells me "can't multiply sequence with non int +type". If I use `p1.__imul__(p2)` instead of +`p1 *= p2`, it successfully executes my code. What's +wrong with me?] + +[*A:] 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). +`` +>>> class X(object): +... def __imul__(self, x): +... print 'imul' +... +>>> x = X() +>>> x *= 1 +`` +To cure this problem, all you need to do is upgrade your Python to +version 2.2.1 or later. + +[endsect] +[section Does Boost.Python work with Mac OS X?] + +It is known to work under 10.2.8 and 10.3 using +Apple's gcc 3.3 compiler: +``gcc (GCC) 3.3 20030304 (Apple Computer, Inc. build 1493)`` +Under 10.2.8 get the August 2003 gcc update (free at [@http://connect.apple.com]). +Under 10.3 get the Xcode Tools v1.0 (also free). + +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: +``./configure --enable-framework +make +make frameworkinstall`` + +The last command requires root privileges because the target +directory is `/Library/Frameworks/Python.framework/Versions/2.3`. +However, the installation does not interfere with the Python +version that ships with 10.2.8. + +It is also crucial to increase the `stacksize` before +starting compilations, e.g.: +``limit stacksize 8192k`` +If the `stacksize` is too small the build might crash with +internal compiler errors. + +Sometimes Apple's compiler exhibits a bug by printing an error +like the following while compiling a +`boost::python::class_` +template instantiation: +`` + .../inheritance.hpp:44: error: cannot + dynamic_cast `p' (of type `struct cctbx::boost_python::::add_pair* + ') to type `void*' (source type is not polymorphic) +`` + +We do not know a general workaround, but if the definition of +`your_type` can be modified the following was found +to work in all cases encountered so far: +`` + 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. + }; +`` +[endsect] +[section How can I find the existing PyObject that holds a C++ object?] + +[: "I am wrapping a function that always returns a pointer to an + already-held C++ object."] + +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: +`` + 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(f()); + assert(xw != 0); + return handle<>(borrowed(xw->self)); + } + + ... + + def("f", f_wrap()); + class_("X", init()) + ... + ; +`` + +Of course, if X has no virtual functions you'll have to use +`static_cast` instead of `dynamic_cast` with no +runtime check that it's valid. This approach also only works if the +`X` object was constructed from Python, because +`X`\ s constructed from C++ are of course never +`X_wrap` objects. + +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 `shared_ptr` is +converted from Python, the shared_ptr actually manages a reference to the +containing Python object. When a shared_ptr 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 `object(p)` 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. + +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. + +[endsect] +[section How can I wrap a function which needs to take ownership of a raw pointer?] + +[*Q:] Part of an API that I'm wrapping goes something like this: + +`` + struct A {}; struct B { void add( A* ); } + where B::add() takes ownership of the pointer passed to it. +`` + +However: + +`` + a = mod.A() + b = mod.B() + b.add( a ) + del a + del b + # python interpreter crashes + # later due to memory corruption. +`` + +Even binding the lifetime of a 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? + +--Bruce Lowery + +Yes: Make sure the C++ object is held by auto_ptr: +`` + class_ >("A") + ... + ; +`` +Then make a thin wrapper function which takes an auto_ptr parameter: +`` + void b_insert(B &b, std::auto_ptr a) + { + b.insert(a.get()); + a.release(); + } +`` +Wrap that as B.add. Note that pointers returned via [link reference.manage_new_object manage_new_object] +will also be held by `auto_ptr`, so this transfer-of-ownership +will also work correctly. + +[endsect] +[section Compilation takes too much time and eats too much memory! + What can I do to make it faster?] + +Please refer to the [link tutorial.python.reducing_compiling_time Reducing Compiling Time] section in the tutorial. + +[endsect] +[section How do I create sub-packages using Boost.Python?] + +Please refer to the [link tutorial.python.creating_packages Creating Packages] section in the tutorial. + +[endsect] +[section error C2064: term does not evaluate to a function taking 2 arguments] + +/Niall Douglas provides these notes:/ + +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: +`` + boost\boost\python\detail\invoke.hpp(76): + error C2064: term does not evaluate to a function taking 2 arguments" +`` +This message is triggered by code like the following: +`` + #include + + using namespace boost::python; + + class FXThread + { + public: + bool setAutoDelete(bool doso) throw(); + }; + + void Export_FXThread() + { + class_< FXThread >("FXThread") + .def("setAutoDelete", &FXThread::setAutoDelete) + ; + } +`` +The bug is related to the `throw()` modifier. +As a workaround cast off the modifier. E.g.: +`` + .def("setAutoDelete", (bool (FXThread::*)(bool)) &FXThread::setAutoDelete) +`` +(The bug has been reported to Microsoft.) + +[endsect] +[section How can I automatically convert my custom string type to and from a Python string?] + +/Ralf W. Grosse-Kunstleve provides these notes:/ + +Below is a small, self-contained demo extension module that shows +how to do this. Here is the corresponding trivial test: +`` + import custom_string + assert custom_string.hello() == "Hello world." + assert custom_string.size("california") == 10 +`` +If you look at the code you will find: + +* A custom `to_python` converter (easy): + `custom_string_to_python_str` + +*A custom lvalue converter (needs more code): + `custom_string_from_python_str` + +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. + +`` + #include + #include + #include + + 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()); + } + + 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*) + 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:: + + BOOST_PYTHON_MODULE(custom_string) + { + sandbox::init_module(); + } +`` +[endsect] +[section Why is my automatic to-python conversion not being found?] + +/Niall Douglas provides these notes:/ + +If you define custom converters similar to the ones +shown above the `def_readonly()` and `def_readwrite()` +member functions provided by `boost::python::class_` for +direct access to your member data will not work as expected. +This is because `def_readonly("bar",&foo::bar)` is +equivalent to: + +`` + .add_property("bar", make_getter(&foo::bar, return_internal_reference())) +`` +Similarly, `def_readwrite("bar",&foo::bar)` is +equivalent to: + +`` + .add_property("bar", make_getter(&foo::bar, return_internal_reference()), + make_setter(&foo::bar, return_internal_reference()) +`` +In order to define return value policies compatible with the +custom conversions replace `def_readonly()` and +`def_readwrite()` by `add_property()`. E.g.: + +`` + .add_property("bar", make_getter(&foo::bar, return_value_policy()), + make_setter(&foo::bar, return_value_policy())) +`` + +[endsect] +[section Is Boost.Python thread-aware/compatible with multiple interpreters?] + +/Niall Douglas provides these notes:/ + +The quick answer to this is: no. + +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 +`boost/python/detail/invoke.hpp` with custom unlock/lock +wrapping of every time Boost.Python enters your code. You must +furthermore take care to /not/ unlock/lock when Boost.Python +is invoking iterator changes via `invoke.hpp`. + +There is a patched `invoke.hpp` 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 [@http://sourceforge.net/projects/tnfox/ this] +SourceForge project location. + +[endsect] \ No newline at end of file diff --git a/doc/glossary.qbk b/doc/glossary.qbk new file mode 100644 index 00000000..bf39fd89 --- /dev/null +++ b/doc/glossary.qbk @@ -0,0 +1,37 @@ +[chapter Glossary + [id glossary] +] + +[variablelist +[[arity] + [The number of argumnts accepted by a function or member function. + Unless otherwise specified, the hidden `this` argument to member + functions is not counted when specifying arity.]] +[[ntbs] + [Null-Terminated Byte String, or 'C'-string. C++ string literals are *ntbs*\ es. + An *ntbs* must never be null.]] +[[raise] + [Exceptions in Python are "raised", not "thrown", as they are in C++. + When this documentation says that some Python exception is "raised" in + the context of C++ code, it means that the corresponding Python exception + is set via the [@http://www.python.org/doc/current/api/exceptionHandling.html Python/'C' API], + and [link reference.errors.throw_error_already_set throw_error_already_set()] is called.]] +[[POD] + [A technical term from the C++ standard. Short for "Plain Ol'Data": + A POD-struct is an aggregate class that has no non-static data members + of type pointer to member, non-POD-struct, non-POD-union (or array of such + types) or reference, and has no user-defined copy assign- ment operator and + no user-defined destructor. Similarly, a POD-union is an aggregate union that + has no non-static data members of type pointer to member, non-POD-struct, + non-POD-union (or array of such types) or reference, and has no + user-defined copy assignment operator and no user-defined destructor. A + POD class is a class that is either a POD-struct or a POD-union. An + aggregate is an array or a class (clause 9) with no user-declared + constructors (12.1), no private or protected non-static data members + (clause 11), no base classes (clause 10), and no virtual functions + (10.3).]] +[[ODR] + [The "One Definition Rule", which says that any entity in a C++ program must have + the same definition in all translation units (object files) which make up a program.]] +] + diff --git a/doc/html/boost.css b/doc/html/boost.css new file mode 100644 index 00000000..986c4050 --- /dev/null +++ b/doc/html/boost.css @@ -0,0 +1,66 @@ +/*============================================================================= + Copyright 2002 William E. Kempf + Distributed under the Boost Software License, Version 1.0. (See accompany- + ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +H1 +{ + FONT-SIZE: 200%; + COLOR: #00008B; +} +H2 +{ + FONT-SIZE: 150%; +} +H3 +{ + FONT-SIZE: 125%; +} +H4 +{ + FONT-SIZE: 108%; +} +BODY +{ + FONT-SIZE: 100%; + BACKGROUND-COLOR: #ffffff; + COLOR: #000000; +} +PRE +{ + MARGIN-LEFT: 2em; + FONT-FAMILY: Courier, + monospace; +} +CODE +{ + FONT-FAMILY: Courier, + monospace; +} +CODE.as_pre +{ + white-space: pre; +} +.index +{ + TEXT-ALIGN: left; +} +.page-index +{ + TEXT-ALIGN: left; +} +.definition +{ + TEXT-ALIGN: left; +} +.footnote +{ + FONT-SIZE: 66%; + VERTICAL-ALIGN: super; + TEXT-DECORATION: none; +} +.function-semantics +{ + CLEAR: left; +} \ No newline at end of file diff --git a/doc/html/boostbook.css b/doc/html/boostbook.css new file mode 100644 index 00000000..d42b3c02 --- /dev/null +++ b/doc/html/boostbook.css @@ -0,0 +1,700 @@ + +/*============================================================================= +Copyright (c) 2004 Joel de Guzman +http://spirit.sourceforge.net/ + +Copyright 2013 Niall Douglas additions for colors and alignment. +Copyright 2013 Paul A. Bristow additions for more colors and alignments. + +Distributed under the Boost Software License, Version 1.0. (See accompany- +ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +/*============================================================================= +Body defaults +=============================================================================*/ + + body + { + margin: 1em; + font-family: sans-serif; + } + +/*============================================================================= +Paragraphs +=============================================================================*/ + + p + { + text-align: left; + font-size: 10pt; + line-height: 1.15; + } + +/*============================================================================= +Program listings +=============================================================================*/ + + /* Code on paragraphs */ + p tt.computeroutput + { + font-size: 9pt; + } + + pre.synopsis + { + font-size: 9pt; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + .programlisting, + .screen + { + font-size: 9pt; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + /* Program listings in tables don't get borders */ + td .programlisting, + td .screen + { + margin: 0pc 0pc 0pc 0pc; + padding: 0pc 0pc 0pc 0pc; + } + +/*============================================================================= +Headings +=============================================================================*/ + + h1, h2, h3, h4, h5, h6 + { + text-align: left; + margin: 1em 0em 0.5em 0em; + font-weight: bold; + } + + h1 { font-size: 140%; } + h2 { font-weight: bold; font-size: 140%; } + h3 { font-weight: bold; font-size: 130%; } + h4 { font-weight: bold; font-size: 120%; } + h5 { font-weight: normal; font-style: italic; font-size: 110%; } + h6 { font-weight: normal; font-style: italic; font-size: 100%; } + + /* Top page titles */ + title, + h1.title, + h2.title + h3.title, + h4.title, + h5.title, + h6.title, + .refentrytitle + { + font-weight: bold; + margin-bottom: 1pc; + } + + h1.title { font-size: 140% } + h2.title { font-size: 140% } + h3.title { font-size: 130% } + h4.title { font-size: 120% } + h5.title { font-size: 110% } + h6.title { font-size: 100% } + + .section h1 + { + margin: 0em 0em 0.5em 0em; + font-size: 140%; + } + + .section h2 { font-size: 140% } + .section h3 { font-size: 130% } + .section h4 { font-size: 120% } + .section h5 { font-size: 110% } + .section h6 { font-size: 100% } + + /* Code on titles */ + h1 tt.computeroutput { font-size: 140% } + h2 tt.computeroutput { font-size: 140% } + h3 tt.computeroutput { font-size: 130% } + h4 tt.computeroutput { font-size: 130% } + h5 tt.computeroutput { font-size: 130% } + h6 tt.computeroutput { font-size: 130% } + + +/*============================================================================= +Author +=============================================================================*/ + + h3.author + { + font-size: 100% + } + +/*============================================================================= +Lists +=============================================================================*/ + + li + { + font-size: 10pt; + line-height: 1.3; + } + + /* Unordered lists */ + ul + { + text-align: left; + } + + /* Ordered lists */ + ol + { + text-align: left; + } + +/*============================================================================= +Links +=============================================================================*/ + + a + { + text-decoration: none; /* no underline */ + } + + a:hover + { + text-decoration: underline; + } + +/*============================================================================= +Spirit style navigation +=============================================================================*/ + + .spirit-nav + { + text-align: right; + } + + .spirit-nav a + { + color: white; + padding-left: 0.5em; + } + + .spirit-nav img + { + border-width: 0px; + } + +/*============================================================================= +Copyright footer +=============================================================================*/ + .copyright-footer + { + text-align: right; + font-size: 70%; + } + + .copyright-footer p + { + text-align: right; + font-size: 80%; + } + +/*============================================================================= +Table of contents +=============================================================================*/ + + div.toc + { + margin: 1pc 4% 0pc 4%; + padding: 0.1pc 1pc 0.1pc 1pc; + font-size: 80%; + line-height: 1.15; + } + + .boost-toc + { + float: right; + padding: 0.5pc; + } + + /* Code on toc */ + .toc .computeroutput { font-size: 120% } + + /* No margin on nested menus */ + + .toc dl dl { margin: 0; } + +/*============================================================================= +Tables +=============================================================================*/ + + .table-title, + div.table p.title + { + margin-left: 4%; + padding-right: 0.5em; + padding-left: 0.5em; + } + + .informaltable table, + .table table + { + width: 92%; + margin-left: 4%; + margin-right: 4%; + } + + div.informaltable table, + div.table table + { + padding: 4px; + } + + /* Table Cells */ + div.informaltable table tr td, + div.table table tr td + { + padding: 0.5em; + text-align: left; + font-size: 9pt; + } + + div.informaltable table tr th, + div.table table tr th + { + padding: 0.5em 0.5em 0.5em 0.5em; + border: 1pt solid white; + font-size: 80%; + } + + table.simplelist + { + width: auto !important; + margin: 0em !important; + padding: 0em !important; + border: none !important; + } + table.simplelist td + { + margin: 0em !important; + padding: 0em !important; + text-align: left !important; + font-size: 9pt !important; + border: none !important; + } + +/*============================================================================= +Blurbs +=============================================================================*/ + + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + font-size: 9pt; /* A little bit smaller than the main text */ + line-height: 1.2; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + p.blurb img + { + padding: 1pt; + } + +/*============================================================================= +Variable Lists +=============================================================================*/ + + div.variablelist + { + margin: 1em 0; + } + + /* Make the terms in definition lists bold */ + div.variablelist dl dt, + span.term + { + font-weight: bold; + font-size: 10pt; + } + + div.variablelist table tbody tr td + { + text-align: left; + vertical-align: top; + padding: 0em 2em 0em 0em; + font-size: 10pt; + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + + div.variablelist dl dt + { + margin-bottom: 0.2em; + } + + div.variablelist dl dd + { + margin: 0em 0em 0.5em 2em; + font-size: 10pt; + } + + div.variablelist table tbody tr td p, + div.variablelist dl dd p + { + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + +/*============================================================================= +Misc +=============================================================================*/ + + /* Title of books and articles in bibliographies */ + span.title + { + font-style: italic; + } + + span.underline + { + text-decoration: underline; + } + + span.strikethrough + { + text-decoration: line-through; + } + + /* Copyright, Legal Notice */ + div div.legalnotice p + { + text-align: left + } + +/*============================================================================= +Colors +=============================================================================*/ + + @media screen + { + body { + background-color: #FFFFFF; + color: #000000; + } + + /* Syntax Highlighting */ + .keyword { color: #0000AA; } + .identifier { color: #000000; } + .special { color: #707070; } + .preprocessor { color: #402080; } + .char { color: teal; } + .comment { color: #800000; } + .string { color: teal; } + .number { color: teal; } + .white_bkd { background-color: #FFFFFF; } + .dk_grey_bkd { background-color: #999999; } + + /* Links */ + a, a .keyword, a .identifier, a .special, a .preprocessor + a .char, a .comment, a .string, a .number + { + color: #005a9c; + } + + a:visited, a:visited .keyword, a:visited .identifier, + a:visited .special, a:visited .preprocessor a:visited .char, + a:visited .comment, a:visited .string, a:visited .number + { + color: #9c5a9c; + } + + h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, + h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, + h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited + { + text-decoration: none; /* no underline */ + color: #000000; + } + + /* Copyright, Legal Notice */ + .copyright + { + color: #666666; + font-size: small; + } + + div div.legalnotice p + { + color: #666666; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid #DCDCDC; + } + + .programlisting, + .screen + { + border: 1px solid #DCDCDC; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Blurbs */ + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + border: 1px solid #DCDCDC; + } + + /* Table of contents */ + div.toc + { + border: 1px solid #DCDCDC; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid #DCDCDC; + } + + div.informaltable table tr th, + div.table table tr th + { + background-color: #F0F0F0; + border: 1px solid #DCDCDC; + } + + .copyright-footer + { + color: #8F8F8F; + } + + /* Misc */ + span.highlight + { + color: #00A000; + } + } + + @media print + { + /* Links */ + a + { + color: black; + } + + a:visited + { + color: black; + } + + .spirit-nav + { + display: none; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid gray; + } + + .programlisting, + .screen + { + border: 1px solid gray; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Table of contents */ + div.toc + { + border: 1px solid gray; + } + + .informaltable table, + .table table + { + border: 1px solid gray; + border-collapse: collapse; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid gray; + } + + div.informaltable table tr th, + div.table table tr th + { + border: 1px solid gray; + } + + table.simplelist tr td + { + border: none !important; + } + + /* Misc */ + span.highlight + { + font-weight: bold; + } + } + +/*============================================================================= +Images +=============================================================================*/ + + span.inlinemediaobject img + { + vertical-align: middle; + } + +/*============================================================================== +Super and Subscript: style so that line spacing isn't effected, see +http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=1&postId=5341 +==============================================================================*/ + +sup, +sub { +height: 0; +line-height: 1; +vertical-align: baseline; +position: relative; + +} + +/* For internet explorer: */ + +* html sup, +* html sub { +vertical-align: bottom; +} + +sup { +bottom: 1ex; +} + +sub { +top: .5ex; +} + +/*============================================================================== +Indexes: pretty much the same as the TOC. +==============================================================================*/ + + .index + { + font-size: 80%; + padding-top: 0px; + padding-bottom: 0px; + margin-top: 0px; + margin-bottom: 0px; + margin-left: 0px; + } + + .index ul + { + padding-left: 3em; + } + + .index p + { + padding: 2px; + margin: 2px; + } + + .index-entry-level-0 + { + font-weight: bold; + } + + .index em + { + font-weight: bold; + } + + +/*============================================================================== +Alignment and coloring use 'role' feature, available from Quickbook 1.6 up. +Added from Niall Douglas for role color and alignment. +http://article.gmane.org/gmane.comp.lib.boost.devel/243318 +*/ + +/* Add text alignment (see http://www.w3schools.com/cssref/pr_text_text-align.asp) */ +span.aligncenter +{ + display: inline-block; width: 100%; text-align: center; +} +span.alignright +{ + display: inline-block; width: 100%; text-align: right; +} +/* alignleft is the default. */ +span.alignleft +{ + display: inline-block; width: 100%; text-align: left; +} + +/* alignjustify stretches the word spacing so that each line has equal width +within a chosen fraction of page width (here arbitrarily 20%). +*Not* useful inside table items as the column width remains the total string width. +Nor very useful, except to temporarily restrict the width. +*/ +span.alignjustify +{ + display: inline-block; width: 20%; text-align: justify; +} + +/* Text colors. +Names at http://www.w3.org/TR/2002/WD-css3-color-20020219/ 4.3. X11 color keywords. +Quickbook Usage: [role red Some red text] + +*/ +span.red { inline-block; color: red; } +span.green { color: green; } +span.lime { color: #00FF00; } +span.blue { color: blue; } +span.navy { color: navy; } +span.yellow { color: yellow; } +span.magenta { color: magenta; } +span.indigo { color: #4B0082; } +span.cyan { color: cyan; } +span.purple { color: purple; } +span.gold { color: gold; } +span.silver { color: silver; } /* lighter gray */ +span.gray { color: #808080; } /* light gray */ diff --git a/doc/html/images/alert.png b/doc/html/images/alert.png new file mode 100644 index 0000000000000000000000000000000000000000..b4645bc7e7cd81f2818bf22aa898e95f89f7b154 GIT binary patch literal 603 zcmeAS@N?(olHy`uVBq!ia0y~yV31^BU=ZVAW?*1oN<7}ez`(#Bl2vQw%VQUVy#($c(b7<_!Z&&*`7 zwYIFTuIA!kP?6(!`t<3^g$y0J3{Q73WQH(YSjJ#(AQj-}VXe>LZ_gkv$q?hiVP&Xj ztS4or%^)MjpsB?1|Nnp9pi5p13=F0vL4Lvi$p8#BTQ7jZgtNdSvY3H^>jMZgI;}C8 z!N9FSxfgB=H7N+NC77H_+N#nawR{=RqTMBX)(LXL|IjinhDSdCyWWZ3S$0kBOZbahGm>{cU3L4X z*xaKNrl+L*2&>`tT{GF}sK6TCoSy58@94C>csZ@3se0z)OD!J`ePg?KNk!eRu!nuZ zwIuy5g5`UyU*2!`JMiPV^UIVvmW1t{f1*^~1#9h_jDIZO*R6JmbN8&QBXd?)zY=(& z`HG+Mis#k2-hNM1nwI_8efYU@yAuCZhY42|Be;Juo!svFUA16}A_D^hgQu&X%Q~lo FCIA+53ZVc1 literal 0 HcmV?d00001 diff --git a/doc/html/images/blank.png b/doc/html/images/blank.png new file mode 100644 index 0000000000000000000000000000000000000000..764bf4f0c3bb4a09960b04b6fa9c9024bca703bc GIT binary patch literal 374 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 literal 0 HcmV?d00001 diff --git a/doc/html/images/callouts/1.png b/doc/html/images/callouts/1.png new file mode 100644 index 0000000000000000000000000000000000000000..6003ad3af44ecde89a963d5af6a4180217319dfb GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`*F|>EaktF{gKeVcsDJ z0oVU;*6~a;Smx2ZrsEQ?ZxM&ygvBnFE?nmtg94rky>!~x8m)3j$<^(USQPg)>&zq; zMi;kRX=V2=&tIr>`d!)XyUpL@9=UmHetuZ+!_#HmOU>-J$pS3-bN!ardIyAF-G1#? z>&)f7E`k#|4sWoP;JM|(l6I_WZ`%~1y>agujE%b%?TB9+mb}(fsxyPFgQGMy*=%;A z(aZyu>`GQPiY$*T-1gu1pAwY3_N%b5cB#xoiRPn8jf*q{Trb|_a%sui&dtzin6_r? zu}%d~p(mAmOGTO#c2u;xJ(}Y^?ex>t7XL(?7U+1p1hOa|ab;w%c)sCoo@_(^WX<=s zr#89B91nl^w~jx#=XQ?S<*?OXYm`>JmO9g8;`^U+STt2<{M7jt yFTo&UT%Db3I{*CoWB+`guig6oxB + + + +]> + + + + + + + + diff --git a/doc/html/images/callouts/10.png b/doc/html/images/callouts/10.png new file mode 100644 index 0000000000000000000000000000000000000000..0426f516a497db7f9a989ae412c381123c882a59 GIT binary patch literal 485 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`(f1)5S5QVovKM!_~JE zMB47_a|Rw%VTn}{6Ibo_{>?on>HF_suX>mE-_|+p)}_VbyG%XWRxDs!Bbdb`rSkCf z_opQpQ)e&z9?Q3;X^2drllMU70&71c8CwuJm{abIp zeHPuYNTZJ3@x#oHxOW1*hRe1@t$mhYkYRMp!NudU$f{L`HtEbcpPpkT-Q%WwW82?% zC04fVjt$l>J1E5m&cv;Mo-ym249h`b!OT;yI|^kU z7g#)~+Iz@=rzNo?Z+rL2lqSFB&0ni{FPmfwyfr;gD5K)Z38R1FYejhuGSfQP|hTIvQJ?m5M8zE|_KJ2Ny0Fm1o>%kU%6J0MhalaBNL z`|XP~Ht29?&a!*3EqAew_mM&!z3HdD7hn7l!t9~x=u!|XzH8m#&o*bC7c(?GuT1E< zIxY74U)KBI?en(Zj`8vg@_IC9@{~!dRw-$!in=2h%i uo%h^T#Pz@K#3`Fjeg5 + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/11.png b/doc/html/images/callouts/11.png new file mode 100644 index 0000000000000000000000000000000000000000..821afc4fa84787cc97485b71e9f2078f45c93dca GIT binary patch literal 410 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`&U3>EaktF{gFX#;)5A z0&V{%irr-ME}D3(<3UjG?A^;f=DTxNc8JvRJ?~omN$9208L_ft0gE{24F|>2&Q_(X zyZRk}S@Y!IJLwtuX$cuSW9kad-E9>}+B4ar@B8JKU&IA}ZdvzvdHazWz|5Z1g ze)`Eh`){a=Ty&?>q6`CxFY1#$=XWS5S;+8pJeF8|am8VmFNNE0pWSjTLp3m4UCF?B z)v7}^cJ1H)wSBfZUSXp*CCGT~*L1 z!O^woK;8cKATG~IcM5iAPD}l8PyF`VZ_(}ou7b0cInG+vv8ev~-ZX{}_a4{SRWsNx zp57$DG;5jTyyy8w3^D7&C6fPqtf+bOwJP3 + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/12.png b/doc/html/images/callouts/12.png new file mode 100644 index 0000000000000000000000000000000000000000..7cec72720fa9bb6f49fc4b405f7e36f20abe7fbd GIT binary patch literal 488 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`(fP)5S5QVovKM+tara zMB3h~S9S>cC`GVy&NA$7e!FZ3*ZX_(gMKMn{jgqg*t>n5-mVwdc+LxmI|e9UlrZu5 zQ({_ROHtjRNV$1z%lk=bT+YJ`-QVnLY|jT_oBf)`qRPnx(gN%Xx|4tEMdaVwoi3 z8lgAcLau*<4)^ratatOor+TqI{wNVS?clathJwW!uZ)j$%&5q+Ew{P&-MZ_q|3(_ifRH$!b{%@XfPPgvO) wR!x~yId8sr_tEzopr0G&e8k^lez literal 0 HcmV?d00001 diff --git a/doc/html/images/callouts/12.svg b/doc/html/images/callouts/12.svg new file mode 100644 index 00000000..9794044c --- /dev/null +++ b/doc/html/images/callouts/12.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/13.png b/doc/html/images/callouts/13.png new file mode 100644 index 0000000000000000000000000000000000000000..5b41e02a670f020ae62b7854482c4ba1980d73cf GIT binary patch literal 509 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`%IK)5S5QVovKN`}4B` zMA$w&XL9s;aOlF(1%)YvneO4jm-o(&U;MKD#e?Mq8+>b)^R3G((>5$`ILflv=tsMT zqri^uWh?XJrteF)Ir(#L@uYSZ#}5m2PWL-;h`yh)YSr?%_21hCg6ylJ<~^TZ68k@M z*0PUs0U}2m4Zrz%{ru!$;?!{|$E-JRd$xd+!qOu@YuZ+=+K?-K{IOu7#Gy?(C029K zJuHwgKK8+3O1mEi<8zsP?~|?OE?SqZ;@R}Hh*OcJN#Q`=cIVYsi%fl`jgRf~&@_Gf zwzE(sdH3B%ReKL@(z)}#{LAm!8Ou74CNVNBn8MT`ef;AL!#4E;rLlAT)H7zW#a>U8 zU^AP|o3>d}=J>$`0|rHwDM43C-@g0)`~9hChd_}fnOvtgEzsbyc%HHSwnVR+$0Qaf z4hDzV>nAp?Vf*l#Q@}~VH~7Z3-c_p%=AWOKD!ECAd8tU(q6Mq8jughk>rJ2Tw)o@M zm#pV3mrVI!!@p|Pp+XrSHQ@j+Lm56tj!LO-Hu>!LzuT|B{(4Tap5^mRI^HKOr#o>( zhECmcH*b>$SLC#%J&RUEtqrq3WKa^{tg=+3a-Mjg$X|1pImHv7|6G6l?EhE#0)GDv Vq@B#jVqjok@O1TaS?83{1OO3{ + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/14.png b/doc/html/images/callouts/14.png new file mode 100644 index 0000000000000000000000000000000000000000..de5bdbd3eb8be01d27b6f1a345d586d0c4d61b2a GIT binary patch literal 499 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`(f6)5S5QVovL&ji+t} zh_HY7zn8PK$&+QbhfZH4OXk6oR~J^xFa4ru^@GK(LHCDmEpzN0DV1hDCj-+7ZjQ+v zYTxf&UV7^JrT0DT=ibj@uHP27{{Ga|pN^VKANF1{d3)jY*E+*vNA@lkcl~(Lphv#f zZSgm;g1vG7SsXu1?TCBVaZcj#*Q&kO-j-$e7zzmX9alE-b>4iFg+V~@k_l_W_wBcH zWmp*BaqNHHW9Xsz@VDKv%bG0$2|bO5Z6>~kGkrGPetRKrdu;6W&)@+-S^-5e@qWpx=%~ppu-*HbtcU?B((KtQse2TO*ZEl8Jswt zRO&J4%x73CvPq};vBd=w-op^F6<=oH98=hD0fB5^~^0#Ht9-5wBo~e + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/15.png b/doc/html/images/callouts/15.png new file mode 100644 index 0000000000000000000000000000000000000000..3fd6ac38603390bf6f9bbfdb85ddb203e2edc421 GIT binary patch literal 507 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`%IO)5S5QVovL&-F>$L z1lS(@e{k6MP=#(Q)65P&Df1-{87Bltt+Mf&((ZAvc!Ef@>!Js&9H9b5iNOkrjBYL6 zJ*_!sB>iV?h@ACiit<@=<+J)R*K4P%cxw9w^X5-kmdSp5TRo@ZmA&eVHGWMv{dC`S zuce2g9b}I0mp%UT(3$h)E?kO6N0T-NtiR6f#9?6EcU;-Tw>eSb#{2IdZ1@=hR$sjr zzyA8Z#}+%3XYST(VGvBTnww-G;h@R7RHW^&qTY1wDM1E2%vZCnP73-ad;I5-GeP_8 zE`G0F6Q(`qeEN%Bd`m@QuDc4b82Acr%ROx3%dny5{(I}bX7&S{bY%G0Jv1kte!3xU z{l(W`FJx^snCW9M|9s%ekN~~u3#V){n|<~=yTas?3Ovp)cJVPNC~di&>!G + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/16.svg b/doc/html/images/callouts/16.svg new file mode 100644 index 00000000..01d6bf81 --- /dev/null +++ b/doc/html/images/callouts/16.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/17.svg b/doc/html/images/callouts/17.svg new file mode 100644 index 00000000..0a04c556 --- /dev/null +++ b/doc/html/images/callouts/17.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/18.svg b/doc/html/images/callouts/18.svg new file mode 100644 index 00000000..1cb891b3 --- /dev/null +++ b/doc/html/images/callouts/18.svg @@ -0,0 +1,21 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/19.svg b/doc/html/images/callouts/19.svg new file mode 100644 index 00000000..e6fbb179 --- /dev/null +++ b/doc/html/images/callouts/19.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/2.png b/doc/html/images/callouts/2.png new file mode 100644 index 0000000000000000000000000000000000000000..f7c1578846cd7e67f148e7bbe3178ec170050e48 GIT binary patch literal 446 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`)q*>EaktF{gFH!7eFB zfwuoy?SYP89?67Uc^u>7$ueKD;_TuU8yCKP?%y^nk6}6Q`Xb ztf|`>GH3mp6jYb?>^RdSfr%@^R!^go|6uIuQi$NDW>upBo%&=x}fma9VINW5Ly|Qkmm3JvHr(Hb1rr&)I%k zqW}1XsO0Up4@Uid#O=~jwU>`!u0>yZkk=jF7J(OKyBQi3I1HqEAMAR!+FC^5{Aa5( zf1b8B8nUgv%H`5>GKER;h_=JWcU60(815ha{H$oF%dBM*eC_{b&TZl;l$m|{>8A+2 z>GpSd7ik$I?GB%onzMHA^lP*F zk0)=tnX|7g@rLFCKI7=6AyTdvVl+z`(%Z>FVdQ I&MBb@0M`i8D*ylh literal 0 HcmV?d00001 diff --git a/doc/html/images/callouts/2.svg b/doc/html/images/callouts/2.svg new file mode 100644 index 00000000..07d03395 --- /dev/null +++ b/doc/html/images/callouts/2.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/images/callouts/20.svg b/doc/html/images/callouts/20.svg new file mode 100644 index 00000000..ccbfd403 --- /dev/null +++ b/doc/html/images/callouts/20.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/21.svg b/doc/html/images/callouts/21.svg new file mode 100644 index 00000000..93ec53fd --- /dev/null +++ b/doc/html/images/callouts/21.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/22.svg b/doc/html/images/callouts/22.svg new file mode 100644 index 00000000..f48c5f3f --- /dev/null +++ b/doc/html/images/callouts/22.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/23.svg b/doc/html/images/callouts/23.svg new file mode 100644 index 00000000..66242129 --- /dev/null +++ b/doc/html/images/callouts/23.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/24.svg b/doc/html/images/callouts/24.svg new file mode 100644 index 00000000..a3d55253 --- /dev/null +++ b/doc/html/images/callouts/24.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/25.svg b/doc/html/images/callouts/25.svg new file mode 100644 index 00000000..56614a97 --- /dev/null +++ b/doc/html/images/callouts/25.svg @@ -0,0 +1,21 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/26.svg b/doc/html/images/callouts/26.svg new file mode 100644 index 00000000..56faeaca --- /dev/null +++ b/doc/html/images/callouts/26.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/27.svg b/doc/html/images/callouts/27.svg new file mode 100644 index 00000000..a75c8121 --- /dev/null +++ b/doc/html/images/callouts/27.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/28.svg b/doc/html/images/callouts/28.svg new file mode 100644 index 00000000..7f8cf1a3 --- /dev/null +++ b/doc/html/images/callouts/28.svg @@ -0,0 +1,23 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/29.svg b/doc/html/images/callouts/29.svg new file mode 100644 index 00000000..cb63adf1 --- /dev/null +++ b/doc/html/images/callouts/29.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/3.png b/doc/html/images/callouts/3.png new file mode 100644 index 0000000000000000000000000000000000000000..3ff0a93931515bb97a045dfa61a8530d87e458fd GIT binary patch literal 431 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`$7M>EaktF{gFH*{(+p zB5wOOu6l7m)8 z=-oKUH}V^&iJyB|uo8LF()AHB5)-MfO`N3nt zvX}OXM~sd8*9*0GtV!A!kzpdmy4F;zn{|?kqeR<^5G@5I1_ong&q>Sg=9!B)JHv7pU)=hauMINB3;oaL&ye>}mU!H{id4Bxig=9%^>^=*s?64R8I`k2o? pd-p8Ef~{sjr?y8+Fx+F*x_2OD_kw447#J8BJYD@<);T3K0RY@Tw*mkF literal 0 HcmV?d00001 diff --git a/doc/html/images/callouts/3.svg b/doc/html/images/callouts/3.svg new file mode 100644 index 00000000..918be806 --- /dev/null +++ b/doc/html/images/callouts/3.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/images/callouts/30.svg b/doc/html/images/callouts/30.svg new file mode 100644 index 00000000..dc43ba1e --- /dev/null +++ b/doc/html/images/callouts/30.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/4.png b/doc/html/images/callouts/4.png new file mode 100644 index 0000000000000000000000000000000000000000..6aa29fc0b48c17aa6ce5540e1af5c00510c33ff7 GIT binary patch literal 441 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`)qx>EaktF{gFH#x5mC zfwup%GG$o)=ergqP)_hu?Cbmc-FuV6=PTSkE z?z;W`K`XyJWKnY38^_LI-}iXo6rn{K^Ugm{NGsVLTQQIQc;ScrMIF~}*~{?xZ|}UC z)%voeOU2Vbu7Bb(%{5!g=daxAHc3V5z+>?E76HlSc>&q{{ zJgU5>EY^K=``x_dYqp*_vnNK+lE-=9auZ+6u0=XLho7HKd(8afJ98Qv1B>H_g?h*I z^7xt(_!*jJt_^x6<$Ce%iJd)$VVYl~OqdVEFZF#=7-s1t%fP_E;OXk;vd$@?2>|9n B#bp2h literal 0 HcmV?d00001 diff --git a/doc/html/images/callouts/4.svg b/doc/html/images/callouts/4.svg new file mode 100644 index 00000000..8eb6a53b --- /dev/null +++ b/doc/html/images/callouts/4.svg @@ -0,0 +1,16 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/images/callouts/5.png b/doc/html/images/callouts/5.png new file mode 100644 index 0000000000000000000000000000000000000000..36e785867ad9b06bb5da296fee61b67cd8159ded GIT binary patch literal 423 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`&U2>EaktF{gFn*{nkj zBCY4o9LZ47@QCRUnZAf+N!}-g*k62kUh<2$=N}3cU-wJsu7~Tf`D?j51GwEfg_G2_ zuV#t97&qf=>*tSit#h_USr*FJFU!>WaGpbPU+ne2DLtw;&jomW^|@TLId}ILd4;Y; z`kGI<1$&J<4oW?f4p9*ch$x|rP+;KqSwET0Ksa~vKtM(>J91HOJ>EhB>xN^tsw+8di7uv`rMqUeL zJtlGLsS$%o&3$<<&56<(YY$o;PcU%UfB(F1o@3V5sOFBi;${Vo2fOrSjvstkva9-x zil;zZBGUt9^BXy4GknxI4hvj-p!#HTV6S6ePsEk3N^VkheYYwwc>v z!48gj&!5^CXy3`&YF5dr$YOKedHr?gg#ir$OfFx%f9Fdu@F;mr4Z2vhci-*k?73P? f@97_A_`n?SY~RWh)zCHu1_lOCS3j3^P6 + + + +]> + + + + + + + + diff --git a/doc/html/images/callouts/6.png b/doc/html/images/callouts/6.png new file mode 100644 index 0000000000000000000000000000000000000000..c943676beafa0562916b058c169951febcd3cddb GIT binary patch literal 431 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`$7M>EaktF{gFH{#8D;%7vjax1W#KXIAnv(J`n z&5VyM+63~m6_r{NIT!+`rAn_gmE-I&+!3QUA?T1q^ClfZ7RG!2%96cqg2wgyaq?lS zMX$X!U8LbO@45W6mvfv$L-`J@Z+FmS&DLGD$|-VMfY)E~efQs=*mUM;<-bcWOZM5Z zTz)B%D3P@Lt`d*4kJ{wr1(Q_j + + + +]> + + + + + + + + diff --git a/doc/html/images/callouts/7.png b/doc/html/images/callouts/7.png new file mode 100644 index 0000000000000000000000000000000000000000..20940de30d2146b73118a08905955162fe985f68 GIT binary patch literal 397 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`z*d>EaktF{gLJ{wyX( zf%f{%yMM5|1Qs>DxO#n#YtRpleGYL4%{eMNMC?4cR!{jhN$+gat*(bhBwQW8eR)?F zba$a+^0L_vzt^7O@l~6=`|-z${Iyee1O}bTzyIC7L&Goql*H!=r=P}oFAaJ)O@ZgI z{@Sm`#{5B@N=kt`V%+OqiyeDxcc)!#?*L7k5+eADVIg?*L>hpfK3x*)1hCVBt; z;|%wV8@Gym{wcFIjN7SWb%BU0N0Y+6yzR|3cK@fSPF7(wKKyx4{o#4fYt#Iv1TDJ# z*2#-AZQqV>`4S8w#?i?>7PHU(+hgr1l-*Nl-OBiY{af+c^=0Sh`7 + + + +]> + + + + + + + + diff --git a/doc/html/images/callouts/8.png b/doc/html/images/callouts/8.png new file mode 100644 index 0000000000000000000000000000000000000000..d8e34d4a09f6dca4f9c22e626d9f9d82b969b02c GIT binary patch literal 434 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`$7P>EaktF{kyy#=ct) z0&EZJryZ5xyvdOv(510`p{HDvlxC~E$|>iVgULHQ3PYvrom?h2P4(>+k=FEToVfLb z-1}ul4-dV}J2m&O{aGGazV^u2>+);2+U^P78~6Tv*4AI1E_e2NCZAD1|9M}poAQ6# z2UUCjU5lzOJ!f0qp`v6c!}s@T(aY_*-6p<)(^RJf%{ZH;pv2Hn%$FKjXEE0=dabFI zOUbTczTJ2ED(5xNoT$P%L(+vssY!q-Q6kB1zW$Oa(QCh^Kc6#2_JRrTx8JslG@1mM zBBvdU`kln8=_3m^%&og1Cq^RrH#tzmz{IfafeFfcH9y85}Sb4q9e0BP^KrT_o{ literal 0 HcmV?d00001 diff --git a/doc/html/images/callouts/8.svg b/doc/html/images/callouts/8.svg new file mode 100644 index 00000000..c1803a3c --- /dev/null +++ b/doc/html/images/callouts/8.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/images/callouts/9.png b/doc/html/images/callouts/9.png new file mode 100644 index 0000000000000000000000000000000000000000..abe636072b61306fbcd6157b95dfdf7e86a77e5d GIT binary patch literal 420 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`&U8>EaktF{gEcf7T%f znb!OIl8YM`EC?0g)MK6LySsR*bBW@-#a{$sD|jaA?Rq5|BVw*<(2>_Fw2;L_Ls+eT z*=m-pP5G8*zMrjje*N{AqvqEc&v$lO8~PeQnNu$u7&XUG^XcT&$oGAZue{@YWbseb zX;0Q#doE68rNi6aM(w}9J~guKY8ESl1YdhX&(saqqyj~D?!KF+)#9L-_*{J2Y1Ks< zObjyp?mceG5^anO3Q8tYyaIvx98EzeZXaKe_`Z|7b6wRX+{3FhZAn{V<2dEM9+du_kptYsE+ z{WKfa2W_~S^T2{nZ8E1=H*3uG*3`)V4^%t_SRAV?Wb9U5edYbrW%=bs0jAGCWzMDv z&-uLjLxRB%P3bLBx;@8}pH%jFEoHiFvT*CZ6}7y~440#x2c4?eefQp-XqD5OV!VD< d@-ZKf|NC_Jf+y*vd<+Z>44$rjF6*2UngH>Mv>N~b literal 0 HcmV?d00001 diff --git a/doc/html/images/callouts/9.svg b/doc/html/images/callouts/9.svg new file mode 100644 index 00000000..bc149d3c --- /dev/null +++ b/doc/html/images/callouts/9.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/images/caution.png b/doc/html/images/caution.png new file mode 100644 index 0000000000000000000000000000000000000000..5b7809ca4a9c8d778087522e5ce04b6e90099595 GIT binary patch literal 1250 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4rT@hhU+WOo?>8NW(e>Jab;j&;NV~o5MYpy zU{F+KFf?Rva$<;zVn|MA$j)XcE@r5%W@u?)XlW_#>0#*UDemd%nKFf8%9P?MQ>y38 zVVEwkZjIWyHF@jSt$X(}?A@Du?i|Cp zbLXyIW4Lzh+_h`h?%iX!chB(NJdh*`E$$X&!4}4&+z{J`|sZwzJC|^ z{$1kxcf;@BzyJTw@c+NS|Nj#IN5NBISn~R-X--a%afBxQ|J!3zMjr_SU zk_iHr)f*lf{$5^Qz}I)@3FlWvw(w~u=1P@VsTP+$RNGvxbHL-(%M6nc6`{zlU zjGQJeveps+!&Jb&mD)L@hA} z1_tL6*NBqf{Irtt#G+IN2MuLS&)mfHRNut(%;anZ6Fnn63k6F{eFF=914D)6qRirw zN{8Ia;*!i{z0_j8l+uFyyb`_S{M?DV6n8K%Fld2|%S_KpEGaEYWk@zRFt#waFg8d` zG)YZPF-fe)lBATd3a!N{b-$VA&f+n^|#(~yCI Ofx*+&&t;ucLK6T%G-N*j literal 0 HcmV?d00001 diff --git a/doc/html/images/caution.svg b/doc/html/images/caution.svg new file mode 100644 index 00000000..4bd586a0 --- /dev/null +++ b/doc/html/images/caution.svg @@ -0,0 +1,68 @@ + + + + + + Attenzione + + + + pulsante + + + + + Open Clip Art Library + + + + + Architetto Francesco Rollandin + + + + + Architetto Francesco Rollandin + + + + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/html/images/draft.png b/doc/html/images/draft.png new file mode 100644 index 0000000000000000000000000000000000000000..0084708c9b8287c51efa6b40b8d492854191455e GIT binary patch literal 17454 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 YsPxZ;53A2HFfcH9y85}Sb4q9e0Fi|iga7~l literal 0 HcmV?d00001 diff --git a/doc/html/images/home.png b/doc/html/images/home.png new file mode 100644 index 0000000000000000000000000000000000000000..5584aacb097a80e66a5320312b6e4eb017af1a06 GIT binary patch literal 358 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rjj7G?$phK4%r{|pQa%*9TgAsieWw;%dHU|?WS z3GfMV6&Dfg?(A@OuseF>a6(*+nzF*onKLh6zO-%YmOy{sw6wJU|Nk%gvq74Hfq|za z$S?Rm0x$^OKX;CSfq}EYBeIx*fm;ZK886+f`@_J%pjzS@Q4*Y=R#Ki=l*-_nm|T>f zo0^iDsNj}alvU8YOY t9}F9JU6`43jMG5vNQA& + + + + + + + +]> + + + + + + + + + + + + + + diff --git a/doc/html/images/important.png b/doc/html/images/important.png new file mode 100644 index 0000000000000000000000000000000000000000..12c90f607a1b27ddde0a7d922ae255e8c90e883e GIT binary patch literal 722 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4rT@hhU+WOo?>8NcoN_f;wr$vARr(hAt9lu zscC6x>EvV>6{VS+EaBwj6ciMco$ZvI98_E!l$@NLot<4>UER|o(bHqOcQ41TYc{y!?kM?_wFg)yJvXsp5^oB z9Pi&Vyniq7|3Ab3{~Z7S3p{_W`TV)z`}cpO z$(;G%_wGG* z?AW<;=dNA5cJJQ3=g*(NfB*jb_wWDz|6hCQ@I3|w2F4_BcNgdM3%p4T42R|DNig) zWpL0?*7VFxOi%SqOwUZtRxr^s(z8&owA44S&^IttNG{4OE~#|Ltt>9dOx8;+)=McZ z$j>X$OU}=oxJz*d0|SE=*tpE}yu^~yqEv=t literal 0 HcmV?d00001 diff --git a/doc/html/images/important.svg b/doc/html/images/important.svg new file mode 100644 index 00000000..dd84f3fe --- /dev/null +++ b/doc/html/images/important.svg @@ -0,0 +1,25 @@ + + + + + + + + +]> + + + + + + + + + + + + + + + diff --git a/doc/html/images/jam.png b/doc/html/images/jam.png new file mode 100644 index 0000000000000000000000000000000000000000..224ed7914bb5a31a407511093500aa1fe9d9e571 GIT binary patch literal 3884 zcmeAS@N?(olHy`uVBq!ia0y~yV5nzcU~uJNV_;xNjW#hE=bLrwBlWk7u9BNWG%WIzG^?ia{Jx0?d2cu65lo_tIq4R{ZpB|^Gj6) zSQHbUotHf@zxm;v$tNPW%s1Luc2<|6?FW0^VrZqF7Q%Y`1Ew|lr=xYj$EHQEz3mDMmMpd z>ejiX)97pynn`5kW z|CRi$_`uF-U0Tl!|N5S1TOOPDXU~o+TYOinI`YoqQ_`=^1)VOOpVS2UPMZHtf92(U zF(~lpmyJ~=b>FwfdM6w>w@64vPjkD9T!BlS8{-PeFW+C~FR$XwJ;(0LL4_y0b2(bBrxt6b;~fkM&QareVtIlX>mx{c)k=f}URyJiaR zcRjOF;pM%D1^TaQcvl$+gnzii-F1xrciDrp+t{xBlnQwM`lzw)`c>DOBDhY4PWZnt zR)FQek=PkocKsFVcH$fQ_AtJdIN(>n{=t*q-~sQq@h3+fzfG`F{L=O>KV|n{Gpl%-%i!=JgyXArJMZ($hYaT!{XP6Jj;Fo) z|Aw2nSEX5*73

m`0On#VPL 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 + + + + + +]> + + + + + + + + + + + diff --git a/doc/html/images/next_disabled.png b/doc/html/images/next_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..10a8c59d7b3741260b7bfe918b62d0670cad8433 GIT binary patch literal 1110 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rjj4rT@h2G_o0{}>n;SkfJR9T^xl_SO6joXo($ zppfhlZ{Pm>`SaViZ};!tyLt1*|NsBbojZ3P6EBL3=9l=JzX3_ zD&{0TNo#1Z_o+&KnDHU@)Rs;LG+GiER_Ffe$!`njxgN@xNAPfH=1 literal 0 HcmV?d00001 diff --git a/doc/html/images/note.png b/doc/html/images/note.png new file mode 100644 index 0000000000000000000000000000000000000000..d0c3c645ab9af6318035b026dd86944b9ddc9114 GIT binary patch literal 490 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4h9AWhNCh`Dhvz^OiAAEE({E-dXuv&t)U99M06BF~bt=lC3t1z!y3OU-_; z>3=1k>J3(3i_72APIz-IDqpqc+E%+vGv;(%KfZ!%@4A+C&xmZ75-RagX8L}A{%x+r zX<~gz))PX{awr=ezabJ<%O$qq%HpE?3}IarYhrI#g}e)4`)(-lYr?KO{@fm?UzpsD z&F7x?_G;CcbIZ>^o0GCAMe@{JfwtZgS9s0dn=t$|`IrrC3yU6#%a-U6G$wZz0 z>m`@($9HNPdGJ4#pEvb;3eT@>Ck6%v=MvY5lHmNblJdl&R0anPWlhiA#Pn3(#PrPM zYy}fNBRvZROG|wN3w;Aah2)~l;*v^-+{)sT%w)aPV!f2og8aM^z2yAdiMtecFfcG^ zfsM;d&r2*RElOoDPD(L1F;6y4H8Hg?FgGwTOER!DNJ%kHHBU4$OExhPxjgw70|Nse jNLN5&dMbmFNrjP#wt==mQ8cF^C=xwg{an^LB{Ts5w*0vf literal 0 HcmV?d00001 diff --git a/doc/html/images/note.svg b/doc/html/images/note.svg new file mode 100644 index 00000000..648299d2 --- /dev/null +++ b/doc/html/images/note.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + diff --git a/doc/html/images/prev.png b/doc/html/images/prev.png new file mode 100644 index 0000000000000000000000000000000000000000..d88a40f923e3c554125f01cd366707c60cfcad04 GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rjj7G?$phK4%r{|pQa%*9TgAsieWw;%dHU|?WS z3GfMV6&DdqOG`60Hr}>%%ZlYo1O0u~loc*tzSP~>;p||S5Et|R|Noh1c$yg)73T~N2spa`a*~JRJ5eh~I1}5!gYtAz;Fo=OPI2WZRmSpDVDTHL^rZN~B=o=X8 z8<-ql-^0nkz!2u?;uumfC;0|1OPoRyGxLNShYX~Tl_Wf9G1_imu)%RA9}mw<0X2^e zQioc&m}WXSvRw^OFi2qFa&lm1W^U?K=~^Ook|m{hVvche^Q6-g?(V)Vn8U=toEqFE UkjD9gfq{X+)78&qol`;+00?PtqyPW_ literal 0 HcmV?d00001 diff --git a/doc/html/images/prev.svg b/doc/html/images/prev.svg new file mode 100644 index 00000000..6d88ffdd --- /dev/null +++ b/doc/html/images/prev.svg @@ -0,0 +1,19 @@ + + + + + + +]> + + + + + + + + + + + diff --git a/doc/html/images/prev_disabled.png b/doc/html/images/prev_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..ab3c17e02d156e7494dbab2f9cd66af46af2358c GIT binary patch literal 1109 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rjj4rT@h2G_o0{}>n;SkfJR9T^xl_SO6joXo($ zppfhlO-<`D(~2b}=LHv2RC7dZWAVCrDh<7Ss(U_A1L-MNQRp<#x>RYL|A z0d8w%7gb?npBLs13>ys`SR)0#F|i0-(0!9|ZvFp)$&5@KPtr;p8yJ{=^Qv)(GIJ<+ zNI0-0Zew5(Fj?c!G-tyG77m3Osc(4d6PFVdQ&MBb@ E0L^J1b^rhX literal 0 HcmV?d00001 diff --git a/doc/html/images/smiley.png b/doc/html/images/smiley.png new file mode 100644 index 0000000000000000000000000000000000000000..30a77f71ce16872d046a1a5d6fd698a2f65a3f62 GIT binary patch literal 867 zcmeAS@N?(olHy`uVBq!ia0y~yU=U|uV36QoW?*1YTQtp`fq{X!*vT`5gM;JtL;nX1 z42*&SJ|V8+B7&<|tz5IBw4@*~EXexT*H!m!O?Pp!sH>^CckiyDuKJ|Dl+(w%CQay1 zOYu8%=FGd73zHKgmoF}|u{3I~kKDVXVbQ_`9c`_Fz7{iQrl~4QMTGi1fByW=jcKLD z*?C#s*_rWAAIx@f)c16=+qAB-t1T`u&hzVsWjnTSn>lml<@5cSX&!B@jUfSci{|F_ z_w^KKXB!)+#6)_3`t<4gwQEt~&MzL%J+!ao-_JD<@64PzGws6Z-hv$8-Me=7btN{` zl~t96rKP3$c$&I9TcsogXQl?mL%y{W;-5&-92C)*?h!W?b)Wnj^{5*w_%-mE4Lj!$7BYguC zr{Y6*7#J8-K`Mgt(@M${i&7bU6O)Vbb5m0?6BXPti&D$;i?WLqd?OT$3=B-#%hsG{ zU|`huba4!+n3FrHHoVC|#v<-Y&ynX`2+ z)ci{*-@n^>-frGI_MA-9eHCQCFMs-NiTvCzJ8a&6h<9#D<(d3(^{E}JLTitR9GSK2 z$*O4*8tU!OHS*&Yg~mSMD)7~hd93j+u`cf5MM<4*zJ;yfFKhYEn9bv3Xeg3g;K-G= z;q?Q<5Qk-d*rznCncd{p+umG~t-YZ3L%_f9;YyrSd?k7nE}0j~xg-T!p1r_pXw_8J z^q9XtRP=q)pSk7_!?YePxacL!`8E4~v$oZii_iB4y^t?YSBana!LlH(Q{_whcc+EB z6^^opPM-68`QEg&=hc<^;brIeKBf1+k=uTZ@Aa)4^R8_EExPXM@|~g)-OB%bBP#i` ie0$=QHXfdLO8@!p%oni+1)dBH3=E#GelF{r5}E*N2(Kal literal 0 HcmV?d00001 diff --git a/doc/html/images/tip.png b/doc/html/images/tip.png new file mode 100644 index 0000000000000000000000000000000000000000..5c4aab3bb3543191c360387c4af9a3cbaa051345 GIT binary patch literal 449 zcmeAS@N?(olHy`uVBq!ia0y~yV31^BV36QoU|?X-y2mNSz`($iDJ87yAgr${wU6ATeb^ycE^w7cIp z?_W?xU6%d(bb~@Shbi-aG=ETBbm~(ogOmrW&bwBIxdt+K+A3yD;V_t}R>0LF5GN)x zed{W(mq$!1ciVpPy1}W+9bm)Xrgda~bSbG?a3DdjluYV+O9SdLnMpASqX+9EZY3c7C@7#N&OTq83NAIrA4U>si~GJ7Ut&0mS)MRMrP)TsYwQg=9VeOrfC+2Nk)mu rLdL(;85kJ&K)M1F(^DCYOe>5`v<1B4~iR4S3j3^P6 + + + + + lamp + + + + office + + lamp + + + + + Open Clip Art Library + + + + + Sergio Luiz Araujo Silva + + + + + Public Domain + + + set 2005 + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/html/images/toc-blank.png b/doc/html/images/toc-blank.png new file mode 100644 index 0000000000000000000000000000000000000000..6ffad17a0c7a78deaae58716e8071cc40cb0b8e0 GIT binary patch literal 318 zcmeAS@N?(olHy`uVBq!ia0y~yVBlw9VBln7W?*2DUznZ3z`$S-;1lA?z`)P|#tmSq zfuVt+q2a)R0}Txg{}~t<{xkdsQ~$xN|NsB{3#)lDFfcGCdAqwXbg;^LFfcI4dAc}; zRNPAb@qhn+dx4sSAN-68Y+`}}843&7&M+`cx!`muLvG^(1_lP_64!{5;QX|b^2DN4 z1_upgP0!rK^itl1hi%%HopDWWCg4y_C{| z{JavqiARt`YJFJnVhX)qGzOMplv!L->5yAl zT#}irms+fsQd*FoSE84kpF44v;tmD|1}(60ndy0nC8b5F42emG<`xDZ$;L?r7Ky3J=GDKJX@I;2(iM=Hp2}coT4AYeplx7Y_5oxZgQu&X%Q~lo FCIGT9P(J_w literal 0 HcmV?d00001 diff --git a/doc/html/images/up.png b/doc/html/images/up.png new file mode 100644 index 0000000000000000000000000000000000000000..17d9c3ec491ae1ba22188ce85985623c92ffa9be GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rjj7G?$phK4%r{|pQa%*9TgAsieWw;%dHU|?X- z3h)VW6&DdqOG|Thu-mqE%ZlYoyE{8BU%nLR@2jS)FmvY2qel)W#Kk;%^zi@x|I?Un z*fKCM@RbDl1^-6|46X<6oM2#J;4JWnEM{Qf76M_$OLy!3FfcHvmbgZg1m~xflqVLY zGWaGY7v<-srer26xMdclmgg5`7c2NiC>R+Sn6#IzInThrAO_OlT$Gwvl9`{U5R#dj z%3x@qZ(yu%U~+tY4<`cyLy@P8V@SoEspmFwHW&!FJyeg_(XezvV9WvAI|r@_>dZZG zPW6aiOT!J--9O?NG0%AP;}ge|4lDQN4=-}8`?JGwx}?mMnO)OdyQdu$nQCjPRV}jm z$u!Qa8E-cQ-r3Nz>Y(YPTd#BPEH+&8GWqfD!}4*53%dA!%#3$cIv;a~fq{X+)78&q Iol`;+0POUaApigX literal 0 HcmV?d00001 diff --git a/doc/html/images/up.svg b/doc/html/images/up.svg new file mode 100644 index 00000000..d31aa9c8 --- /dev/null +++ b/doc/html/images/up.svg @@ -0,0 +1,19 @@ + + + + + + +]> + + + + + + + + + + + diff --git a/doc/html/images/up_disabled.png b/doc/html/images/up_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..e22bc8712192df3a8faa3264b0ec71ff3aaaa96c GIT binary patch literal 1115 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rjj4rT@h2G_o0{}>n;SkfJR9T^xl_SO6joXo($ zppfhl|Nrwy-~uYR zhzc&Dg3GAj3M#mY3a+7o>!{!cD!7RXZlQwPsNfDNxQhzzp@RFU-~lRlhzcH|g2$-f z2`YGs3Z9{Y=cwQXDtL(sUZH~5sNfAMc#8_&p@R3Q-~%f7hzdTTg3qYn3o7`E3cjI& z@2KDhD)@;CexZWjsNfGO_=^hup@RP~@T}IQi-CcGuO!GX7$yd$8C(zCIl;idaKO{W zF{ENn(v#GNhX4QTi=1XMFdktN{`IZ@p>>FWLcsvS9SfKMdlAq$6s7@ONV`8frfZ~QMdG-hBC2vApc;y96* zmcYQFpvLCIAmDK02m=$xYzYU3L}6wQg@_sdlHD~JI1CtW_~{utEVY`?z`(%Z>FVdQ I&MBb@06Fw0-2eap literal 0 HcmV?d00001 diff --git a/doc/html/images/warning.png b/doc/html/images/warning.png new file mode 100644 index 0000000000000000000000000000000000000000..1c33db8f34a8b42b373179b46a2d8d8a10e061a9 GIT binary patch literal 1241 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4rT@hhU+WOo?>8NW(e>JaphoO5CF?5GB9W| zFc>m0I59AIF)#!%FhnshWHT@nGcZ&$Ftji*^e`|?VPKe2T|Fl#Xiikroa*YO3=B&x zEth(EEp2I8I%UezrAyZ`FswB+TsvjTRtAQxnwndCdbZA)vvujxty{P5WnkF5cJ1D+ zTaPg?91{>YCLwX`*s*gA4Ce#{&Phm|)6~4iz;I1d^V+p*_ZS%N-Mjakf#JEL;`8Uv z-!m}0=iqq%{{43bhVS3M|7T$MKMF=efJz}yVEuRs0|NtNlDE4HLkFv@2Ll7c3r`ov zkcwNmlWOyu3izvS7ejxP>R-!INP5f(XN|IS^C^Iyp?`SUk1vQO?s(K&l| zi|Nkt0@~*ymDp65*E-HED6u(s{Mfrxmah{JrgAMTIq)Du?nC5nnYTRgThA|azEdIl zD^uvV>~q(b?>`Fd;xnAbe7so1I$-&keKN}|vNNOCvX<~g{)wp7{&hR__v^cBU*Gq* zV3YS!cBPWsl#eNWc|~nAXWMOB8tQWBuXo=4>}cytyX_5F^Az{bVJ>7~U~n#RjVKAu zPb(=;EJ|f?&`{R&%uP&B^-WCAOwLv?(KFJsP_VSrH?Yt*FjPn`$}BFabjYnNF3C*R zOD)z*DJ{s)E742N&z-nSaR&nfgBIAh%=Em(lG377hGY|?B=Z!b6jL*k#Ka_13kwTN zLrZf@a|7cv1EVApQ-8txlNlHo_&~Y>64O%|j7%zwOtcNO4T_>U4H+017(8A5T-G@y GGywozG)2h( literal 0 HcmV?d00001 diff --git a/doc/html/images/warning.svg b/doc/html/images/warning.svg new file mode 100644 index 00000000..fc8d7484 --- /dev/null +++ b/doc/html/images/warning.svg @@ -0,0 +1,23 @@ + + + + + + + + +]> + + + + + + + + + + + + + diff --git a/doc/index.qbk b/doc/index.qbk new file mode 100644 index 00000000..eaf0df9c --- /dev/null +++ b/doc/index.qbk @@ -0,0 +1,19 @@ +[library Boost.Python + [quickbook 1.3] + [authors [Abrahams, David], [Seefeld, Stefan]] + [copyright 2002 2003 2004 2005 2015 David Abrahams, Stefan Seefeld] + [category inter-language support] + [id python] + [purpose + Reflects C++ classes and functions into Python + ] + [license + 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]) + ] +] + +[/ QuickBook Document version 1.3 ] + +[include preface.qbk] diff --git a/doc/preface.qbk b/doc/preface.qbk new file mode 100644 index 00000000..b04d88e7 --- /dev/null +++ b/doc/preface.qbk @@ -0,0 +1,26 @@ +[preface Introduction +[quickbook 1.6] +] + +[section Synopsis] + +Welcome to version 2 of Boost.Python, a C++ library which enables seamless interoperability between C++ and the Python programming language. The new version has been rewritten from the ground up, with a more convenient and flexible interface, and many new capabilities, including support for: + + * References and Pointers + * Globally Registered Type Coercions + * Automatic Cross-Module Type Conversions + * Efficient Function Overloading + * C++ to Python Exception Translation + * Default Arguments + * Keyword Arguments + * Manipulating Python objects in C++ + * Exporting C++ Iterators as Python Iterators + * Documentation Strings + +The development of these features was funded in part by grants to Boost Consulting from the Lawrence Livermore National Laboratories and by the Computational Crystallography Initiative at Lawrence Berkeley National Laboratories. + +[endsect] +[section Articles] + +"Building Hybrid Systems With Boost Python", by Dave Abrahams and Ralf W. Grosse-Kunstleve (PDF) +[endsect] diff --git a/doc/python.qbk b/doc/python.qbk new file mode 100644 index 00000000..bec810a9 --- /dev/null +++ b/doc/python.qbk @@ -0,0 +1,61 @@ +[book Boost.Python + [quickbook 1.7] + [authors [Abrahams, David], [Seefeld, Stefan]] + [copyright 2002 - 2015 David Abrahams, Stefan Seefeld] + [category inter-language support] + [id python] + [purpose + Reflects C++ classes and functions into Python + ] + [license + 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]) + ] +] + +[def _boost_ [@http://www.boost.org Boost]] +[def _bb_ [@http://www.boost.org/build Boost.Build]] +[def _bb_list_ [@http://www.boost.org/more/mailing_lists.htm#jamboost Boost.Build mailing list]] +[def _bp_list_ [@http://www.boost.org/more/mailing_lists.htm#cplussig Boost.Python mailing list]] +[def _tutorial_ [@tutorial/index.html Tutorial]] +[def _reference_ [@reference/index.html Reference Manual]] +[def _gsg_ Boost [@http://www.boost.org/more/getting_started/ Getting Started Guide]] + +[h2 Synopsis] + +Welcome to Boost.Python, a C++ library which enables seamless interoperability between C++ and the Python programming language. The library includes support for: + +* References and Pointers +* Globally Registered Type Coercions +* Automatic Cross-Module Type Conversions +* Efficient Function Overloading +* C++ to Python Exception Translation +* Default Arguments +* Keyword Arguments +* Manipulating Python objects in C++ +* Exporting C++ Iterators as Python Iterators +* Documentation Strings + +The development of these features was funded in part by grants to [@http://www.boost-consulting.com Boost Consulting] from the [@http://www.llnl.gov Lawrence Livermore National Laboratories] and by the [@http://cci.lbl.gov Computational Crystallography Initiative] at Lawrence Berkeley National Laboratories. + +[section Contents] + +* _tutorial_ +* [link building Building and Testing] +* _reference_ +* [link configuration Configuration Information] +* [link glossary Glossary] +* Support Resources +* [link faq Frequently Asked Questions (FAQs)] + +[endsect] + +[h2 Articles] + +"Building Hybrid Systems With Boost Python", by Dave Abrahams and Ralf W. Grosse-Kunstleve (PDF) + +[include building.qbk] +[include configuration.qbk] +[include faq.qbk] +[include glossary.qbk] \ No newline at end of file diff --git a/doc/reference.qbk b/doc/reference.qbk new file mode 100644 index 00000000..e87613e0 --- /dev/null +++ b/doc/reference.qbk @@ -0,0 +1,25 @@ +[book Boost.Python Reference Manual + [quickbook 1.7] + [authors [Abrahams, David], [Seefeld, Stefan]] + [copyright 2002 2003 2004 2005 2015 David Abrahams, Stefan Seefeld] + [category inter-language support] + [id reference] + [dirname reference] + [purpose + Reflects C++ classes and functions into Python + ] + [license + 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] + ] +] + +[include reference/concepts.qbk] +[include reference/components.qbk] +[include reference/objects.qbk] +[include reference/functions.qbk] +[include reference/conversion.qbk] +[include reference/embedding.qbk] +[include reference/utility.qbk] +[include reference/topics.qbk] diff --git a/doc/reference/args.qbk b/doc/reference/args.qbk new file mode 100644 index 00000000..0c73d5b2 --- /dev/null +++ b/doc/reference/args.qbk @@ -0,0 +1,64 @@ +[section args.hpp] +[section Introduction] +Supplies a family of overloaded functions for specifying argument keywords for wrapped C++ functions. +[section keyword-expressions] +A keyword-expression results in an object which holds a sequence of ntbses, and whose type encodes the number of keywords specified. The keyword-expression may contain default values for some or all of the keywords it holds +[endsect] +[endsect] +[section Class `arg`] +The objects of class arg are keyword-expressions holding one keyword ( size one ) +`` +namespace boost { namespace python +{ + struct arg + { + template + arg &operator = (T const &value); + explicit arg (char const *name){elements[0].name = name;} + }; + +}} +`` +[endsect] +[section Class `arg` constructor] +``arg(char const* name);`` +[variablelist +[[Requires][The argument must be a ntbs.]] +[[Effects][Constructs an arg object holding a keyword with name name.]] +] +[endsect] +[section Class `arg` operator=] +``template arg &operator = (T const &value);`` +[variablelist +[[Requires][The argument must convertible to python.]] +[[Effects][Assigns default value for the keyword.]] +[[Returns][Reference to `this`.]] +] +[endsect] +[section Keyword-expression operator,] +`` +keyword-expression operator , (keyword-expression, const arg &kw) const +keyword-expression operator , (keyword-expression, const char *name) const; +`` +[variablelist +[[Requires][The argument name must be a ntbs.]] +[[Effects][Extends the keyword-expression argument with one more keyword.]] +[[Returns][The extended keyword-expression.]] +] +[endsect] +[section Example] +`` +#include +using namespace boost::python; + +int f(double x, double y, double z=0.0, double w=1.0); + +BOOST_PYTHON_MODULE(xxx) +{ + def("f", f + , ( arg("x"), "y", arg("z")=0.0, arg("w")=1.0 ) + ); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/call.qbk b/doc/reference/call.qbk new file mode 100644 index 00000000..f0245ce1 --- /dev/null +++ b/doc/reference/call.qbk @@ -0,0 +1,26 @@ +[section call.hpp] +[section Introduction] + defines the call family of overloaded function templates, used to invoke Python callable objects from C++. +[endsect] +[section Function `call`] +`` +template +R call(PyObject* callable, A1 const&, A2 const&, ... An const&) +`` +[variablelist +[[Requires][R is a pointer type, reference type, or a complete type with an accessible copy constructor]] +[[Effects][Invokes callable(a1, a2, ...an) in Python, where a1...an are the arguments to call(), converted to Python objects. ]] +[[Returns][The result of the Python call, converted to the C++ type R.]] +[[Rationale][For a complete semantic description and rationale, see this page. ]] +] +[endsect] +[section Example] +The following C++ function applies a Python callable object to its two arguments and returns the result. If a Python exception is raised or the result can't be converted to a double, an exception is thrown. +`` +double apply2(PyObject* func, double x, double y) +{ + return boost::python::call(func, x, y); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/call_method.qbk b/doc/reference/call_method.qbk new file mode 100644 index 00000000..6366d76a --- /dev/null +++ b/doc/reference/call_method.qbk @@ -0,0 +1,80 @@ +[section call_method.hpp] +[section Introduction] + defines the call_method family of overloaded function templates, used to invoke callable attributes of Python objects from C++. +[endsect] +[section Function `call_method`] +`` +template +R call_method(PyObject* self, char const* method, A1 const&, A2 const&, ... An const&) +`` +[variablelist +[[Requires][R is a pointer type, reference type, or a complete type with an accessible copy constructor]] +[[Effects][Invokes self.method(a1, a2, ...an) in Python, where a1...an are the arguments to call_method(), converted to Python objects. For a complete semantic description, see this page.]] +[[Returns][The result of the Python call, converted to the C++ type R.]] +[[Rationale][call_method is critical to implementing C++ virtual functions which are overridable in Python, as shown by the example below.]] +] +[endsect] +[section Example] +The following C++ illustrates the use of call_method in wrapping a class with a virtual function that can be overridden in Python: +C++ Module Definition +`` +#include +#include +#include +#include + +// class to be wrapped +class Base +{ + public: + virtual char const* class_name() const { return "Base"; } + virtual ~Base(); +}; + +bool is_base(Base* b) +{ + return !std::strcmp(b->class_name(), "Base"); +} + +// Wrapper code begins here +using namespace boost::python; + +// Callback class +class Base_callback : public Base +{ + public: + Base_callback(PyObject* self) : m_self(self) {} + + char const* class_name() const { return call_method(m_self, "class_name"); } + char const* Base_name() const { return Base::class_name(); } + private: + PyObject* const m_self; +}; + +using namespace boost::python; +BOOST_PYTHON_MODULE(my_module) +{ + def("is_base", is_base); + + class_("Base") + .def("class_name", &Base_callback::Base_name) + ; + +} +`` +Python code: +`` +>>> from my_module import * +>>> class Derived(Base): +... def __init__(self): +... Base.__init__(self) +... def class_name(self): +... return self.__class__.__name__ +... +>>> is_base(Base()) # calls the class_name() method from C++ +1 +>>> is_base(Derived()) +0 +`` +[endsect] +[endsect] diff --git a/doc/reference/calling.qbk b/doc/reference/calling.qbk new file mode 100644 index 00000000..1a2c38b8 --- /dev/null +++ b/doc/reference/calling.qbk @@ -0,0 +1,65 @@ +[section Calling Python Functions and Methods] +[section Introduction] +The simplest way to call a Python function from C++, given an object instance f holding the function, is simply to invoke its function call operator. +``f("tea", 4, 2) // In Python: f('tea', 4, 2)`` + And of course, a method of an object instance x can be invoked by using the function-call operator of the corresponding attribute: +``x.attr("tea")(4, 2); // In Python: x.tea(4, 2)`` +If you don't have an object instance, Boost.Python provides two families of function templates, call and call_method, for invoking Python functions and methods respectively on PyObject*s. The interface for calling a Python function object (or any Python callable object) looks like: +``call(callable_object, a1, a2... aN);`` +Calling a method of a Python object is similarly easy: +``call_method(self_object, "method-name", a1, a2... aN);`` + This comparitively low-level interface is the one you'll use when implementing C++ virtual functions that can be overridden in Python. +[endsect] +[section Argument Handling] +Arguments are converted to Python according to their type. By default, the arguments a1...aN are copied into new Python objects, but this behavior can be overridden by the use of ptr() and ref(): +`` +class X : boost::noncopyable +{ + ... +}; + +void apply(PyObject* callable, X& x) +{ + // Invoke callable, passing a Python object which holds a reference to x + boost::python::call(callable, boost::ref(x)); +} +`` + In the table below, x denotes the actual argument object and cv denotes an optional cv-qualification: "const", "volatile", or "const volatile". + +[table +[[Argument Type][Behavior]] +[[`T cv &` +`T cv`][The Python argument is created by the same means used for the return value of a wrapped C++ function returning T. When T is a class type, that normally means *x is copy-constructed into the new Python object.]] +[[T*][If x == 0, the Python argument will be None. Otherwise, the Python argument is created by the same means used for the return value of a wrapped C++ function returning T. When T is a class type, that normally means *x is copy-constructed into the new Python object.]] +[[boost::reference_wrapper][The Python argument contains a pointer to, rather than a copy of, x.get(). Note: failure to ensure that no Python code holds a reference to the resulting object beyond the lifetime of *x.get() may result in a crash!]] +[[pointer_wrapper][If x.get() == 0, the Python argument will be None. Otherwise, the Python argument contains a pointer to, rather than a copy of, *x.get(). Note: failure to ensure that no Python code holds a reference to the resulting object beyond the lifetime of *x.get() may result in a crash!]] +] +[endsect] +[section Result Handling] + In general, call() and call_method() return ResultType by exploiting all lvalue and rvalue from_python converters registered for ResultType and returning a copy of the result. However, when ResultType is a pointer or reference type, Boost.Python searches only for lvalue converters. To prevent dangling pointers and references, an exception will be thrown if the Python result object has only a single reference count. +[endsect] +[section Rationale] +In general, to get Python arguments corresponding to a1...aN, a new Python object must be created for each one; should the C++ object be copied into that Python object, or should the Python object simply hold a reference/pointer to the C++ object? In general, the latter approach is unsafe, since the called function may store a reference to the Python object somewhere. If the Python object is used after the C++ object is destroyed, we'll crash Python. + +In keeping with the philosophy that users on the Python side shouldn't have to worry about crashing the interpreter, the default behavior is to copy the C++ object, and to allow a non-copying behavior only if the user writes boost::ref(a1) instead of a1 directly. At least this way, the user doesn't get dangerous behavior "by accident". It's also worth noting that the non-copying ("by-reference") behavior is in general only available for class types, and will fail at runtime with a Python exception if used otherwise[1]. + +However, pointer types present a problem: one approach is to refuse to compile if any aN has pointer type: after all, a user can always pass *aN to pass "by-value" or ref(*aN) to indicate a pass-by-reference behavior. However, this creates a problem for the expected null pointer to None conversion: it's illegal to dereference a null pointer value. + +The compromise I've settled on is this: + +# The default behavior is pass-by-value. If you pass a non-null pointer, the pointee is copied into a new Python object; otherwise the corresponding Python argument will be None. +# if you want by-reference behavior, use ptr(aN) if aN is a pointer and ref(aN) otherwise. If a null pointer is passed to ptr(aN), the corresponding Python argument will be None. + +As for results, we have a similar problem: if ResultType is allowed to be a pointer or reference type, the lifetime of the object it refers to is probably being managed by a Python object. When that Python object is destroyed, our pointer dangles. The problem is particularly bad when the ResultType is char const* - the corresponding Python String object is typically uniquely-referenced, meaning that the pointer dangles as soon as call(...) returns. + +The old Boost.Python v1 deals with this issue by refusing to compile any uses of call(), but this goes both too far and not far enough. It goes too far because there are cases where the owning Python string object survives beyond the call (just for instance, when it's the name of a Python class), and it goes not far enough because we might just as well have the same problem with a returned pointer or reference of any other type. + +In Boost.Python v2 this is dealt with by: + +# lifting the compile-time restriction on const char* callback returns +# detecting the case when the reference count on the result Python object is 1 and throwing an + exception inside of call(...) when U is a pointer or reference type. + +This should be acceptably safe because users have to explicitly specify a pointer/reference for U in call, and they will be protected against dangles at runtime, at least long enough to get out of the call(...) invocation. +[endsect] +[endsect] diff --git a/doc/reference/class.qbk b/doc/reference/class.qbk new file mode 100644 index 00000000..cc6a293d --- /dev/null +++ b/doc/reference/class.qbk @@ -0,0 +1,300 @@ +[section class.hpp] +[section Introduction] +`` defines the interface through which users expose their C++ classes to Python. It declares the `class_` class template, which is parameterized on the class type being exposed. It also exposes the `init`, `optional` and `bases` utility class templates, which are used in conjunction with `class_`. + +`` contains a forward declaration of the `class_` class template. +[endsect] +[section Classes] +[section Class template `class_`] +Creates a Python class associated with the C++ type passed as its first parameter. Although it has four template parameters, only the first one is required. The three optional arguments can actually be supplied *in any order*\ ; Boost.Python determines the role of the argument from its type. +[table + [[Template Parameter][Requirements][Semantics][Default]] + [[`T`][A class type.][The class being wrapped][]] + [[Bases] + [A specialization of `bases<...>` which specifies previously-exposed C++ base classes of `T`.] + [Registers `from_python` conversions from wrapped `T` instances to each of its exposed direct and indirect bases. For each polymorphic base `B`, registers conversions from indirectly-held wrapped `B` instances to `T`.][`bases<>`]] + [[HeldType][Must be `T`, a class derived from `T`, or a `Dereferenceable` type for which `pointee::type` is `T` or a class derived from `T`.][Specifies the type that is actually embedded in a Python object wrapping a `T` instance when `T`\ 's constructor is called or when a `T` or `T*` is converted to Python without the use of `ptr`, `ref`, or Call Policies such as `return_internal_reference`. More details below.][`T`]] + [[NonCopyable][If supplied, must be `boost::noncopyable`.][Suppresses automatic registration of `to_python` conversions which copy `T` instances. Required when `T` has no publicly-accessible copy constructor.][An unspecified type other than boost::noncopyable.]] +] +[section HeldType Semantics] + +# If HeldType is derived from `T`, its exposed constructor(s) must accept an initial `PyObject*` argument which refers back to the Python object that contains the HeldType instance, as shown in this example. This argument is not included in the init-expression passed to `def(init_expr)`, below, nor is it passed explicitly by users when Python instances of `T` are created. This idiom allows C++ virtual functions which will be overridden in Python to access the Python object so the Python method can be invoked. Boost.Python automatically registers additional converters which allow wrapped instances of `T` to be passed to wrapped C++ functions expecting HeldType arguments. +# Because Boost.Python will always allow wrapped instances of `T` to be passed in place of HeldType arguments, specifying a smart pointer for HeldType allows users to pass Python `T` instances where a smart pointer-to-T is expected. Smart pointers such as `std::auto_ptr<>` or `boost::shared_ptr<>` which contain a nested type `element_type` designating the referent type are automatically supported; additional smart pointer types can be supported by specializing `pointee`. +# As in case 1 above, when HeldType is a smart pointer to a class derived from `T`, the initial `PyObject*` argument must be supplied by all of HeldType's exposed constructors. +# Except in cases 1 and 3, users may optionally specify that T itself gets initialized with a similar initial `PyObject*` argument by specializing `has_back_reference`. + +[endsect] +[section Class template `class_` synopsis] +`` + namespace boost { namespace python + { + template + , class HeldType = T + , class NonCopyable = unspecified + > + class class_ : public object + { + // Constructors with default __init__ + class_(char const* name); + class_(char const* name, char const* docstring); + + // Constructors, specifying non-default __init__ + template + class_(char const* name, Init); + template + class_(char const* name, char const* docstring, Init); + + // Exposing additional __init__ functions + template + class_& def(Init); + + // defining methods + template + class_& def(char const* name, F f); + template + class_& def(char const* name, Fn fn, A1 const&); + template + class_& def(char const* name, Fn fn, A1 const&, A2 const&); + template + class_& def(char const* name, Fn fn, A1 const&, A2 const&, A3 const&); + + // declaring method as static + class_& staticmethod(char const* name); + + // exposing operators + template + class_& def(detail::operator_); + + // Raw attribute modification + template + class_& setattr(char const* name, U const&); + + // exposing data members + template + class_& def_readonly(char const* name, D T::*pm); + + template + class_& def_readwrite(char const* name, D T::*pm); + + // exposing static data members + template + class_& def_readonly(char const* name, D const& d); + template + class_& def_readwrite(char const* name, D& d); + + // property creation + template + void add_property(char const* name, Get const& fget, char const* doc=0); + template + void add_property( + char const* name, Get const& fget, Set const& fset, char const* doc=0); + + template + void add_static_property(char const* name, Get const& fget); + template + void add_static_property(char const* name, Get const& fget, Set const& fset); + + // pickle support + template + self& def_pickle(PickleSuite const&); + self& enable_pickling(); + }; + }} +`` +[endsect] +[section Class template `class_` constructors] +`` + class_(char const* name); + class_(char const* name, char const* docstring); + template + class_(char const* name, Init init_spec); + template + class_(char const* name, char const* docstring, Init init_spec); +`` + +[variablelist + [[Requires][name is an ntbs which conforms to Python's identifier naming rules. If docstring is supplied, it must be an ntbs. If `init_spec` is supplied, it must be either the special enumeration constant `no_init` or an init-expression compatible with `T`.]] + [[Effects][Constructs a `class_` object holding a Boost.Python extension class named name. The named attribute of the current scope is bound to the new extension class. + * If supplied, the value of docstring is bound to the `__doc__` attribute of the extension class. + * If `init_spec` is `no_init`, a special `__init__` function is generated which always raises a Python exception. Otherwise, `this->def(init_spec)` is called. + * If `init_spec` is not supplied, `this->def(init<>())` is called.]] + [[Rationale][Allowing the user to specify constructor arguments in the `class_<>` constructor helps her to avoid the common run-time errors which result from invoking wrapped member functions without having exposed an `__init__` function which creates the requisite `T` instance. Types which are not default-constructible will cause a compile-time error unless `Init` is supplied. The user must always supply name as there is currently no portable method to derive the text of the class name from its type.]] +] +[endsect] +[section Class template `class_` modifier functions] +`` + template + class_& def(Init init_expr); +`` + +[variablelist + [[Requires][`init_expr` is the result of an init-expression compatible with `T`.]] + [[Effects][For each valid prefix `P` of `Init`, adds an `__init__(...)` function overload to the extension class accepting P as arguments. Each overload generated constructs an object of HeldType according to the semantics described above, using a copy of init_expr's call policies. If the longest valid prefix of Init contains N types and init_expr holds M keywords, an initial sequence of the keywords are used for all but the first N - M arguments of each overload.]] + [[Returns][`*this`]] + [[Rationale][Allows users to easily expose a class' constructor to Python.]] +] +`` + template + class_& def(char const* name, Fn fn); + template + class_& def(char const* name, Fn fn, A1 const& a1); + template + class_& def(char const* name, Fn fn, A1 const& a1, A2 const& a2); + template + class_& def(char const* name, Fn fn, A1 const& a1, A2 const& a2, A3 const& a3); +`` +[variablelist + [[Requires][name is an ntbs which conforms to Python's identifier naming rules. + * If a1 is the result of an overload-dispatch-expression, only the second form is allowed and fn must be a pointer to function or pointer to member function whose arity is the same as A1's maximum arity. + + [*Effects:] For each prefix P of Fn's sequence of argument types, beginning with the one whose length is A1's minimum arity, adds a name(...) method overload to the extension class. Each overload generated invokes a1's call-expression with P, using a copy of a1's call policies. If the longest valid prefix of A1 contains N types and a1 holds M keywords, an initial sequence of the keywords are used for all but the first N - M arguments of each overload. + +* Otherwise, a single method overload is built around fn, which must not be null: + + * If fn is a function pointer, its first argument must be of the form U, U cv&, U cv*, or U cv* const&, where T* is convertible to U*, and a1-a3, if supplied, may be selected in any order from the table below. + * Otherwise, if fn is a member function pointer, its target must be T or one of its public base classes, and a1-a3, if supplied, may be selected in any order from the table below. + * Otherwise, Fn must be [derived from] object, and a1-a2, if supplied, may be selcted in any order from the first two rows of the table below. To be useful, fn should be callable. + [table + [[Mnemonic Name][Requirements/Type properties][Effects]] + [[docstring][Any ntbs][Value will be bound to the __doc__ attribute of the resulting method overload. If an earlier overload supplied a docstring, two newline characters and the new docstring are appended to it.]] + [[policies][A model of CallPolicies][A copy will be used as the call policies of the resulting method overload.]] + [[keywords][The result of a keyword-expression specifying no more arguments than the arity of fn.][A copy will be used as the call policies of the resulting method overload.]] + ] +]] + [[Returns][`*this`]] +] +``class_& staticmethod(char const* name);`` +[variablelist + [[Requires][name is an ntbs which conforms to Python's identifier naming rules, and corresponds to a method whose overloads have all been defined.]] + [[Effects][Replaces the existing named attribute x with the result of invoking staticmethod(x) in Python. Specifies that the corresponding method is static and therefore no object instance will be passed to it. This is equivalent to the Python statement:]] +] +``setattr(self, name, staticmethod(getattr(self, name)))`` +[variablelist + [[Note][Attempting to invoke def(name,...) after invoking staticmethod(name) will raise a RuntimeError.]] + [[Returns][`*this`]] +] +`` + template + class_& setattr(char const* name, U const& u); +`` +[variablelist + [[Requires][name is an ntbs which conforms to Python's identifier naming rules.]] + [[Effects][Converts u to Python and adds it to the attribute dictionary of the extension class: + ``PyObject_SetAttrString(this->ptr(), name, object(u).ptr());``]] + [[Returns][`*this`]] +] +`` + template + void add_property(char const* name, Get const& fget, char const* doc=0); + template + void add_property( + char const* name, Get const& fget, Set const& fset, char const* doc=0); +`` +[variablelist + [[Requires][name is an ntbs which conform to Python's identifier naming rules.]] + [[Effects][Creates a new Python property class instance, passing object(fget) (and object(fset) in the second form) with an (optional) docstring doc to its constructor, then adds that property to the Python class object under construction with the given attribute name.]] + [[Returns][`*this`]] + [[Rationale][Allows users to easily expose functions that can be invoked from Python with attribute access syntax.]] +] +`` + template + void add_static_property(char const* name, Get const& fget); + template + void add_static_property(char const* name, Get const& fget, Set const& fset); +`` +[variablelist + [[Requires][name is an ntbs which conforms to Python's identifier naming rules.]] + [[Effects][Creates a Boost.Python.StaticProperty object, passing object(fget) (and object(fset) in the second form) to its constructor, then adds that property to the Python class under construction with the given attribute name. StaticProperty is a special subclass of Python's property class which can be called without an initial self argument.]] + [[Returns][`*this`]] + [[Rationale][Allows users to easily expose functions that can be invoked from Python with static attribute access syntax.]] +] +`` + template + class_& def_readonly(char const* name, D T::*pm, char const* doc=0); + template + class_& def_readonly(char const* name, D const& d); +`` +[variablelist + [[Requires][name is an ntbs which conforms to Python's identifier naming rules. doc is also an ntbs.]] + [[Effects][``this->add_property(name, make_getter(pm), doc);`` and ``this->add_static_property(name, make_getter(d));`` respectively.]] + [[Returns][`*this`]] + [[Rationale][Allows users to easily expose a class' data member or free variable such that it can be inspected from Python with a natural syntax.]] +] +`` + template + class_& def_readwrite(char const* name, D T::*pm, char const* doc=0); + template + class_& def_readwrite(char const* name, D& d); +`` +[variablelist +[[Effects][``this->add_property(name, make_getter(pm), make_setter(pm), doc);`` and ``this->add_static_property(name, make_getter(d), make_setter(d));`` respectively.]] +[[Returns][`*this`]] +[[Rationale][Allows users to easily expose a class' data or free variable member such that it can be inspected and set from Python with a natural syntax.]] +] +`` + template + class_& def_pickle(PickleSuite const&); +`` +[variablelist +[[Requires][PickleSuite must be publically derived from pickle_suite.]] +[[Effects][Defines a legal combination of the special attributes and methods: __getinitargs__, __getstate__, __setstate__, __getstate_manages_dict__, __safe_for_unpickling__, __reduce__]] +[[Returns][`*this`]] +[[Rationale][Provides an easy to use high-level interface for establishing complete pickle support for the wrapped class. The user is protected by compile-time consistency checks.]] +] +``class_& enable_pickling();`` +[variablelist +[[Effects][Defines the __reduce__ method and the __safe_for_unpickling__ attribute.]] +[[Returns][`*this`]] +[[Rationale][Light-weight alternative to def_pickle(). Enables implementation of pickle support from Python.]] +] +[endsect] +[endsect] +[section Class template bases] +An MPL sequence which can be used in class_<...> instantiations indicate a list of base classes. +[section Class template bases synopsis] +`` +namespace boost { namespace python +{ + template + struct bases + {}; +}} +`` +[endsect] +[endsect] +[endsect] +[section Examples] +Given a C++ class declaration: +`` +class Foo : public Bar, public Baz +{ + public: + Foo(int x, char const* y); + Foo(double); + + std::string const& name() { return m_name; } + void name(char const*); + + double value; // public data + private: + ... +}; +`` +A corresponding Boost.Python extension class can be created with: +`` +using namespace boost::python; + +class_ >("Foo", + "This is Foo's docstring." + "It describes our Foo extension class", + + init(args("x","y"), "__init__ docstring") + ) + .def(init()) + .def("get_name", &Foo::get_name, return_internal_reference<>()) + .def("set_name", &Foo::set_name) + .def_readwrite("value", &Foo::value); +`` +[endsect] +[endsect] diff --git a/doc/reference/components.qbk b/doc/reference/components.qbk new file mode 100644 index 00000000..70a2969a --- /dev/null +++ b/doc/reference/components.qbk @@ -0,0 +1,18 @@ +[chapter High Level Components + [quickbook 1.7] +] + +[include class.qbk] +[include def.qbk] +[include def_visitor.qbk] +[include docstring_options.qbk] +[include enum.qbk] +[include errors.qbk] +[include exception_translator.qbk] +[include init.qbk] +[include iterator.qbk] +[include module.qbk] +[include operators.qbk] +[include scope.qbk] +[include stl_iterator.qbk] +[include wrapper.qbk] diff --git a/doc/reference/concepts.qbk b/doc/reference/concepts.qbk new file mode 100644 index 00000000..7d3e2c92 --- /dev/null +++ b/doc/reference/concepts.qbk @@ -0,0 +1,134 @@ +[chapter Concepts + [quickbook 1.7] +] + +[section CallPolicies] +[section Introduction] + +Models of the CallPolicies concept are used to specialize the behavior of Python callable objects +generated by Boost.Python to wrapped C++ objects like function and member function pointers, +providing three behaviors: + +# `precall` - Python argument tuple management before the wrapped object is invoked +# `result_converter` - C++ return value handling +# `postcall` - Python argument tuple and result management after the wrapped object is invoked +# `extract_return_type` - metafunction for extracting the return type from a given signature type sequence + +[endsect] +[section CallPolicies Composition] + +In order to allow the use of multiple models of CallPolicies in the same callable object, +Boost.Python's CallPolicies class templates provide a chaining interface which allows them to be +recursively composed. This interface takes the form of an optional template parameter, Base which +defaults to default_call_policies. By convention, the precall function of the Base is invoked after +the precall function supplied by the outer template, and the postcall function of the Base is invoked +before the postcall function of the outer template. If a result_converter is supplied by the outer +template, it replaces any result_converter supplied by the Base. For an example, see +return_internal_reference. + +[endsect] +[section Concept Requirements] +[table + [[Expression][Type][Result/Semantics]] + [[`x.precall(a)`][convertible to bool] + [returns false and PyErr_Occurred() != 0 upon failure, true otherwise.]] + [[`P::result_converter`][A model of ResultConverterGenerator.] + [An MPL unary Metafunction Class used produce the "preliminary" result object.]] + [[`x.postcall(a, r)`][convertible to PyObject*] + [0 0 and PyErr_Occurred() != 0 upon failure. Must "conserve references" even in the event of an exception. In other words, if r is not returned, its reference count must be decremented; if another existing object is returned, its reference count must be incremented.]] + [[`P::extract_return_type`][A model of Metafunction.] + [An MPL unary Metafunction used extract the return type from a given signature. By default it is derived from mpl::front.]] +] +[endsect] +[endsect] +[section Dereferenceable] +[section Introduction] +Instances of a Dereferenceable type can be used like a pointer to access an lvalue. +[endsect] +[section Concept Requirements] +In the table below, T is a model of Dereferenceable, and x denotes an object of type T. In addition, all pointers are Dereferenceable. +[table + [[Expression][Result][Operational Semantics]] + [[`get_pointer(x)`][convertible to pointee::type*] + [&*x, or a null pointer ]] +] +[endsect] +[endsect] +[section Extractor] +[section Introduction] +An Extractor is a class which Boost.Python can use to extract C++ objects from Python objects, and is typically used by facilities that define from_python conversions for "traditional" Python extension types. +[endsect] +[section Concept Requirements] +In the table below, X denotes a model of Extractor and a denotes an instance of a Python object type. +[table + [[Expression][Type][Semantics]] + [[`X::execute(a)`][non-void ] + [Returns the C++ object being extracted. The execute function must not be overloaded.]] + [[`&a.ob_type`][PyTypeObject**] + [Points to the ob_type field of an object which is layout-compatible with PyObject]] +] +[endsect] +[section Notes] +Informally, an Extractor's execute member must be a non-overloaded static function whose single argument is a Python object type. Acceptable Python object types include those publicly (and unambiguously) derived from PyObject, and POD types which are layout-compatible with PyObject. +[endsect] +[endsect] +[section HolderGenerator] +[section Introduction] +A HolderGenerator is a unary metafunction class which returns types suitable for holding instances of its argument in a wrapped C++ class instance. +[endsect] +[section Concept Requirements] +In the table below, G denotes an type which models HolderGenerator, and X denotes a class type. +[table + [[Expression][Requirements]] + [[`G::apply::type`][A concrete subclass of instance_holder which can hold objects of type X. ]] +] +[endsect] +[endsect] +[section ResultConverter] +[section Introduction] +A ResultConverter for a type T is a type whose instances can be used to convert C++ return values of type T to_python. A ResultConverterGenerator is an MPL unary metafunction class which, given the return type of a C++ function, returns a ResultConverter for that type. ResultConverters in Boost.Python generally inspect library's registry of converters to find a suitable converter, but converters which don't use the registry are also possible. +[endsect] +[section ResultConverter Concept Requirements] +In the table below, C denotes a ResultConverter type for a type R , c denotes an object of type C , and r denotes an object of type R. +[table + [[Expression][Type][Semantics]] + [[`C c`][] + [Constructs a c object.]] + [[`c.convertible()`][convertible to bool] + [false iff no conversion from any R value to a Python object is possible.]] + [[`c(r)`][convertible to PyObject*] + [A pointer to a Python object corresponding to r, or 0 iff r could not be converted to_python, in which case PyErr_Occurred should return non-zero.]] + [[`c.get_pytype()`][PyTypeObject const *] + [A pointer to a Python Type object corresponding to result of the conversion, or 0. Used for documentation generation. If 0 is returned the generated type in the documentation will be object .]] +] +[endsect] +[section ResultConverterGenerator Concept Requirements] +In the table below, G denotes a ResultConverterGenerator type and R denotes a possible C++ function return type. +[table + [[Expression][Requirements]] + [[`G::apply::type`][A ResultConverter type for R.]] +] +[endsect] +[endsect] +[section ObjectWrapper] +[section Introduction] +This page defines two concepts used to describe classes which manage a Python objects, and which are intended to support usage with a Python-like syntax. +[endsect] +[section ObjectWrapper Concept Requirements] +Models of the ObjectWrapper concept have object as a publicly-accessible base class, and are used to supply special construction behavior and/or additional convenient functionality through (often templated) member functions. Except when the return type R is itself an TypeWrapper, a member function invocation of the form ``x.some_function(a1, a2,...an)`` always has semantics equivalent to: +``extract(x.attr("some_function")(object(a1), object(a2),...object(an)))()`` (see [link caveat] below). +[endsect] +[section TypeWrapper Concept Requirements] +TypeWrapper is a refinement of ObjectWrapper which is associated with a particular Python type X. For a given TypeWrapper T, a valid constructor expression ``T(a1, a2,...an)`` builds a new T object managing the result of invoking X with arguments corresponding to ``object(a1), object(a2),...object(an)``. +When used as arguments to wrapped C++ functions, or as the template parameter to extract<>, only instances of the associated Python type will be considered a match. +[endsect] +[section Caveat] +The upshot of the special member function invocation rules when the return type is a TypeWrapper is that it is possible for the returned object to manage a Python object of an inappropriate type. This is not usually a serious problem; the worst-case result is that errors will be detected at runtime a little later than they might otherwise be. For an example of how this can occur, note that the dict member function items returns an object of type list. Now suppose the user defines this dict subclass in Python: +`` + >>> class mydict(dict): + ... def items(self): + ... return tuple(dict.items(self)) # return a tuple +`` +Since an instance of mydict is also an instance of dict, when used as an argument to a wrapped C++ function, boost::python::dict can accept objects of Python type mydict. Invoking items() on this object can result in an instance of boost::python::list which actually holds a Python tuple. Subsequent attempts to use list methods (e.g. append, or any other mutating operation) on this object will raise the same exception that would occur if you tried to do it from Python. +[endsect] +[endsect] diff --git a/doc/reference/conversion.qbk b/doc/reference/conversion.qbk new file mode 100644 index 00000000..6f6268b4 --- /dev/null +++ b/doc/reference/conversion.qbk @@ -0,0 +1,10 @@ +[chapter To/From Python Type Conversion + [quickbook 1.7] +] + +[include extract.qbk] +[include implicit.qbk] +[include lvalue_from_pytype.qbk] +[include opaque_pointer_converter.qbk] +[include to_python_converter.qbk] +[include register_ptr_to_python.qbk] diff --git a/doc/reference/copy_const_reference.qbk b/doc/reference/copy_const_reference.qbk new file mode 100644 index 00000000..0066a395 --- /dev/null +++ b/doc/reference/copy_const_reference.qbk @@ -0,0 +1,58 @@ +[section copy_const_reference.hpp] +[section Class `copy_const_reference`] +copy_const_reference is a model of ResultConverterGenerator which can be used to wrap C++ functions returning a reference-to-const type such that the referenced value is copied into a new Python object. +`` +namespace boost { namespace python +{ + struct copy_const_reference + { + template struct apply; + }; +}} +`` +[endsect] +[section Class `copy_const_reference` metafunctions] +``template struct apply`` +[variablelist +[[Requires][T is U const& for some U.]] +[[Returns][typedef to_python_value type;]] +] +[endsect] +[section Example] +C++ module definition: +`` +#include +#include +#include +#include + +// classes to wrap +struct Bar { int x; } + +struct Foo { + Foo(int x) : { b.x = x; } + Bar const& get_bar() const { return b; } + private: + Bar b; +}; + +// Wrapper code +using namespace boost::python; +BOOST_PYTHON_MODULE(my_module) +{ + class_("Bar"); + + class_("Foo", init()) + .def("get_bar", &Foo::get_bar + , return_value_policy()) + ; +} +`` +Python code: +`` +>>> from my_module import * +>>> f = Foo(3) # create a Foo object +>>> b = f.get_bar() # make a copy of the internal Bar object +`` +[endsect] +[endsect] diff --git a/doc/reference/copy_non_const_reference.qbk b/doc/reference/copy_non_const_reference.qbk new file mode 100644 index 00000000..d30d4328 --- /dev/null +++ b/doc/reference/copy_non_const_reference.qbk @@ -0,0 +1,58 @@ +[section copy_non_const_reference.hpp] +[section Class `copy_non_const_reference`] +copy_non_const_reference is a model of ResultConverterGenerator which can be used to wrap C++ functions returning a reference-to-non-const type such that the referenced value is copied into a new Python object. +`` +namespace boost { namespace python +{ + struct copy_non_const_reference + { + template struct apply; + }; +}} +`` +[endsect] +[section Class `copy_non_const_reference` metafunctions] +``template struct apply`` +[variablelist +[[Requires][`T` is `U &` for some non-const `U`.]] +[[Returns][`typedef to_python_value type`;]] +] +[endsect] +[section Example] +C++ module definition: +`` +#include +#include +#include +#include + +// classes to wrap +struct Bar { int x; } + +struct Foo { + Foo(int x) : { b.x = x; } + Bar& get_bar() { return b; } + private: + Bar b; +}; + +// Wrapper code +using namespace boost::python; +BOOST_PYTHON_MODULE(my_module) +{ + class_("Bar"); + + class_("Foo", init()) + .def("get_bar", &Foo::get_bar + , return_value_policy()) + ; +} +`` +Python code: +`` +>>> from my_module import * +>>> f = Foo(3) # create a Foo object +>>> b = f.get_bar() # make a copy of the internal Bar object +`` +[endsect] +[endsect] diff --git a/doc/reference/data_members.qbk b/doc/reference/data_members.qbk new file mode 100644 index 00000000..6b034aea --- /dev/null +++ b/doc/reference/data_members.qbk @@ -0,0 +1,98 @@ +[section data_members.hpp] +[section Introduction] +make_getter() and make_setter() are the functions used internally by class_<>::def_readonly and class_<>::def_readwrite to produce Python callable objects which wrap C++ data members. +[endsect] +[section Functions] +`` +template +object make_getter(D C::*pm); + +template +object make_getter(D C::*pm, Policies const& policies); +`` +[variablelist +[[Requires][Policies is a model of CallPolicies.]] +[[Effects][Creates a Python callable object which accepts a single argument that can be converted from_python to C*, and returns the corresponding member D member of the C object, converted to_python. If policies is supplied, it will be applied to the function as described here. Otherwise, the library attempts to determine whether D is a user-defined class type, and if so uses return_internal_reference<> +for Policies. Note that this test may inappropriately choose return_internal_reference<> in some cases when D is a smart pointer type. This is a known defect.]] +[[Returns][An instance of object which holds the new Python callable object.]] +] +`` +template +object make_getter(D const& d); +template +object make_getter(D const& d, Policies const& policies); + +template +object make_getter(D const* p); +template +object make_getter(D const* p, Policies const& policies); +`` +[variablelist +[[Requires][Policies is a model of CallPolicies.]] +[[Effects][Creates a Python callable object which accepts no arguments and returns d or *p, converted to_python on demand. If policies is supplied, it will be applied to the function as described here. Otherwise, the library attempts to determine whether D is a user-defined class type, and if so uses reference_existing_object for Policies.]] +[[Returns][An instance of object which holds the new Python callable object.]] +] +`` +template +object make_setter(D C::*pm); + +template +object make_setter(D C::*pm, Policies const& policies); +`` +[variablelist +[[Requires][Policies is a model of CallPolicies.]] +[[Effects][Creates a Python callable object which, when called from Python, expects two arguments which can be converted from_python to C* and D const&, respectively, and sets the corresponding D member of the C object. If policies is supplied, it will be applied to the function as described here.]] +[[Returns][An instance of object which holds the new Python callable object.]] +] +`` +template +object make_setter(D& d); +template +object make_setter(D& d, Policies const& policies); + +template +object make_setter(D* p); +template +object make_setter(D* p, Policies const& policies); +`` +[variablelist +[[Requires][Policies is a model of CallPolicies.]] +[[Effects][Creates a Python callable object which accepts one argument, which is converted from Python to D const& and written into d or *p, respectively. If policies is supplied, it will be applied to the function as described here.]] +[[Returns][An instance of object which holds the new Python callable object.]] +] +[endsect] +[section Example] +The code below uses make_getter and make_setter to expose a data member as functions: +`` +#include +#include +#include + +struct X +{ + X(int x) : y(x) {} + int y; +}; + +using namespace boost::python; + +BOOST_PYTHON_MODULE_INIT(data_members_example) +{ + class_("X", init()) + .def("get", make_getter(&X::y)) + .def("set", make_setter(&X::y)) + ; +} +`` +It can be used this way in Python: +`` +>>> from data_members_example import * +>>> x = X(1) +>>> x.get() +1 +>>> x.set(2) +>>> x.get() +2 +`` +[endsect] +[endsect] diff --git a/doc/reference/def.qbk b/doc/reference/def.qbk new file mode 100644 index 00000000..11032e4a --- /dev/null +++ b/doc/reference/def.qbk @@ -0,0 +1,54 @@ +[section def.hpp] +[section Introduction] +`def()` is the function which can be used to expose C++ functions and callable objects as Python functions in the current scope. +[endsect] +[section Functions] +`` +template +void def(char const* name, F f); + +template +void def(char const* name, Fn fn, A1 const&); + +template +void def(char const* name, Fn fn, A1 const&, A2 const&); + +template +void def(char const* name, Fn fn, A1 const&, A2 const&, A3 const&); +`` +[variablelist +[[Requires][name is an ntbs which conforms to Python's identifier naming rules. + +* If `Fn` is [derived from] object, it will be added to the current scope as a single overload. To be useful, fn should be callable. +* If a1 is the result of an overload-dispatch-expression, only the second form is allowed and fn must be a pointer to function or pointer to member function whose arity is the same as A1's maximum arity. + + [*Effects:] For each prefix P of Fn's sequence of argument types, beginning with the one whose length is A1's minimum arity, adds a name(...) function overload to the current scope. Each overload generated invokes a1's call-expression with P, using a copy of a1's call policies. If the longest valid prefix of A1 contains N types and a1 holds M keywords, an initial sequence of the keywords are used for all but the first N - M arguments of each overload. + +* Otherwise, fn must be a non-null function or member function pointer, and a single function overload built around fn is added to the current scope. If any of a1-a3 are supplied, they may be selected in any order from the table below. + + [table + [[Mnemonic Name][Requirements/Type properties][Effects]] + [[docstring][Any ntbs][Value will be bound to the __doc__ attribute of the resulting method overload.]] + [[policies][A model of CallPolicies][A copy will be used as the call policies of the resulting method overload.]] + [[keywords][The result of a keyword-expression specifying no more arguments than the arity of fn.][A copy will be used as the call policies of the resulting method overload.]] +] +]] +] +[endsect] +[section Example] +`` +#include +#include +#include + +using namespace boost::python; + +char const* foo(int x, int y) { return "foo"; } + +BOOST_PYTHON_MODULE(def_test) +{ + def("foo", foo, args("x", "y"), "foo's docstring"); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/def_visitor.qbk b/doc/reference/def_visitor.qbk new file mode 100644 index 00000000..57a5fe1d --- /dev/null +++ b/doc/reference/def_visitor.qbk @@ -0,0 +1,61 @@ +[section def_visitor.hpp] +[section Introduction] + provides a generic visitation interface through which the class_ def member functionality can be extended non-intrusively to avoid cluttering the class_ interface. It declares the def_visitor class template, which is parameterized on the derived type DerivedVisitor, which provides the actual def functionality through its visit member functions. +[endsect] +[section Class `def_visitor`] +The class def_visitor is a base class paramaterized by its derived class. The def_visitor class is a protocol class. Its derived class, DerivedVisitor, is expected to have a member function visit. The def_visitor class is never instantiated directly. Instead, an instance of its subclass, DerivedVisitor, is passed on as an argument to the class_ def member function. + +`` +namespace boost { namespace python { + + template + class def_visitor {}; +} +`` + +[variablelist + [[Requires][The client supplied class DerivedVisitor template parameter is expected to: + * be privately derived from def_visitor + * grant friend access to class def_visitor_access + * define either or both visit member functions listed in the table below: + [table + [[Expression][Return Type][Requirements][Effects]] + [[`visitor.visit(cls)`][`void`] + [cls is an instance of a class_ being wrapped to Python. visitor is a def_visitor derived class.] + [A call to cls.def(visitor) forwards to this member function.]] + [[`visitor.visit(cls, name, options)`][`void`] + [cls is a class_ instance, name is a C string. visitor is a def_visitor derived class. options is a context specific optional argument.] + [A call to cls.def(name, visitor) or cls.def(name, visitor, options) forwards to this member function. ]]] + ]] + ] +[endsect] +[section Example] +`` +class X {/*...*/}; + +class my_def_visitor : boost::python::def_visitor +{ + friend class def_visitor_access; + + template + void visit(classT& c) const + { + c + .def("foo", &my_def_visitor::foo) + .def("bar", &my_def_visitor::bar) + ; + } + + static void foo(X& self); + static void bar(X& self); +}; + +BOOST_PYTHON_MODULE(my_ext) +{ + class_("X") + .def(my_def_visitor()) + ; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/default_call_policies.qbk b/doc/reference/default_call_policies.qbk new file mode 100644 index 00000000..3569e0f7 --- /dev/null +++ b/doc/reference/default_call_policies.qbk @@ -0,0 +1,58 @@ +[section default_call_policies.hpp] +[section Class `default_call_policies`] +default_call_policies is a model of CallPolicies with no precall or postcall behavior and a result_converter which handles by-value returns. Wrapped C++ functions and member functions use default_call_policies unless otherwise specified. You may find it convenient to derive new models of CallPolicies from default_call_policies. +`` +namespace boost { namespace python +{ + struct default_call_policies + { + static bool precall(PyObject*); + static PyObject* postcall(PyObject*, PyObject* result); + typedef default_result_converter result_converter; + template struct extract_return_type : mpl::front{}; + }; +}} +`` +[endsect] +[section Class `default_call_policies` static functions] +``bool precall(PyObject*);`` +[variablelist +[[Returns][true]] +[[Throws][nothing]] +] +``PyObject* postcall(PyObject*, PyObject* result);`` +[variablelist +[[Returns][result]] +[[Throws][nothing]] +] +[endsect] +[section Class `default_result_converter`] +default_result_converter is a model of ResultConverterGenerator which can be used to wrap C++ functions returning non-pointer types, `char const*`, and `PyObject*`, by-value. +`` +namespace boost { namespace python +{ + struct default_result_converter + { + template struct apply; + }; +}} +`` +[endsect] +[section Class `default_result_converter` metafunctions] +``template struct apply`` +[variablelist +[[Requires][T is not a reference type. If T is a pointer type, T is const char* or PyObject*. ]] +[[Returns][typedef to_python_value type;]] +] +[endsect] +[section Example] +This example comes from the Boost.Python implementation itself. Because the return_value_policy class template does not implement precall or postcall behavior, its default base class is default_call_policies: +`` +template +struct return_value_policy : Base +{ + typedef Handler result_converter; +}; +`` +[endsect] +[endsect] diff --git a/doc/reference/dict.qbk b/doc/reference/dict.qbk new file mode 100644 index 00000000..c6cbcfbd --- /dev/null +++ b/doc/reference/dict.qbk @@ -0,0 +1,71 @@ +[section dict.hpp] +[section Introduction] +Exposes a TypeWrapper for the Python dict type. +[endsect] +[section Class `dict`] +Exposes the mapping protocol of Python's built-in dict type. The semantics of the constructors and member functions defined below can be fully understood by reading the TypeWrapper concept definition. Since dict is publicly derived from object, the public object interface applies to dict instances as well. +`` +namespace boost { namespace python +{ + class dict : public object + { + dict(); + + template< class T > + dict(T const & data); + + // modifiers + void clear(); + dict copy(); + + template + tuple popitem(); + + template + object setdefault(T const &k); + + template + object setdefault(T1 const & k, T2 const & d); + + void update(object_cref E); + + template< class T > + void update(T const & E); + + // observers + list values() const; + + object get(object_cref k) const; + + template + object get(T const & k) const; + + object get(object_cref k, object_cref d) const; + object get(T1 const & k, T2 const & d) const; + + bool has_key(object_cref k) const; + + template< class T > + bool has_key(T const & k) const; + + list items() const; + object iteritems() const; + object iterkeys() const; + object itervalues() const; + list keys() const; + }; +}} +`` +[endsect] +[section Example] +`` +using namespace boost::python; +dict swap_object_dict(object target, dict d) +{ + dict result = extract(target.attr("__dict__")); + target.attr("__dict__") = d; + return result; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/docstring_options.qbk b/doc/reference/docstring_options.qbk new file mode 100644 index 00000000..a937d477 --- /dev/null +++ b/doc/reference/docstring_options.qbk @@ -0,0 +1,214 @@ +[section docstring_options.hpp] +[section Introduction] +Boost.Python supports user-defined docstrings with automatic appending of C++ signatures. These features are enabled by default. The class docstring_options is available to selectively suppress the user-defined docstrings, signatures, or both. +[endsect] +[section Class `docstring_options`] +Controls the appearance of docstrings of wrapped functions and member functions for the life-time of the instance. The instances are noncopyable to eliminate the possibility of surprising side effects. + +``namespace boost { namespace python { + + class docstring_options : boost::noncopyable + { + public: + docstring_options(bool show_all=true); + docstring_options(bool show_user_defined, bool show_signatures); + docstring_options(bool show_user_defined, bool show_py_signatures, bool show_cpp_signatures); + ~docstring_options(); + void disable_user_defined(); + void enable_user_defined(); + void disable_signatures(); + void enable_signatures(); + void disable_py_signatures(); + void enable_py_signatures(); + void disable_cpp_signatures(); + void enable_cpp_signatures(); + void disable_all(); + void enable_all(); + }; + +}} + +`` +[endsect] +[section Class dostring_options constructors] +`` +docstring_options(bool show_all=true); +`` +[variablelist +[[Effects][Constructs a docstring_options object which controls the appearance of function and member-function docstrings defined in the code that follows. If show_all is true, both the user-defined docstrings and the automatically generated Python and C++ signatures are shown. If show_all is false the __doc__ attributes are None.]] +] +`` +docstring_options(bool show_user_defined, bool show_signatures); +`` +[variablelist +[[Effects][Constructs a docstring_options object which controls the appearance of function and member-function docstrings defined in the code that follows. Iff show_user_defined is true, the user-defined docstrings are shown. Iff show_signatures is true, Python and C++ signatures are automatically added. If both show_user_defined and show_signatures are false, the __doc__ attributes are None.]] +] +`` +docstring_options(bool show_user_defined, bool show_py_signatures, bool show_cpp_signatures); +`` +[variablelist +[[Effects][Constructs a docstring_options object which controls the appearance of function and member-function docstrings defined in the code that follows. Iff show_user_defined is true, the user-defined docstrings are shown. Iff show_py_signatures is true, Python signatures are automatically added. Iff show_cpp_signatures is true, C++ signatures are automatically added. If all parameters are false, the __doc__ attributes are None.]] +] +[endsect] +[section Class docstring_options destructor] +``~docstring_options();`` +[variablelist +[[Effects][Restores the previous state of the docstring options. In particular, if docstring_options instances are in nested C++ scopes the settings effective in the enclosing scope are restored. If the last docstring_options instance goes out of scope the default "all on" settings are restored.]]] +[endsect] +[section Class docstring_options modifier functions] +`` +void disable_user_defined(); +void enable_user_defined(); +void disable_signatures(); +void enable_signatures(); +void disable_py_signatures(); +void enable_py_signatures(); +void disable_cpp_signatures(); +void enable_cpp_signatures(); +void disable_all(); +void enable_all(); +`` +These member functions dynamically change the appearance of docstrings in the code that follows. The *_user_defined() and *_signatures() member functions are provided for fine-grained control. The *_all() member functions are convenient shortcuts to manipulate all settings simultaneously. +[endsect] +[section Example] +[section Docstring options defined at compile time] +`` +#include +#include +#include + +void foo() {} + +BOOST_PYTHON_MODULE(demo) +{ + using namespace boost::python; + docstring_options doc_options(DEMO_DOCSTRING_SHOW_ALL); + def("foo", foo, "foo doc"); +} +`` +If compiled with -DDEMO_DOCSTRING_SHOW_ALL=true: +`` +>>> import demo +>>> print demo.foo.__doc__ +foo() -> None : foo doc +C++ signature: + foo(void) -> void +`` +If compiled with -DDEMO_DOCSTRING_SHOW_ALL=false: +`` +>>> import demo +>>> print demo.foo.__doc__ +None +`` +[endsect] +[section Selective suppressions] +`` +#include +#include +#include +#include + +int foo1(int i) { return i; } +int foo2(long l) { return static_cast(l); } +int foo3(float f) { return static_cast(f); } +int foo4(double d) { return static_cast(d); } + +BOOST_PYTHON_MODULE(demo) +{ + using namespace boost::python; + docstring_options doc_options; + def("foo1", foo1, arg("i"), "foo1 doc"); + doc_options.disable_user_defined(); + def("foo2", foo2, arg("l"), "foo2 doc"); + doc_options.disable_signatures(); + def("foo3", foo3, arg("f"), "foo3 doc"); + doc_options.enable_user_defined(); + def("foo4", foo4, arg("d"), "foo4 doc"); + doc_options.enable_py_signatures(); + def("foo5", foo4, arg("d"), "foo5 doc"); + doc_options.disable_py_signatures(); + doc_options.enable_cpp_signatures(); + def("foo6", foo4, arg("d"), "foo6 doc"); +} +`` +Python code: +`` +>>> import demo +>>> print demo.foo1.__doc__ +foo1( (int)i) -> int : foo1 doc +C++ signature: + foo1(int i) -> int +>>> print demo.foo2.__doc__ +foo2( (int)l) -> int : +C++ signature: + foo2(long l) -> int +>>> print demo.foo3.__doc__ +None +>>> print demo.foo4.__doc__ +foo4 doc +>>> print demo.foo5.__doc__ +foo5( (float)d) -> int : foo5 doc +>>> print demo.foo6.__doc__ +foo6 doc +C++ signature: + foo6(double d) -> int +`` +[endsect] +[section Wrapping from multiple C++ scopes] +`` +#include +#include +#include +#include + +int foo1(int i) { return i; } +int foo2(long l) { return static_cast(l); } + +int bar1(int i) { return i; } +int bar2(long l) { return static_cast(l); } + +namespace { + + void wrap_foos() + { + using namespace boost::python; + // no docstring_options here + // -> settings from outer C++ scope are in effect + def("foo1", foo1, arg("i"), "foo1 doc"); + def("foo2", foo2, arg("l"), "foo2 doc"); + } + + void wrap_bars() + { + using namespace boost::python; + bool show_user_defined = true; + bool show_signatures = false; + docstring_options doc_options(show_user_defined, show_signatures); + def("bar1", bar1, arg("i"), "bar1 doc"); + def("bar2", bar2, arg("l"), "bar2 doc"); + } +} + +BOOST_PYTHON_MODULE(demo) +{ + boost::python::docstring_options doc_options(false); + wrap_foos(); + wrap_bars(); +} +`` +Python code: +`` +>>> import demo +>>> print demo.foo1.__doc__ +None +>>> print demo.foo2.__doc__ +None +>>> print demo.bar1.__doc__ +bar1 doc +>>> print demo.bar2.__doc__ +bar2 doc +`` + +[endsect] +[endsect] +[endsect] diff --git a/doc/reference/embedding.qbk b/doc/reference/embedding.qbk new file mode 100644 index 00000000..77461b9b --- /dev/null +++ b/doc/reference/embedding.qbk @@ -0,0 +1,6 @@ +[chapter Embedding + [quickbook 1.7] +] + +[include exec.qbk] +[include import.qbk] diff --git a/doc/reference/enum.qbk b/doc/reference/enum.qbk new file mode 100644 index 00000000..032b9f9c --- /dev/null +++ b/doc/reference/enum.qbk @@ -0,0 +1,107 @@ +[section enum.hpp] +[section Introduction] + defines the interface through which users expose their C++ enumeration types to Python. It declares the enum_ class template, which is parameterized on the enumeration type being exposed. +[endsect] +[section Class template `enum_`] +Creates a Python class derived from Python's int type which is associated with the C++ type passed as its first parameter. +`` +namespace boost { namespace python +{ + template + class enum_ : public object + { + enum_(char const* name, char const* doc = 0); + enum_& value(char const* name, T); + enum_& export_values(); + }; +}} +`` +[endsect] +[section Class template `enum_` constructors] +``enum_(char const* name, char const* doc=0);`` +[variablelist +[[Requires][name is an ntbs which conforms to Python's identifier naming rules. ]] +[[Effects][Constructs an enum_ object holding a Python extension type derived from int which is named name. The named attribute of the current scope is bound to the new extension type.]] +] +[endsect] +[section Class template `enum_` modifier functions] +``enum_& value(char const* name, T x);`` +[variablelist +[[Requires][name is an ntbs which conforms to Python's identifier naming rules. ]] +[[Effects][adds an instance of the wrapped enumeration type with value x to the type's dictionary as the named attribute.]] +[[Returns][`*this`]] +] +``enum_& export_values();`` +[variablelist +[[Effects][sets attributes in the current scope with the same names and values as all enumeration values exposed so far by calling value().]] +[[Returns][`*this`]] +] +[endsect] +[section Example] +C++ module definition +`` +#include +#include +#include + +using namespace boost::python; + +enum color { red = 1, green = 2, blue = 4 }; + +color identity_(color x) { return x; } + +BOOST_PYTHON_MODULE(enums) +{ + enum_("color") + .value("red", red) + .value("green", green) + .export_values() + .value("blue", blue) + ; + + def("identity", identity_); +} +`` +Interactive Python: +`` +>>> from enums import * + +>>> identity(red) +enums.color.red + +>>> identity(color.red) +enums.color.red + +>>> identity(green) +enums.color.green + +>>> identity(color.green) +enums.color.green + +>>> identity(blue) +Traceback (most recent call last): + File "", line 1, in ? +NameError: name 'blue' is not defined + +>>> identity(color.blue) +enums.color.blue + +>>> identity(color(1)) +enums.color.red + +>>> identity(color(2)) +enums.color.green + +>>> identity(color(3)) +enums.color(3) + +>>> identity(color(4)) +enums.color.blue + +>>> identity(1) +Traceback (most recent call last): + File "", line 1, in ? +TypeError: bad argument type for built-in operation +`` +[endsect] +[endsect] diff --git a/doc/reference/errors.qbk b/doc/reference/errors.qbk new file mode 100644 index 00000000..9e64cc6c --- /dev/null +++ b/doc/reference/errors.qbk @@ -0,0 +1,142 @@ +[section errors.hpp] +[section Introduction] + provides types and functions for managing and translating between Python and C++ exceptions. This is relatively low-level functionality that is mostly used internally by Boost.Python. Users should seldom need it. +[endsect] +[section Class `error_already_set`] +error_already_set is an exception type which can be thrown to indicate that a Python error has occurred. If thrown, the precondition is that PyErr_Occurred() returns a value convertible to true. Portable code shouldn't throw this exception type directly, but should instead use throw_error_already_set(), below. +`` +namespace boost { namespace python +{ + class error_already_set {}; +}} +`` +[endsect] +[section Functions] +`` +template bool handle_exception(T f) throw(); +void handle_exception() throw(); +`` +[variablelist +[[Requires][The first form requires that the expression function0(f) is valid. The second form requires that a C++ exception is currently being handled (see section 15.1 in the C++ standard).]] +[[Effects][The first form calls f() inside a try block which first attempts to use all registered exception translators. If none of those translates the exception, the catch clauses then set an appropriate Python exception for the C++ exception caught, returning true if an exception was thrown, false otherwise. The second form passes a function which rethrows the exception currently being handled to the first form.]] +[[Postconditions][No exception is being handled]] +[[Throws][nothing]] +[[Rationale][At inter-language boundaries it is important to ensure that no C++ exceptions escape, since the calling language usually doesn't have the equipment necessary to properly unwind the stack. Use handle_exception to manage exception translation whenever your C++ code is called directly from the Python API. This is done for you automatically by the usual function wrapping facilities: make_function(), make_constructor(), def() and class_::def(). The second form can be more convenient to use (see the example below), but various compilers have problems when exceptions are rethrown from within an enclosing try block.]] +] +``template T* expect_non_null(T* x);`` +[variablelist +[[Returns][x]] +[[Throws][error_already_set() iff x == 0.]] +[[Rationale][Simplifies error-handling when calling functions in the Python/C API which return 0 on error.]] +] +``void throw_error_already_set();`` +[variablelist +[[Effects][throw error_already_set();]] +[[Rationale][Simplifies error-handling when calling functions in the Python/C API which return 0 on error.]] +] +``void throw_error_already_set();`` +[variablelist +[[Effects][throw error_already_set();]] +[[Rationale][Many platforms and compilers are not able to consistently catch exceptions thrown across shared library boundaries. Using this function from the Boost.Python library ensures that the appropriate catch block in handle_exception() can catch the exception.]] +] +[endsect] +[section Example] +`` +#include +#include +#include +#include + +// Returns a std::string which has the same value as obj's "__name__" +// attribute. +std::string get_name(boost::python::object obj) +{ + // throws if there's no __name__ attribute + PyObject* p = boost::python::expect_non_null( + PyObject_GetAttrString(obj.ptr(), "__name__")); + + char const* s = PyString_AsString(p); + if (s != 0) + Py_DECREF(p); + + // throws if it's not a Python string + std::string result( + boost::python::expect_non_null( + PyString_AsString(p))); + + Py_DECREF(p); // Done with p + + return result; +} + +// +// Demonstrate form 1 of handle_exception +// + +// Place into result a Python Int object whose value is 1 if a and b have +// identical "__name__" attributes, 0 otherwise. +void same_name_impl(PyObject*& result, boost::python::object a, boost::python::object b) +{ + result = PyInt_FromLong( + get_name(a) == get_name(a2)); +} + +object borrowed_object(PyObject* p) +{ + return boost::python::object( + boost::python::handle<>( + boost::python::borrowed(a1))); +} + +// This is an example Python 'C' API interface function +extern "C" PyObject* +same_name(PyObject* args, PyObject* keywords) +{ + PyObject* a1; + PyObject* a2; + PyObject* result = 0; + + if (!PyArg_ParseTuple(args, const_cast("OO"), &a1, &a2)) + return 0; + + // Use boost::bind to make an object compatible with + // boost::Function0 + if (boost::python::handle_exception( + boost::bind(same_name_impl, boost::ref(result), borrowed_object(a1), borrowed_object(a2)))) + { + // an exception was thrown; the Python error was set by + // handle_exception() + return 0; + } + + return result; +} + +// +// Demonstrate form 2 of handle_exception. Not well-supported by all +// compilers. +// +extern "C" PyObject* +same_name2(PyObject* args, PyObject* keywords) +{ + PyObject* a1; + PyObject* a2; + PyObject* result = 0; + + if (!PyArg_ParseTuple(args, const_cast("OO"), &a1, &a2)) + return 0; + + try { + return PyInt_FromLong( + get_name(borrowed_object(a1)) == get_name(borrowed_object(a2))); + } + catch(...) + { + // If an exception was thrown, translate it to Python + boost::python::handle_exception(); + return 0; + } +} +`` +[endsect] +[endsect] diff --git a/doc/reference/exception_translator.qbk b/doc/reference/exception_translator.qbk new file mode 100644 index 00000000..9edc1e70 --- /dev/null +++ b/doc/reference/exception_translator.qbk @@ -0,0 +1,51 @@ +[section exception_translator.hpp] +[section Introduction] +As described here, it is important to make sure that exceptions thrown by C++ code do not pass into the Python interpreter core. By default, Boost.Python translates all C++ exceptions thrown by wrapped functions and module init functions into Python, but the default translators are extremely limited: most C++ exceptions will appear in Python as a RuntimeError exception whose representation is 'Unidentifiable C++ Exception'. To produce better error messages, users can register additional exception translators as described below. +[endsect] +[section Function `register_exception_translator`] +`` +template +void register_exception_translator(Translate translate); +`` +[variablelist +[[Requires][Translate is Copyconstructible, and the following code must be well-formed: +``void f(ExceptionType x) { translate(x); }``. +The expression `translate(x)` must either throw a C++ exception, or a subsequent call to `PyErr_Occurred()` must return 1. ]] +[[Effects][Adds a copy of translate to the sequence of exception translators tried when Boost.Python catches an exception that is about to pass into Python's core interpreter. The new translator will get "first shot" at translating all exceptions matching the catch clause shown above. Any subsequently-registered translators will be allowed to translate the exception earlier. A translator which cannot translate a given C++ exception can re-throw it, and it will be handled by a translator which was registered earlier (or by the default translator).]] +] +[endsect] +[section Example] +`` +#include +#include +#include +#include + +struct my_exception : std::exception +{ + char const* what() throw() { return "One of my exceptions"; } +}; + +void translate(my_exception const& e) +{ + // Use the Python 'C' API to set up an exception object + PyErr_SetString(PyExc_RuntimeError, e.what()); +} + +void something_which_throws() +{ + ... + throw my_exception(); + ... +} + +BOOST_PYTHON_MODULE(exception_translator_ext) +{ + using namespace boost::python; + register_exception_translator(&translate); + + def("something_which_throws", something_which_throws); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/exec.qbk b/doc/reference/exec.qbk new file mode 100644 index 00000000..fcf164b1 --- /dev/null +++ b/doc/reference/exec.qbk @@ -0,0 +1,84 @@ +[section exec.hpp] +[section Introduction] +Exposes a mechanism for embedding the python interpreter into C++ code. +[endsect] +[section Function `eval`] +`` +object eval(str expression, + object globals = object(), + object locals = object()); +`` +[variablelist +[[Effects][Evaluate Python expression from expression in the context specified by the dictionaries globals and locals. ]] +[[Returns][An instance of object which holds the value of the expression.]] +] +[endsect] +[section Function `exec`] +`` +object exec(str code, + object globals = object(), + object locals = object()); +`` +[variablelist +[[Effects][Execute Python source code from code in the context specified by the dictionaries globals and locals. ]] +[[Returns][ An instance of object which holds the result of executing the code. ]] +] +[endsect] +[section Function `exec_file`] +`` +object exec_file(str filename, + object globals = object(), + object locals = object()); +`` +[variablelist +[[Effects][Execute Python source code from the file named by filename in the context specified by the dictionaries globals and locals.]] +[[Returns][An instance of object which holds the result of executing the code. ]] +] +[endsect] +[section Examples] + The following example demonstrates the use of import and exec to define a function in python, and later call it from within C++. + +`` +#include +#include + +using namespace boost::python; + +void greet() +{ + // Retrieve the main module. + object main = import("__main__"); + + // Retrieve the main module's namespace + object global(main.attr("__dict__")); + + // Define greet function in Python. + object result = exec( + "def greet(): \n" + " return 'Hello from Python!' \n", + global, global); + + // Create a reference to it. + object greet = global["greet"]; + + // Call it. + std::string message = extract(greet()); + std::cout << message << std::endl; +} + `` + Instead of embedding the python script into a string, we could also store it in an a file... +`` +def greet(): + return 'Hello from Python!' +`` + ... and execute that instead. + +`` + // ... + // Load the greet function from a file. + object result = exec_file(script, global, global); + // ... +} +`` +[endsect] +[endsect] diff --git a/doc/reference/extract.qbk b/doc/reference/extract.qbk new file mode 100644 index 00000000..af4b5b17 --- /dev/null +++ b/doc/reference/extract.qbk @@ -0,0 +1,99 @@ +[section extract.hpp] +[section Introduction] +Exposes a mechanism for extracting C++ object values from generalized Python objects. Note that `extract<...>` can also be used to "downcast" an object to some specific ObjectWrapper. Because invoking a mutable python type with an argument of the same type (e.g. `list([1,2]`) typically makes a copy of the argument object, this may be the only way to access the ObjectWrapper's interface on the original object. +[endsect] +[section Class template `extract`] +`extract` can be used to extract a value of an arbitrary C++ type from an instance of object. Two usages are supported: + +# `extract(o)` is a temporary object which is implicitly convertible to `T` (explicit conversion is also available through the object's function-call operator). However, if no conversion is available which can convert o to an object of type `T`, a Python TypeError exception will be raised. +# `extract x(o);` constructs an extractor whose `check()` member function can be used to ask whether a conversion is available without causing an exception to be thrown. + +`` +namespace boost { namespace python +{ + template + struct extract + { + typedef unspecified result_type; + + extract(PyObject*); + extract(object const&); + + result_type operator()() const; + operator result_type() const; + + bool check() const; + }; +}} +`` +[endsect] +[section Class template `extract` constructors and destructor] +`` +extract(PyObject* p); +extract(object const&); +`` +[variablelist +[[Requires][The first form requires that p is non-null.]] +[[Effects][Stores a pointer to the Python object managed by its constructor argument. In particular, the reference count of the object is not incremented. The onus is on the user to be sure it is not destroyed before the extractor's conversion function is called.]] +] +[endsect] +[section Class template `extract` observer functions] +`` +result_type operator()() const; +operator result_type() const; +`` +[variablelist +[[Effects][Converts the stored pointer to result_type, which is either T or T const&. ]] +[[Returns][An object of result_type corresponding to the one referenced by the stored pointer.]] +[[Throws][error_already_set and sets a TypeError if no such conversion is available. May also emit other unspecified exceptions thrown by the converter which is actually used.]] +] +`` bool check() const;`` +[variablelist +[[Postconditions][None. In particular, note that a return value of true does not preclude an exception being thrown from operator result_type() or operator()().]] +[[Returns][false only if no conversion from the stored pointer to T is available.]] +] +[endsect] +[section Example] +`` +#include +using namespace boost::python; +int Print(str s) +{ + // extract a C string from the Python string object + char const* c_str = extract(s); + + // Print it using printf + std::printf("%s\n", c_str); + + // Get the Python string's length and convert it to an int + return extract(s.attr("__len__")()) +} +`` + The following example shows how extract can be used along with class_<...> to create and access an instance of a wrapped C++ class. +`` +struct X +{ + X(int x) : v(x) {} + int value() { return v; } + private: + int v; +}; + +BOOST_PYTHON_MODULE(extract_ext) +{ + object x_class( + class_("X", init()) + .def("value", &X::value)) + ; + + // Instantiate an X object through the Python interface. + // Its lifetime is now managed by x_obj. + object x_obj = x_class(3); + + // Get a reference to the C++ object out of the Python object + X& x = extract(x_obj); + assert(x.value() == 3); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/function_doc_signature.qbk b/doc/reference/function_doc_signature.qbk new file mode 100644 index 00000000..048895b9 --- /dev/null +++ b/doc/reference/function_doc_signature.qbk @@ -0,0 +1,129 @@ +[section function_doc_signature.hpp] +[section Introduction] +Boost.Python supports docstrings with automatic appending of Pythonic and C++ signatures. This feature is implemented by class function_doc_signature_generator The class uses all of the overloads, supplied arg names and default values, as well as the user-defined docstrings, to generate documentation for a given function. +[endsect] +[section Class `function_doc_signature_generator`] +The class has only one public function which returns a list of strings documenting the overloads of a function. +`` +namespace boost { namespace python { namespace objects { + + class function_doc_signature_generator + { + public: + static list function_doc_signatures(function const *f); + }; + +}}} +`` +[endsect] +[section Example] +`` +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::python; + +tuple f(int x = 1, double y = 4.25, char const* z = "wow") +{ + return make_tuple(x, y, z); +} + +BOOST_PYTHON_FUNCTION_OVERLOADS(f_overloads, f, 0, 3) + + +struct X +{ + tuple f(int x = 1, double y = 4.25, char const* z = "wow") + { + return make_tuple(x, y, z); + } +}; + +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, (arg("x")=1, arg("y")=4.25, arg("z")="wow") + , "This is f's docstring" + ); + + def("raw", raw_function(raw_func)); + + def("f1", f, f_overloads("f1's docstring", args("x", "y", "z"))); + + + class_("X", "This is X's docstring", init<>(args("self"))) + .def("f", &X::f + , "This is X.f's docstring" + , args("self","x", "y", "z")) + + ; + +} +`` +Python code: +`` +>>> import args_ext +>>> help(args_ext) +Help on module args_ext: + +NAME + args_ext + +FILE + args_ext.pyd + +CLASSES + Boost.Python.instance(__builtin__.object) + X + + class X(Boost.Python.instance) + | This is X's docstring + | + | Method resolution order: + | X + | Boost.Python.instance + | __builtin__.object + | + | Methods defined here: + | + | __init__(...) + | __init__( (object)self) -> None : + | C++ signature: + | void __init__(struct _object *) + | + | f(...) + | f( (X)self, (int)x, (float)y, (str)z) -> tuple : This is X.f's docstring + | C++ signature: + | class boost::python::tuple f(struct X {lvalue},int,double,char const *) + | + | ................. + | +FUNCTIONS + f(...) + f([ (int)x=1 [, (float)y=4.25 [, (str)z='wow']]]) -> tuple : This is f's docstring + C++ signature: + class boost::python::tuple f([ int=1 [,double=4.25 [,char const *='wow']]]) + + f1(...) + f1([ (int)x [, (float)y [, (str)z]]]) -> tuple : f1's docstring + C++ signature: + class boost::python::tuple f1([ int [,double [,char const *]]]) + + raw(...) + object raw(tuple args, dict kwds) : + C++ signature: + object raw(tuple args, dict kwds) +`` +[endsect] +[endsect] diff --git a/doc/reference/functions.qbk b/doc/reference/functions.qbk new file mode 100644 index 00000000..40b220cd --- /dev/null +++ b/doc/reference/functions.qbk @@ -0,0 +1,35 @@ +[chapter Function Invocation and Creation + [quickbook 1.7] +] + +[include args.qbk] +[include call.qbk] +[include call_method.qbk] +[include data_members.qbk] +[include make_function.qbk] +[include overloads.qbk] +[include ptr.qbk] +[include raw_function.qbk] +[section Function documentation] +[include function_doc_signature.qbk] +[include pytype_function.qbk] +[endsect] +[section Models of CallPolicies] +[include default_call_policies.qbk] +[include return_arg.qbk] +[include return_internal_reference.qbk] +[include return_value_policy.qbk] +[include with_custodian_and_ward.qbk] +[endsect] +[section Models of ResultConverter] +[include to_python_indirect.qbk] +[include to_python_value.qbk] +[endsect] +[section Models of ResultConverterGenerator] +[include copy_const_reference.qbk] +[include copy_non_const_reference.qbk] +[include manage_new_object.qbk] +[include reference_existing_object.qbk] +[include return_by_value.qbk] +[include return_opaque_pointer.qbk] +[endsect] diff --git a/doc/reference/handle.qbk b/doc/reference/handle.qbk new file mode 100644 index 00000000..c0c2c26c --- /dev/null +++ b/doc/reference/handle.qbk @@ -0,0 +1,190 @@ +[section handle.hpp] +[section Introduction] + provides class template handle, a smart pointer for managing reference-counted Python objects. +[endsect] +[section Class template `handle`] +handle is a smart pointer to a Python object type; it holds a pointer of type T*, where T is its template parameter. T must be either a type derived from PyObject or a POD type whose initial sizeof(PyObject) bytes are layout-compatible with PyObject. Use handle<> at the boundary between the Python/'C' API and high-level code; prefer object for a generalized interface to Python objects. + +In this document, the term "upcast" refers to an operation which converts a pointer Y* to a base class pointer T* via static_cast if Y is derived from T, or via C-style cast (T*) if it is not. However, in the latter case the "upcast" is ill-formed if the initial sizeof(PyObject) bytes of Y are not layout-compatible with PyObject. + +`` +namespace boost { namespace python +{ + template + class handle + { + typedef unspecified-member-function-pointer bool_type; + + public: // types + typedef T element_type; + + public: // member functions + ~handle(); + + template + explicit handle(detail::borrowed >* p); + + template + explicit handle(null_ok >* p); + + template + explicit handle(detail::borrowed* p); + + template + explicit handle(null_ok* p); + + template + explicit handle(Y* p); + + handle(); + + handle& operator=(handle const& r); + + template + handle& operator=(handle const & r); // never throws + + + template + handle(handle const& r); + + handle(handle const& r); + + T* operator-> () const; + T& operator* () const; + T* get() const; + void reset(); + T* release(); + + operator bool_type() const; // never throws + private: + T* m_p; + }; + + template struct null_ok; + namespace detail { template struct borrowed; } +}} +`` +[section Class template `handle` constructors and destructor] +``virtual ~handle();`` +[variablelist +[[Effects][`Py_XDECREF(upcast(m_p))`]] +] +``template +explicit handle(detail::borrowed >* p); +`` +[variablelist +[[Effects][ +``Py_XINCREF(upcast(p)); +m_p = upcast(p); +`` +]] +] +``template +explicit handle(null_ok >* p);`` +[variablelist +[[Effects][ +``Py_XINCREF(upcast(p)); + m_p = upcast(p); +`` +]] +] +``template +explicit handle(detail::borrowed* p);`` +[variablelist +[[Effects][ +``Py_XINCREF(upcast(p)); + m_p = upcast(expect_non_null(p)); +`` +]] +] +``template +explicit handle(null_ok* p); +`` +[variablelist +[[Effects][`m_p = upcast(p);`]] +] +`` +template +explicit handle(Y* p); +`` +[variablelist +[[Effects][`m_p = upcast(expect_non_null(p));`]] +] +`` +handle(); +`` +[variablelist +[[Effects][`m_p = 0;`]] +] +`` +template +handle(handle const& r); +handle(handle const& r); +`` +[variablelist +[[Effects][m_p = r.m_p; Py_XINCREF(upcast(m_p));]] +] +[endsect] +[section Class template `handle` modifiers] +`` +handle& operator=(handle const& r); +template +handle& operator=(handle const & r); // never throws +`` +[variablelist +[[Effects][`Py_XINCREF(upcast(r.m_p)); Py_XDECREF( upcast(m_p)); m_p = r.m_p;`]] +] +`` +T* release(); +`` +[variablelist +[[Effects][`T* x = m_p; m_p = 0; return x;`]] +] +`` +void reset(); +`` +[variablelist +[[Effects][`*this = handle();`]] +] +[endsect] +[section Class template `handle` observers] +`` +T* operator-> () const; +T* get() const; +`` +[variablelist +[[Returns][`m_p;`]] +] +`` +T& operator* () const; +`` +[variablelist +[[Returns][`*m_p;`]] +] +`` +operator bool_type() const; // never throws +`` +[variablelist +[[Returns][`0` if `m_p == 0`, a pointer convertible to true otherwise.]] +] +[endsect] +[endsect] +[section Function `borrowed`] +`` +template +detail::borrowed* borrowed(T* p) +{ + return (detail::borrowed*)p; +} +`` +[endsect] +[section Function `allow_null`] +`` +template +null_ok* allow_null(T* p) +{ + return (null_ok*)p; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/has_back_reference.qbk b/doc/reference/has_back_reference.qbk new file mode 100644 index 00000000..7d76783f --- /dev/null +++ b/doc/reference/has_back_reference.qbk @@ -0,0 +1,115 @@ +[section has_back_reference.hpp] +[section Introduction] + defines the predicate metafunction has_back_reference<>, which can be specialized by the user to indicate that a wrapped class instance holds a PyObject* corresponding to a Python object. +[endsect] +[section Class template `has_back_reference`] +A unary metafunction whose value is true iff its argument is a pointer_wrapper<>. +`` +namespace boost { namespace python +{ + template class has_back_reference + { + typedef mpl::false_ type; + }; +}} +`` + +A " metafunction" that is inspected by Boost.Python to determine how wrapped classes can be constructed. + +`type::value` is an integral constant convertible to bool of unspecified type. +Specializations may substitute a true-valued integral constant wrapper for type iff for each invocation of `class_::def(init< type-sequence...>())` and the implicitly wrapped copy constructor (unless it is noncopyable), there exists a corresponding constructor `WrappedClass::WrappedClass(PyObject*, type-sequence...)`. If such a specialization exists, the WrappedClass constructors will be called with a "back reference" pointer to the corresponding Python object whenever they are invoked from Python. The easiest way to provide this nested type is to derive the specialization from `mpl::true_`. + +[endsect] +[section Examples] +In C++: +`` +#include +#include +#include +#include +#include + +using namespace boost::python; +using boost::shared_ptr; + +struct X +{ + X(PyObject* self) : m_self(self), m_x(0) {} + X(PyObject* self, int x) : m_self(self), m_x(x) {} + X(PyObject* self, X const& other) : m_self(self), m_x(other.m_x) {} + + handle<> self() { return handle<>(borrowed(m_self)); } + int get() { return m_x; } + void set(int x) { m_x = x; } + + PyObject* m_self; + int m_x; +}; + +// specialize has_back_reference for X +namespace boost { namespace python +{ + template <> + struct has_back_reference + : mpl::true_ + {}; +}} + +struct Y +{ + Y() : m_x(0) {} + Y(int x) : m_x(x) {} + int get() { return m_x; } + void set(int x) { m_x = x; } + + int m_x; +}; + +shared_ptr +Y_self(shared_ptr self) { return self; } + +BOOST_PYTHON_MODULE(back_references) +{ + class_("X") + .def(init()) + .def("self", &X::self) + .def("get", &X::get) + .def("set", &X::set) + ; + + class_ >("Y") + .def(init()) + .def("get", &Y::get) + .def("set", &Y::set) + .def("self", Y_self) + ; +} +`` + The following Python session illustrates that x.self() returns the same Python object on which it is invoked, while y.self() must create a new Python object which refers to the same Y instance. + +In Python: +`` +>>> from back_references import * +>>> x = X(1) +>>> x2 = x.self() +>>> x2 is x +1 +>>> (x.get(), x2.get()) +(1, 1) +>>> x.set(10) +>>> (x.get(), x2.get()) +(10, 10) +>>> +>>> +>>> y = Y(2) +>>> y2 = y.self() +>>> y2 is y +0 +>>> (y.get(), y2.get()) +(2, 2) +>>> y.set(20) +>>> (y.get(), y2.get()) +(20, 20) +`` +[endsect] +[endsect] diff --git a/doc/reference/implicit.qbk b/doc/reference/implicit.qbk new file mode 100644 index 00000000..5d1c8763 --- /dev/null +++ b/doc/reference/implicit.qbk @@ -0,0 +1,69 @@ +[section implicit.hpp] +[section Introduction] + implicitly_convertible allows Boost.Python to implicitly take advantage of a C++ implicit or explicit conversion when matching Python objects to C++ argument types. +[endsect] +[section Function template `implicit_convertible`] +`` +template +void implicitly_convertible(); +`` +[table +[[Parameter][Description]] +[[Source][The source type of the implicit conversion]] +[[Target][The target type of the implicit conversion]] +] +[variablelist +[[Requires][The declaration Target t(s);, where s is of type Source, is valid.]] +[[Effects][registers an rvalue from_python converter to Target which can succeed for any PyObject* p iff there exists any registered converter which can produce Source rvalues]] +[[Rationale][C++ users expect to be able to take advantage of the same sort of interoperability in Python as they do in C++.]] +] +[endsect] +[section Example] +In C++: +`` +#include +#include +#include + +using namespace boost::python; + +struct X +{ + X(int x) : v(x) {} + operator int() const { return v; } + int v; +}; + +int x_value(X const& x) +{ + return x.v; +} + +X make_x(int n) { return X(n); } + +BOOST_PYTHON_MODULE(implicit_ext) +{ + def("x_value", x_value); + def("make_x", make_x); + + class_("X", + init()) + ; + + implicitly_convertible(); + implicitly_convertible(); +} +`` +In Python: +`` +>>> from implicit_ext import * +>>> x_value(X(42)) +42 +>>> x_value(42) +42 +>>> x = make_x(X(42)) +>>> x_value(x) +42 +`` +[endsect] +[endsect] diff --git a/doc/reference/import.qbk b/doc/reference/import.qbk new file mode 100644 index 00000000..3c86a9e1 --- /dev/null +++ b/doc/reference/import.qbk @@ -0,0 +1,31 @@ +[section import.hpp] +[section Introduction] +Exposes a mechanism for importing python modules. +[endsect] +[section Function `import`] +``object import(str name);`` +[variablelist +[[Effects][Imports the module named by name.]] +[[Returns][An instance of object which holds a reference to the imported module.]] +] +[endsect] +[section Examples] + The following example demonstrates the use of import to access a function in python, and later call it from within C++. +`` +#include +#include + +using namespace boost::python; + +void print_python_version() +{ + // Load the sys module. + object sys = import("sys"); + + // Extract the python version. + std::string version = extract(sys.attr("version")); + std::cout << version << std::endl; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/indexing.qbk b/doc/reference/indexing.qbk new file mode 100644 index 00000000..d5480fab --- /dev/null +++ b/doc/reference/indexing.qbk @@ -0,0 +1,279 @@ +[section Indexing support] +[section Introduction] + Indexing is a Boost Python facility for easy exportation of indexable C++ containers to Python. Indexable containers are containers that allow random access through the operator[] (e.g. std::vector). + +While Boost Python has all the facilities needed to expose indexable C++ containers such as the ubiquitous std::vector to Python, the procedure is not as straightforward as we'd like it to be. Python containers do not map easily to C++ containers. Emulating Python containers in C++ (see Python Reference Manual, Emulating container types) using Boost Python is non trivial. There are a lot of issues to consider before we can map a C++ container to Python. These involve implementing wrapper functions for the methods __len__, __getitem__, __setitem__, __delitem__, __iter__ and __contains. + +The goals: + +* Make indexable C++ containers behave exactly as one would expect a Python container to behave. +* Provide default reference semantics for container element indexing (__getitem__) such that c[i] can be mutable. Require: + + `` + val = c[i] + c[i].m() + val == c[i] + `` + + where m is a non-const (mutating) member function (method). +* Return safe references from __getitem__ such that subsequent adds and deletes to and from the container will not result in dangling references (will not crash Python). +* Support slice indexes. +* Accept Python container arguments (e.g. lists, tuples) wherever appropriate. +* Allow for extensibility through re-definable policy classes. +* Provide predefined support for the most common STL and STL like indexable containers. + +[endsect] +[section The Indexing Interface] + The indexing_suite class is the base class for the management of C++ containers intended to be integrated to Python. The objective is make a C++ container look and feel and behave exactly as we'd expect a Python container. The class automatically wraps these special Python methods (taken from the Python reference: Emulating container types): + +[variablelist +[[__len__(self)] + [Called to implement the built-in function len() Should return the length of the object, an integer >= 0. Also, an object that doesn't define a __nonzero__() method and whose __len__() method returns zero is considered to be false in a Boolean context.]] +[[__getitem__(self, key)] +[Called to implement evaluation of self[key]. For sequence types, the accepted keys should be integers and slice objects. Note that the special interpretation of negative indexes (if the class wishes to emulate a sequence type) is up to the __getitem__() method. If key is of an inappropriate type, TypeError may be raised; if of a value outside the set of indexes for the sequence (after any special interpretation of negative values), IndexError should be raised. Note: for loops expect that an IndexError will be raised for illegal indexes to allow proper detection of the end of the sequence.]] +[[__setitem__(self, key, value)] + [Called to implement assignment to self[key]. Same note as for __getitem__(). This should only be implemented for mappings if the objects support changes to the values for keys, or if new keys can be added, or for sequences if elements can be replaced. The same exceptions should be raised for improper key values as for the __getitem__() method.]] +[[__delitem__(self, key)] + [Called to implement deletion of self[key]. Same note as for __getitem__(). This should only be implemented for mappings if the objects support removal of keys, or for sequences if elements can be removed from the sequence. The same exceptions should be raised for improper key values as for the __getitem__() method.]] +[[__iter__(self)] + [This method is called when an iterator is required for a container. This method should return a new iterator object that can iterate over all the objects in the container. For mappings, it should iterate over the keys of the container, and should also be made available as the method iterkeys(). + +Iterator objects also need to implement this method; they are required to return themselves. For more information on iterator objects, see "Iterator Types" in the Python Library Reference.]] + +[[__contains__(self, item)] + [Called to implement membership test operators. Should return true if item is in self, false otherwise. For mapping objects, this should consider the keys of the mapping rather than the values or the key-item pairs.]] + ] +[endsect] +[section index_suite sub-classes] + The indexing_suite is not meant to be used as is. A couple of policy functions must be supplied by subclasses of indexing_suite. However, a set of indexing_suite subclasses for the standard indexable STL containers will be provided, In most cases, we can simply use the available predefined suites. In some cases, we can refine the predefined suites to suit our needs. +[endsect] +[section vector_index_suite] + The vector_indexing_suite class is a predefined indexing_suite derived class designed to wrap std::vector (and std::vector like [i.e. a class with std::vector interface]) classes. It provides all the policies required by the indexing_suite. + +Example usage: +`` +class X {...}; +... +class_ >("XVec") + .def(vector_indexing_suite >()) +; +`` + + XVec is now a full-fledged Python container (see the example in full, along with its python test). +[endsect] +[section map_index_suite] + The map_indexing_suite class is a predefined indexing_suite derived class designed to wrap std::map (and std::map like [i.e. a class with std::map interface]) classes. It provides all the policies required by the indexing_suite. + +Example usage: + +`` +class X {...}; +... + +class_ >("XMap") + .def(map_indexing_suite >()) +; +`` + + By default indexed elements are returned by proxy. This can be disabled by supplying true in the NoProxy template parameter. XMap is now a full-fledged Python container (see the example in full, along with its python test). +[endsect] +[section `indexing_suite` class] +`` indexing_suite`` + +[table +[[Template Parameter][Requirements][Semantics][Default]] +[[Container][A class type][ The container type to be wrapped to Python. ][]] +[[DerivedPolicies][A subclass of indexing_suite][ Derived classes provide the policy hooks. See DerivedPolicies below. ][]] +[[NoProxy][A boolean][ By default indexed elements have Python reference semantics and are returned by proxy. This can be disabled by supplying true in the NoProxy template parameter. ][false]] +[[NoSlice][A boolean][ Do not allow slicing. ][false]] +[[Data][][The container's data type.][Container::value_type]] +[[Index][][The container's index type.][Container::size_type]] +[[Key][][The container's key type.][Container::value_type]] +] +`` +template +class indexing_suite : unspecified +{ +public: + indexing_suite(); // default constructor +} +`` +[section DerivedPolicies] + +Derived classes provide the hooks needed by the indexing_suite: +`` +data_type& +get_item(Container& container, index_type i); + +static object +get_slice(Container& container, index_type from, index_type to); + +static void +set_item(Container& container, index_type i, data_type const& v); + +static void +set_slice( + Container& container, index_type from, + index_type to, data_type const& v +); + +template +static void +set_slice(Container& container, index_type from, + index_type to, Iter first, Iter last +); + +static void +delete_item(Container& container, index_type i); + +static void +delete_slice(Container& container, index_type from, index_type to); + +static size_t +size(Container& container); + +template +static bool +contains(Container& container, T const& val); + +static index_type +convert_index(Container& container, PyObject* i); + +static index_type +adjust_index(index_type current, index_type from, + index_type to, size_type len); +`` + + Most of these policies are self explanatory. However, convert_index and adjust_index deserve some explanation. + + convert_index converts a Python index into a C++ index that the container can handle. For instance, negative indexes in Python, by convention, start counting from the right(e.g. C[-1] indexes the rightmost element in C). convert_index should handle the necessary conversion for the C++ container (e.g. convert -1 to C.size()-1). convert_index should also be able to convert the type of the index (A dynamic Python type) to the actual type that the C++ container expects. + + When a container expands or contracts, held indexes to its elements must be adjusted to follow the movement of data. For instance, if we erase 3 elements, starting from index 0 from a 5 element vector, what used to be at index 4 will now be at index 1: + +`` + [a][b][c][d][e] ---> [d][e] + ^ ^ + 4 1 +`` + + adjust_index takes care of the adjustment. Given a current index, the function should return the adjusted index when data in the container at index from..to is replaced by len elements. +[endsect] +[endsect] +[section class `vector_indexing_suite`] +[table +[[Template Parameter][Requirements][Semantics][Default]] +[[Container][A class type][ The container type to be wrapped to Python. ][]] +[[NoProxy][A boolean][ By default indexed elements have Python reference semantics and are returned by proxy. This can be disabled by supplying true in the NoProxy template parameter. ][false]] +[[DerivedPolicies][A subclass of indexing_suite][ The vector_indexing_suite may still be derived to further tweak any of the predefined policies. Static polymorphism through CRTP (James Coplien. "Curiously Recurring Template Pattern". C++ Report, Feb. 1995) enables the base indexing_suite class to call policy function of the most derived class ][]] +] +`` +template +class vector_indexing_suite : unspecified_base +{ +public: + + typedef typename Container::value_type data_type; + typedef typename Container::value_type key_type; + typedef typename Container::size_type index_type; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + + data_type& + get_item(Container& container, index_type i); + + static object + get_slice(Container& container, index_type from, index_type to); + + static void + set_item(Container& container, index_type i, data_type const& v); + + static void + set_slice(Container& container, index_type from, + index_type to, data_type const& v); + + template + static void + set_slice(Container& container, index_type from, + index_type to, Iter first, Iter last); + + static void + delete_item(Container& container, index_type i); + + static void + delete_slice(Container& container, index_type from, index_type to); + + static size_t + size(Container& container); + + static bool + contains(Container& container, key_type const& key); + + static index_type + convert_index(Container& container, PyObject* i); + + static index_type + adjust_index(index_type current, index_type from, + index_type to, size_type len); +}; +`` +[endsect] +[section class `map_indexing_suite`] +[table +[[Template Parameter][Requirements][Semantics][Default]] +[[Container][ A class type ][ The container type to be wrapped to Python. ][]] +[[NoProxy][ A boolean ][ By default indexed elements have Python reference semantics and are returned by proxy. This can be disabled by supplying true in the NoProxy template parameter. ][ false ]] +[[DerivedPolicies][ A subclass of indexing_suite ][ The vector_indexing_suite may still be derived to further tweak any of the predefined policies. Static polymorphism through CRTP (James Coplien. "Curiously Recurring Template Pattern". C++ Report, Feb. 1995) enables the base indexing_suite class to call policy function of the most derived class ][]] +] +`` +template +class map_indexing_suite : unspecified_base +{ +public: + + typedef typename Container::value_type value_type; + typedef typename Container::value_type::second_type data_type; + typedef typename Container::key_type key_type; + typedef typename Container::key_type index_type; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + + static data_type& + get_item(Container& container, index_type i); + + static void + set_item(Container& container, index_type i, data_type const& v); + + static void + delete_item(Container& container, index_type i); + + static size_t + size(Container& container); + + static bool + contains(Container& container, key_type const& key); + + static bool + compare_index(Container& container, index_type a, index_type b); + + static index_type + convert_index(Container& container, PyObject* i); +}; +`` +[endsect] +[endsect] diff --git a/doc/reference/init.qbk b/doc/reference/init.qbk new file mode 100644 index 00000000..f8e1975f --- /dev/null +++ b/doc/reference/init.qbk @@ -0,0 +1,91 @@ +[section init.hpp] +[section Introduction] + defines the interface for exposing C++ constructors to Python as extension class __init__ functions. +[section init-expressions] +An init-expression is used to describe a family of __init__ methods to be generated for an extension class, and the result has the following properties: +[variablelist +[[docstring][An ntbs whose value will bound to the method's __doc__ attribute]] +[[keywords][A keyword-expression which will be used to name (a trailing subsequence of) the arguments to the generated __init__ function(s).]] +[[call_policies][An instance of a model of CallPolicies.]] +[[argument_types][An MPL sequence of C++ argument types which will be used to construct the wrapped C++ object. An init expression has one or more valid prefixes which are given by a sequence of prefixes of its argument types.]] +] +[endsect] +[endsect] +[section Class template `init`] +A MPL sequence which can be used to specify a family of one or more __init__ functions. Only the last Ti supplied may be an instantiation of optional<...>. + +`` +namespace boost { namespace python +{ + template + struct init + { + init(char const* doc = 0); + template init(Keywords const& kw, char const* doc = 0); + template init(char const* doc, Keywords const& kw); + + template + unspecified operator[](CallPolicies const& policies) const + }; +}} +`` +[section Class template `init` constructors] +`` +init(char const* doc = 0); +template init(Keywords const& kw, char const* doc = 0); +template init(char const* doc, Keywords const& kw); +`` +[variablelist +[[Requires][If supplied, doc is an ntbs. If supplied, kw is the result of a ]] +[[Effects][The result is an init-expression whose docstring is doc and whose keywords are a reference to kw. If the first form is used, the resulting expression's keywords are empty. The expression's call policies are an instance of default_call_policies. If Tn is optional, the expression's valid prefixes are given by: ``(T1, T2,...Tn-1), (T1, T2,...Tn-1 , U1), (T1, T2,...Tn-1 , U1, U2), ...(T1, T2,...Tn-1 , U1, U2,...Um)``. +Otherwise, the expression has one valid prefix given by the the template arguments the user specified. ]] +] +[endsect] +[section Class template `init` observer functions] +`` +template +unspecified operator[](Policies const& policies) const +`` +[variablelist +[[Requires][Policies is a model of CallPolicies.]] +[[Effects][Returns a new init-expression with all the same properties as the init object except that its call policies are replaced by a reference to policies.]] +] +[endsect] +[endsect] +[section Class template `optional` ] +A MPL sequence which can be used to specify the optional arguments to an __init__ function. +`` +namespace boost { namespace python +{ + template + struct optional {}; +}} +`` +[endsect] +[section Example] +Given the C++ declarations: +`` +class Y; +class X +{ + public: + X(int x, Y* y) : m_y(y) {} + X(double); + private: + Y* m_y; +}; +`` +A corresponing Boost.Python extension class can be created with: +`` +using namespace boost::python; + +class_("X", "This is X's docstring.", + init(args("x","y"), "X.__init__'s docstring")[ + with_custodian_and_ward<1,3>()] + ) + .def(init()) + ; + +`` +[endsect] +[endsect] diff --git a/doc/reference/instance_holder.qbk b/doc/reference/instance_holder.qbk new file mode 100644 index 00000000..b73580e1 --- /dev/null +++ b/doc/reference/instance_holder.qbk @@ -0,0 +1,92 @@ +[section instance_holder.hpp] +[section Introduction] + provides class instance_holder, the base class for types which hold C++ instances of wrapped classes. +[endsect] +[section Class template `instance_holder`] +instance_holder is an abstract base class whose concrete derived classes hold C++ class instances within their Python object wrappers. To allow multiple inheritance in Python from C++ class wrappers, each such Python object contains a chain of instance_holders. When an __init__ function for a wrapped C++ class is invoked, a new instance_holder instance is created and installed in the Python object using its install() function. Each concrete class derived from instance_holder must provide a holds() implementation which allows Boost.Python to query it for the type(s) it is holding. In order to support the held type's wrapped constructor(s), the class must also provide constructors that can accept an initial PyObject* argument referring to the owning Python object, and which forward the rest of their arguments to the constructor of the held type. The initial argument is needed to enable virtual function overriding in Python, and may be ignored, depending on the specific instance_holder subclass. +`` +namespace boost { namespace python +{ + class instance_holder : noncopyable + { + public: + // destructor + virtual ~instance_holder(); + + // instance_holder modifiers + void install(PyObject* inst) throw(); + + // instance_holder observers + virtual void* holds(type_info) = 0; + }; +}} +`` +[section Class `intance_holder` destructor] +``virtual ~instance_holder();`` +[variablelist +[[Effects][destroys the object]] +] +[endsect] +[section Class `intance_holder` modifiers] +``void install(PyObject* inst) throw();`` +[variablelist +[[Requires][inst is a Python instance of a wrapped C++ class type, or is a type derived from a wrapped C++ class type. ]] +[[Effects][installs the new instance at the head of the Python object's chain of held instances. ]] +[[Throws][nothing]] +] +[endsect] +[section Class `intance_holder` observers] +``virtual void *holds(type_info x) = 0;`` +[variablelist +[[Returns][A pointer to an object of the type described by `x` if `*this` contains such an object, 0 otherwise. ]] +] +[endsect] +[endsect] +[section Examples] + The following is a simplified version of the instance holder template used by Boost.Python to wrap classes held by smart pointers: + +`` +template +struct pointer_holder : instance_holder +{ + // construct from the SmartPtr type + pointer_holder(SmartPtr p) + :m_p(p) + + // Forwarding constructors for the held type + pointer_holder(PyObject*) + :m_p(new Value()) + { + } + + template + pointer_holder(PyObject*,A0 a0) + :m_p(new Value(a0)) + { + } + + template + pointer_holder(PyObject*,A0 a0,A1 a1) + :m_p(new Value(a0,a1)) + { + } + ... + + private: // required holder implementation + void* holds(type_info dst_t) + { + // holds an instance of the SmartPtr type... + if (dst_t == python::type_id()) + return &this->m_p; + + // ...and an instance of the SmartPtr's element_type, if the + // pointer is non-null + return python::type_id() == dst_t ? &*this->m_p : 0; + } + + private: // data members + SmartPtr m_p; +}; + `` +[endsect] +[endsect] diff --git a/doc/reference/iterator.qbk b/doc/reference/iterator.qbk new file mode 100644 index 00000000..9b59bc0c --- /dev/null +++ b/doc/reference/iterator.qbk @@ -0,0 +1,111 @@ +[section iterator.hpp] +[section Introduction] + provides types and functions for creating Python iterators from C++ Containers and Iterators. Note that if your class_ supports random-access iterators, implementing `__getitem__` (also known as the Sequence Protocol) may serve you better than using this facility: Python will automatically create an iterator type for you (see `iter()`), and each access can be range-checked, leaving no possiblity of accessing through an invalidated C++ iterator. +[endsect] +[section Class template `iterator`] +Instances of `iterator` hold a reference to a callable Python object which, when invoked from Python, expects a single argument c convertible to C and creates a Python iterator that traverses `[c.begin(), c.end())`. The optional CallPolicies P can be used to control how elements are returned during iteration. + +In the table below, c is an instance of Container. + +[table +[[Template Parameter][Requirements][Semantics][Default]] +[[Container][`[c.begin(),c.end()`) is a valid Iterator range.][The result will convert its argument to c and call c.begin() and c.end() to acquire iterators. To invoke Container's const begin() and end() functions, make it const.][ ]] +[[NextPolicies][A default-constructible model of CallPolicies.][Applied to the resulting iterators' next() method.][An unspecified model of CallPolicies which always makes a copy of the result of deferencing the underlying C++ iterator]] +] + +`` +namespace boost { namespace python + { + template + struct iterator : object + { + iterator(); + }; + }} +`` +[endsect] +[section Class template iterator constructors] +``iterator()`` + +[variablelist +[[Effects][Initializes its base class with the result of: +``range(&iterators::begin, &iterators::end)``]] +[[Postconditions][this->get() points to a Python callable object which creates a Python iterator as described above.]] +[[Rationale][Provides an easy way to create iterators for the common case where a C++ class being wrapped provides begin() and end().]] +] +[endsect] +[section Class template `iterators`] +A utility class template which provides a way to reliably call its argument's begin() and end() member functions. Note that there is no portable way to take the address of a member function of a C++ standard library container, so iterators<> can be particularly helpful when wrapping them. + +In the table below, x is an instance of C. +[table +[[Required Valid Expression][Type]] +[[x.begin()][Convertible to C::const_iterator if C is a const type; convertible to C::iterator otherwise.]] +[[x.end()][Convertible to C::const_iterator if C is a const type; convertible to C::iterator otherwise.]] +] +`` +namespace boost { namespace python +{ + template + struct iterators + { + typedef typename C::const_iterator iterator; + static iterator begin(C& x); + static iterator end(C& x); + }; +}} +`` +[endsect] +[section Class template iterators nested types] +If C is a const type,``typedef typename C::const_iterator iterator;`` +Otherwise: ``typedef typename C::iterator iterator;`` +[endsect] +[section Class template iterators static functions] +``static iterator begin(C&);`` +[variablelist [[Returns][`x.begin()`]]] +``static iterator end(C&);`` +[variablelist [[Returns][`x.end()`]]] +[endsect] +[section Functions] +`` +template +object range(Accessor1 start, Accessor2 finish); + +template +object range(Accessor1 start, Accessor2 finish); + +template +object range(Accessor1 start, Accessor2 finish); +`` +[variablelist +[[Requires][ NextPolicies is a default-constructible model of CallPolicies.]] +[[Effects][The first form creates a Python callable object which, when invoked, converts its argument to a Target object x, and creates a Python iterator which traverses `[bind(start,_1)(x), bind(finish,_1)(x))`, applying NextPolicies to the iterator's next() function. +The second form is identical to the first, except that Target is deduced from Accessor1 as follows: + +# If Accessor1 is a function type, Target is the type of its first argument. +# If Accessor1 is a data member pointer of the form `R (T::*)`, Target is identical to `T`. +# If Accessor1 is a member function pointer of the form `R (T::*)(arguments...) cv-opt`, where cv-opt is an optional cv-qualifier, Target is identical to `T`. + +The third form is identical to the second, except that NextPolicies is an unspecified model of CallPolicies which always makes a copy of the result of deferencing the underlying C++ iterator + +]] +[[Rationale][The use of boost::bind() allows C++ iterators to be accessed through functions, member functions or data member pointers. Customization of NextPolicies (e.g. using return_internal_reference) is useful when it is expensive to copy sequence elements of a wrapped class type. Customization of Target is useful when Accessor1 is a function object, or when a base class of the intended target type would otherwise be deduced.]] +] +[endsect] +[section Example] +`` +#include +#include + +#include + +using namespace boost::python; +BOOST_PYTHON_MODULE(demo) +{ + class_ >("dvec") + .def("__iter__", iterator >()) + ; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/list.qbk b/doc/reference/list.qbk new file mode 100644 index 00000000..05ebaa04 --- /dev/null +++ b/doc/reference/list.qbk @@ -0,0 +1,60 @@ +[section list.hpp] +[section Introduction] +Exposes a TypeWrapper for the Python list type. +[endsect] +[section Class `list`] +Exposes the mapping protocol of Python's built-in list type. The semantics of the constructors and member functions defined below can be fully understood by reading the TypeWrapper concept definition. Since list is publicly derived from object, the public object interface applies to list instances as well.`` +namespace boost { namespace python +{ + class list : public object + { + public: + list(); // new list + + template + explicit list(T const& sequence); + + template + void append(T const& x); + + template + long count(T const& value) const; + + template + void extend(T const& x); + + template + long index(T const& x) const; + + template + void insert(object const& index, T const& x); // insert object before index + + object pop(); // remove and return item at index (default last) + object pop(long index); + object pop(object const& index); + + template + void remove(T const& value); + + void reverse(); // reverse *IN PLACE* + + void sort(); // sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1 + + template + void sort(T const& value); + }; +}} +`` +[endsect] +[section Example] +`` +using namespace boost::python; + +// Return the number of zeroes in the list +long zeroes(list l) +{ + return l.count(0); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/long.qbk b/doc/reference/long.qbk new file mode 100644 index 00000000..2d390a3f --- /dev/null +++ b/doc/reference/long.qbk @@ -0,0 +1,38 @@ +[section long.hpp] +[section Introduction] +Exposes a TypeWrapper for the Python long integer type. +[endsect] +[section Class `long_`] +Exposes the numeric type protocol of Python's built-in long type. The semantics of the constructors and member functions defined below can be fully understood by reading the TypeWrapper concept definition. Since long_ is publicly derived from object, the public object interface applies to long_ instances as well. +`` +namespace boost { namespace python +{ + class long_ : public object + { + public: + long_(); // new long_ + + template + explicit long_(T const& rhs); + + template + long_(T const& rhs, U const& base); + }; +}} +`` +[endsect] +[section Example] +`` +namespace python = boost::python; + +// compute a factorial without overflowing +python::long_ fact(long n) +{ + if (n == 0) + return python::long_(1); + else + return n * fact(n - 1); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/lvalue_from_pytype.qbk b/doc/reference/lvalue_from_pytype.qbk new file mode 100644 index 00000000..5adc8733 --- /dev/null +++ b/doc/reference/lvalue_from_pytype.qbk @@ -0,0 +1,120 @@ +[section lvalue_from_pytype.hpp] +[section Introduction] + supplies a facility for extracting C++ objects from within Python instances of a given type. This is typically useful for dealing with "traditional" Python extension types. +[endsect] +[section Class template `lvalue_from_pytype`] +Class template lvalue_from_pytype will register from_python converters which, given an object of the given Python type, can extract references and pointers to a particular C++ type. Its template arguments are: + + In the table below, x denotes an object of type PythonObject& +[table +[[Parameter][Requirements][Semantics]] +[[Extractor][a model of Extractor whose execute function returns a reference type.][Extracts the lvalue from the Python object once its type has been confirmed]] +[[python_type][A compile-time constant PyTypeObject*][The Python type of instances convertible by this converter. Python subtypes are also convertible.]] +] +`` +namespace boost { namespace python +{ + template + struct lvalue_from_pytype + { + lvalue_from_pytype(); + }; +}} +`` +[section Class template `lvalue_from_pytype` constructor] +``lvalue_from_pytype();`` +[variablelist +[[Effects][Registers converters which can convert Python objects of the given type to lvalues of the type returned by Extractor::execute.]] +] +[endsect] +[endsect] +[section Class template `extract_identity`] +extract_identity is a model of Extractor which can be used in the common case where the C++ type to be extracted is the same as the Python object type. +`` +namespace boost { namespace python +{ + template + struct extract_identity + { + static InstanceType& execute(InstanceType& c); + }; +}} +`` +[section Class template `extract_identity` static functions] +``InstanceType& execute(InstanceType& c);`` +[variablelist +[[Returns][c]] +] +[endsect] +[endsect] +[section Class template `extract_member`] +extract_member is a model of Extractor which can be used in the common case in the common case where the C++ type to be extracted is a member of the Python object. +`` +namespace boost { namespace python +{ + template + struct extract_member + { + static MemberType& execute(InstanceType& c); + }; +}} +`` +[section Class template `extract_member` static functions] +``static MemberType& execute(InstanceType& c);`` +[variablelist +[[Returns][`c.*member`]] +] +[endsect] +[endsect] +[section Example] + This example presumes that someone has implemented the standard noddy example module from the Python documentation, and we want to build a module which manipulates Noddys. Since noddy_NoddyObject is so simple that it carries no interesting information, the example is a bit contrived: it assumes you want to keep track of one particular object for some reason. This module would have to be dynamically linked to the module which defines noddy_NoddyType. + +In C++: +`` +#include +#include +#include +#include + +// definition lifted from the Python docs +typedef struct { + PyObject_HEAD +} noddy_NoddyObject; + +using namespace boost::python; +static handle cache; + +bool is_cached(noddy_NoddyObject* x) +{ + return x == cache.get(); +} + +void set_cache(noddy_NoddyObject* x) +{ + cache = handle(borrowed(x)); +} + +BOOST_PYTHON_MODULE(noddy_cache) +{ + def("is_cached", is_cached); + def("set_cache", set_cache); + + // register Noddy lvalue converter + lvalue_from_pytype,&noddy_NoddyType>(); +} +`` +In Python: +`` +>>> import noddy +>>> n = noddy.new_noddy() +>>> import noddy_cache +>>> noddy_cache.is_cached(n) +0 +>>> noddy_cache.set_cache(n) +>>> noddy_cache.is_cached(n) +1 +>>> noddy_cache.is_cached(noddy.new_noddy()) +0 +`` +[endsect] +[endsect] diff --git a/doc/reference/make_function.qbk b/doc/reference/make_function.qbk new file mode 100644 index 00000000..56df0d58 --- /dev/null +++ b/doc/reference/make_function.qbk @@ -0,0 +1,83 @@ +[section make_function.hpp] +[section Introduction] +make_function() and make_constructor() are the functions used internally by def() and class_<>::def() to produce Python callable objects which wrap C++ functions and member functions. +[endsect] +[section Functions] +`` +template +object make_function(F f) + +template +object make_function(F f, Policies const& policies) + +template +object make_function(F f, Policies const& policies, KeywordsOrSignature const& ks) + +template +object make_function(F f, Policies const& policies, Keywords const& kw, Signature const& sig) +`` +[variablelist +[[Requires][F is a function pointer or member function pointer type. If policies are supplied, it must be a model of CallPolicies. If kewords are supplied, it must be the result of a keyword-expression specifying no more arguments than the arity of f.]] +[[Effects][Creates a Python callable object which, when called from Python, converts its arguments to C++ and calls f. If F is a pointer-to-member-function type, the target object of the function call (*this) will be taken from the first Python argument, and subsequent Python arguments will be used as the arguments to f. + +* If policies are supplied, it will be applied to the function as described here. +* If keywords are supplied, the keywords will be applied in order to the final arguments of the resulting function. +* If Signature is supplied, it should be an instance of an MPL front-extensible sequence representing the function's return type followed by its argument types. Pass a Signature when wrapping function object types whose signatures can't be deduced, or when you wish to override the types which will be passed to the wrapped function. ]] +[[Returns][An instance of object which holds the new Python callable object.]] +[[Caveats][An argument of pointer type may be 0 if None is passed from Python. An argument type which is a constant reference may refer to a temporary which was created from the Python object for just the duration of the call to the wrapped function, for example a std::vector conjured up by the conversion process from a Python list. Use a non-const reference argument when a persistent lvalue is required. ]] +] +`` +template +object make_constructor(F f) + +template +object make_constructor(F f, Policies const& policies) + +template +object make_constructor(F f, Policies const& policies, KeywordsOrSignature const& ks) + +template +object make_constructor(F f, Policies const& policies, Keywords const& kw, Signature const& sig) +`` +[variablelist +[[Requires][F is a function pointer type. If policies are supplied, it must be a model of CallPolicies. If kewords are supplied, it must be the result of a keyword-expression specifying no more arguments than the arity of f.]] +[[Effects][Creates a Python callable object which, when called from Python, converts its arguments to C++ and calls f.]] +[[Returns][An instance of object which holds the new Python callable object.]] +] + +[endsect] +[section Example] +C++ function exposed below returns a callable object wrapping one of two functions. +`` +#include +#include + +char const* foo() { return "foo"; } +char const* bar() { return "bar"; } + +using namespace boost::python; +object choose_function(bool selector) +{ + if (selector) + return boost::python::make_function(foo); + else + return boost::python::make_function(bar); +} + +BOOST_PYTHON_MODULE(make_function_test) +{ + def("choose_function", choose_function); +} +`` +It can be used this way in Python: +`` +>>> from make_function_test import * +>>> f = choose_function(1) +>>> g = choose_function(0) +>>> f() +'foo' +>>> g() +'bar' +`` +[endsect] +[endsect] diff --git a/doc/reference/manage_new_object.qbk b/doc/reference/manage_new_object.qbk new file mode 100644 index 00000000..df3840f9 --- /dev/null +++ b/doc/reference/manage_new_object.qbk @@ -0,0 +1,56 @@ +[section manage_new_object.hpp] +[section Class `manage_new_object`] +manage_new_object is a model of ResultConverterGenerator which can be used to wrap C++ functions which return a pointer to an object allocated with a new-expression, and expect the caller to take responsibility for deleting that object. +`` +namespace boost { namespace python +{ + struct manage_new_object + { + template struct apply; + }; +}} +`` +[endsect] +[section Class `manage_new_object` metafunctions] +``template struct apply`` +[variablelist +[[Requires][`T` is `U*` for some `U`.]] +[[Returns][`typedef to_python_indirect type;`]] +] +[endsect] +[section Example] +In C++: +`` +#include +#include +#include +#include + + +struct Foo { + Foo(int x) : x(x){} + int get_x() { return x; } + int x; +}; + +Foo* make_foo(int x) { return new Foo(x); } + +// Wrapper code +using namespace boost::python; +BOOST_PYTHON_MODULE(my_module) +{ + def("make_foo", make_foo, return_value_policy()) + class_("Foo") + .def("get_x", &Foo::get_x) + ; +} +`` +Python code: +`` +>>> from my_module import * +>>> f = make_foo(3) # create a Foo object +>>> f.get_x() +3 +`` +[endsect] +[endsect] diff --git a/doc/reference/module.qbk b/doc/reference/module.qbk new file mode 100644 index 00000000..ce194c29 --- /dev/null +++ b/doc/reference/module.qbk @@ -0,0 +1,41 @@ +[section module.hpp] +[section Introduction] +This header provides the basic facilities needed to create a Boost.Python extension module. +[endsect] +[section Macros] +`BOOST_PYTHON_MODULE(name)` is used to declare Python module initialization functions. The name argument must exactly match the name of the module to be initialized, and must conform to Python's identifier naming rules. Where you would normally write + +`` +extern "C" void initname() +{ + ... +} +`` +Boost.Python modules should be initialized with +`` +BOOST_PYTHON_MODULE(name) +{ + ... +} +`` +This macro generates two functions in the scope where it is used: `extern "C" void initname()`, and `void init_module_name()`, whose body must follow the macro invocation. `init_name` passes `init_module_name` to `handle_exception()` so that any C++ exceptions generated are safely processeed. During the body of `init_name`, the current scope refers to the module being initialized. +[endsect] +[section Examples] +C++ module definition: +`` +#include + +BOOST_PYTHON_MODULE(xxx) +{ + throw "something bad happened" +} +`` +Interactive Python: +`` +>>> import xxx +Traceback (most recent call last): + File "", line 1, in ? +RuntimeError: Unidentifiable C++ Exception +`` +[endsect] +[endsect] diff --git a/doc/reference/numeric.qbk b/doc/reference/numeric.qbk new file mode 100644 index 00000000..b0e6a8cb --- /dev/null +++ b/doc/reference/numeric.qbk @@ -0,0 +1,153 @@ +[section numeric.hpp] +[section Introduction] +Exposes a TypeWrapper for the Python array type. +[endsect] +[section Class `array`] +Provides access to the array types of Numerical Python's Numeric and NumArray modules. With the exception of the functions documented below, the semantics of the constructors and member functions defined below can be fully understood by reading the TypeWrapper concept definition. Since array is publicly derived from object, the public object interface applies to array instances as well. + +The default behavior is to use numarray.NDArray as the associated Python type if the numarray module is installed in the default location. Otherwise it falls back to use Numeric.ArrayType. If neither extension module is installed, overloads of wrapped C++ functions with numeric::array parameters will never be matched, and other attempted uses of numeric::array will raise an appropriate Python exception. The associated Python type can be set manually using the set_module_and_type(...) static function. +`` +namespace boost { namespace python { namespace numeric +{ + class array : public object + { + public: + object astype(); + template + object astype(Type const& type_); + + template + array new_(Type const& type_) const; + + template + void resize(Sequence const& x); + void resize(long x1); + void resize(long x1, long x2); + ... + void resize(long x1, long x2,...long xn); + + template + void setshape(Sequence const& x); + void setshape(long x1); + void setshape(long x1, long x2); + ... + void setshape(long x1, long x2,...long xn); + + template + void put(Indices const& indices, Values const& values); + + template + object take(Sequence const& sequence, long axis = 0); + + template + void tofile(File const& f) const; + + object factory(); + template + object factory(Sequence const&); + template + object factory(Sequence const&, Typecode const&, bool copy = true, bool savespace = false); + template + object factory(Sequence const&, Typecode const&, bool copy, bool savespace, Type const&); + template + object factory(Sequence const&, Typecode const&, bool copy, bool savespace, Type const&, Shape const&); + + template + explicit array(T1 const& x1); + template + explicit array(T1 const& x1, T2 const& x2); + ... + template + explicit array(T1 const& x1, T2 const& x2,...Tn const& xn); + + static void set_module_and_type(); + static void set_module_and_type(char const* package_path = 0, char const* type_name = 0); + static void get_module_name(); + + object argmax(long axis=-1); + + object argmin(long axis=-1); + + object argsort(long axis=-1); + + void byteswap(); + + object copy() const; + + object diagonal(long offset = 0, long axis1 = 0, long axis2 = 1) const; + + void info() const; + + bool is_c_array() const; + bool isbyteswapped() const; + void sort(); + object trace(long offset = 0, long axis1 = 0, long axis2 = 1) const; + object type() const; + char typecode() const; + + object getflat() const; + long getrank() const; + object getshape() const; + bool isaligned() const; + bool iscontiguous() const; + long itemsize() const; + long nelements() const; + object nonzero() const; + + void ravel(); + object repeat(object const& repeats, long axis=0); + void setflat(object const& flat); + void swapaxes(long axis1, long axis2); + str tostring() const; + void transpose(object const& axes = object()); + object view() const; + }; +}}} +`` +[endsect] +[section Class `array` observer functions] +`` +object factory(); +template +object factory(Sequence const&); +template +object factory(Sequence const&, Typecode const&, bool copy = true, bool savespace = false); +template +object factory(Sequence const&, Typecode const&, bool copy, bool savespace, Type const&); +template +object factory(Sequence const&, Typecode const&, bool copy, bool savespace, Type const&, Shape const&); +`` +These functions map to the underlying array type's array() function family. They are not called "array" because of the C++ limitation that you can't define a member function with the same name as its enclosing class. +`` +template +array new_(Type const&) const; +`` +This function maps to the underlying array type's new() function. It is not called "new" because that is a keyword in C++. +[endsect] +[section Class `array` static functions] +`` +static void set_module_and_type(char const* package_path, char const* type_name); +static void set_module_and_type(); +`` +[variablelist +[[Requires][package_path and type_name, if supplied, is an ntbs.]] +[[Effects][The first form sets the package path of the module that supplies the type named by type_name to package_path. The second form restores the default search behavior. The associated Python type will be searched for only the first time it is needed, and thereafter the first time it is needed after an invocation of set_module_and_type.]] +] +``static std::string get_module_name()`` +[variablename +[[Effects][Returns the name of the module containing the class that will be held by new numeric::array instances.]] +] +[endsect] +[section Example] +`` +#include +#include + +// sets the first element in a 2d numeric array +void set_first_element(numeric::array& y, double value) +{ + y[make_tuple(0,0)] = value; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/object.qbk b/doc/reference/object.qbk new file mode 100644 index 00000000..65881dac --- /dev/null +++ b/doc/reference/object.qbk @@ -0,0 +1,574 @@ +[section object.hpp] +[section Introduction] +Exposes the generic Python object wrapper class object, and related classes. In order to avoid some potenential problems with argument-dependent lookup and the generalized operators defined on object, all these facilities are defined in namespace boost::python::api, and object is imported into namespace boost::python with a using-declaration. +[endsect] +[section Class `slice_nil`] +`` +class slice_nil; +static const _ = slice_nil(); +`` +A type that can be used to get the effect of leaving out an index in a Python slice expression: +`` +>>> x[:-1] +>>> x[::-1] +`` +C++ equivalent: +`` +x.slice(_,-1) +x[slice(_,_,-1)] +`` +[endsect] +[section Class `const_attribute_policies`] +The policies which are used for proxies representing an attribute access to a const object. +`` +namespace boost { namespace python { namespace api +{ + struct const_attribute_policies + { + typedef char const* key_type; + static object get(object const& target, char const* key); + }; +}}} +`` +[endsect] +[section Class `const_attribute_policies` static functions] +`` +static object get(object const& target, char const* key); +`` +[variablelist +[[Requires][key is an ntbs.]] +[[Effects][accesses the attribute of target named by key.]] +[[Returns][An object managing the result of the attribute access.]] +[[Throws][error_already_set if a Python exception is raised.]] +] +[endsect] +[section Class `attribute_policies`] +The policies which are used for proxies representing an attribute access to a mutable object. +`` +namespace boost { namespace python { namespace api +{ + struct attribute_policies : const_attribute_policies + { + static object const& set(object const& target, char const* key, object const& value); + static void del(object const&target, char const* key); + }; +}}} +`` +[endsect] +[section Class `attribute_policies` static functions] +`` +static object const& set(object const& target, char const* key, object const& value); +`` +[variablelist +[[Requires][key is an ntbs.]] +[[Effects][sets the attribute of target named by key to value.]] +[[Throws][error_already_set if a Python exception is raised.]] +] +`` +static void del(object const&target, char const* key); +`` +[variablelist +[[Requires][key is an ntbs.]] +[[Effects][deletes the attribute of target named by key.]] +[[Throws][error_already_set if a Python exception is raised.]] +] +[endsect] +[section Class `const_objattribute_policies`] +The policies which are used for proxies representing an attribute access to a const object when the attribute name is given as a const object. +`` +namespace boost { namespace python { namespace api +{ + struct const_objattribute_policies + { + typedef object const& key_type; + static object get(object const& target, object const& key); + }; +}}} +`` +[endsect] +[section Class `const_objattribute_policies` static functions] +`` +static object get(object const& target, object const& key); +`` +[variablelist +[[Requires][key is an object holding a string.]] +[[Effects][accesses the attribute of target named by key.]] +[[Returns][An object managing the result of the attribute access.]] +[[Throws][error_already_set if a Python exception is raised.]] +] +[endsect] +[section Class `objattribute_policies`] +The policies which are used for proxies representing an attribute access to a mutable object when the attribute name is given as a const object. +`` +namespace boost { namespace python { namespace api +{ + struct objattribute_policies : const_objattribute_policies + { + static object const& set(object const& target, object const& key, object const& value); + static void del(object const&target, object const& key); + }; +}}} +`` +[endsect] +[section Class `objattribute_policies` static functions] +`` +static object const& set(object const& target, object const& key, object const& value); +`` +[variablelist +[[Requires][key is an object holding a string.]] +[[Effects][sets the attribute of target named by key to value.]] +[[Throws][error_already_set if a Python exception is raised.]] +] +`` +static void del(object const&target, object const& key); +`` +[variablelist +[[Requires][key is an object holding a string.]] +[[Effects][deletes the attribute of target named by key.]] +[[Throws][error_already_set if a Python exception is raised.]] +] +[endsect] +[section Class `const_item_policies`] +The policies which are used for proxies representing an item access (via the Python bracket operators []) to a const object. +`` +namespace boost { namespace python { namespace api +{ + struct const_item_policies + { + typedef object key_type; + static object get(object const& target, object const& key); + }; +}}} +`` +[endsect] +[section Class `const_item_policies` static functions] +`` +static object get(object const& target, object const& key); +`` +[variablelist +[[Effects][accesses the item of target specified by key.]] +[[Returns][An object managing the result of the item access.]] +[[Throws][error_already_set if a Python exception is raised.]] +] +[endsect] +[section Class `item_policies`] +The policies which are used for proxies representing an item access (via the Python bracket operators []) to a mutable object. +`` +namespace boost { namespace python { namespace api +{ + struct item_policies : const_item_policies + { + static object const& set(object const& target, object const& key, object const& value); + static void del(object const& target, object const& key); + }; +}}} +`` +[endsect] +[section Class `item_policies` static functions] +`` +static object const& set(object const& target, object const& key, object const& value); +`` +[variablelist +[[Effects][sets the item of target specified by key to value.]] +[[Throws][error_already_set if a Python exception is raised.]] +] +`` +static void del(object const& target, object const& key); +`` +[variablelist +[[Effects][deletes the item of target specified by key.]] +[[Throws][ error_already_set if a Python exception is raised.]] +] +[endsect] +[section Class `const_slice_policies`] +The policies which are used for proxies representing an slice access (via the Python slice notation [x:y]) to a const object. +`` +namespace boost { namespace python { namespace api +{ + struct const_slice_policies + { + typedef std::pair, handle<> > key_type; + static object get(object const& target, key_type const& key); + }; +}}} +`` +[endsect] +[section Class `const_slice_policies` static functions] +`` +static object get(object const& target, key_type const& key); +`` +[variablelist +[[Effects][accesses the slice of target specified by key.]] +[[Returns][An object managing the result of the slice access.]] +[[Throws][error_already_set if a Python exception is raised.]] +] +[endsect] +[section Class `slice_policies`] +The policies which are used for proxies representing an slice access to a mutable object. +`` +namespace boost { namespace python { namespace api +{ + struct slice_policies : const_slice_policies + { + static object const& set(object const& target, key_type const& key, object const& value); + static void del(object const& target, key_type const& key); + }; +}}} +`` +[endsect] +[section Class `slice_policies` static functions] +`` +static object const& set(object const& target, key_type const& key, object const& value); +`` +[variablelist +[[Effects][sets the slice of target specified by key to value.]] +[[Throws][error_already_set if a Python exception is raised.]] +] +`` +static void del(object const& target, key_type const& key); +`` +[variablelist +[[Effects][deletes the slice of target specified by key.]] +[[Throws][error_already_set if a Python exception is raised.]] +] +[endsect] +[section Class template `object_operators`] +This is the base class of object and its proxy template used to supply common interface: member functions, and operators which must be defined within the class body. Its template parameter U is expected to be a class derived from object_operators. In practice users should never use this class directly, but it is documented here because it supplies important interface to object and its proxies. +`` +namespace boost { namespace python { namespace api +{ + template + class object_operators + { + public: + // function call + // + object operator()() const; + + template + object operator()(A0 const&) const; + template + object operator()(A0 const&, A1 const&) const; + ... + template + object operator()(A0 const&, A1 const&,...An const&) const; + + detail::args_proxy operator* () const; + object operator()(detail::args_proxy const &args) const; + object operator()(detail::args_proxy const &args, + detail::kwds_proxy const &kwds) const; + + // truth value testing + // + typedef unspecified bool_type; + operator bool_type() const; + + // Attribute access + // + proxy attr(char const*) const; + proxy attr(char const*); + proxy attr(object const&) const; + proxy attr(object const&); + + // item access + // + template + proxy operator[](T const& key) const; + + template + proxy operator[](T const& key); + + // slicing + // + template + proxy slice(T const& start, V const& end) const + + template + proxy slice(T const& start, V const& end); + }; +}}} +`` +[endsect] +[section Class template `object_operators` observer functions] +`` +object operator()() const; +template +object operator()(A0 const&) const; +template +object operator()(A0 const&, A1 const&) const; +... +template +object operator()(A0 const& a1, A1 const& a2,...An const& aN) const; +`` +[variablelist +[[Effects][`call(object(*static_cast(this)).ptr(), a1, a2,...aN)`]] +] +``object operator()(detail::args_proxy const &args) const; `` +[variablelist +[[Effects][`call object with arguments given by the tuple args`]] +] +``object operator()(detail::args_proxy const &args, + detail::kwds_proxy const &kwds) const; + +`` +[variablelist +[[Effects][`call object with arguments given by the tuple args, and named arguments given by the dictionary kwds`]] +] +``operator bool_type() const;`` +[variablelist +[[Effects][Tests truth value of `*this`.]] +[[Returns][`call(object(*static_cast(this)).ptr(), a1, a2,...aN)`]] +] +`` +proxy attr(char const* name) const; +proxy attr(char const* name); +`` +[variablelist +[[Requires][name is an ntbs.]] +[[Effects][accesses the named attribute of *this.]] +[[Returns][a proxy object which binds object(*static_cast(this)) as its target, and name as its key.]] +] +`` +proxy attr(const object& name) const; +proxy attr(const object& name); +`` +[variablelist +[[Requires][name is a object holding a string.]] +[[Effects][accesses the named attribute of *this.]] +[[Returns][a proxy object which binds object(*static_cast(this)) as its target, and name as its key.]] +] +`` +template +proxy operator[](T const& key) const; +template +proxy operator[](T const& key); +`` +[variablelist +[[Effects][accesses the item of *this indicated by key.]] +[[Returns][a proxy object which binds object(*static_cast(this)) as its target, and object(key) as its key.]] +] +`` +template +proxy slice(T const& start; start, V const& finish) const +template +proxy slice(T const& start; start, V const& finish); +`` +[variablelist +[[Effects][accesses the slice of *this indicated by std::make_pair(object(start), object(finish)).]] +[[Returns][a proxy object which binds object(*static_cast(this)) as its target, and std::make_pair(object(start), object(finish)) as its key.]] +] +[endsect] +[section Class `object`] +The intention is that object acts as much like a Python variable as possible. Thus expressions you'd expect to work in Python should generally work in the same way from C++. Most of object's interface is provided by its base class object_operators, and the free functions defined in this header. +`` +namespace boost { namespace python { namespace api +{ + class object : public object_operators + { + public: + object(); + object(object const&); + template + explicit object(T const& x); + + ~object(); + + object& operator=(object const&); + PyObject* ptr() const; + bool is_none() const; + }; +}}} +`` +[endsect] +[section Class `object` constructors and destructor] +``object();`` +[variablelist +[[Effects][Constructs an object managing a reference to the Python None object.]] +[[Throws][nothing.]] +] +``template +explicit object(T const& x); +`` +[variablelist +[[Effects][converts x to python and manages a reference to it.]] +[[Throws][error_already_set and sets a Python TypeError exception if no such conversion is possible.]] +] +`` +~object(); +`` +[variablelist +[[Effects][decrements the reference count of the internally-held object.]] +] +[endsect] +[section Class `object` modifiers] +``PyObject* ptr() const;`` + +[variablelist +[[Returns] [a pointer to the internally-held Python object.]] +] +``bool is_none() const;`` + +[variablelist +[[Returns] [result of (ptr() == Py_None)]] +] +[endsect] +[section Class template `proxy`] +This template is instantiated with various Policies described in this document in order to implement attribute, item, and slice access for object. It stores an object of type Policies::key_type. +`` +namespace boost { namespace python { namespace api +{ + template + class proxy : public object_operators > + { + public: + operator object() const; + + proxy const& operator=(proxy const&) const; + template + inline proxy const& operator=(T const& rhs) const; + + void del() const; + + template + proxy operator+=(R const& rhs); + template + proxy operator-=(R const& rhs); + template + proxy operator*=(R const& rhs); + template + proxy operator/=(R const& rhs); + template + proxy operator%=(R const& rhs); + template + proxy operator<<=(R const& rhs); + template + proxy operator>>=(R const& rhs); + template + proxy operator&=(R const& rhs); + template + proxy operator|=(R const& rhs); + }; +}}} +`` +[endsect] +[section Class template `proxy` observer functions] +``operator object() const;`` +[variablelist +[[Effects][applies Policies::get(target, key ) with the proxy's target and key objects.]] +] +[endsect] +[section Class template `proxy` modifier functions] +`` +proxy const& operator=(proxy const& rhs) const; +template +inline proxy const& operator=(T const& rhs) const; +`` +[variablelist +[[Effects][ Policies::set(target, key , object(rhs)) with the proxy's target and key objects.]] +] +`` +template +proxy operator+=(R const& rhs); +template +proxy operator-=(R const& rhs); +template +proxy operator*=(R const& rhs); +template +proxy operator/=(R const& rhs); +template +proxy operator%=(R const& rhs); +template +proxy operator<<=(R const& rhs); +template +proxy operator>>=(R const& rhs); +template +proxy operator&=(R const& rhs); +template +proxy operator|=(R const& rhs); +`` +[variablelist +[[Effects][for a given operator@=, object(*this) @= rhs;]] +[[Returns][`*this`]] +] +``void del() const;`` +[variablelist +[[Effects][Policies::del(target, key ) with the proxy's target and key objects.]] +] +[endsect] +[section Functions] +`` +template +void del(proxy const& x); +`` +[variablelist +[[Effects][`x.del()`]] +] +`` +template object operator>(L const&l,R const&r); +template object operator>=(L const&l,R const&r); +template object operator<(L const&l,R const&r); +template object operator<=(L const&l,R const&r); +template object operator==(L const&l,R const&r); +template object operator!=(L const&l,R const&r); +`` +[variablelist +[[Effects][returns the result of applying the operator to object(l) and object(r), respectively, in Python.]] +] +`` +template object operator+(L const&l,R const&r); +template object operator-(L const&l,R const&r); +template object operator*(L const&l,R const&r); +template object operator/(L const&l,R const&r); +template object operator%(L const&l,R const&r); +template object operator<<(L const&l,R const&r); +template object operator>>(L const&l,R const&r); +template object operator&(L const&l,R const&r); +template object operator^(L const&l,R const&r); +template object operator|(L const&l,R const&r); +`` +[variablelist +[[Effects][returns the result of applying the operator to object(l) and object(r), respectively, in Python.]] +] +`` +template object& operator+=(object&l,R const&r); +template object& operator-=(object&l,R const&r); +template object& operator*=(object&l,R const&r); +template object& operator/=(object&l,R const&r); +template object& operator%=(object&l,R const&r); +template object& operator<<=(object&l,R const&r) +template object& operator>>=(object&l,R const&r); +template object& operator&=(object&l,R const&r); +template object& operator^=(object&l,R const&r); +template object& operator|=(object&l,R const&r); +`` +[variablelist +[[Effects][assigns to l the result of applying the corresponding Python inplace operator to l and object(r), respectively.]] +[[Returns][l]] +] +``long len(object const& obj);`` +[variablelist +[[Effects][`PyObject_Length(obj.ptr())`]] +[[Returns][`len()` of object.]] +] +[endsect] +[section Example] +Python code: +`` +def sum_items(seq): + result = 0 + for x in seq: + result += x + return result +`` +C++ version +`` +object sum_items(object seq) +{ + object result = object(0); + for (int i = 0; i < len(seq); ++i) + result += seq[i]; + return result; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/objects.qbk b/doc/reference/objects.qbk new file mode 100644 index 00000000..80ce257c --- /dev/null +++ b/doc/reference/objects.qbk @@ -0,0 +1,12 @@ +[chapter Object Wrappers + [quickbook 1.7] +] + +[include dict.qbk] +[include list.qbk] +[include long.qbk] +[include numeric.qbk] +[include object.qbk] +[include str.qbk] +[include slice.qbk] +[include tuple.qbk] diff --git a/doc/reference/opaque_pointer_converter.qbk b/doc/reference/opaque_pointer_converter.qbk new file mode 100644 index 00000000..93eb0b53 --- /dev/null +++ b/doc/reference/opaque_pointer_converter.qbk @@ -0,0 +1,30 @@ +[section opaque_pointer_converter.hpp] +[section Introduction] +opaque<> registers itself as a converter from Python objects to pointers to undefined types and vice versa. +`` +namespace boost { namespace python +{ + template + struct opaque + { + opaque(); + }; +}} +`` +[section Class template opaque constructor] +``opaque();`` +[variablelist +[[Effects][ +* Registers the instance as a lvalue_from_pytype converter from Python objects into opaque pointers. + The Python Objects created are named after the type pointed to by the opaque pointer being wrapped. +* Registers the instance as a to_python_converter from opaque pointers to Python objects. +]] +] +[note If there is already an instance registered by another module, this instance doesn't try to register again in order to avoid warnings about multiple registrations.] + +[endsect] +[section Macro `BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee)`] +This macro must be used to define specializations of the type_id function which can't be instantiated for incomplete types. +[note The macro must be invoked in every translation unit which uses the opaque converter.] +[endsect] +[endsect] diff --git a/doc/reference/operators.qbk b/doc/reference/operators.qbk new file mode 100644 index 00000000..b9792f5a --- /dev/null +++ b/doc/reference/operators.qbk @@ -0,0 +1,257 @@ +[section operators.hpp] +[section Introduction] + provides types and functions for automatically generating Python special methods from the corresponding C++ constructs. Most of these constructs are operator expressions, hence the name. To use the facility, substitute the self object for an object of the class type being wrapped in the expression to be exposed, and pass the result to class_<>::def(). Much of what is exposed in this header should be considered part of the implementation, so is not documented in detail here. +[endsect] +[section Class `self_ns::self_t`] +`self_ns::self_t` is the actual type of the self object. The library isolates `self_t` in its own namespace, `self_ns`, in order to prevent the generalized operator templates which operate on it from being found by argument-dependent lookup in other contexts. This should be considered an implementation detail, since users should never have to mention `self_t` directly. +`` +namespace boost { namespace python { namespace self_ns { +{ + unspecified-type-declaration self_t; + + // inplace operators + template operator_ operator+=(self_t, T); + template operator_ operator-=(self_t, T); + template operator_ operator*=(self_t, T); + template operator_ operator/=(self_t, T); + template operator_ operator%=(self_t, T); + template operator_ operator>>=(self_t, T); + template operator_ operator<<=(self_t, T); + template operator_ operator&=(self_t, T); + template operator_ operator^=(self_t, T); + template operator_ operator|=(self_t, T); + + // comparisons + template operator_ operator==(L const&, R const&); + template operator_ operator!=(L const&, R const&); + template operator_ operator<(L const&, R const&); + template operator_ operator>(L const&, R const&); + template operator_ operator<=(L const&, R const&); + template operator_ operator>=(L const&, R const&); + + // non-member operations + template operator_ operator+(L const&, R const&); + template operator_ operator-(L const&, R const&); + template operator_ operator*(L const&, R const&); + template operator_ operator/(L const&, R const&); + template operator_ operator%(L const&, R const&); + template operator_ operator>>(L const&, R const&); + template operator_ operator<<(L const&, R const&); + template operator_ operator&(L const&, R const&); + template operator_ operator^(L const&, R const&); + template operator_ operator|(L const&, R const&); + template operator_ pow(L const&, R const&); + + // unary operations + operator_ operator-(self_t); + operator_ operator+(self_t); + operator_ operator~(self_t); + operator_ operator!(self_t); + + // value operations + operator_ int_(self_t); + operator_ long_(self_t); + operator_ float_(self_t); + operator_ complex_(self_t); + operator_ str(self_t); + + operator_ repr(self_t); +}}}; +`` +The tables below describe the methods generated when the results of the expressions described are passed as arguments to class_<>::def(). x is an object of the class type being wrapped. +[section `self_t` inplace operators] +In the table below, If r is an object of type other, y is an object of type T; otherwise, y is an object of the same type as r. +[table +[[C++ Expression][Python Method Name][C++ Implementation]] +[[`self += r`][`__iadd__`][`x += y`]] +[[`self -= r`][`__isub__`][`x -= y`]] +[[`self *= r`][`__imul__`][`x *= y`]] +[[`self /= r`][`__idiv__`][`x /= y`]] +[[`self %= r`][`__imod__`][`x %= y`]] +[[`self >>= r`][`__irshift__`][`x >>= y`]] +[[`self <<= r`][`__ilshift__`][`x <<= y`]] +[[`self &= r`][`__iand__`][`x &= y`]] +[[`self ^= r`][`__ixor__`][`x ^= y`]] +[[`self |= r`][`__ior__`][`x |= y`]] +] +[endsect] +[section `self_t` comparison functions] +In the tables below, if r is of type self_t, y is an object of the same type as x; +if l or r is an object of type other, y is an object of type T; +otherwise, y is an object of the same type as l or r. +l is never of type self_t. + +The column of Python Expressions illustrates the expressions that will be supported in Python for objects convertible to the types of x and y. The secondary operation arises due to Python's reflection rules for rich comparison operators, and are only used when the corresponding operation is not defined as a method of the y object. +[table +[[C++ Expression][Python Method Name][C++ Implementation][Python Expression (primary, secondary)]] +[[`self == r`][`__eq__`][`x == y`][`x == y`, `y == x`]] +[[`l == self`][`__eq__`][`y == x`][`y == x`, `x == y`]] +[[`self != r`][`__nq__`][`x != y`][`x != y`, `y != x`]] +[[`l != self`][`__nq__`][`y != x`][`y != x`, `x != y`]] +[[`self < r`][`__lt__`][`x < y`][`x < y`, `y > x`]] +[[`l < self`][`__gt__`][`y < x`][`y > x`, `x < y`]] +[[`self > r`][`__gt__`][`x > y`][`x > y`, `y < x`]] +[[`l > self`][`__lt__`][`y > x`][`y < x`, `x > y`]] +[[`self <= r`][`__le__`][`x <= y`][`x <= y`, `y >= x`]] +[[`l <= self`][`__ge__`][`y <= x`][`y >= x`, `x <= y`]] +[[`self >= r`][`__ge__`][`x >= y`][`x >= y`, `y <= x`]] +[[`l <= self`][`__le__`][`y >= x`][`y <= x`, `x >= y`]] +] +[endsect] +[section `self_t` non-member operations] +The operations whose names begin with "__r" below will only be called if the left-hand operand does not already support the given operation, as described here. +[table +[[C++ Expression][Python Method Name][C++ Implementation]] +[[`self + r`][`__add__`][`x + y`]] +[[`l + self`][`__radd__`][`y + x`]] +[[`self - r`][`__sub__`][`x - y`]] +[[`l - self`][`__rsub__`][`y - x`]] +[[`self * r`][`__mult__`][`x * y`]] +[[`l * self`][`__rmult__`][`y * x`]] +[[`self / r`][`__div__`][`x / y`]] +[[`l / self`][`__rdiv__`][`y / x`]] +[[`self % r`][`__mod__`][`x % y`]] +[[`l % self`][`__rmod__`][`y % x`]] +[[`self >> r`][`__rshift__`][`x >> y`]] +[[`l >> self`][`__rrshift__`][`y >> x`]] +[[`self << r`][`__lshift__`][`x << y`]] +[[`l << self`][`__rlshift__`][`y << x`]] +[[`self & r`][`__and__`][`x & y`]] +[[`l & self`][`__rand__`][`y & x`]] +[[`self ^ r`][`__xor__`][`x ^ y`]] +[[`l ^ self`][`__rxor__`][`y ^ x`]] +[[`self | r`][`__or__`][`x | y`]] +[[`l | self`][`__ror__`][`y | x`]] +[[`pow(self, r)`][`__pow__`][`x ** y`]] +[[`pow(l, self)`][`__rpow__`][`y ** x`]] +] +[endsect] +[section `self_t` unary operations] +[table +[[C++ Expression][Python Method Name][C++ Implementation]] +[[`-self`][`__neg__`][`-x`]] +[[`+self`][`__pos__`][`+x`]] +[[`~self`][`__invert__`][`~x`]] +[[`not self` or `!self`][`__nonzero__`][`!!x`]] +] +[endsect] +[section `self_t` value operations] +[table +[[C++ Expression][Python Method Name][C++ Implementation]] +[[`int_(self)`][`__int__`][`long(x)`]] +[[`long_(self)`][`__long__`][`PyLong_FromLong(x)`]] +[[`float_(self)`][`__float__`][`double(x)`]] +[[`complex_(self)`][`__complex__`][`std::complex(x)`]] +[[`str(self)`][`__str__`][`lexical_cast(x)`]] +[[`repr(self)`][`__repr__`][`lexical_cast(x)`]] +] +[endsect] +[endsect] +[section Class template `other`] +Instances of other can be used in operator expressions with self; the result is equivalent to the same expression with a T object in place of other. Use other to prevent construction of a T object in case it is heavyweight, when no constructor is available, or simply for clarity. +`` +namespace boost { namespace python +{ + template + struct other + { + }; +}} +`` +[endsect] +[section Class template `detail::operator_`] +Instantiations of detail::operator_<> are used as the return type of operator expressions involving self. This should be considered an implementation detail and is only documented here as a way of showing how the result of self-expressions match calls to class_<>::def(). +`` +namespace boost { namespace python { namespace detail +{ + template + struct operator_ + { + }; +}}} +`` +[endsect] +[section Object `self`] +`` +namespace boost { namespace python +{ + using self_ns::self; +}} +`` +[endsect] +[section Example] +`` +#include +#include +#include +#include + +struct number + : boost::integer_arithmetic +{ + explicit number(long x_) : x(x_) {} + operator long() const { return x; } + + template + number& operator+=(T const& rhs) + { x += rhs; return *this; } + + template + number& operator-=(T const& rhs) + { x -= rhs; return *this; } + + template + number& operator*=(T const& rhs) + { x *= rhs; return *this; } + + template + number& operator/=(T const& rhs) + { x /= rhs; return *this; } + + template + number& operator%=(T const& rhs) + { x %= rhs; return *this; } + + long x; +}; + +using namespace boost::python; +BOOST_PYTHON_MODULE(demo) +{ + class_("number", init()) + // interoperate with self + .def(self += self) + .def(self + self) + .def(self -= self) + .def(self - self) + .def(self *= self) + .def(self * self) + .def(self /= self) + .def(self / self) + .def(self %= self) + .def(self % self) + + // Convert to Python int + .def(int_(self)) + + // interoperate with long + .def(self += long()) + .def(self + long()) + .def(long() + self) + .def(self -= long()) + .def(self - long()) + .def(long() - self) + .def(self *= long()) + .def(self * long()) + .def(long() * self) + .def(self /= long()) + .def(self / long()) + .def(long() / self) + .def(self %= long()) + .def(self % long()) + .def(long() % self) + ; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/overloads.qbk b/doc/reference/overloads.qbk new file mode 100644 index 00000000..09a89f6d --- /dev/null +++ b/doc/reference/overloads.qbk @@ -0,0 +1,97 @@ +[section overloads.hpp] +[section Introduction] +Defines facilities for generating families of overloaded Python functions and extension class methods from C++ functions and member functions with default arguments, or from similar families of C++ overloads +[section overload-dispatch-expressions] +An overload-dispatch-expression is used to describe a family of overloaded methods to be generated for an extension class. It has the following properties: +[variablelist +[[docstring][An ntbs whose value will bound to the methods' __doc__ attribute]] +[[keywords][A keyword-expression which will be used to name (a trailing subsequence of) the arguments to the generated methods.]] +[[call policies][An instance of some type which models CallPolicies.]] +[[minimum arity][The minimum number of arguments to be accepted by a generated method overload.]] +[[maximum arity][The maximum number of arguments to be accepted by a generated method overload.]] +] +[endsect] +[endsect] +[section OverloadDispatcher Concept] +An OverloadDispatcher X is a class which has a minimum arity and a maximum arity, and for which the following following are valid overload-dispatch-expressions, with the same minimum and maximum arity as the OverloadDispatcher. +`` +X() +X(docstring) +X(docstring, keywords) +X(keywords, docstring) +X()[policies] +X(docstring)[policies] +X(docstring, keywords)[policies] +X(keywords, docstring)[policies] +`` +* If policies are supplied, it must be an instance of a type which models CallPolicies, and will be used as the result's call policies. Otherwise the result's call policies will be an instance of default_call_policies. +* If docstring is supplied it must be an ntbs, and will be used as the result's docstring. Otherwise the result has an empty docstring. +* If keywords is supplied it must be the result of a keyword-expression whose length is no greater than X's maximum arity, and will be used as the result's keywords. Otherwise the result's keywords will be empty. +[endsect] +[section Macros] +`` +BOOST_PYTHON_FUNCTION_OVERLOADS(name, func_id, min_args, max_args) +`` +Expands to the definition of an OverloadDispatcher called name in the current scope which can be used to generate the following function invocation: +``func_id(a1, a2,...ai);`` +for all `min_args <= i <= max_args`. +`` +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(name, member_name, min_args, max_args) +`` +Expands to the definition of an OverloadDispatcher called name in the current scope which can be used to generate the following function invocation: +``x.member_name(a1, a2,...ai);`` +for all min_args <= i <= max_args, where x is a reference to an object of class type. +[endsect] +[section Example] +`` +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::python; + +tuple f(int x = 1, double y = 4.25, char const* z = "wow") +{ + return make_tuple(x, y, z); +} + +BOOST_PYTHON_FUNCTION_OVERLOADS(f_overloads, f, 0, 3) + +struct Y {}; +struct X +{ + Y& f(int x, double y = 4.25, char const* z = "wow") + { + return inner; + } + Y inner; +}; + +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(f_member_overloads, f, 1, 3) + +BOOST_PYTHON_MODULE(args_ext) +{ + def("f", f, + f_overloads( + args("x", "y", "z"), "This is f's docstring" + )); + + + class_("Y") + ; + + class_("X", "This is X's docstring") + .def("f1", &X::f, + f_member_overloads( + args("x", "y", "z"), "f's docstring" + )[return_internal_reference<>()] + ) + ; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/pickle.qbk b/doc/reference/pickle.qbk new file mode 100644 index 00000000..c451a7a4 --- /dev/null +++ b/doc/reference/pickle.qbk @@ -0,0 +1,159 @@ +[section Pickle support] +[section Introduction] +Pickle is a Python module for object serialization, also known as persistence, marshalling, or flattening. + +It is often necessary to save and restore the contents of an object to a file. One approach to this problem is to write a pair of functions that read and write data from a file in a special format. A powerful alternative approach is to use Python's pickle module. Exploiting Python's ability for introspection, the pickle module recursively converts nearly arbitrary Python objects into a stream of bytes that can be written to a file. + +The Boost Python Library supports the pickle module through the interface as described in detail in the Python Library Reference for pickle. This interface involves the special methods __getinitargs__, __getstate__ and __setstate__ as described in the following. Note that Boost.Python is also fully compatible with Python's cPickle module. +[endsect] +[section The Pickle Interface] +At the user level, the Boost.Python pickle interface involves three special methods: +[variablelist +[[__getinitargs__][When an instance of a Boost.Python extension class is pickled, the pickler tests if the instance has a __getinitargs__ method. This method must return a Python tuple (it is most convenient to use a boost::python::tuple). When the instance is restored by the unpickler, the contents of this tuple are used as the arguments for the class constructor. + +If __getinitargs__ is not defined, pickle.load will call the constructor (__init__) without arguments; i.e., the object must be default-constructible.]] +[[__getstate__][ When an instance of a Boost.Python extension class is pickled, the pickler tests if the instance has a __getstate__ method. This method should return a Python object representing the state of the instance.]] +[[__setstate__][When an instance of a Boost.Python extension class is restored by the unpickler (pickle.load), it is first constructed using the result of __getinitargs__ as arguments (see above). Subsequently the unpickler tests if the new instance has a __setstate__ method. If so, this method is called with the result of __getstate__ (a Python object) as the argument.]] +] + +The three special methods described above may be .def()'ed individually by the user. However, Boost.Python provides an easy to use high-level interface via the boost::python::pickle_suite class that also enforces consistency: __getstate__ and __setstate__ must be defined as pairs. Use of this interface is demonstrated by the following examples. +[endsect] +[section Example] +There are three files in boost/libs/python/test that show how to provide pickle support. +[section pickle1.cpp] +The C++ class in this example can be fully restored by passing the appropriate argument to the constructor. Therefore it is sufficient to define the pickle interface method __getinitargs__. This is done in the following way: +Definition of the C++ pickle function: +`` +struct world_pickle_suite : boost::python::pickle_suite +{ + static + boost::python::tuple + getinitargs(world const& w) + { + return boost::python::make_tuple(w.get_country()); + } +}; +`` +Establishing the Python binding: +`` +class_("world", args()) + // ... + .def_pickle(world_pickle_suite()) + // ... +`` +[endsect] +[section pickle2.cpp] +The C++ class in this example contains member data that cannot be restored by any of the constructors. Therefore it is necessary to provide the __getstate__/__setstate__ pair of pickle interface methods: + +Definition of the C++ pickle functions: +`` +struct world_pickle_suite : boost::python::pickle_suite + { + static + boost::python::tuple + getinitargs(const world& w) + { + // ... + } + + static + boost::python::tuple + getstate(const world& w) + { + // ... + } + + static + void + setstate(world& w, boost::python::tuple state) + { + // ... + } + }; +`` +Establishing the Python bindings for the entire suite: +`` + class_("world", args()) + // ... + .def_pickle(world_pickle_suite()) + // ... + +`` + +For simplicity, the __dict__ is not included in the result of __getstate__. This is not generally recommended, but a valid approach if it is anticipated that the object's __dict__ will always be empty. Note that the safety guard described below will catch the cases where this assumption is violated. +[endsect] +[section pickle3.cpp] +This example is similar to pickle2.cpp. However, the object's __dict__ is included in the result of __getstate__. This requires a little more code but is unavoidable if the object's __dict__ is not always empty. +[endsect] +[endsect] +[section Pitfall and Safety Guard] +The pickle protocol described above has an important pitfall that the end user of a Boost.Python extension module might not be aware of: + +[*__getstate__ is defined and the instance's __dict__ is not empty.] + +The author of a Boost.Python extension class might provide a __getstate__ method without considering the possibilities that: +* his class is used in Python as a base class. Most likely the __dict__ of instances of the derived class needs to be pickled in order to restore the instances correctly. +* the user adds items to the instance's __dict__ directly. Again, the __dict__ of the instance then needs to be pickled. + +To alert the user to this highly unobvious problem, a safety guard is provided. If __getstate__ is defined and the instance's __dict__ is not empty, Boost.Python tests if the class has an attribute __getstate_manages_dict__. An exception is raised if this attribute is not defined: + +`` + RuntimeError: Incomplete pickle support (__getstate_manages_dict__ not set) +`` + +To resolve this problem, it should first be established that the __getstate__ and __setstate__ methods manage the instances's __dict__ correctly. Note that this can be done either at the C++ or the Python level. Finally, the safety guard should intentionally be overridden. E.g. in C++ (from pickle3.cpp): + +`` +struct world_pickle_suite : boost::python::pickle_suite + { + // ... + + static bool getstate_manages_dict() { return true; } + }; +`` + +Alternatively in Python: + +`` +import your_bpl_module +class your_class(your_bpl_module.your_class): + __getstate_manages_dict__ = 1 + def __getstate__(self): + # your code here + def __setstate__(self, state): + # your code here + +`` +[endsect] +[section Practical Advice] + +* In Boost.Python extension modules with many extension classes, providing complete pickle support for all classes would be a significant overhead. In general complete pickle support should only be implemented for extension classes that will eventually be pickled. +* Avoid using __getstate__ if the instance can also be reconstructed by way of __getinitargs__. This automatically avoids the pitfall described above. +* If __getstate__ is required, include the instance's __dict__ in the Python object that is returned. + +[endsect] +[section Light-weight alternative: pickle support implemented in Python] +The pickle4.cpp example demonstrates an alternative technique for implementing pickle support. First we direct Boost.Python via the class_::enable_pickling() member function to define only the basic attributes required for pickling: + +`` + class_("world", args()) + // ... + .enable_pickling() + // ... +`` +This enables the standard Python pickle interface as described in the Python documentation. By "injecting" a __getinitargs__ method into the definition of the wrapped class we make all instances pickleable: + +`` + # import the wrapped world class + from pickle4_ext import world + + # definition of __getinitargs__ + def world_getinitargs(self): + return (self.get_country(),) + + # now inject __getinitargs__ (Python is a dynamic language!) + world.__getinitargs__ = world_getinitargs +`` +See also the tutorial section on injecting additional methods from Python. +[endsect] +[endsect] diff --git a/doc/reference/pointee.qbk b/doc/reference/pointee.qbk new file mode 100644 index 00000000..ec77af1d --- /dev/null +++ b/doc/reference/pointee.qbk @@ -0,0 +1,47 @@ +[section pointee.hpp] +[section Introduction] + introduces a traits metafunction template pointee that can be used to extract the "pointed-to" type from the type of a pointer or smart pointer. +[endsect] +[section Class template `pointee`] +pointee is used by the class_<...> template to deduce the type being held when a pointer or smart pointer type is used as its HeldType argument. +`` +namespace boost { namespace python +{ + template struct pointee + { + typedef T::element_type type; + }; + + // specialization for pointers + template struct pointee + { + typedef T type; + }; +} +`` +[endsect] +[section Examples] + Given a 3rd-party smart pointer type smart_pointer, one might partially specialize pointee > so that it can be used as the HeldType for a class wrapper: +`` +#include +#include +#include + +namespace boost { namespace python +{ + template struct pointee > + { + typedef T type; + }; +}} + +BOOST_PYTHON_MODULE(pointee_demo) +{ + class_ >("third_party_class") + .def(...) + ... + ; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/ptr.qbk b/doc/reference/ptr.qbk new file mode 100644 index 00000000..c369eccf --- /dev/null +++ b/doc/reference/ptr.qbk @@ -0,0 +1,118 @@ +[section ptr.hpp] +[section Introduction] + defines the ptr() function template, which allows users to specify how to convert C++ pointer values to python in the context of implementing overridable virtual functions, invoking Python callable objects, or explicitly converting C++ objects to Python. Normally, when passing pointers to Python callbacks, the pointee is copied to ensure that the Python object never holds a dangling reference. To specify that the new Python object should merely contain a copy of a pointer p, the user can pass ptr(p) instead of passing p directly. This interface is meant to mirror the use of boost::ref(), which can be similarly used to prevent copying of referents. + +ptr(p) returns an instance of pointer_wrapper<>, which can be detected using the is_pointer_wrapper<> metafunction; unwrap_pointer<> is a metafunction which extracts the original pointer type from a pointer_wrapper<>. These classes can be thought of as implementation details. +[endsect] +[section Functions] +`` +template +pointer_wrapper ptr(T x); +`` +[variablelist +[[Requires][T is a pointer type.]] +[[Returns][pointer_wrapper(x)]] +[[Throws][nothing.]] +] +[endsect] +[section Class template `pointer_wrapper`] +A "type envelope" which is returned by ptr(), used to indicate reference semantics for pointers passed to Python callbacks. +`` +namespace boost { namespace python +{ + template class pointer_wrapper + { + public: + typedef Ptr type; + + explicit pointer_wrapper(Ptr x); + operator Ptr() const; + Ptr get() const; + }; +}} +`` +[endsect] +[section Class template `pointer_wrapper` types] +`` +typedef Ptr type; +`` +The type of the pointer being wrapped. +[endsect] +[section Class template `pointer_wrapper` constructors and destructor] +`` +explicit pointer_wrapper(Ptr x); +`` +[variablelist +[[Requires][Ptr is a pointer type]] +[[Effects][Stores x in a the pointer_wrapper<>. ]] +[[Throws][nothing.]] +] +[endsect] +[section Class template `pointer_wrapper` observer functions] +`` +operator Ptr() const; +Ptr get() const; +`` +[variablelist +[[Returns][a copy of the stored pointer. ]] +[[Rationale][pointer_wrapper is intended to be a stand-in for the actual pointer type, but sometimes it's better to have an explicit way to retrieve the pointer. ]] +] +[endsect] +[section Metafunctions] +[section Class template `is_pointer_wrapper`] +A unary metafunction whose value is true iff its argument is a pointer_wrapper<>. +`` +namespace boost { namespace python +{ + template class is_pointer_wrapper + { + static unspecified value = ...; + }; +}} +`` +[variablelist +[[Returns][true iff T is a specialization of pointer_wrapper<>. +value is an integral constant convertible to bool of unspecified type ]] +] +[endsect] +[section Class template `unwrap_pointer`] +A unary metafunction which extracts the wrapped pointer type from a specialization of pointer_wrapper<>. +`` +namespace boost { namespace python +{ + template class unwrap_pointer + { + typedef unspecified type; + }; +}} +`` +[variablelist +[[Returns][T::type if T is a specialization of pointer_wrapper<>, T otherwise ]] +] +[endsect] +[endsect] +[section Example] +This example illustrates the use of ptr() to prevent an object from being copied: +`` +#include +#include + +class expensive_to_copy +{ + ... +}; + +void pass_as_arg(expensive_to_copy* x, PyObject* f) +{ + // call the Python function f, passing a Python object built around + // which refers to *x by-pointer. + // + // *** Note: ensuring that *x outlives the argument to f() is *** + // *** up to the user! Failure to do so could result in a crash! *** + + boost::python::call(f, ptr(x)); +} +... +`` +[endsect] +[endsect] diff --git a/doc/reference/pytype_function.qbk b/doc/reference/pytype_function.qbk new file mode 100644 index 00000000..9f67cb1e --- /dev/null +++ b/doc/reference/pytype_function.qbk @@ -0,0 +1,194 @@ +[section pytype_function.hpp] +[section Introduction] +To support Pythonic signatures the converters should supply a get_pytype function returning a pointer to the associated PyTypeObject. See for example ResultConverter or to_python_converter. The classes in this header file are meant to be used when implmenting get_pytype. There are also _direct versions of the templates of class T which should be used with undecorated type parameter, expected to be in the conversion registry when the module loads. +[endsect] +[section Class `wrap_pytype`] + This template generates a static get_pytype member returning the template parameter. +`` +namespace boost { namespace python { namespace converter{ + + template < PyTypeObject const *pytype > + class wrap_pytype + { + public: + static PyTypeObject const *get_pytype(){return pytype; } + }; + +}}} +`` +[endsect] +[section Class `registered_pytype`] + This template should be used with template parameters which are (possibly decorated) types exported to python using class_. The generated a static get_pytype member returns the corresponding python type. +`` +namespace boost { namespace python { namespace converter{ + + template < class T > + class registered_pytype + { + public: + static PyTypeObject const *get_pytype(); + }; + +}}} +`` +[endsect] +[section Class `expected_from_python_type`] +This template generates a static get_pytype member which inspects the registered from_python converters for the type T and returns a matching python type. +`` +namespace boost { namespace python { namespace converter{ + + template < class T > + class expected_from_python_type + { + public: + static PyTypeObject const *get_pytype(); + }; + +}}} +`` +[endsect] +[section Class `to_python_target_type`] + This template generates a static get_pytype member returning the python type to which T can be converted. +`` +namespace boost { namespace python { namespace converter{ + + template < class T > + class to_python_target_type + { + public: + static PyTypeObject const *get_pytype(); + }; + +}}} +`` +[endsect] +[section Example] + This example presumes that someone has implemented the standard noddy example module from the Python documentation, and placed the corresponding declarations in "noddy.h". Because noddy_NoddyObject is the ultimate trivial extension type, the example is a bit contrived: it wraps a function for which all information is contained in the type of its return value. + +C++ module definition: +`` +#include +#include +#include "noddy.h" + +struct tag {}; +tag make_tag() { return tag(); } + +using namespace boost::python; + +struct tag_to_noddy +#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //unnecessary overhead if py signatures are not supported +: wrap_pytype<&noddy_NoddyType> //inherits get_pytype from wrap_pytype +#endif +{ + static PyObject* convert(tag const& x) + { + return PyObject_New(noddy_NoddyObject, &noddy_NoddyType); + } +}; + +BOOST_PYTHON_MODULE(to_python_converter) +{ + def("make_tag", make_tag); + to_python_converter(); //"true" because tag_to_noddy has member get_pytype +} +`` +The following example registers to and from python converters using the templates expected_from_python_type and to_pyhton_target_type. +`` +#include +#include +#include +#include +#include + +using namespace boost::python; + +struct A +{ +}; + +struct B +{ + A a; + B(const A& a_):a(a_){} +}; + +// Converter from A to python int +struct BToPython +#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //unnecessary overhead if py signatures are not supported + : converter::to_python_target_type //inherits get_pytype +#endif +{ + static PyObject* convert(const B& b) + { + return incref(object(b.a).ptr()); + } +}; + +// Conversion from python int to A +struct BFromPython +{ + BFromPython() + { + boost::python::converter::registry::push_back + ( &convertible + , &construct + , type_id< B >() +#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //invalid if py signatures are not supported + , &converter::expected_from_python_type::get_pytype//convertible to A can be converted to B +#endif + ); + } + + static void* convertible(PyObject* obj_ptr) + { + extract ex(obj_ptr); + if (!ex.check()) return 0; + return obj_ptr; + } + + static void construct( + PyObject* obj_ptr, + converter::rvalue_from_python_stage1_data* data) + { + void* storage = ( + (converter::rvalue_from_python_storage< B >*)data)-> storage.bytes; + + extract ex(obj_ptr); + new (storage) B(ex()); + data->convertible = storage; + } +}; + + +B func(const B& b) { return b ; } + +BOOST_PYTHON_MODULE(pytype_function_ext) +{ + to_python_converter< B , BToPython +#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //invalid if py signatures are not supported + ,true +#endif + >(); //has get_pytype + BFromPython(); + + class_("A") ; + + def("func", &func); + +} + + + +>>> from pytype_function_ext import * +>>> print func.__doc__ +func( (A)arg1) -> A : + C++ signature: + struct B func(struct B) +`` +[endsect] +[endsect] diff --git a/doc/reference/raw_function.qbk b/doc/reference/raw_function.qbk new file mode 100644 index 00000000..ce474469 --- /dev/null +++ b/doc/reference/raw_function.qbk @@ -0,0 +1,44 @@ +[section raw_function.hpp] +[section Introduction] +raw_function(...) is used to convert a function taking a tuple and a dict into a Python callable object which accepts a variable number of arguments and arbitrary keyword arguments. +[endsect] +[section Function `raw_function`] +`` +template +object raw_function(F f, std::size_t min_args = 0); +`` +[variablelist +[[Requires][f(tuple(), dict()) is well-formed.]] +[[Returns][a callable object which requires at least min_args arguments. When called, the actual non-keyword arguments will be passed in a tuple as the first argument to f, and the keyword arguments will be passed in a dict as the second argument to f. ]] +] +[endsect] +[section Example] +C++: +`` +#include +#include +#include +#include +#include + +using namespace boost::python; + +tuple raw(tuple args, dict kw) +{ + return make_tuple(args, kw); +} + +BOOST_PYTHON_MODULE(raw_test) +{ + def("raw", raw_function(raw)); +} +`` +Python: +`` +>>> from raw_test import * + +>>> raw(3, 4, foo = 'bar', baz = 42) +((3, 4), {'foo': 'bar', 'baz': 42}) +`` +[endsect] +[endsect] diff --git a/doc/reference/reference_existing_object.qbk b/doc/reference/reference_existing_object.qbk new file mode 100644 index 00000000..80b55b69 --- /dev/null +++ b/doc/reference/reference_existing_object.qbk @@ -0,0 +1,75 @@ +[section reference_existing_object.hpp] +[section Class `reference_existing_object`] +reference_existing_object is a model of ResultConverterGenerator which can be used to wrap C++ functions which return a reference or pointer to a C++ object. When the wrapped function is called, the value referenced by its return value is not copied. A new Python object is created which contains a pointer to the referent, and no attempt is made to ensure that the lifetime of the referent is at least as long as that of the corresponding Python object. Thus, it can be highly dangerous to use reference_existing_object without additional lifetime management from such models of CallPolicies as with_custodian_and_ward. This class is used in the implementation of return_internal_reference. +`` +namespace boost { namespace python +{ + struct reference_existing_object + { + template struct apply; + }; +}} +`` +[endsect] +[section Class `reference_existing_object` metafunctions] +``template struct apply`` +[variablelist +[[Requires][`T` is `U&` or `U*` for some `U`.]] +[[Returns][`typedef to_python_indirect type;`, where V is a class whose static execute function constructs an instance holder containing an unowned U* pointing to the referent of the wrapped function's return value.]] +] +[endsect] +[section Example] +In C++: +`` +#include +#include +#include +#include +#include + +// classes to wrap +struct Singleton +{ + Singleton() : x(0) {} + + int exchange(int n) // set x and return the old value + { + std::swap(n, x); + return n; + } + + int x; +}; + +Singleton& get_it() +{ + static Singleton just_one; + return just_one; +} + +// Wrapper code +using namespace boost::python; +BOOST_PYTHON_MODULE(singleton) +{ + def("get_it", get_it, + return_value_policy()); + + class_("Singleton") + .def("exchange", &Singleton::exchange) + ; +} +`` +Python code: +`` +>>> import singleton +>>> s1 = singleton.get_it() +>>> s2 = singleton.get_it() +>>> id(s1) == id(s2) # s1 and s2 are not the same object +0 +>>> s1.exchange(42) # but they reference the same C++ Singleton +0 +>>> s2.exchange(99) +42 +`` +[endsect] +[endsect] diff --git a/doc/reference/register_ptr_to_python.qbk b/doc/reference/register_ptr_to_python.qbk new file mode 100644 index 00000000..d6c3236e --- /dev/null +++ b/doc/reference/register_ptr_to_python.qbk @@ -0,0 +1,88 @@ +[section register_ptr_to_python.hpp] +[section Introduction] + supplies register_ptr_to_python, a function template which registers a conversion for smart pointers to Python. The resulting Python object holds a copy of the converted smart pointer, but behaves as though it were a wrapped copy of the pointee. If the pointee type has virtual functions and the class representing its dynamic (most-derived) type has been wrapped, the Python object will be an instance of the wrapper for the most-derived type. More than one smart pointer type for a pointee's class can be registered. + + Note that in order to convert a Python X object to a smart_ptr& (non-const reference), the embedded C++ object must be held by smart_ptr, and that when wrapped objects are created by calling the constructor from Python, how they are held is determined by the HeldType parameter to class_<...> instances. +[endsect] +[section Function `register_ptr_to_python`] +`` +template +void register_ptr_to_python() +`` +[variablelist +[[Requires][`P` is Dereferenceable.]] +[[Effects][Allows conversions to-python of P instances. ]] +] +[endsect] +[endsect] +[section Example] + Here is an example of a module that contains a class A with virtual functions and some functions that work with boost::shared_ptr. + +In C++: +`` +struct A +{ + virtual int f() { return 0; } +}; + +shared_ptr New() { return shared_ptr( new A() ); } + +int Ok( const shared_ptr& a ) { return a->f(); } + +int Fail( shared_ptr& a ) { return a->f(); } + +struct A_Wrapper: A +{ + A_Wrapper(PyObject* self_): self(self_) {} + int f() { return call_method(self, "f"); } + int default_f() { return A::f(); } + PyObject* self; +}; + +BOOST_PYTHON_MODULE(register_ptr) +{ + class_("A") + .def("f", &A::f, &A_Wrapper::default_f) + ; + + def("New", &New); + def("Ok", &Call); + def("Fail", &Fail); + + register_ptr_to_python< shared_ptr >(); +} +`` +In Python: +`` +>>> from register_ptr import * +>>> a = A() +>>> Ok(a) # ok, passed as shared_ptr +0 +>>> Fail(a) # passed as shared_ptr&, and was created in Python! +Traceback (most recent call last): + File "", line 1, in ? +TypeError: bad argument type for built-in operation +>>> +>>> na = New() # now "na" is actually a shared_ptr +>>> Ok(a) +0 +>>> Fail(a) +0 +>>> +`` +If shared_ptr is registered as follows: +`` +class_ >("A") + .def("f", &A::f, &A_Wrapper::default_f) +; +`` +There will be an error when trying to convert shared_ptr to shared_ptr: +`` +>>> a = New() +Traceback (most recent call last): +File "", line 1, in ? +TypeError: No to_python (by-value) converter found for C++ type: class boost::shared_ptr +>>> +`` +[endsect] +[endsect] diff --git a/doc/reference/return_arg.qbk b/doc/reference/return_arg.qbk new file mode 100644 index 00000000..ccd0dfc5 --- /dev/null +++ b/doc/reference/return_arg.qbk @@ -0,0 +1,91 @@ +[section return_arg.hpp] +[section Introduction] +return_arg and return_self instantiations are models of CallPolicies which return the specified argument parameter (usually *this) of a wrapped (member) function. +[endsect] +[section Class `return_arg`] +[table +[[Parameter][Requirements][Description][Default]] + [[arg_pos][A positive compile-time constant of type std::size_t.][the position of the argument to be returned.][1]] +[[Base][A model of CallPolicies][Used for policy composition. Any result_converter it supplies will be overridden by return_arg, but its precall and postcall policies are composed as described here CallPolicies.][default_call_policies]] + ] +`` +namespace boost { namespace python +{ + template + struct return_arg : Base + { + static PyObject* postcall(PyObject*, PyObject* result); + struct result_converter{ template struct apply; }; + template struct extract_return_type : mpl::at_c{}; + + }; +}} +`` +[endsect] +[section Class `return_arg` static functions] +``PyObject* postcall(PyObject* args, PyObject* result);`` +[variablelist +[[Requires][`PyTuple_Check(args) != 0` and `PyTuple_Size(args) != 0`]] +[[Returns][PyTuple_GetItem(args,arg_pos-1)]] +] +[endsect] +[section Class template `return_self`] +`` +namespace boost { namespace python +{ + template + struct return_self + : return_arg<1,Base> + {}; +}} +`` +[endsect] +[section Example] +C++ module definition: +`` +#include +#include +#include + +struct Widget +{ + Widget() :sensitive_(true){} + bool get_sensitive() const { return sensitive_; } + void set_sensitive(bool s) { this->sensitive_ = s; } + private: + bool sensitive_; +}; + +struct Label : Widget +{ + Label() {} + + std::string get_label() const { return label_; } + void set_label(const std::string &l){ label_ = l; } + + private: + std::string label_; +}; + +using namespace boost::python; +BOOST_PYTHON_MODULE(return_self_ext) +{ + class_("Widget") + .def("sensitive", &Widget::get_sensitive) + .def("sensitive", &Widget::set_sensitive, return_self<>()) + ; + + class_ >("Label") + .def("label", &Label::get_label) + .def("label", &Label::set_label, return_self<>()) + ; +} +`` +Python code: +`` +>>> from return_self_ext import * +>>> l1 = Label().label("foo").sensitive(false) +>>> l2 = Label().sensitive(false).label("foo") +`` +[endsect] +[endsect] diff --git a/doc/reference/return_by_value.qbk b/doc/reference/return_by_value.qbk new file mode 100644 index 00000000..a0ace5b1 --- /dev/null +++ b/doc/reference/return_by_value.qbk @@ -0,0 +1,62 @@ +[section return_by_value.hpp] +[section Class `return_by_value`] +return_by_value is a model of ResultConverterGenerator which can be used to wrap C++ functions returning any reference or value type such that the return value is copied into a new Python object. +`` +namespace boost { namespace python +{ + struct return_by_value + { + template struct apply; + }; +}} +`` +[endsect] +[section Class `return_by_value` metafunctions] +``template struct apply`` +[variablelist +[[Returns][`typedef to_python_value type;`]] +] +[endsect] +[section Example] +In C++: +`` +#include +#include +#include +#include + +// classes to wrap +struct Bar { }; + +Bar global_bar; + +// functions to wrap: +Bar b1(); +Bar& b2(); +Bar const& b3(); + +// Wrapper code +using namespace boost::python; +template +void def_void_function(char const* name, R (*f)()) +{ + def(name, f, return_value_policy()); +} + +BOOST_PYTHON_MODULE(my_module) +{ + class_("Bar"); + def_void_function("b1", b1); + def_void_function("b2", b2); + def_void_function("b3", b3); +} +`` +Python code: +`` +>>> from my_module import * +>>> b = b1() # each of these calls +>>> b = b2() # creates a brand +>>> b = b3() # new Bar object +`` +[endsect] +[endsect] diff --git a/doc/reference/return_internal_reference.qbk b/doc/reference/return_internal_reference.qbk new file mode 100644 index 00000000..49bf1ed7 --- /dev/null +++ b/doc/reference/return_internal_reference.qbk @@ -0,0 +1,88 @@ +[section return_internal_reference.hpp] +[section Introduction] + return_internal_reference instantiations are models of CallPolicies which allow pointers and references to objects held internally by a free or member function argument or from the target of a member function to be returned safely without making a copy of the referent. The default for its first template argument handles the common case where the containing object is the target (*this) of a wrapped member function. +[endsect] +[section Class template `return_internal_reference`] +[table + [[Parameter][Requirements][Description][Default]] + [[owner_arg][A positive compile-time constant of type std::size_t.][The index of the parameter which contains the object to which the reference or pointer is being returned. If used to wrap a member function, parameter 1 is the target object (*this). Note that if the target Python object type doesn't support weak references, a Python TypeError exception will be raised when the function being wrapped is called.][]] + [[Base][A model of CallPolicies][Used for policy composition. Any result_converter it supplies will be overridden by return_internal_reference, but its precall and postcall policies are composed as described here CallPolicies.][default_call_policies]] +] +`` +namespace boost { namespace python +{ + template + struct return_internal_reference : Base + { + static PyObject* postcall(PyObject*, PyObject* result); + typedef reference_existing_object result_converter; + }; +}} +`` +[endsect] +[section Class `return_internal_reference` static functions] +``PyObject* postcall(PyObject* args, PyObject* result);`` +[variablelist +[[Requires][`PyTuple_Check(args) != 0`]] +[[Returns][ `with_custodian_and_ward_postcall::postcall(args, result)`]] +] +[endsect] +[section Example] +C++ module definition: +`` +#include +#include +#include + +class Bar +{ + public: + Bar(int x) : x(x) {} + int get_x() const { return x; } + void set_x(int x) { this->x = x; } + private: + int x; +}; + +class Foo +{ + public: + Foo(int x) : b(x) {} + + // Returns an internal reference + Bar const& get_bar() const { return b; } + + private: + Bar b; +}; + +using namespace boost::python; +BOOST_PYTHON_MODULE(internal_refs) +{ + class_("Bar", init()) + .def("get_x", &Bar::get_x) + .def("set_x", &Bar::set_x) + ; + + class_("Foo", init()) + .def("get_bar", &Foo::get_bar + , return_internal_reference<>()) + ; +} +`` +Python code: +`` +>>> from internal_refs import * +>>> f = Foo(3) +>>> b1 = f.get_bar() +>>> b2 = f.get_bar() +>>> b1.get_x() +3 +>>> b2.get_x() +3 +>>> b1.set_x(42) +>>> b2.get_x() +42 +`` +[endsect] +[endsect] diff --git a/doc/reference/return_opaque_pointer.qbk b/doc/reference/return_opaque_pointer.qbk new file mode 100644 index 00000000..89ad0744 --- /dev/null +++ b/doc/reference/return_opaque_pointer.qbk @@ -0,0 +1,95 @@ +[section return_opaque_pointer.hpp] +[section Class `return_opaqe_pointer`] +return_opaque_pointer is a model of ResultConverterGenerator which can be used to wrap C++ functions returning pointers to undefined types such that the return value is copied into a new Python object. + +In addition to specifying the return_opaque_pointer policy the BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID macro must be used to define specializations for the type_id function on the type pointed to by returned pointer. +`` +namespace boost { namespace python +{ + struct return_opaque_pointer + { + template struct apply; + }; +}} +`` +[endsect] +[section Class `return_opaque_pointer` metafunctions] +``template struct apply`` +[variablelist +[[Returns][`detail::opaque_conversion_holder type;`]] +] +[endsect] +[section Example] +In C++: +`` +# include +# include +# include +# include + +typedef struct opaque_ *opaque; + +opaque the_op = ((opaque) 0x47110815); + +opaque get () { return the_op; } +void use (opaque op) { + if (op != the_op) + throw std::runtime_error (std::string ("failed")); +} + +void failuse (opaque op) { + if (op == the_op) + throw std::runtime_error (std::string ("success")); +} + +BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(opaque_) + +namespace bpl = boost::python; + +BOOST_PYTHON_MODULE(opaque_ext) +{ + bpl::def ( + "get", &::get, bpl::return_value_policy()); + bpl::def ("use", &::use); + bpl::def ("failuse", &::failuse); +} +`` +Python code: +`` +""" +>>> from opaque_ext import * +>>> # +>>> # Check for correct conversion +>>> use(get()) +>>> failuse(get()) +Traceback (most recent call last): + ... +RuntimeError: success +>>> # +>>> # Check that there is no conversion from integers ... +>>> use(0) +Traceback (most recent call last): + ... +TypeError: bad argument type for built-in operation +>>> # +>>> # ... and from strings to opaque objects +>>> use("") +Traceback (most recent call last): + ... +TypeError: bad argument type for built-in operation +""" +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + sys.exit(run()[0]) +`` +[endsect] +[endsect] diff --git a/doc/reference/return_value_policy.qbk b/doc/reference/return_value_policy.qbk new file mode 100644 index 00000000..cd82f7dc --- /dev/null +++ b/doc/reference/return_value_policy.qbk @@ -0,0 +1,59 @@ +[section return_value_policy.hpp] +[section Introduction] + return_value_policy instantiations are simply models of CallPolicies which are composed of a ResultConverterGenerator and optional Base CallPolicies. +[endsect] +[section Class template `return_value_policy`] +[table +[[Parameter][Requirements][Default]] + [[ResultConverterGenerator][A model of ResultConverterGenerator][]] +[[Base][A model of CallPolicies][default_call_policies]] + ] +`` +namespace boost { namespace python +{ + template + struct return_value_policy : Base + { + typedef ResultConverterGenerator result_converter; + }; +}} +`` +[endsect] +[section Example] +C++ module definition: +`` +#include +#include +#include +#include + +// classes to wrap +struct Bar { int x; } + +struct Foo { + Foo(int x) : { b.x = x; } + Bar const& get_bar() const { return b; } + private: + Bar b; +}; + +// Wrapper code +using namespace boost::python; +BOOST_PYTHON_MODULE(my_module) +{ + class_("Bar"); + + class_("Foo", init()) + .def("get_bar", &Foo::get_bar + , return_value_policy()) + ; +} +`` +Python code: +`` +>>> from my_module import * +>>> f = Foo(3) # create a Foo object +>>> b = f.get_bar() # make a copy of the internal Bar object +`` +[endsect] +[endsect] diff --git a/doc/reference/scope.qbk b/doc/reference/scope.qbk new file mode 100644 index 00000000..03cf595c --- /dev/null +++ b/doc/reference/scope.qbk @@ -0,0 +1,83 @@ +[section scope.hpp] +[section Introduction] +Defines facilities for querying and controlling the Python scope (namespace) which will contain new wrapped classes and functions. +[endsect] +[section Class `scope`] +The scope class has an associated global Python object which controls the Python namespace in which new extension classes and wrapped functions will be defined as attributes. Default-constructing a new scope object binds it to the associated global Python object. Constructing a scope object with an argument changes the associated global Python object to the one held by the argument, until the lifetime of the scope object ends, at which time the associated global Python object reverts to what it was before the scope object was constructed. +`` +namespace boost { namespace python +{ + class scope : public object + { + public: + scope(scope const&); + scope(object const&); + scope(); + ~scope() + private: + void operator=(scope const&); + }; +}} +`` +[endsect] +[section Class scope constructors and destructor] +`` +explicit scope(scope const& x); +explicit scope(object const& x); +`` +Stores a reference to the current associated scope object, and sets the associated scope object to the one referred to by x.ptr(). The object base class is initialized with x. + +``scope();`` + +Stores a reference to the current associated scope object. The object base class is initialized with the current associated scope object. Outside any module initialization function, the current associated Python object is None. + +``~scope()`` + +Sets the current associated Python object to the stored object. +[endsect] +[section Example] +The following example shows how scope setting can be used to define nested classes. + +C++ Module definition: +`` +#include +#include +#include +using namespace boost::python; + +struct X +{ + void f() {} + + struct Y { int g() { return 42; } }; +}; + +BOOST_PYTHON_MODULE(nested) +{ + // add some constants to the current (module) scope + scope().attr("yes") = 1; + scope().attr("no") = 0; + + // Change the current scope + scope outer + = class_("X") + .def("f", &X::f) + ; + + // Define a class Y in the current scope, X + class_("Y") + .def("g", &X::Y::g) + ; +} +`` +Interactive Python: +`` +>>> import nested +>>> nested.yes +1 +>>> y = nested.X.Y() +>>> y.g() +42 +`` +[endsect] +[endsect] diff --git a/doc/reference/slice.qbk b/doc/reference/slice.qbk new file mode 100644 index 00000000..fae1dd9a --- /dev/null +++ b/doc/reference/slice.qbk @@ -0,0 +1,136 @@ +[section slice.hpp] +[section Introduction] +Exposes a TypeWrapper for the Python slice type. +[endsect] +[section Class `slice`] +Exposes the extended slicing protocol by wrapping the built-in slice type. The semantics of the constructors and member functions defined below can be fully understood by reading the TypeWrapper concept definition. Since slice is publicly derived from object, the public object interface applies to slice instances as well. +`` +namespace boost { namespace python +{ + class slice : public object + { + public: + slice(); // create an empty slice, equivalent to [::] + + template + slice(Int1 start, Int2 stop); + + template + slice(Int1 start, Int2 stop, Int3 step); + + // Access the parameters this slice was created with. + object start(); + object stop(); + object step(); + + // The return type of slice::get_indices() + template + struct range + { + RandomAccessIterator start; + RandomAccessIterator stop; + int step; + }; + + template + range + get_indices( + RandomAccessIterator const& begin, + RandomAccessIterator const& end); + }; +}} +`` +[endsect] +[section Class `slice` constructors] +``slice();`` +[variablelist +[[Effects][constructs a slice with default stop, start, and step values. Equivalent to the slice object created as part of the Python expression `base[::]`.]] +[[Throws][nothing]] +] +`` +template +slice(Int1 start, Int2 stop); +`` +[variablelist +[[Requires][`start`, `stop`, and `step` are of type `slice_nil` or convertible to type `object`.]] +[[Effects][constructs a new slice with default step value and the provided start and stop values. Equivalent to the slice object created by the built-in Python function `slice(start,stop)`, or as part of the Python expression `base[start:stop]`.]] +[[Throws][`error_already_set` and sets a Python TypeError exception if no conversion is possible from the arguments to type object.]] +] +`` +template +slice(Int1 start, Int2 stop, Int3 step); +`` +[variablelist +[[Requires][`start`, `stop`, and `step` are `slice_nil` or convertible to type `object`.]] +[[Effects][constructs a new slice with start stop and step values. Equivalent to the slice object created by the built-in Python function `slice(start,stop,step)`, or as part of the Python expression `base[start:stop:step]`.]] +[[Throws][`error_already_set` and sets a Python TypeError exception if no conversion is possible from the arguments to type object.]] +] +[endsect] +[section Class `slice` observer functions] +`` +object slice::start() const; +object slice::stop() const; +object slice::step() const; +`` +[variablelist +[[Effects][None]] +[[Throws][nothing]] +[[Returns][the parameter that the slice was created with. If the parameter was omitted or `slice_nil` was used when the slice was created, than that parameter will be a reference to `PyNone` and compare equal to a default-constructed object. In principal, any object may be used when creating a slice object, but in practice they are usually integers.]] +] +`` +template +slice::range +slice::get_indices( + RandomAccessIterator const& begin, + RandomAccessIterator const& end) const; +`` +[variablelist +[[Arguments][A pair of STL-conforming Random Access Iterators that form a half-open range.]] +[[Effects][Create a RandomAccessIterator pair that defines a fully-closed range within the `[begin,end)` range of its arguments. This function translates this slice's indices while accounting for the effects of any PyNone or negative indices, and non-singular step sizes.]] +[[Returns][a `slice::range` that has been initialized with a non-zero value of step and a pair of RandomAccessIterators that point within the range of this functions arguments and define a closed interval.]] +[[Throws][Raises a Python TypeError exception if any of this slice's arguments are neither references to PyNone nor convertible to int. Throws `std::invalid_argument` if the resulting range would be empty. You should always wrap calls to `slice::get_indices()` within `try { ...; } catch (std::invalid_argument) {}` to handle this case and take appropriate action.]] +[[Rationale][closed-interval: If an open interval were used, then for step size other than 1, the required state for the end iterator would point beyond the one-past-the-end position or before the beginning of the specified range. +exceptions on empty slice: It is impossible to define a closed interval over an empty range, so some other form of error checking would have to be used to prevent undefined behavior. In the case where the exception is not caught, it will simply be translated to Python by the default exception handling mechanisms. ]] +] +[endsect] +[section Example] +`` +using namespace boost::python; + +// Perform an extended slice of a Python list. +// Warning: extended slicing was not supported for built-in types prior +// to Python 2.3 +list odd_elements(list l) +{ + return l[slice(_,_,2)]; +} + +// Perform a multidimensional extended slice of a Numeric.array +numeric::array even_columns(numeric::array arr) +{ + // select every other column, starting with the second, of a 2-D array. + // Equivalent to "return arr[:, 1::2]" in Python. + return arr[make_tuple( slice(), slice(1,_,2))]; +} + +// Perform a summation over a slice of a std::vector. +double partial_sum(std::vector const& Foo, const slice index) +{ + slice::range::const_iterator> bounds; + try { + bounds = index.get_indices<>(Foo.begin(), Foo.end()); + } + catch (std::invalid_argument) { + return 0.0; + } + double sum = 0.0; + while (bounds.start != bounds.stop) { + sum += *bounds.start; + std::advance( bounds.start, bounds.step); + } + sum += *bounds.start; + return sum; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/ssize_t.qbk b/doc/reference/ssize_t.qbk new file mode 100644 index 00000000..53bfa268 --- /dev/null +++ b/doc/reference/ssize_t.qbk @@ -0,0 +1,27 @@ +[section ssize_t.hpp] +[section Introduction] +Python 2.5 introduces a new Py_ssize_t typedef and two related macros (PEP 353). The header imports these definitions into the boost::python namespace as ssize_t, ssize_t_max, and ssize_t_min. Appropriate definitions are provided for backward compatibility with previous Python versions. +[endsect] +[section Typedefs] +Imports Py_ssize_t into the boost::python namespace if available, or provides an appropriate typedef for backward compatibility: +`` +#if PY_VERSION_HEX >= 0x02050000 +typedef Py_ssize_t ssize_t; +#else +typedef int ssize_t; +#endif +`` +[endsect] +[section Constants] +Imports PY_SSIZE_T_MAX and PY_SSIZE_T_MIN as constants into the boost::python namespace if available, or provides appropriate constants for backward compatibility: +`` +#if PY_VERSION_HEX >= 0x02050000 +ssize_t const ssize_t_max = PY_SSIZE_T_MAX; +ssize_t const ssize_t_min = PY_SSIZE_T_MIN; +#else +ssize_t const ssize_t_max = INT_MAX; +ssize_t const ssize_t_min = INT_MIN; +#endif +`` +[endsect] +[endsect] diff --git a/doc/reference/stl_iterator.qbk b/doc/reference/stl_iterator.qbk new file mode 100644 index 00000000..593b0bcb --- /dev/null +++ b/doc/reference/stl_iterator.qbk @@ -0,0 +1,108 @@ +[section stl_iterator.hpp] +[section Introduction] + provides types for creating C++ Iterators from Python iterables. +[endsect] +[section Class template `stl_input_iterator`] +Instances of stl_input_iterator hold a Python iterator and adapt it for use with STL algorithms. stl_input_iterator satisfies the requirements for an Input Iterator. +[table +[[Template Parameter][Requirements][Semantics][Default]] +[[ValueType][ValueType must be CopyConstructible.][Dereferencing an instance of stl_input_iterator will return an rvalue of type ValueType.][None]] +] +`` +namespace boost { namespace python +{ + template + struct stl_input_iterator + { + typedef std::ptrdiff_t difference_type; + typedef ValueType value_type; + typedef ValueType* pointer; + typedef ValueType reference; + typedef std::input_iterator_tag iterator_category; + + stl_input_iterator(); + stl_input_iterator(object const& ob); + + stl_input_iterator& operator++(); + stl_input_iterator operator++(int); + + ValueType operator*() const; + + friend bool operator==(stl_input_iterator const& lhs, stl_input_iterator const& rhs); + friend bool operator!=(stl_input_iterator const& lhs, stl_input_iterator const& rhs); + private: + object it; // For exposition only + object ob; // For exposition only + }; +}} +`` +[endsect] +[section Class template `stl_input_iterator` constructors] +`` +stl_input_iterator() +`` +[variablelist +[[Effects][Creates a past-the-end input iterator, useful for signifying the end of a sequence. ]] +[[Postconditions][`this` is past-the-end]] +[[Throws][Nothing.]] +] +``stl_input_iterator(object const& ob)`` +[variablelist +[[Effects][Calls ob.attr("__iter__")() and stores the resulting Python iterator object in this->it. Then, calls this->it.attr("next")() and stores the result in this->ob. If the sequence is exhausted, sets this->ob to object(). ]] +[[Postconditions][this is a dereferenceable or past-the-end.]] +] +[endsect] +[section Class template `stl_input_iterator` modifiers] +`` +stl_input_iterator &operator++() +`` +[variablelist +[[Effects][Calls this->it.attr("next")() and stores the result in this->ob. If the sequence is exhausted, sets this->ob to object(). ]] +[[Postconditions][this is a dereferenceable or past-the-end.]] +[[Returns][`*this`]] +] +``stl_input_iterator &operator++(int)`` +[variablelist +[[Effects][`stl_input_iterator tmp = *this; ++*this; return tmp;`]] +[[Postconditions][this is a dereferenceable or past-the-end.]] +] +[endsect] +[section Class template `stl_input_iterator` observers] +`` +ValueType operator*() const +`` +[variablelist +[[Effects][Returns the current element in the sequence. ]] +[[Returns][`extract(this->ob);`]] +] +`` +friend bool operator==(stl_input_iterator const& lhs, stl_input_iterator const& rhs) +`` +[variablelist +[[Effects][Returns true if both iterators are dereferenceable or if both iterators are past-the-end, false otherwise. ]] +[[Returns][`(lhs.ob == object()) == (rhs.ob == object())`]] +] +`` +friend bool operator!=(stl_input_iterator const& lhs, stl_input_iterator const& rhs) +`` +[variablelist +[[Effects][Returns false if both iterators are dereferenceable or if both iterators are past-the-end, true otherwise. ]] +[[Returns][`!(lhs == rhs)`]] +] +[endsect] +[section Example] +`` +#include +#include + +#include + +using namespace boost::python; +std::list sequence_to_int_list(object const& ob) +{ + stl_input_iterator begin(ob), end; + return std::list(begin, end); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/str.qbk b/doc/reference/str.qbk new file mode 100644 index 00000000..5a279264 --- /dev/null +++ b/doc/reference/str.qbk @@ -0,0 +1,153 @@ +[section str.hpp] +[section Introduction] +Exposes a TypeWrapper for the Python str type. +[endsect] +[section Class `str`] +Exposes the string methods of Python's built-in str type. The semantics of the constructors and member functions defined below, except for the two-argument constructors which construct str objects from a range of characters, can be fully understood by reading the TypeWrapper concept definition. Since str is publicly derived from object, the public object interface applies to str instances as well. +`` +namespace boost { namespace python +{ + class str : public object + { + public: + str(); // new str + + str(char const* s); // new str + + str(char const* start, char const* finish); // new str + str(char const* start, std::size_t length); // new str + + template + explicit str(T const& other); + + str capitalize() const; + + template + str center(T const& width) const; + + template + long count(T const& sub) const; + template + long count(T1 const& sub,T2 const& start) const; + template + long count(T1 const& sub,T2 const& start, T3 const& end) const; + + object decode() const; + template + object decode(T const& encoding) const; + template + object decode(T1 const& encoding, T2 const& errors) const; + + object encode() const; + template + object encode(T const& encoding) const; + template + object encode(T1 const& encoding, T2 const& errors) const; + + template + bool endswith(T const& suffix) const; + template + bool endswith(T1 const& suffix, T2 const& start) const; + template + bool endswith(T1 const& suffix, T2 const& start, T3 const& end) const; + + str expandtabs() const; + template + str expandtabs(T const& tabsize) const; + + template + long find(T const& sub) const; + template + long find(T1 const& sub, T2 const& start) const; + template + long find(T1 const& sub, T2 const& start, T3 const& end) const; + + template + long index(T const& sub) const; + template + long index(T1 const& sub, T2 const& start) const; + template + long index(T1 const& sub, T2 const& start, T3 const& end) const; + + bool isalnum() const; + bool isalpha() const; + bool isdigit() const; + bool islower() const; + bool isspace() const; + bool istitle() const; + bool isupper() const; + + template + str join(T const& sequence) const; + + template + str ljust(T const& width) const; + + str lower() const; + str lstrip() const; + + template + str replace(T1 const& old, T2 const& new_) const; + template + str replace(T1 const& old, T2 const& new_, T3 const& maxsplit) const; + + template + long rfind(T const& sub) const; + template + long rfind(T1 const& sub, T2 const& start) const; + template + long rfind(T1 const& sub, T2 const& start, T3 const& end) const; + + template + long rindex(T const& sub) const; + template + long rindex(T1 const& sub, T2 const& start) const; + template + long rindex(T1 const& sub, T2 const& start, T3 const& end) const; + + template + str rjust(T const& width) const; + + str rstrip() const; + + list split() const; + template + list split(T const& sep) const; + template + list split(T1 const& sep, T2 const& maxsplit) const; + + list splitlines() const; + template + list splitlines(T const& keepends) const; + + template + bool startswith(T const& prefix) const; + template + bool startswidth(T1 const& prefix, T2 const& start) const; + template + bool startswidth(T1 const& prefix, T2 const& start, T3 const& end) const; + + str strip() const; + str swapcase() const; + str title() const; + + template + str translate(T const& table) const; + template + str translate(T1 const& table, T2 const& deletechars) const; + + str upper() const; + }; +}} +`` +[endsect] +[section Example] +`` +using namespace boost::python; +str remove_angle_brackets(str x) +{ + return x.strip('<').strip('>'); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/to_python_converter.qbk b/doc/reference/to_python_converter.qbk new file mode 100644 index 00000000..beee59ae --- /dev/null +++ b/doc/reference/to_python_converter.qbk @@ -0,0 +1,90 @@ +[section to_python_converter.hpp] +[section Introduction] + to_python_converter registers a conversion from objects of a given C++ type into a Python object. +[section Class template `to_python_converter`] +to_python_converter adds a wrapper around a static member function of its second template parameter, handling low-level details such as insertion into the converter registry. + + In the table below, x denotes an object of type T + [table +[[Parameter][Requirements][Description]] +[[T][][The C++ type of the source object in the conversion]] +[[Conversion][PyObject* p = Conversion::convert(x), +if p == 0, PyErr_Occurred() != 0.][A class type whose static member function convert does the real work of the conversion.]] +[[bool has_get_pytype=false][] +[Optional member - if Conversion has get_pytype member supply true for this parameters. If present get_pytype is used to document the return type of functions using this conversion. The get_pytype may be implemented using the classes and functions from pytype_function.hpp NOTE : For backward compatibility this parameter may be passed after checking if BOOST_PYTHON_SUPPORTS_PY_SIGNATURES is defined (see here).] +] + +`` +namespace boost { namespace python +{ + template + struct to_python_converter + { + to_python_converter(); + }; +}} +`` +[section Class template `to_python_converter` constructor] +``to_python_converter();`` +[variablelist +[[Effects][Registers a to_python converter which uses Conversion::convert() to do its work.]] +] +[endsect] +[endsect] +[section Example] + This example presumes that someone has implemented the standard noddy example module from the Python documentation, and placed the corresponding declarations in "noddy.h". Because noddy_NoddyObject is the ultimate trivial extension type, the example is a bit contrived: it wraps a function for which all information is contained in the type of its return value. + +In C++: +`` +#include +#include +#include "noddy.h" + +struct tag {}; +tag make_tag() { return tag(); } + +using namespace boost::python; + +struct tag_to_noddy +{ + static PyObject* convert(tag const& x) + { + return PyObject_New(noddy_NoddyObject, &noddy_NoddyType); + } + static PyTypeObject const* get_pytype() + { + return &noddy_NoddyType; + } +}; + +BOOST_PYTHON_MODULE(to_python_converter) +{ + def("make_tag", make_tag); + to_python_converter(); //"true" because tag_to_noddy has member get_pytype +} +`` +In Python: +`` +>>> import to_python_converter +>>> def always_none(): +... return None +... +>>> def choose_function(x): +... if (x % 2 != 0): +... return to_python_converter.make_tag +... else: +... return always_none +... +>>> a = [ choose_function(x) for x in range(5) ] +>>> b = [ f() for f in a ] +>>> type(b[0]) + +>>> type(b[1]) + +>>> type(b[2]) + +>>> type(b[3]) + +`` +[endsect] +[endsect] diff --git a/doc/reference/to_python_indirect.qbk b/doc/reference/to_python_indirect.qbk new file mode 100644 index 00000000..c1ccb59f --- /dev/null +++ b/doc/reference/to_python_indirect.qbk @@ -0,0 +1,65 @@ +[section to_python_indirect.hpp] +[section Introduction] + supplies a way to construct new Python objects that hold wrapped C++ class instances via a pointer or smart pointer. + [endsect] +[section Class `to_python_indirect`] +Class template to_python_indirect converts objects of its first argument type to python as extension class instances, using the ownership policy provided by its 2nd argument. +[table +[[Parameter][Requirements][Description]] + [[T][Either U cv& (where cv is any optional cv-qualification) or a Dereferenceable type such that *x is convertible to U const&, where U is a class type. ][A type deferencing a C++ class exposed to Python using class template class_. ]] +[[MakeHolder][h = MakeHolder::execute(p); ][A class whose static execute() creates an instance_holder. ]] + ] +Instantiations of to_python_indirect are models of ResultConverter. +`` +namespace boost { namespace python +{ + template + struct to_python_indirect + { + static bool convertible(); + PyObject* operator()(T ptr_or_reference) const; + private: + static PyTypeObject* type(); + }; +}} +`` +[endsect] +[section Class `to_python_indirect` observers] +``PyObject* operator()(T x) const;`` +[variablelist +[[Requires][`x` refers to an object (if it is a pointer type, it is non-null). `convertible() == true`.]] +[[Effects][Creates an appropriately-typed Boost.Python extension class instance, uses MakeHolder to create an instance_holder from x, installs the instance_holder in the new extension class instance, and returns a pointer to it.]] +] +[endsect] +[section Class `to_python_indirect` statics] +``bool convertible()`` +[variablelist +[[Effects][Returns true iff any module has registered a Python type corresponding to U. ]] +] +[endsect] +[endsect] +[section Example] + This example replicates the functionality of reference_existing_object, but without some of the compile-time error checking. +`` +struct make_reference_holder +{ + typedef boost::python::objects::instance_holder* result_type; + template + static result_type execute(T* p) + { + return new boost::python::objects::pointer_holder(p); + } +}; + +struct reference_existing_object +{ + // metafunction returning the ResultConverter + template + struct apply + { + typedef boost::python::to_python_indirect type; + }; +}; +`` +[endsect] +[endsect] diff --git a/doc/reference/to_python_value.qbk b/doc/reference/to_python_value.qbk new file mode 100644 index 00000000..b91bc4b7 --- /dev/null +++ b/doc/reference/to_python_value.qbk @@ -0,0 +1,34 @@ +[section to_python_value.hpp] +[section Introduction] +to_python_value is a model of ResultConverter which copies its argument into a new Python object. +[endsect] +[section Class template `to_python_value`] +`` +namespace boost { namespace python +{ + template + struct to_python_value + { + typedef typename add_reference< + typename add_const::type + >::type argument_type; + + static bool convertible(); + PyObject* operator()(argument_type) const; + }; +}} +`` +[endsect] +[section Class `to_python_value` observers] +``static bool convertible();`` +[variablelist +[[Returns][true iff a converter has been registered which can convert T to python by-value. ]] +] +``PyObject* operator()(argument_type x) const;`` +[variablelist +[[Requires][`convertible() == true`]] +[[Effects][converts `x` to python]] +[[Returns][the resulting Python object iff a converter for T has been registered, 0 otherwise. ]] +] +[endsect] +[endsect] diff --git a/doc/reference/topics.qbk b/doc/reference/topics.qbk new file mode 100644 index 00000000..644f20d4 --- /dev/null +++ b/doc/reference/topics.qbk @@ -0,0 +1,7 @@ +[chapter Topics + [quickbook 1.7] +] + +[include calling.qbk] +[include pickle.qbk] +[include indexing.qbk] diff --git a/doc/reference/tuple.qbk b/doc/reference/tuple.qbk new file mode 100644 index 00000000..464e754e --- /dev/null +++ b/doc/reference/tuple.qbk @@ -0,0 +1,52 @@ +[section tuple.hpp] +[section Introduction] +Exposes a TypeWrapper for the Python tuple type. +[endsect] +[section Class `tuple`] +Exposes the interface of Python's built-in tuple type. The semantics of the constructors and member functions defined below can be fully understood by reading the TypeWrapper concept definition. Since tuple is publicly derived from object, the public object interface applies to tuple instances as well. +`` +namespace boost { namespace python +{ + class tuple : public object + { + // tuple() -> an empty tuple + tuple(); + + // tuple(sequence) -> tuple initialized from sequence's items + template + explicit tuple(T const& sequence) + }; +}} +`` +[endsect] +[section Function `make_tuple`] +`` +namespace boost { namespace python +{ + tuple make_tuple(); + + template + tuple make_tuple(A0 const& a0); + + template + tuple make_tuple(A0 const& a0, A1 const& a1); + ... + template + tuple make_tuple(A0 const& a0, A1 const& a1,...An const& an); +}} +`` +[variablelist +[[Effect][Constructs a new tuple object composed of `object(a0), + object(a0),...object(an)`. ]] +] +[endsect] +[section Example] +`` +using namespace boost::python; +tuple head_and_tail(object sequence) +{ + return make_tuple(sequence[0],sequence[-1]); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/type_id.qbk b/doc/reference/type_id.qbk new file mode 100644 index 00000000..672129a4 --- /dev/null +++ b/doc/reference/type_id.qbk @@ -0,0 +1,76 @@ +[section type_id.hpp] +[section Introduction] + provides types and functions for runtime type identification like those of of . It exists mostly to work around certain compiler bugs and platform-dependent interactions with shared libraries. +[endsect] +[section Class template `type_info`] +type_info instances identify a type. As std::type_info is specified to (but unlike its implementation in some compilers), boost::python::type_info never represents top-level references or cv-qualification (see section 5.2.8 in the C++ standard). Unlike std::type_info, boost::python::type_info instances are copyable, and comparisons always work reliably across shared library boundaries. +`` +namespace boost { namespace python +{ + class type_info : totally_ordered + { + public: + // constructor + type_info(std::type_info const& = typeid(void)); + + // comparisons + bool operator<(type_info const& rhs) const; + bool operator==(type_info const& rhs) const; + + // observers + char const* name() const; + }; +}} +`` +[section Class template `type_info` constructor] +``type_info(std::type_info const& = typeid(void));`` +[variablelist +[[Effects][`constructs a type_info object which identifies the same type as its argument.`]] +[[Rationale][Since it is occasionally necessary to make an array of type_info objects a benign default argument is supplied. Note: this constructor does not correct for non-conformance of compiler typeid() implementations. See type_id, below.]] +] +[endsect] +[section Class template `type_info` comparison] +``bool operator<(type_info const &rhs) const;`` +[variablelist +[[Effects][yields a total order over type_info objects.]] +] +``bool operator==(type_info const &rhs) const;`` +[variablelist +[[Returns][true iff the two values describe the same type.]] +[[Note][The use of totally_ordered as a private base class supplies operators <=, >=, >, and !=]] +] +[endsect] +[section Class template `type_info` observers] +`` +char const* name() const; +`` +[variablelist +[[Returns][The result of calling name() on the argument used to construct the object.]] +] +[endsect] +[endsect] +[section Functions] +`` +std::ostream& operator<<(std::ostream&s, type_info const&x); +`` +[variablelist +[[Effects][Writes a description of the type described by to x into s.]] +[[Rationale][Not every C++ implementation provides a truly human-readable type_info::name() string, but for some we may be able to decode the string and produce a reasonable representation.]] +[[Note][On some non-conforming C++ implementations, the code is not actually as simple as described above; the semantics are adjusted to work as-if the C++ implementation were conforming.]] +] +[endsect] +[section Example] + The following example, though silly, illustrates how the type_id facility might be used +`` +#include + +// Returns true iff the user passes an int argument +template +bool is_int(T x) +{ + using boost::python::type_id; + return type_id() == type_id(); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/utility.qbk b/doc/reference/utility.qbk new file mode 100644 index 00000000..3123cd8d --- /dev/null +++ b/doc/reference/utility.qbk @@ -0,0 +1,10 @@ +[chapter Utility and Infrastructure + [quickbook 1.7] +] + +[include has_back_reference.qbk] +[include instance_holder.qbk] +[include pointee.qbk] +[include handle.qbk] +[include type_id.qbk] +[include ssize_t.qbk] diff --git a/doc/reference/with_custodian_and_ward.qbk b/doc/reference/with_custodian_and_ward.qbk new file mode 100644 index 00000000..fad79beb --- /dev/null +++ b/doc/reference/with_custodian_and_ward.qbk @@ -0,0 +1,72 @@ +[section with_custodian_and_ward.hpp] +[section Introduction] +This header provides facilities for establishing a lifetime dependency between two of a function's Python argument or result objects. The ward object will not be destroyed until after the custodian as long as the custodian object supports weak references (Boost.Python extension classes all support weak references). If the custodian object does not support weak references and is not None, an appropriate exception will be thrown. The two class templates with_custodian_and_ward and with_custodian_and_ward_postcall differ in the point at which they take effect. + +In order to reduce the chance of inadvertently creating dangling pointers, the default is to do lifetime binding before the underlying C++ object is invoked. However, before invocation the result object is not available, so with_custodian_and_ward_postcall is provided to bind lifetimes after invocation. Also, if a C++ exception is thrown after with_custodian_and_ward<>::precall but before the underlying C++ object actually stores a pointer, the lifetime of the custodian and ward objects will be artificially bound together, so one might choose with_custodian_and_ward_postcall instead, depending on the semantics of the function being wrapped. + +Please note that this is not the appropriate tool to use when wrapping functions which transfer ownership of a raw pointer across the function-call boundary. Please see the FAQ if you want to do that. +[endsect] +[section Class `with_custodian_and_ward`] +[table +[[Parameter][Requirements][Description][Default]] + [[custodian][ A positive compile-time constant of type std::size_t. ][ The 1-based index of the parameter which is the dependency in the lifetime relationship to be established. If used to wrap a member function, parameter 1 is the target object (*this). Note that if the target Python object type doesn't support weak references, a Python TypeError exception will be raised when the C++ object being wrapped is called. ][]] +[[ward][ A positive compile-time constant of type std::size_t. ][ The 1-based index of the parameter which is the dependent in the lifetime relationship to be established. If used to wrap a member function, parameter 1 is the target object (*this). ][]] +[[Base][ A model of CallPolicies ][ Used for policy composition. ][default_call_policies]] + ] +`` +namespace boost { namespace python +{ + template + struct with_custodian_and_ward : Base + { + static bool precall(PyObject* args); + }; +}}`` +[endsect] +[section Class `with_custodian_and_ward` static functions] +``bool precall(PyObject* args);`` +[variablelist +[[Requires][`PyTuple_Check(args) != 0`]] +[[Effects][Makes the lifetime of the argument indicated by ward dependent on the lifetime of the argument indicated by custodian. ]] +[[Returns][false and PyErr_Occurred() != 0 upon failure, true otherwise.]] +] +[endsect] + +[section Class `with_custodian_and_ward_postcall`] +[table +[[Parameter][Requirements][Description][Default]] + [[custodian][ A positive compile-time constant of type std::size_t. ][ The index of the parameter which is the dependency in the lifetime relationship to be established. Zero indicates the result object; 1 indicates the first argument. If used to wrap a member function, parameter 1 is the target object (*this). Note that if the target Python object type doesn't support weak references, a Python TypeError exception will be raised when the C++ object being wrapped is called. ][]] +[[ward][ A positive compile-time constant of type std::size_t. ][ The index of the parameter which is the dependent in the lifetime relationship to be established. Zero indicates the result object; 1 indicates the first argument. If used to wrap a member function, parameter 1 is the target object (*this). ][]] +[[Base][ A model of CallPolicies ][ Used for policy composition. ][default_call_policies]] + ] +`` +namespace boost { namespace python +{ + template + struct with_custodian_and_ward_postcall : Base + { + static PyObject* postcall(PyObject* args, PyObject* result); + }; +}} +`` +[endsect] +[section Class `with_custodian_and_ward_postcall` static functions] +``PyObject *postcall(PyObject* args, PyObject* result);`` +[variablelist +[[Requires][`PyTuple_Check(args) != 0`, `result != 0`]] +[[Effects][Makes the lifetime of the object indicated by ward dependent on the lifetime of the object indicated by custodian. ]] +[[Returns][0 and PyErr_Occurred() != 0 upon failure, true otherwise. ]] +] +[endsect] +[section Example] +The following example shows how with_custodian_and_ward_postcall is used by the library to implement return_internal_reference +`` +template +struct return_internal_reference + : with_custodian_and_ward_postcall<0, owner_arg, Base> +{ + typedef reference_existing_object result_converter; +}; +`` +[endsect] +[endsect] diff --git a/doc/reference/wrapper.qbk b/doc/reference/wrapper.qbk new file mode 100644 index 00000000..3d2f4b8f --- /dev/null +++ b/doc/reference/wrapper.qbk @@ -0,0 +1,117 @@ +[section wrapper.hpp] +[section Introduction] +To wrap a class T such that its virtual functions can be "overridden in Python"—so that the corresponding method of a Python derived class will be called when the virtual function is invoked from C++—you must create a C++ wrapper class derived from ``T`` that overrides those virtual functions so that they call into Python. This header contains classes that can be used to make that job easier. +[endsect] +[section Class override] +Encapsulates a Python override of a C++ virtual function. An override object either holds a callable Python object or None. +`` +namespace boost +{ + class override : object + { + public: + unspecified operator() const; + template + unspecified operator(A0) const; + template + unspecified operator(A0, A1) const; + ... + template + unspecified operator(A0, A1, ...An) const; + }; +}; +`` +[endsect] +[section Class override observer functions] +`` +unspecified operator() const; +template +unspecified operator(A0) const; +template +unspecified operator(A0, A1) const; +... +template +unspecified operator(A0, A1, ...An) const; +`` +[variablelist +[[Effects][If *this holds a callable Python object, it is invoked with the specified arguments in the manner specified here. Otherwise, throws error_already_set .]] +[[Returns][An object of unspecified type that holds the Python result of the invocation and, when converted to a C++ type R, attempts to convert that result object to R. If that conversion fails, throws error_already_set.]] +] +[endsect] +[section Class template wrapper] +Deriving your wrapper class from both `T` and `wrapper` makes writing that derived class easier. +`` +namespace boost +{ + class wrapper + { + protected: + override get_override(char const* name) const; + }; +}; +`` +[endsect] +[section Class wrapper observer functions] +``override get_override(char const* name) const;`` +[variablelist +[[Requires][name is a ntbs.]] +[[Returns][If *this is the C++ base class subobject of a Python derived class instance that overrides the named function, returns an override object that delegates to the Python override. Otherwise, returns an override object that holds None.]] +] +[endsect] +[section Example] +`` +#include +#include +#include +#include + +using namespace boost::python; + +// Class with one pure virtual function +struct P +{ + virtual ~P(){} + virtual char const* f() = 0; + char const* g() { return "P::g()"; } +}; + +struct PCallback : P, wrapper

+{ + char const* f() + { + return this->get_override("f")(); + } +}; + +// Class with one non-pure virtual function +struct A +{ + virtual ~A(){} + virtual char const* f() { return "A::f()"; } +}; + +struct ACallback : A, wrapper +{ + char const* f() + { + if (override f = this->get_override("f")) + return f(); + return A::f(); + } + + char const* default_f() { return this->A::f(); } +}; + +BOOST_PYTHON_MODULE_INIT(polymorphism) +{ + class_("P") + .def("f", pure_virtual(&P::f)) + ; + + class_("A") + .def("f", &A::f, &ACallback::default_f) + ; +} +`` +[endsect] +[endsect] diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk new file mode 100644 index 00000000..3d3f6947 --- /dev/null +++ b/doc/tutorial.qbk @@ -0,0 +1,1982 @@ +[article Boost.Python Tutorial + [authors [de Guzman, Joel], [Abrahams, David]] + [copyright 2002 2003 2004 2005 Joel de Guzman, David Abrahams] + [category inter-language support] + [id tutorial] + [purpose + Reflects C++ classes and functions into Python + ] + [license + 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] + ] +] + +[/ QuickBook Document version 0.9 ] + +[def __note__ [$images/note.png]] +[def __alert__ [$images/alert.png]] +[def __tip__ [$images/tip.png]] +[def :-) [$images/smiley.png]] +[def __jam__ [$images/jam.png]] + +[section QuickStart] + +The Boost Python Library is a framework for interfacing Python and +C++. It allows you to quickly and seamlessly expose C++ classes +functions and objects to Python, and vice-versa, using no special +tools -- just your C++ compiler. It is designed to wrap C++ interfaces +non-intrusively, so that you should not have to change the C++ code at +all in order to wrap it, making Boost.Python ideal for exposing +3rd-party libraries to Python. The library's use of advanced +metaprogramming techniques simplifies its syntax for users, so that +wrapping code takes on the look of a kind of declarative interface +definition language (IDL). + +[h2 Hello World] + +Following C/C++ tradition, let's start with the "hello, world". A C++ +Function: + + char const* greet() + { + return "hello, world"; + } + +can be exposed to Python by writing a Boost.Python wrapper: + + #include + + BOOST_PYTHON_MODULE(hello_ext) + { + using namespace boost::python; + def("greet", greet); + } + +That's it. We're done. We can now build this as a shared library. The +resulting DLL is now visible to Python. Here's a sample Python session: + +[python] + + >>> import hello_ext + >>> print hello_ext.greet() + hello, world + +[c++] + +[:['[*Next stop... Building your Hello World module from start to finish...]]] + +[endsect] +[section:hello Building Hello World] + +[h2 From Start To Finish] + +Now the first thing you'd want to do is to build the Hello World module and +try it for yourself in Python. In this section, we will outline the steps +necessary to achieve that. We will use the build tool that comes bundled +with every boost distribution: [*bjam]. + +[note [*Building without bjam] + +Besides bjam, there are of course other ways to get your module built. +What's written here should not be taken as "the one and only way". +There are of course other build tools apart from [^bjam]. + +Take note however that the preferred build tool for Boost.Python is bjam. +There are so many ways to set up the build incorrectly. Experience shows +that 90% of the "I can't build Boost.Python" problems come from people +who had to use a different tool. +] + +We will skip over the details. Our objective will be to simply create +the hello world module and run it in Python. For a complete reference to +building Boost.Python, check out: [@../../../building.html +building.html]. After this brief ['bjam] tutorial, we should have built +the DLLs and run a python program using the extension. + +The tutorial example can be found in the directory: +[^libs/python/example/tutorial]. There, you can find: + +* hello.cpp +* hello.py +* Jamroot + +The [^hello.cpp] file is our C++ hello world example. The [^Jamroot] is +a minimalist ['bjam] script that builds the DLLs for us. Finally, +[^hello.py] is our Python program that uses the extension in +[^hello.cpp]. + +Before anything else, you should have the bjam executable in your boost +directory or somewhere in your path such that [^bjam] can be executed in +the command line. Pre-built Boost.Jam executables are available for most +platforms. The complete list of Bjam executables can be found +[@http://sourceforge.net/project/showfiles.php?group_id=7586 here]. + +[h2 Let's Jam!] +__jam__ + +[@../../../../example/tutorial/Jamroot Here] is our minimalist Jamroot +file. Simply copy the file and tweak [^use-project boost] to where your +boost root directory is and your OK. + +The comments contained in the Jamrules file above should be sufficient +to get you going. + +[h2 Running bjam] + +['bjam] is run using your operating system's command line interpreter. + +[:Start it up.] + +A file called user-config.jam in your home directory is used to +configure your tools. In Windows, your home directory can be found by +typing: + +[pre +ECHO %HOMEDRIVE%%HOMEPATH% +] + +into a command prompt window. Your file should at least have the rules +for your compiler and your python installation. A specific example of +this on Windows would be: + +[pre +# MSVC configuration +using msvc : 8.0 ; + +# Python configuration +using python : 2.4 : C:/dev/tools/Python/ ; +] + +The first rule tells Bjam to use the MSVC 8.0 compiler and associated +tools. The second rule provides information on Python, its version and +where it is located. The above assumes that the Python installation is +in [^C:/dev/tools\/Python/]. If you have one fairly "standard" python +installation for your platform, you might not need to do this. + +Now we are ready... Be sure to [^cd] to [^libs/python/example/tutorial] +where the tutorial [^"hello.cpp"] and the [^"Jamroot"] is situated. + +Finally: + + bjam + +It should be building now: + +[pre +cd C:\dev\boost\libs\python\example\tutorial +bjam +...patience... +...found 1101 targets... +...updating 35 targets... +] + +And so on... Finally: + +[pre + Creating library /path-to-boost_python.dll/ + Creating library /path-to-'''hello_ext'''.exp/ +'''**passed**''' ... hello.test +...updated 35 targets... +] + +Or something similar. If all is well, you should now have built the DLLs and +run the Python program. + +[:[*There you go... Have fun!]] + +[endsect] +[section:exposing Exposing Classes] + +Now let's expose a C++ class to Python. + +Consider a C++ class/struct that we want to expose to Python: + + struct World + { + void set(std::string msg) { this->msg = msg; } + std::string greet() { return msg; } + std::string msg; + }; + +We can expose this to Python by writing a corresponding Boost.Python +C++ Wrapper: + + #include + using namespace boost::python; + + BOOST_PYTHON_MODULE(hello) + { + class_("World") + .def("greet", &World::greet) + .def("set", &World::set) + ; + } + +Here, we wrote a C++ class wrapper that exposes the member functions +[^greet] and [^set]. Now, after building our module as a shared library, we +may use our class [^World] in Python. Here's a sample Python session: + +[python] + + >>> import hello + >>> planet = hello.World() + >>> planet.set('howdy') + >>> planet.greet() + 'howdy' + +[section Constructors] + +Our previous example didn't have any explicit constructors. +Since [^World] is declared as a plain struct, it has an implicit default +constructor. Boost.Python exposes the default constructor by default, +which is why we were able to write + + >>> planet = hello.World() + +We may wish to wrap a class with a non-default constructor. Let us +build on our previous example: + +[c++] + + struct World + { + World(std::string msg): msg(msg) {} // added constructor + void set(std::string msg) { this->msg = msg; } + std::string greet() { return msg; } + std::string msg; + }; + +This time [^World] has no default constructor; our previous +wrapping code would fail to compile when the library tried to expose +it. We have to tell [^class_] about the constructor we want to +expose instead. + + #include + using namespace boost::python; + + BOOST_PYTHON_MODULE(hello) + { + class_("World", init()) + .def("greet", &World::greet) + .def("set", &World::set) + ; + } + +[^init()] exposes the constructor taking in a +[^std::string] (in Python, constructors are spelled +"[^"__init__"]"). + +We can expose additional constructors by passing more [^init<...>]s to +the [^def()] member function. Say for example we have another World +constructor taking in two doubles: + + class_("World", init()) + .def(init()) + .def("greet", &World::greet) + .def("set", &World::set) + ; + +On the other hand, if we do not wish to expose any constructors at +all, we may use [^no_init] instead: + + class_("Abstract", no_init) + +This actually adds an [^__init__] method which always raises a +Python RuntimeError exception. + +[endsect] +[section Class Data Members] + +Data members may also be exposed to Python so that they can be +accessed as attributes of the corresponding Python class. Each data +member that we wish to be exposed may be regarded as [*read-only] or +[*read-write]. Consider this class [^Var]: + + struct Var + { + Var(std::string name) : name(name), value() {} + std::string const name; + float value; + }; + +Our C++ [^Var] class and its data members can be exposed to Python: + + class_("Var", init()) + .def_readonly("name", &Var::name) + .def_readwrite("value", &Var::value); + +Then, in Python, assuming we have placed our Var class inside the namespace +hello as we did before: + +[python] + + >>> x = hello.Var('pi') + >>> x.value = 3.14 + >>> print x.name, 'is around', x.value + pi is around 3.14 + +Note that [^name] is exposed as [*read-only] while [^value] is exposed +as [*read-write]. + + >>> x.name = 'e' # can't change name + Traceback (most recent call last): + File "", line 1, in ? + AttributeError: can't set attribute + +[endsect] +[section Class Properties] + +In C++, classes with public data members are usually frowned +upon. Well designed classes that take advantage of encapsulation hide +the class' data members. The only way to access the class' data is +through access (getter/setter) functions. Access functions expose class +properties. Here's an example: + +[c++] + + struct Num + { + Num(); + float get() const; + void set(float value); + ... + }; + +However, in Python attribute access is fine; it doesn't neccessarily break +encapsulation to let users handle attributes directly, because the +attributes can just be a different syntax for a method call. Wrapping our +[^Num] class using Boost.Python: + + class_("Num") + .add_property("rovalue", &Num::get) + .add_property("value", &Num::get, &Num::set); + +And at last, in Python: + +[python] + + >>> x = Num() + >>> x.value = 3.14 + >>> x.value, x.rovalue + (3.14, 3.14) + >>> x.rovalue = 2.17 # error! + +Take note that the class property [^rovalue] is exposed as [*read-only] +since the [^rovalue] setter member function is not passed in: + +[c++] + + .add_property("rovalue", &Num::get) + +[endsect] +[section Inheritance] + +In the previous examples, we dealt with classes that are not polymorphic. +This is not often the case. Much of the time, we will be wrapping +polymorphic classes and class hierarchies related by inheritance. We will +often have to write Boost.Python wrappers for classes that are derived from +abstract base classes. + +Consider this trivial inheritance structure: + + struct Base { virtual ~Base(); }; + struct Derived : Base {}; + +And a set of C++ functions operating on [^Base] and [^Derived] object +instances: + + void b(Base*); + void d(Derived*); + Base* factory() { return new Derived; } + +We've seen how we can wrap the base class [^Base]: + + class_("Base") + /*...*/ + ; + +Now we can inform Boost.Python of the inheritance relationship between +[^Derived] and its base class [^Base]. Thus: + + class_ >("Derived") + /*...*/ + ; + +Doing so, we get some things for free: + +# Derived automatically inherits all of Base's Python methods + (wrapped C++ member functions) +# [*If] Base is polymorphic, [^Derived] objects which have been passed to + Python via a pointer or reference to [^Base] can be passed where a pointer + or reference to [^Derived] is expected. + +Now, we will expose the C++ free functions [^b] and [^d] and [^factory]: + + def("b", b); + def("d", d); + def("factory", factory); + +Note that free function [^factory] is being used to generate new +instances of class [^Derived]. In such cases, we use +[^return_value_policy] to instruct Python to adopt +the pointer to [^Base] and hold the instance in a new Python [^Base] +object until the the Python object is destroyed. We will see more of +Boost.Python [link python.call_policies call policies] later. + + // Tell Python to take ownership of factory's result + def("factory", factory, + return_value_policy()); + +[endsect] + +[section Class Virtual Functions] + +In this section, we will learn how to make functions behave polymorphically +through virtual functions. Continuing our example, let us add a virtual function +to our [^Base] class: + + struct Base + { + virtual ~Base() {} + virtual int f() = 0; + }; + +One of the goals of Boost.Python is to be minimally intrusive on an existing C++ +design. In principle, it should be possible to expose the interface for a 3rd +party library without changing it. It is not ideal to add anything to our class +`Base`. Yet, when you have a virtual function that's going to be overridden in +Python and called polymorphically *from C++*, we'll need to add some +scaffoldings to make things work properly. What we'll do is write a class +wrapper that derives from `Base` that will unintrusively hook into the virtual +functions so that a Python override may be called: + + struct BaseWrap : Base, wrapper + { + int f() + { + return this->get_override("f")(); + } + }; + +Notice too that in addition to inheriting from `Base`, we also multiply- +inherited `wrapper` (See [@../../../v2/wrapper.html Wrapper]). The +`wrapper` template makes the job of wrapping classes that are meant to +overridden in Python, easier. + +[blurb __alert__ [*MSVC6/7 Workaround] + +If you are using Microsoft Visual C++ 6 or 7, you have to write `f` as: + +`return call(this->get_override("f").ptr());`.] + +BaseWrap's overridden virtual member function `f` in effect calls the +corresponding method of the Python object through `get_override`. + +Finally, exposing `Base`: + + class_("Base") + .def("f", pure_virtual(&Base::f)) + ; + +`pure_virtual` signals Boost.Python that the function `f` is a pure virtual +function. + +[note [*member function and methods] + +Python, like many object oriented languages uses the term [*methods]. +Methods correspond roughly to C++'s [*member functions]] + +[endsect] + +[section Virtual Functions with Default Implementations] + +We've seen in the previous section how classes with pure virtual functions are +wrapped using Boost.Python's [@../../../v2/wrapper.html class wrapper] +facilities. If we wish to wrap [*non]-pure-virtual functions instead, the +mechanism is a bit different. + +Recall that in the [link python.class_virtual_functions previous section], we +wrapped a class with a pure virtual function that we then implemented in C++, or +Python classes derived from it. Our base class: + + struct Base + { + virtual int f() = 0; + }; + +had a pure virtual function [^f]. If, however, its member function [^f] was +not declared as pure virtual: + + struct Base + { + virtual ~Base() {} + virtual int f() { return 0; } + }; + +We wrap it this way: + + struct BaseWrap : Base, wrapper + { + int f() + { + if (override f = this->get_override("f")) + return f(); // *note* + return Base::f(); + } + + int default_f() { return this->Base::f(); } + }; + +Notice how we implemented `BaseWrap::f`. Now, we have to check if there is an +override for `f`. If none, then we call `Base::f()`. + +[blurb __alert__ [*MSVC6/7 Workaround] + +If you are using Microsoft Visual C++ 6 or 7, you have to rewrite the line +with the `*note*` as: + +`return call(f.ptr());`.] + +Finally, exposing: + + class_("Base") + .def("f", &Base::f, &BaseWrap::default_f) + ; + +Take note that we expose both `&Base::f` and `&BaseWrap::default_f`. +Boost.Python needs to keep track of 1) the dispatch function [^f] and 2) the +forwarding function to its default implementation [^default_f]. There's a +special [^def] function for this purpose. + +In Python, the results would be as expected: + +[python] + + >>> base = Base() + >>> class Derived(Base): + ... def f(self): + ... return 42 + ... + >>> derived = Derived() + +Calling [^base.f()]: + + >>> base.f() + 0 + +Calling [^derived.f()]: + + >>> derived.f() + 42 + +[endsect] +[section Class Operators/Special Functions] + +[h2 Python Operators] + +C is well known for the abundance of operators. C++ extends this to the +extremes by allowing operator overloading. Boost.Python takes advantage of +this and makes it easy to wrap C++ operator-powered classes. + +Consider a file position class [^FilePos] and a set of operators that take +on FilePos instances: + +[c++] + + class FilePos { /*...*/ }; + + FilePos operator+(FilePos, int); + FilePos operator+(int, FilePos); + int operator-(FilePos, FilePos); + FilePos operator-(FilePos, int); + FilePos& operator+=(FilePos&, int); + FilePos& operator-=(FilePos&, int); + bool operator<(FilePos, FilePos); + +The class and the various operators can be mapped to Python rather easily +and intuitively: + + class_("FilePos") + .def(self + int()) // __add__ + .def(int() + self) // __radd__ + .def(self - self) // __sub__ + .def(self - int()) // __sub__ + .def(self += int()) // __iadd__ + .def(self -= other()) + .def(self < self); // __lt__ + +The code snippet above is very clear and needs almost no explanation at +all. It is virtually the same as the operators' signatures. Just take +note that [^self] refers to FilePos object. Also, not every class [^T] that +you might need to interact with in an operator expression is (cheaply) +default-constructible. You can use [^other()] in place of an actual +[^T] instance when writing "self expressions". + +[h2 Special Methods] + +Python has a few more ['Special Methods]. Boost.Python supports all of the +standard special method names supported by real Python class instances. A +similar set of intuitive interfaces can also be used to wrap C++ functions +that correspond to these Python ['special functions]. Example: + + class Rational + { public: operator double() const; }; + + Rational pow(Rational, Rational); + Rational abs(Rational); + ostream& operator<<(ostream&,Rational); + + class_("Rational") + .def(float_(self)) // __float__ + .def(pow(self, other)) // __pow__ + .def(abs(self)) // __abs__ + .def(str(self)) // __str__ + ; + +Need we say more? + +[note What is the business of `operator<<`? +Well, the method `str` requires the `operator<<` to do its work (i.e. +`operator<<` is used by the method defined by `def(str(self))`.] + +[endsect] +[endsect] [/ Exposing Classes ] + +[section Functions] + +In this chapter, we'll look at Boost.Python powered functions in closer +detail. We will see some facilities to make exposing C++ functions to +Python safe from potential pifalls such as dangling pointers and +references. We will also see facilities that will make it even easier for +us to expose C++ functions that take advantage of C++ features such as +overloading and default arguments. + +[:['Read on...]] + +But before you do, you might want to fire up Python 2.2 or later and type +[^>>> import this]. + +[pre +>>> import this +The Zen of Python, by Tim Peters +Beautiful is better than ugly. +Explicit is better than implicit. +Simple is better than complex. +Complex is better than complicated. +Flat is better than nested. +Sparse is better than dense. +Readability counts. +Special cases aren't special enough to break the rules. +Although practicality beats purity. +Errors should never pass silently. +Unless explicitly silenced. +In the face of ambiguity, refuse the temptation to guess. +There should be one-- and preferably only one --obvious way to do it +Although that way may not be obvious at first unless you're Dutch. +Now is better than never. +Although never is often better than *right* now. +If the implementation is hard to explain, it's a bad idea. +If the implementation is easy to explain, it may be a good idea. +Namespaces are one honking great idea -- let's do more of those! +] + +[section Call Policies] + +In C++, we often deal with arguments and return types such as pointers +and references. Such primitive types are rather, ummmm, low level and +they really don't tell us much. At the very least, we don't know the +owner of the pointer or the referenced object. No wonder languages +such as Java and Python never deal with such low level entities. In +C++, it's usually considered a good practice to use smart pointers +which exactly describe ownership semantics. Still, even good C++ +interfaces use raw references and pointers sometimes, so Boost.Python +must deal with them. To do this, it may need your help. Consider the +following C++ function: + + X& f(Y& y, Z* z); + +How should the library wrap this function? A naive approach builds a +Python X object around result reference. This strategy might or might +not work out. Here's an example where it didn't + + >>> x = f(y, z) # x refers to some C++ X + >>> del y + >>> x.some_method() # CRASH! + +What's the problem? + +Well, what if f() was implemented as shown below: + + X& f(Y& y, Z* z) + { + y.z = z; + return y.x; + } + +The problem is that the lifetime of result X& is tied to the lifetime +of y, because the f() returns a reference to a member of the y +object. This idiom is is not uncommon and perfectly acceptable in the +context of C++. However, Python users should not be able to crash the +system just by using our C++ interface. In this case deleting y will +invalidate the reference to X. We have a dangling reference. + +Here's what's happening: + +# [^f] is called passing in a reference to [^y] and a pointer to [^z] +# A reference to [^y.x] is returned +# [^y] is deleted. [^x] is a dangling reference +# [^x.some_method()] is called +# [*BOOM!] + +We could copy result into a new object: + +[python] + + >>> f(y, z).set(42) # Result disappears + >>> y.x.get() # No crash, but still bad + 3.14 + +This is not really our intent of our C++ interface. We've broken our +promise that the Python interface should reflect the C++ interface as +closely as possible. + +Our problems do not end there. Suppose Y is implemented as follows: + +[c++] + + struct Y + { + X x; Z* z; + int z_value() { return z->value(); } + }; + +Notice that the data member [^z] is held by class Y using a raw +pointer. Now we have a potential dangling pointer problem inside Y: + + >>> x = f(y, z) # y refers to z + >>> del z # Kill the z object + >>> y.z_value() # CRASH! + +For reference, here's the implementation of [^f] again: + + X& f(Y& y, Z* z) + { + y.z = z; + return y.x; + } + +Here's what's happening: + +# [^f] is called passing in a reference to [^y] and a pointer to [^z] +# A pointer to [^z] is held by [^y] +# A reference to [^y.x] is returned +# [^z] is deleted. [^y.z] is a dangling pointer +# [^y.z_value()] is called +# [^z->value()] is called +# [*BOOM!] + +[h2 Call Policies] + +Call Policies may be used in situations such as the example detailed above. +In our example, [^return_internal_reference] and [^with_custodian_and_ward] +are our friends: + + def("f", f, + return_internal_reference<1, + with_custodian_and_ward<1, 2> >()); + +What are the [^1] and [^2] parameters, you ask? + + return_internal_reference<1 + +Informs Boost.Python that the first argument, in our case [^Y& y], is the +owner of the returned reference: [^X&]. The "[^1]" simply specifies the +first argument. In short: "return an internal reference [^X&] owned by the +1st argument [^Y& y]". + + with_custodian_and_ward<1, 2> + +Informs Boost.Python that the lifetime of the argument indicated by ward +(i.e. the 2nd argument: [^Z* z]) is dependent on the lifetime of the +argument indicated by custodian (i.e. the 1st argument: [^Y& y]). + +It is also important to note that we have defined two policies above. Two +or more policies can be composed by chaining. Here's the general syntax: + + policy1 > > + +Here is the list of predefined call policies. A complete reference detailing +these can be found [@../../../v2/reference.html#models_of_call_policies here]. + +* [*with_custodian_and_ward]: Ties lifetimes of the arguments +* [*with_custodian_and_ward_postcall]: Ties lifetimes of the arguments and results +* [*return_internal_reference]: Ties lifetime of one argument to that of result +* [*return_value_policy with T one of:] + * [*reference_existing_object]: naive (dangerous) approach + * [*copy_const_reference]: Boost.Python v1 approach + * [*copy_non_const_reference]: + * [*manage_new_object]: Adopt a pointer and hold the instance + +[blurb :-) [*Remember the Zen, Luke:] + +"Explicit is better than implicit" + +"In the face of ambiguity, refuse the temptation to guess" +] + +[endsect] +[section Overloading] + +The following illustrates a scheme for manually wrapping an overloaded +member functions. Of course, the same technique can be applied to wrapping +overloaded non-member functions. + +We have here our C++ class: + + struct X + { + bool f(int a) + { + return true; + } + + bool f(int a, double b) + { + return true; + } + + bool f(int a, double b, char c) + { + return true; + } + + int f(int a, int b, int c) + { + return a + b + c; + }; + }; + +Class X has 4 overloaded functions. We will start by introducing some +member function pointer variables: + + bool (X::*fx1)(int) = &X::f; + bool (X::*fx2)(int, double) = &X::f; + bool (X::*fx3)(int, double, char)= &X::f; + int (X::*fx4)(int, int, int) = &X::f; + +With these in hand, we can proceed to define and wrap this for Python: + + .def("f", fx1) + .def("f", fx2) + .def("f", fx3) + .def("f", fx4) + +[endsect] +[section Default Arguments] + +Boost.Python wraps (member) function pointers. Unfortunately, C++ function +pointers carry no default argument info. Take a function [^f] with default +arguments: + + int f(int, double = 3.14, char const* = "hello"); + +But the type of a pointer to the function [^f] has no information +about its default arguments: + + int(*g)(int,double,char const*) = f; // defaults lost! + +When we pass this function pointer to the [^def] function, there is no way +to retrieve the default arguments: + + def("f", f); // defaults lost! + +Because of this, when wrapping C++ code, we had to resort to manual +wrapping as outlined in the [link python.overloading previous section], or +writing thin wrappers: + + // write "thin wrappers" + int f1(int x) { return f(x); } + int f2(int x, double y) { return f(x,y); } + + /*...*/ + + // in module init + def("f", f); // all arguments + def("f", f2); // two arguments + def("f", f1); // one argument + +When you want to wrap functions (or member functions) that either: + +* have default arguments, or +* are overloaded with a common sequence of initial arguments + +[h2 BOOST_PYTHON_FUNCTION_OVERLOADS] + +Boost.Python now has a way to make it easier. For instance, given a function: + + int foo(int a, char b = 1, unsigned c = 2, double d = 3) + { + /*...*/ + } + +The macro invocation: + + BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 1, 4) + +will automatically create the thin wrappers for us. This macro will create +a class [^foo_overloads] that can be passed on to [^def(...)]. The third +and fourth macro argument are the minimum arguments and maximum arguments, +respectively. In our [^foo] function the minimum number of arguments is 1 +and the maximum number of arguments is 4. The [^def(...)] function will +automatically add all the foo variants for us: + + def("foo", foo, foo_overloads()); + +[h2 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] + +Objects here, objects there, objects here there everywhere. More frequently +than anything else, we need to expose member functions of our classes to +Python. Then again, we have the same inconveniences as before when default +arguments or overloads with a common sequence of initial arguments come +into play. Another macro is provided to make this a breeze. + +Like [^BOOST_PYTHON_FUNCTION_OVERLOADS], +[^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] may be used to automatically create +the thin wrappers for wrapping member functions. Let's have an example: + + struct george + { + void + wack_em(int a, int b = 0, char c = 'x') + { + /*...*/ + } + }; + +The macro invocation: + + BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(george_overloads, wack_em, 1, 3) + +will generate a set of thin wrappers for george's [^wack_em] member function +accepting a minimum of 1 and a maximum of 3 arguments (i.e. the third and +fourth macro argument). The thin wrappers are all enclosed in a class named +[^george_overloads] that can then be used as an argument to [^def(...)]: + + .def("wack_em", &george::wack_em, george_overloads()); + +See the [@../../../v2/overloads.html#BOOST_PYTHON_FUNCTION_OVERLOADS-spec overloads reference] +for details. + +[h2 init and optional] + +A similar facility is provided for class constructors, again, with +default arguments or a sequence of overloads. Remember [^init<...>]? For example, +given a class X with a constructor: + + struct X + { + X(int a, char b = 'D', std::string c = "constructor", double d = 0.0); + /*...*/ + } + +You can easily add this constructor to Boost.Python in one shot: + + .def(init >()) + +Notice the use of [^init<...>] and [^optional<...>] to signify the default +(optional arguments). + +[endsect] +[section Auto-Overloading] + +It was mentioned in passing in the previous section that +[^BOOST_PYTHON_FUNCTION_OVERLOADS] and [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] +can also be used for overloaded functions and member functions with a +common sequence of initial arguments. Here is an example: + + void foo() + { + /*...*/ + } + + void foo(bool a) + { + /*...*/ + } + + void foo(bool a, int b) + { + /*...*/ + } + + void foo(bool a, int b, char c) + { + /*...*/ + } + +Like in the previous section, we can generate thin wrappers for these +overloaded functions in one-shot: + + BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 0, 3) + +Then... + + .def("foo", (void(*)(bool, int, char))0, foo_overloads()); + +Notice though that we have a situation now where we have a minimum of zero +(0) arguments and a maximum of 3 arguments. + +[h2 Manual Wrapping] + +It is important to emphasize however that [*the overloaded functions must +have a common sequence of initial arguments]. Otherwise, our scheme above +will not work. If this is not the case, we have to wrap our functions +[link python.overloading manually]. + +Actually, we can mix and match manual wrapping of overloaded functions and +automatic wrapping through [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] and +its sister, [^BOOST_PYTHON_FUNCTION_OVERLOADS]. Following up on our example +presented in the section [link python.overloading on overloading], since the +first 4 overload functins have a common sequence of initial arguments, we +can use [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] to automatically wrap the +first three of the [^def]s and manually wrap just the last. Here's +how we'll do this: + + BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(xf_overloads, f, 1, 4) + +Create a member function pointers as above for both X::f overloads: + + bool (X::*fx1)(int, double, char) = &X::f; + int (X::*fx2)(int, int, int) = &X::f; + +Then... + + .def("f", fx1, xf_overloads()); + .def("f", fx2) + +[endsect] +[endsect] [/ Functions ] + +[section:object Object Interface] + +Python is dynamically typed, unlike C++ which is statically typed. Python +variables may hold an integer, a float, list, dict, tuple, str, long etc., +among other things. In the viewpoint of Boost.Python and C++, these +Pythonic variables are just instances of class [^object]. We will see in +this chapter how to deal with Python objects. + +As mentioned, one of the goals of Boost.Python is to provide a +bidirectional mapping between C++ and Python while maintaining the Python +feel. Boost.Python C++ [^object]s are as close as possible to Python. This +should minimize the learning curve significantly. + +[$images/python.png] + +[section Basic Interface] + +Class [^object] wraps [^PyObject*]. All the intricacies of dealing with +[^PyObject]s such as managing reference counting are handled by the +[^object] class. C++ object interoperability is seamless. Boost.Python C++ +[^object]s can in fact be explicitly constructed from any C++ object. + +To illustrate, this Python code snippet: + +[python] + + def f(x, y): + if (y == 'foo'): + x[3:7] = 'bar' + else: + x.items += y(3, x) + return x + + def getfunc(): + return f; + +Can be rewritten in C++ using Boost.Python facilities this way: + +[c++] + + object f(object x, object y) { + if (y == "foo") + x.slice(3,7) = "bar"; + else + x.attr("items") += y(3, x); + return x; + } + object getfunc() { + return object(f); + } + +Apart from cosmetic differences due to the fact that we are writing the +code in C++, the look and feel should be immediately apparent to the Python +coder. + +[endsect] +[section Derived Object types] + +Boost.Python comes with a set of derived [^object] types corresponding to +that of Python's: + +* list +* dict +* tuple +* str +* long_ +* enum + +These derived [^object] types act like real Python types. For instance: + + str(1) ==> "1" + +Wherever appropriate, a particular derived [^object] has corresponding +Python type's methods. For instance, [^dict] has a [^keys()] method: + + d.keys() + +[^make_tuple] is provided for declaring ['tuple literals]. Example: + + make_tuple(123, 'D', "Hello, World", 0.0); + +In C++, when Boost.Python [^object]s are used as arguments to functions, +subtype matching is required. For example, when a function [^f], as +declared below, is wrapped, it will only accept instances of Python's +[^str] type and subtypes. + + void f(str name) + { + object n2 = name.attr("upper")(); // NAME = name.upper() + str NAME = name.upper(); // better + object msg = "%s is bigger than %s" % make_tuple(NAME,name); + } + +In finer detail: + + str NAME = name.upper(); + +Illustrates that we provide versions of the str type's methods as C++ +member functions. + + object msg = "%s is bigger than %s" % make_tuple(NAME,name); + +Demonstrates that you can write the C++ equivalent of [^"format" % x,y,z] +in Python, which is useful since there's no easy way to do that in std C++. + +[blurb + __alert__ [*Beware] the common pitfall of forgetting that the constructors + of most of Python's mutable types make copies, just as in Python. +] + +Python: +[python] + + >>> d = dict(x.__dict__) # copies x.__dict__ + >>> d['whatever'] = 3 # modifies the copy + +C++: +[c++] + + dict d(x.attr("__dict__")); // copies x.__dict__ + d['whatever'] = 3; // modifies the copy + +[h2 class_ as objects] + +Due to the dynamic nature of Boost.Python objects, any [^class_] may +also be one of these types! The following code snippet wraps the class +(type) object. + +We can use this to create wrapped instances. Example: + + object vec345 = ( + class_("Vec2", init()) + .def_readonly("length", &Point::length) + .def_readonly("angle", &Point::angle) + )(3.0, 4.0); + + assert(vec345.attr("length") == 5.0); + +[endsect] +[section Extracting C++ objects] + +At some point, we will need to get C++ values out of object instances. This +can be achieved with the [^extract] function. Consider the following: + + double x = o.attr("length"); // compile error + +In the code above, we got a compiler error because Boost.Python +[^object] can't be implicitly converted to [^double]s. Instead, what +we wanted to do above can be achieved by writing: + + double l = extract(o.attr("length")); + Vec2& v = extract(o); + assert(l == v.length()); + +The first line attempts to extract the "length" attribute of the Boost.Python +[^object]. The second line attempts to ['extract] the [^Vec2] object from held +by the Boost.Python [^object]. + +Take note that we said "attempt to" above. What if the Boost.Python [^object] +does not really hold a [^Vec2] type? This is certainly a possibility considering +the dynamic nature of Python [^object]s. To be on the safe side, if the C++ type +can't be extracted, an appropriate exception is thrown. To avoid an exception, +we need to test for extractibility: + + extract x(o); + if (x.check()) { + Vec2& v = x(); ... + +__tip__ The astute reader might have noticed that the [^extract] +facility in fact solves the mutable copying problem: + + dict d = extract(x.attr("__dict__")); + d["whatever"] = 3; // modifies x.__dict__ ! + + +[endsect] +[section Enums] + +Boost.Python has a nifty facility to capture and wrap C++ enums. While +Python has no [^enum] type, we'll often want to expose our C++ enums to +Python as an [^int]. Boost.Python's enum facility makes this easy while +taking care of the proper conversions from Python's dynamic typing to C++'s +strong static typing (in C++, ints cannot be implicitly converted to +enums). To illustrate, given a C++ enum: + + enum choice { red, blue }; + +the construct: + + enum_("choice") + .value("red", red) + .value("blue", blue) + ; + +can be used to expose to Python. The new enum type is created in the +current [^scope()], which is usually the current module. The snippet above +creates a Python class derived from Python's [^int] type which is +associated with the C++ type passed as its first parameter. + +[note [*what is a scope?] + +The scope is a class that has an associated global Python object which +controls the Python namespace in which new extension classes and wrapped +functions will be defined as attributes. Details can be found +[@../../../v2/scope.html here].] + +You can access those values in Python as + +[python] + + >>> my_module.choice.red + my_module.choice.red + +where my_module is the module where the enum is declared. You can also +create a new scope around a class: + +[c++] + + scope in_X = class_("X") + .def( ... ) + .def( ... ) + ; + + // Expose X::nested as X.nested + enum_("nested") + .value("red", red) + .value("blue", blue) + ; + +[def Py_Initialize [@http://www.python.org/doc/current/api/initialization.html#l2h-652 Py_Initialize]] +[def Py_Finalize [@http://www.python.org/doc/current/api/initialization.html#l2h-656 Py_Finalize]] +[def Py_XINCREF [@http://www.python.org/doc/current/api/countingRefs.html#l2h-65 Py_XINCREF]] +[def Py_XDECREF [@http://www.python.org/doc/current/api/countingRefs.html#l2h-67 Py_XDECREF]] +[def PyImport_AppendInittab [@http://www.python.org/doc/current/api/importing.html#l2h-137 PyImport_AppendInittab]] +[def PyImport_AddModule [@http://www.python.org/doc/current/api/importing.html#l2h-125 PyImport_AddModule]] +[def PyModule_New [@http://www.python.org/doc/current/api/moduleObjects.html#l2h-591 PyModule_New]] +[def PyModule_GetDict [@http://www.python.org/doc/current/api/moduleObjects.html#l2h-594 PyModule_GetDict]] + +[endsect] + +[section:creating_python_object Creating `boost::python::object` from `PyObject*`] + +When you want a `boost::python::object` to manage a pointer to `PyObject*` pyobj one does: + + boost::python::object o(boost::python::handle<>(pyobj)); + +In this case, the `o` object, manages the `pyobj`, it won’t increase the reference count on construction. + +Otherwise, to use a borrowed reference: + + boost::python::object o(boost::python::handle<>(boost::python::borrowed(pyobj))); + +In this case, `Py_INCREF` is called, so `pyobj` is not destructed when object o goes out of scope. + +[endsect] [/ creating_python_object ] + +[endsect] [/ Object Interface] + +[section Embedding] + +By now you should know how to use Boost.Python to call your C++ code from +Python. However, sometimes you may need to do the reverse: call Python code +from the C++-side. This requires you to ['embed] the Python interpreter +into your C++ program. + +Currently, Boost.Python does not directly support everything you'll need +when embedding. Therefore you'll need to use the +[@http://www.python.org/doc/current/api/api.html Python/C API] to fill in +the gaps. However, Boost.Python already makes embedding a lot easier and, +in a future version, it may become unnecessary to touch the Python/C API at +all. So stay tuned... :-) + +[h2 Building embedded programs] + +To be able to embed python into your programs, you have to link to +both Boost.Python's as well as Python's own runtime library. + +Boost.Python's library comes in two variants. Both are located +in Boost's [^/libs/python/build/bin-stage] subdirectory. On Windows, the +variants are called [^boost_python.lib] (for release builds) and +[^boost_python_debug.lib] (for debugging). If you can't find the libraries, +you probably haven't built Boost.Python yet. See +[@../../../building.html Building and Testing] on how to do this. + +Python's library can be found in the [^/libs] subdirectory of +your Python directory. On Windows it is called pythonXY.lib where X.Y is +your major Python version number. + +Additionally, Python's [^/include] subdirectory has to be added to your +include path. + +In a Jamfile, all the above boils down to: + +[pre +projectroot c:\projects\embedded_program ; # location of the program + +# bring in the rules for python +SEARCH on python.jam = $(BOOST_BUILD_PATH) ; +include python.jam ; + +exe embedded_program # name of the executable + : #sources + embedded_program.cpp + : # requirements + boost_python c:\boost\libs\python + $(PYTHON_PROPERTIES) + $(PYTHON_LIB_PATH) + $(PYTHON_EMBEDDED_LIBRARY) ; +] + +[h2 Getting started] + +Being able to build is nice, but there is nothing to build yet. Embedding +the Python interpreter into one of your C++ programs requires these 4 +steps: + +# '''#include''' [^] + +# Call Py_Initialize() to start the interpreter and create the [^__main__] module. + +# Call other Python C API routines to use the interpreter. + +[/ # Call Py_Finalize() to stop the interpreter and release its resources.] + +[note [*Note that at this time you must not call Py_Finalize() to stop the +interpreter. This may be fixed in a future version of boost.python.] +] + +(Of course, there can be other C++ code between all of these steps.) + +[:['[*Now that we can embed the interpreter in our programs, lets see how to put it to use...]]] + +[section Using the interpreter] + +As you probably already know, objects in Python are reference-counted. +Naturally, the [^PyObject]s of the Python C API are also reference-counted. +There is a difference however. While the reference-counting is fully +automatic in Python, the Python C API requires you to do it +[@http://www.python.org/doc/current/c-api/refcounting.html by hand]. This is +messy and especially hard to get right in the presence of C++ exceptions. +Fortunately Boost.Python provides the [@../../../v2/handle.html handle] and +[@../../../v2/object.html object] class templates to automate the process. + +[h2 Running Python code] + +Boost.python provides three related functions to run Python code from C++. + + object eval(str expression, object globals = object(), object locals = object()) + object exec(str code, object globals = object(), object locals = object()) + object exec_file(str filename, object globals = object(), object locals = object()) + +eval evaluates the given expression and returns the resulting value. +exec executes the given code (typically a set of statements) returning the result, +and exec_file executes the code contained in the given file. + +The [^globals] and [^locals] parameters are Python dictionaries +containing the globals and locals of the context in which to run the code. +For most intents and purposes you can use the namespace dictionary of the +[^__main__] module for both parameters. + +Boost.python provides a function to import a module: + + object import(str name) + +import imports a python module (potentially loading it into the running process +first), and returns it. + +Let's import the [^__main__] module and run some Python code in its namespace: + + object main_module = import("__main__"); + object main_namespace = main_module.attr("__dict__"); + + object ignored = exec("hello = file('hello.txt', 'w')\n" + "hello.write('Hello world!')\n" + "hello.close()", + main_namespace); + +This should create a file called 'hello.txt' in the current directory +containing a phrase that is well-known in programming circles. + +[h2 Manipulating Python objects] + +Often we'd like to have a class to manipulate Python objects. +But we have already seen such a class above, and in the +[@python/object.html previous section]: the aptly named [^object] class +and its derivatives. We've already seen that they can be constructed from +a [^handle]. The following examples should further illustrate this fact: + + object main_module = import("__main__"); + object main_namespace = main_module.attr("__dict__"); + object ignored = exec("result = 5 ** 2", main_namespace); + int five_squared = extract(main_namespace["result"]); + +Here we create a dictionary object for the [^__main__] module's namespace. +Then we assign 5 squared to the result variable and read this variable from +the dictionary. Another way to achieve the same result is to use eval instead, +which returns the result directly: + + object result = eval("5 ** 2"); + int five_squared = extract(result); + +[h2 Exception handling] + +If an exception occurs in the evaluation of the python expression, +[@../../../v2/errors.html#error_already_set-spec error_already_set] is thrown: + + try + { + object result = eval("5/0"); + // execution will never get here: + int five_divided_by_zero = extract(result); + } + catch(error_already_set const &) + { + // handle the exception in some way + } + +The [^error_already_set] exception class doesn't carry any information in itself. +To find out more about the Python exception that occurred, you need to use the +[@http://www.python.org/doc/api/exceptionHandling.html exception handling functions] +of the Python C API in your catch-statement. This can be as simple as calling +[@http://www.python.org/doc/api/exceptionHandling.html#l2h-70 PyErr_Print()] to +print the exception's traceback to the console, or comparing the type of the +exception with those of the [@http://www.python.org/doc/api/standardExceptions.html +standard exceptions]: + + catch(error_already_set const &) + { + if (PyErr_ExceptionMatches(PyExc_ZeroDivisionError)) + { + // handle ZeroDivisionError specially + } + else + { + // print all other errors to stderr + PyErr_Print(); + } + } + +(To retrieve even more information from the exception you can use some of the other +exception handling functions listed [@http://www.python.org/doc/api/exceptionHandling.html here].) + +[endsect] +[endsect] [/ Embedding] + +[section Iterators] + +In C++, and STL in particular, we see iterators everywhere. Python also has +iterators, but these are two very different beasts. + +[*C++ iterators:] + +* C++ has 5 type categories (random-access, bidirectional, forward, input, output) +* There are 2 Operation categories: reposition, access +* A pair of iterators is needed to represent a (first/last) range. + +[*Python Iterators:] + +* 1 category (forward) +* 1 operation category (next()) +* Raises StopIteration exception at end + +The typical Python iteration protocol: [^[*for y in x...]] is as follows: + +[python] + + iter = x.__iter__() # get iterator + try: + while 1: + y = iter.next() # get each item + ... # process y + except StopIteration: pass # iterator exhausted + +Boost.Python provides some mechanisms to make C++ iterators play along +nicely as Python iterators. What we need to do is to produce +appropriate `__iter__` function from C++ iterators that is compatible +with the Python iteration protocol. For example: + +[c++] + + object get_iterator = iterator >(); + object iter = get_iterator(v); + object first = iter.next(); + +Or for use in class_<>: + + .def("__iter__", iterator >()) + +[*range] + +We can create a Python savvy iterator using the range function: + +* range(start, finish) +* range(start, finish) + +Here, start/finish may be one of: + +* member data pointers +* member function pointers +* adaptable function object (use Target parameter) + +[*iterator] + +* iterator() + +Given a container [^T], iterator is a shortcut that simply calls [^range] +with &T::begin, &T::end. + +Let's put this into action... Here's an example from some hypothetical +bogon Particle accelerator code: + +[python] + + f = Field() + for x in f.pions: + smash(x) + for y in f.bogons: + count(y) + +Now, our C++ Wrapper: + +[c++] + + class_("Field") + .property("pions", range(&F::p_begin, &F::p_end)) + .property("bogons", range(&F::b_begin, &F::b_end)); + +[*stl_input_iterator] + +So far, we have seen how to expose C++ iterators and ranges to Python. +Sometimes we wish to go the other way, though: we'd like to pass a +Python sequence to an STL algorithm or use it to initialize an STL +container. We need to make a Python iterator look like an STL iterator. +For that, we use `stl_input_iterator<>`. Consider how we might +implement a function that exposes `std::list::assign()` to +Python: + +[c++] + + template + void list_assign(std::list& l, object o) { + // Turn a Python sequence into an STL input range + stl_input_iterator begin(o), end; + l.assign(begin, end); + } + + // Part of the wrapper for list + class_ >("list_int") + .def("assign", &list_assign) + // ... + ; + +Now in Python, we can assign any integer sequence to `list_int` objects: + +[python] + + x = list_int(); + x.assign([1,2,3,4,5]) + +[endsect] +[section:exception Exception Translation] + +All C++ exceptions must be caught at the boundary with Python code. This +boundary is the point where C++ meets Python. Boost.Python provides a +default exception handler that translates selected standard exceptions, +then gives up: + + raise RuntimeError, 'unidentifiable C++ Exception' + +Users may provide custom translation. Here's an example: + + struct PodBayDoorException; + void translator(PodBayDoorException const& x) { + PyErr_SetString(PyExc_UserWarning, "I'm sorry Dave..."); + } + BOOST_PYTHON_MODULE(kubrick) { + register_exception_translator< + PodBayDoorException>(translator); + ... + +[endsect] +[section:techniques General Techniques] + +Here are presented some useful techniques that you can use while wrapping code with Boost.Python. + +[section Creating Packages] + +A Python package is a collection of modules that provide to the user a certain +functionality. If you're not familiar on how to create packages, a good +introduction to them is provided in the +[@http://www.python.org/doc/current/tut/node8.html Python Tutorial]. + +But we are wrapping C++ code, using Boost.Python. How can we provide a nice +package interface to our users? To better explain some concepts, let's work +with an example. + +We have a C++ library that works with sounds: reading and writing various +formats, applying filters to the sound data, etc. It is named (conveniently) +[^sounds]. Our library already has a neat C++ namespace hierarchy, like so: + + sounds::core + sounds::io + sounds::filters + +We would like to present this same hierarchy to the Python user, allowing him +to write code like this: + + import sounds.filters + sounds.filters.echo(...) # echo is a C++ function + +The first step is to write the wrapping code. We have to export each module +separately with Boost.Python, like this: + + /* file core.cpp */ + BOOST_PYTHON_MODULE(core) + { + /* export everything in the sounds::core namespace */ + ... + } + + /* file io.cpp */ + BOOST_PYTHON_MODULE(io) + { + /* export everything in the sounds::io namespace */ + ... + } + + /* file filters.cpp */ + BOOST_PYTHON_MODULE(filters) + { + /* export everything in the sounds::filters namespace */ + ... + } + +Compiling these files will generate the following Python extensions: +[^core.pyd], [^io.pyd] and [^filters.pyd]. + +[note The extension [^.pyd] is used for python extension modules, which +are just shared libraries. Using the default for your system, like [^.so] for +Unix and [^.dll] for Windows, works just as well.] + +Now, we create this directory structure for our Python package: + +[pre +sounds/ + \_\_init\_\_.py + core.pyd + filters.pyd + io.pyd +] + +The file [^\_\_init\_\_.py] is what tells Python that the directory [^sounds/] is +actually a Python package. It can be a empty file, but can also perform some +magic, that will be shown later. + +Now our package is ready. All the user has to do is put [^sounds] into his +[@http://www.python.org/doc/current/tut/node8.html#SECTION008110000000000000000 PYTHONPATH] +and fire up the interpreter: + +[python] + + >>> import sounds.io + >>> import sounds.filters + >>> sound = sounds.io.open('file.mp3') + >>> new_sound = sounds.filters.echo(sound, 1.0) + +Nice heh? + +This is the simplest way to create hierarchies of packages, but it is not very +flexible. What if we want to add a ['pure] Python function to the filters +package, for instance, one that applies 3 filters in a sound object at once? +Sure, you can do this in C++ and export it, but why not do so in Python? You +don't have to recompile the extension modules, plus it will be easier to write +it. + +If we want this flexibility, we will have to complicate our package hierarchy a +little. First, we will have to change the name of the extension modules: + +[c++] + + /* file core.cpp */ + BOOST_PYTHON_MODULE(_core) + { + ... + /* export everything in the sounds::core namespace */ + } + +Note that we added an underscore to the module name. The filename will have to +be changed to [^_core.pyd] as well, and we do the same to the other extension modules. +Now, we change our package hierarchy like so: + +[pre +sounds/ + \_\_init\_\_.py + core/ + \_\_init\_\_.py + _core.pyd + filters/ + \_\_init\_\_.py + _filters.pyd + io/ + \_\_init\_\_.py + _io.pyd +] + +Note that we created a directory for each extension module, and added a +\_\_init\_\_.py to each one. But if we leave it that way, the user will have to +access the functions in the core module with this syntax: + +[python] + + >>> import sounds.core._core + >>> sounds.core._core.foo(...) + +which is not what we want. But here enters the [^\_\_init\_\_.py] magic: everything +that is brought to the [^\_\_init\_\_.py] namespace can be accessed directly by the +user. So, all we have to do is bring the entire namespace from [^_core.pyd] +to [^core/\_\_init\_\_.py]. So add this line of code to [^sounds/core/\_\_init\_\_.py]: + + from _core import * + +We do the same for the other packages. Now the user accesses the functions and +classes in the extension modules like before: + + >>> import sounds.filters + >>> sounds.filters.echo(...) + +with the additional benefit that we can easily add pure Python functions to +any module, in a way that the user can't tell the difference between a C++ +function and a Python function. Let's add a ['pure] Python function, +[^echo_noise], to the [^filters] package. This function applies both the +[^echo] and [^noise] filters in sequence in the given [^sound] object. We +create a file named [^sounds/filters/echo_noise.py] and code our function: + + import _filters + def echo_noise(sound): + s = _filters.echo(sound) + s = _filters.noise(sound) + return s + +Next, we add this line to [^sounds/filters/\_\_init\_\_.py]: + + from echo_noise import echo_noise + +And that's it. The user now accesses this function like any other function +from the [^filters] package: + + >>> import sounds.filters + >>> sounds.filters.echo_noise(...) + +[endsect] +[section Extending Wrapped Objects in Python] + +Thanks to Python's flexibility, you can easily add new methods to a class, +even after it was already created: + + >>> class C(object): pass + >>> + >>> # a regular function + >>> def C_str(self): return 'A C instance!' + >>> + >>> # now we turn it in a member function + >>> C.__str__ = C_str + >>> + >>> c = C() + >>> print c + A C instance! + >>> C_str(c) + A C instance! + +Yes, Python rox. :-) + +We can do the same with classes that were wrapped with Boost.Python. Suppose +we have a class [^point] in C++: + +[c++] + + class point {...}; + + BOOST_PYTHON_MODULE(_geom) + { + class_("point")...; + } + +If we are using the technique from the previous session, +[link python.creating_packages Creating Packages], we can code directly +into [^geom/\_\_init\_\_.py]: + +[python] + + from _geom import * + + # a regular function + def point_str(self): + return str((self.x, self.y)) + + # now we turn it into a member function + point.__str__ = point_str + +[*All] point instances created from C++ will also have this member function! +This technique has several advantages: + +* Cut down compile times to zero for these additional functions +* Reduce the memory footprint to virtually zero +* Minimize the need to recompile +* Rapid prototyping (you can move the code to C++ if required without changing the interface) + +You can even add a little syntactic sugar with the use of metaclasses. Let's +create a special metaclass that "injects" methods in other classes. + + # The one Boost.Python uses for all wrapped classes. + # You can use here any class exported by Boost instead of "point" + BoostPythonMetaclass = point.__class__ + + class injector(object): + class __metaclass__(BoostPythonMetaclass): + def __init__(self, name, bases, dict): + for b in bases: + if type(b) not in (self, type): + for k,v in dict.items(): + setattr(b,k,v) + return type.__init__(self, name, bases, dict) + + # inject some methods in the point foo + class more_point(injector, point): + def __repr__(self): + return 'Point(x=%s, y=%s)' % (self.x, self.y) + def foo(self): + print 'foo!' + +Now let's see how it got: + + >>> print point() + Point(x=10, y=10) + >>> point().foo() + foo! + +Another useful idea is to replace constructors with factory functions: + + _point = point + + def point(x=0, y=0): + return _point(x, y) + +In this simple case there is not much gained, but for constructurs with +many overloads and/or arguments this is often a great simplification, again +with virtually zero memory footprint and zero compile-time overhead for +the keyword support. + +[endsect] +[section Reducing Compiling Time] + +If you have ever exported a lot of classes, you know that it takes quite a good +time to compile the Boost.Python wrappers. Plus the memory consumption can +easily become too high. If this is causing you problems, you can split the +class_ definitions in multiple files: + +[c++] + + /* file point.cpp */ + #include + #include + + void export_point() + { + class_("point")...; + } + + /* file triangle.cpp */ + #include + #include + + void export_triangle() + { + class_("triangle")...; + } + +Now you create a file [^main.cpp], which contains the [^BOOST_PYTHON_MODULE] +macro, and call the various export functions inside it. + + void export_point(); + void export_triangle(); + + BOOST_PYTHON_MODULE(_geom) + { + export_point(); + export_triangle(); + } + +Compiling and linking together all this files produces the same result as the +usual approach: + + #include + #include + #include + + BOOST_PYTHON_MODULE(_geom) + { + class_("point")...; + class_("triangle")...; + } + +but the memory is kept under control. + +This method is recommended too if you are developing the C++ library and +exporting it to Python at the same time: changes in a class will only demand +the compilation of a single cpp, instead of the entire wrapper code. + +[note If you're exporting your classes with [@../../../../pyste/index.html Pyste], +take a look at the [^--multiple] option, that generates the wrappers in +various files as demonstrated here.] + +[note This method is useful too if you are getting the error message +['"fatal error C1204:Compiler limit:internal structure overflow"] when compiling +a large source file, as explained in the [@../../../v2/faq.html#c1204 FAQ].] + +[endsect] +[endsect] [/ General Techniques] +