diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/boost/libs/python | |
parent | Initial commit. (diff) | |
download | ceph-6d07fdb6bb33b1af39833b850bb6cf8af79fe293.tar.xz ceph-6d07fdb6bb33b1af39833b850bb6cf8af79fe293.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/python')
245 files changed, 22330 insertions, 0 deletions
diff --git a/src/boost/libs/python/Jamfile b/src/boost/libs/python/Jamfile new file mode 100644 index 000000000..32e87d80f --- /dev/null +++ b/src/boost/libs/python/Jamfile @@ -0,0 +1,68 @@ +# Copyright (c) 2018 Stefan Seefeld +# All rights reserved. +# +# 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 option ; +import regex ; +import python ; + +# +# The `version-suffix` rule really belongs into python.jam, and +# should be moved there. `split-version` is only duplicated here +# as a prerequisite. (See https://github.com/boostorg/build/pull/290) +# + + +# Validate the version string and extract the major/minor part we care about. +# +local rule split-version ( version ) +{ + local major-minor = [ MATCH "^([0-9]+)\.([0-9]+)(.*)$" : $(version) : 1 2 3 ] ; + if ! $(major-minor[2]) || $(major-minor[3]) + { + ECHO "Warning: \"using python\" expects a two part (major, minor) version number; got" $(version) instead ; + + # Add a zero to account for the missing digit if necessary. + major-minor += 0 ; + } + + return $(major-minor[1]) $(major-minor[2]) ; +} + +# Define a version suffix for libraries depending on Python. +# For example, Boost.Python built for Python 2.7 uses the suffix "27" +rule version-suffix ( version ) +{ + local major-minor = [ split-version $(version) ] ; + local suffix = $(major-minor:J="") ; + return $(suffix) ; +} + + +# Python build id (for Python libraries only). +python-id = [ option.get "python-buildid" ] ; +if $(python-id) +{ + PYTHON_ID = [ regex.replace $(python-id) "[*\\/:.\"\']" _ ] ; +} + +rule python-tag ( name : type ? : property-set ) +{ + local result = $(name) ; + if $(type) in STATIC_LIB SHARED_LIB IMPORT_LIB + { + local version = [ $(property-set).get <python> ] ; + local lib-suffix = [ version-suffix $(version) ] ; + result = $(result)$(lib-suffix) ; + } + if $(type) in STATIC_LIB SHARED_LIB IMPORT_LIB && $(PYTHON_ID) + { + result = $(result)-$(PYTHON_ID) ; + } + + # forward to the boost tagging rule + return [ tag $(result) : $(type) : $(property-set) ] ; +} diff --git a/src/boost/libs/python/LICENSE_1_0.txt b/src/boost/libs/python/LICENSE_1_0.txt new file mode 100644 index 000000000..36b7cd93c --- /dev/null +++ b/src/boost/libs/python/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/boost/libs/python/README.md b/src/boost/libs/python/README.md new file mode 100644 index 000000000..7646d3a87 --- /dev/null +++ b/src/boost/libs/python/README.md @@ -0,0 +1,60 @@ +![logo](https://raw.githubusercontent.com/boostorg/python/develop/doc/images/bpl.png) + +# Synopsis + +[![Join the chat at https://gitter.im/boostorg/python](https://badges.gitter.im/boostorg/python.svg)](https://gitter.im/boostorg/python?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +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 + +See the [Boost.Python](http://boostorg.github.io/python) documentation for details. + +**Hint :** Check out the [development version](http://boostorg.github.io/python/develop) of the documentation to see work in progress. + +# Building [![Build Status](https://travis-ci.org/boostorg/python.svg?branch=develop)](https://travis-ci.org/boostorg/python) [![Build status](https://ci.appveyor.com/api/projects/status/cgx9xma6v3gjav92/branch/develop?svg=true)](https://ci.appveyor.com/project/stefanseefeld/python/branch/develop) + + +While Boost.Python is part of the Boost C++ Libraries super-project, and thus can be compiled as part of Boost, it can also be compiled and installed stand-alone, i.e. against a pre-installed Boost package. + +## Prerequisites + +* [Python](http://www.python.org) +* [Boost](http://www.boost.org) +* [Faber](https://stefanseefeld.github.io/faber) + +## Build + +Run + +``` +faber +``` +to build the library. + +## Test + +Run + +``` +faber test.report +``` +to run the tests. + +## Build docs + +Run + +``` +faber doc.html +``` +to build the documentation. diff --git a/src/boost/libs/python/build/Jamfile b/src/boost/libs/python/build/Jamfile new file mode 100644 index 000000000..34f99dde7 --- /dev/null +++ b/src/boost/libs/python/build/Jamfile @@ -0,0 +1,161 @@ +# Copyright David Abrahams 2001-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) + +import os ; +import indirect ; +import modules ; +import feature ; +import property ; +import python ; + +if ! [ python.configured ] && ! ( --without-python in [ modules.peek : ARGV ] ) +{ + # Attempt default configuration of python + import toolset : using ; + using python ; +} + +if [ python.configured ] || ( --without-python in [ modules.peek : ARGV ] ) +{ + alias config-warning ; +} +else +{ + message config-warning + : "warning: No python installation configured and autoconfiguration" + : "note: failed. See http://www.boost.org/libs/python/doc/building.html" + : "note: for configuration instructions or pass --without-python to" + : "note: suppress this message and silently skip all Boost.Python targets" + ; +} + +if [ python.configured ] +{ +project boost/python + : source-location ../src + ; + +rule cond ( test ? : yes * : no * ) { if $(test) { return $(yes) ; } else { return $(no) ; } } +rule unless ( test ? : yes * : no * ) { if ! $(test) { return $(yes) ; } else { return $(no) ; } } +local rule eq ( a : b ) { if $(a) = $(b) { return 1 ; } } + +lib boost_python + : # sources + list.cpp + long.cpp + dict.cpp + tuple.cpp + str.cpp + slice.cpp + + converter/from_python.cpp + converter/registry.cpp + converter/type_id.cpp + object/enum.cpp + object/class.cpp + object/function.cpp + object/inheritance.cpp + object/life_support.cpp + object/pickle_support.cpp + errors.cpp + module.cpp + converter/builtin_converters.cpp + converter/arg_to_python_base.cpp + object/iterator.cpp + object/stl_iterator.cpp + object_protocol.cpp + object_operators.cpp + wrapper.cpp + import.cpp + exec.cpp + object/function_doc_signature.cpp + : # requirements + <link>static:<define>BOOST_PYTHON_STATIC_LIB + <define>BOOST_PYTHON_SOURCE + + # On Windows, all code using Python has to link to the Python + # import library. + # + # On *nix we never link libboost_python to libpython. When + # extending Python, all Python symbols are provided by the + # Python interpreter executable. When embedding Python, the + # client executable is expected to explicitly link to + # /python//python (the target representing libpython) itself. + # + # python_for_extensions is a target defined by Boost.Build to + # provide the Python include paths, and on Windows, the Python + # import library, as usage requirements. + [ cond [ python.configured ] : <library>/python//python_for_extensions ] + + # we prevent building when there is no python available + # as it's not possible anyway, and to cause dependents to + # fail to build + [ unless [ python.configured ] : <build>no ] + <dependency>config-warning + <python-debugging>on:<define>BOOST_DEBUG_PYTHON + -<tag>@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag + <tag>@$(__name__).python-tag + <conditional>@python.require-py + + : # default build + <link>shared + : # usage requirements + <link>static:<define>BOOST_PYTHON_STATIC_LIB + <python-debugging>on:<define>BOOST_DEBUG_PYTHON + ; + +numpy-include = [ python.numpy-include ] ; +lib boost_numpy + : # sources + numpy/dtype.cpp + numpy/matrix.cpp + numpy/ndarray.cpp + numpy/numpy.cpp + numpy/scalars.cpp + numpy/ufunc.cpp + : # requirements + <link>static:<define>BOOST_NUMPY_STATIC_LIB + <define>BOOST_NUMPY_SOURCE + [ cond [ python.numpy ] : <library>/python//python_for_extensions ] + [ unless [ python.numpy ] : <build>no ] + <include>$(numpy-include) + <library>boost_python + <python-debugging>on:<define>BOOST_DEBUG_PYTHON + -<tag>@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag + <tag>@$(__name__).python-tag + <conditional>@python.require-py + + : # default build + <link>shared + : # usage requirements + <link>static:<define>BOOST_NUMPY_STATIC_LIB + <python-debugging>on:<define>BOOST_DEBUG_PYTHON + ; + +# boost-install creates `stage` and `install` targets +# +# `stage` stages (builds and copies into `stage/lib`) the given libraries +# `boost_python` and `boost_numpy` and their dependencies and is similar +# to issuing `b2 --with-python stage` from top level +# +# `install` installs the two libraries and their dependencies and is similar +# to issuing `b2 --with-python install` from top level + +boost-install boost_python boost_numpy ; + +} +else +{ + +# When Python isn't configured, the above `boost-install` is not executed, +# so we create empty `stage` and `install` targets that do nothing but issue +# a warning message unless `--without-python` is given + +alias stage : config-warning ; +explicit stage ; + +alias install : config-warning ; +explicit install ; + +} diff --git a/src/boost/libs/python/example/Jamroot b/src/boost/libs/python/example/Jamroot new file mode 100644 index 000000000..fe9d69ecc --- /dev/null +++ b/src/boost/libs/python/example/Jamroot @@ -0,0 +1,35 @@ +# Copyright Stefan Seefeld 2016. +# 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 python ; + +if ! [ python.configured ] +{ + ECHO "warning: no Python configured in user-config.jam" ; + ECHO "warning: will use default configuration" ; + using python ; +} + +# Adjust the following if Boost.Python isn't installed in a default location +lib boost_python ; + +project + : requirements +# <include>/path/to/boost/python + <library>boost_python +; + +rule run-test ( test-name : sources + ) +{ + import testing ; + testing.make-test run-pyd : $(sources) : : $(test-name) ; +} + +build-project quickstart ; +build-project tutorial ; +if [ python.numpy ] +{ + build-project numpy ; +} diff --git a/src/boost/libs/python/example/README.md b/src/boost/libs/python/example/README.md new file mode 100644 index 000000000..b090cbe1e --- /dev/null +++ b/src/boost/libs/python/example/README.md @@ -0,0 +1,11 @@ +![logo](https://raw.githubusercontent.com/boostorg/python/develop/doc/images/bpl.png) + +# Examples + +This directory contains various examples using Boost.Python. +You may compile these using the `bjam` command either in this directory +or in any of the subdirectories. +You may need to adjust the paths in the Jamroot file if Boost.Python +is not installed in a default location. +See http://boostorg.github.io/python/doc/html/building/no_install_quickstart.html +for details. diff --git a/src/boost/libs/python/example/numpy/Jamfile b/src/boost/libs/python/example/numpy/Jamfile new file mode 100644 index 000000000..ac70a6ff0 --- /dev/null +++ b/src/boost/libs/python/example/numpy/Jamfile @@ -0,0 +1,29 @@ +# Copyright Stefan Seefeld 2016. +# 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 python ; + +# Adjust the following if Boost.Python isn't installed in a default location +lib boost_numpy + : + : <search>/usr/local/Boost/lib + <include>/usr/local/Boost/include + ; + +project numpy + : requirements + <include>/usr/local/Boost/include + <library>boost_numpy + <location>. + ; + +exe simple : simple.cpp boost_numpy /python//python ; +exe dtype : dtype.cpp boost_numpy /python//python ; +exe ndarray : ndarray.cpp /python//python ; +exe fromdata : fromdata.cpp /python//python ; +exe ufunc : ufunc.cpp /python//python ; +exe wrap : wrap.cpp /python//python ; + +python-extension gaussian : gaussian.cpp ; diff --git a/src/boost/libs/python/example/numpy/demo_gaussian.py b/src/boost/libs/python/example/numpy/demo_gaussian.py new file mode 100644 index 000000000..0b1c78995 --- /dev/null +++ b/src/boost/libs/python/example/numpy/demo_gaussian.py @@ -0,0 +1,37 @@ +# Copyright Jim Bosch 2010-2012. +# 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 numpy +import gaussian + +mu = numpy.zeros(2, dtype=float) +sigma = numpy.identity(2, dtype=float) +sigma[0, 1] = 0.15 +sigma[1, 0] = 0.15 + +g = gaussian.bivariate_gaussian(mu, sigma) + +r = numpy.linspace(-40, 40, 1001) +x, y = numpy.meshgrid(r, r) + +z = g(x, y) + +s = z.sum() * (r[1] - r[0])**2 +print "sum (should be ~ 1):", s + +xc = (z * x).sum() / z.sum() +print "x centroid (should be ~ %f): %f" % (mu[0], xc) + +yc = (z * y).sum() / z.sum() +print "y centroid (should be ~ %f): %f" % (mu[1], yc) + +xx = (z * (x - xc)**2).sum() / z.sum() +print "xx moment (should be ~ %f): %f" % (sigma[0,0], xx) + +yy = (z * (y - yc)**2).sum() / z.sum() +print "yy moment (should be ~ %f): %f" % (sigma[1,1], yy) + +xy = 0.5 * (z * (x - xc) * (y - yc)).sum() / z.sum() +print "xy moment (should be ~ %f): %f" % (sigma[0,1], xy) diff --git a/src/boost/libs/python/example/numpy/dtype.cpp b/src/boost/libs/python/example/numpy/dtype.cpp new file mode 100644 index 000000000..749a36b5e --- /dev/null +++ b/src/boost/libs/python/example/numpy/dtype.cpp @@ -0,0 +1,49 @@ +// Copyright Ankit Daftery 2011-2012. +// 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) + +/** + * @brief An example to show how to create ndarrays with built-in python data types, and extract + * the types and values of member variables + * + * @todo Add an example to show type conversion. + * Add an example to show use of user-defined types + * + */ + +#include <boost/python/numpy.hpp> +#include <iostream> + +namespace p = boost::python; +namespace np = boost::python::numpy; + +int main(int argc, char **argv) +{ + // Initialize the Python runtime. + Py_Initialize(); + // Initialize NumPy + np::initialize(); + // Create a 3x3 shape... + p::tuple shape = p::make_tuple(3, 3); + // ...as well as a type for C++ double + np::dtype dtype = np::dtype::get_builtin<double>(); + // Construct an array with the above shape and type + np::ndarray a = np::zeros(shape, dtype); + // Print the array + std::cout << "Original array:\n" << p::extract<char const *>(p::str(a)) << std::endl; + // Print the datatype of the elements + std::cout << "Datatype is:\n" << p::extract<char const *>(p::str(a.get_dtype())) << std::endl ; + // Using user defined dtypes to create dtype and an array of the custom dtype + // First create a tuple with a variable name and its dtype, double, to create a custom dtype + p::tuple for_custom_dtype = p::make_tuple("ha",dtype) ; + // The list needs to be created, because the constructor to create the custom dtype + // takes a list of (variable,variable_type) as an argument + p::list list_for_dtype ; + list_for_dtype.append(for_custom_dtype) ; + // Create the custom dtype + np::dtype custom_dtype = np::dtype(list_for_dtype) ; + // Create an ndarray with the custom dtype + np::ndarray new_array = np::zeros(shape,custom_dtype); + +} diff --git a/src/boost/libs/python/example/numpy/fromdata.cpp b/src/boost/libs/python/example/numpy/fromdata.cpp new file mode 100644 index 000000000..bd073cc69 --- /dev/null +++ b/src/boost/libs/python/example/numpy/fromdata.cpp @@ -0,0 +1,48 @@ +// Copyright Ankit Daftery 2011-2012. +// 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) + +/** + * @brief An example to show how to access data using raw pointers. This shows that you can use and + * manipulate data in either Python or C++ and have the changes reflected in both. + */ + +#include <boost/python/numpy.hpp> +#include <iostream> + +namespace p = boost::python; +namespace np = boost::python::numpy; + + +int main(int argc, char **argv) +{ + // Initialize the Python runtime. + Py_Initialize(); + // Initialize NumPy + np::initialize(); + // Create an array in C++ + int arr[] = {1,2,3,4} ; + // Create the ndarray in Python + np::ndarray py_array = np::from_data(arr, np::dtype::get_builtin<int>() , p::make_tuple(4), p::make_tuple(4), p::object()); + // Print the ndarray that we just created, and the source C++ array + std::cout << "C++ array :" << std::endl ; + for (int j=0;j<4;j++) + { + std::cout << arr[j] << ' ' ; + } + std::cout << std::endl << "Python ndarray :" << p::extract<char const *>(p::str(py_array)) << std::endl; + // Change an element in the python ndarray + py_array[1] = 5 ; + // And see if the C++ container is changed or not + std::cout << "Is the change reflected in the C++ array used to create the ndarray ? " << std::endl ; + for (int j = 0;j<4 ; j++) + { + std::cout << arr[j] << ' ' ; + } + // Conversely, change it in C++ + arr[2] = 8 ; + // And see if the changes are reflected in the Python ndarray + std::cout << std::endl << "Is the change reflected in the Python ndarray ?" << std::endl << p::extract<char const *>(p::str(py_array)) << std::endl; + +} diff --git a/src/boost/libs/python/example/numpy/gaussian.cpp b/src/boost/libs/python/example/numpy/gaussian.cpp new file mode 100644 index 000000000..5f138b397 --- /dev/null +++ b/src/boost/libs/python/example/numpy/gaussian.cpp @@ -0,0 +1,315 @@ +// Copyright Jim Bosch 2010-2012. +// 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 <boost/python/numpy.hpp> + +#include <cmath> +#include <memory> + +#ifndef M_PI +#include <boost/math/constants/constants.hpp> +const double M_PI = boost::math::constants::pi<double>(); +#endif + +namespace bp = boost::python; +namespace bn = boost::python::numpy; + +/** + * A 2x2 matrix class, purely for demonstration purposes. + * + * Instead of wrapping this class with Boost.Python, we'll convert it to/from numpy.ndarray. + */ +class matrix2 { +public: + + double & operator()(int i, int j) { + return _data[i*2 + j]; + } + + double const & operator()(int i, int j) const { + return _data[i*2 + j]; + } + + double const * data() const { return _data; } + +private: + double _data[4]; +}; + +/** + * A 2-element vector class, purely for demonstration purposes. + * + * Instead of wrapping this class with Boost.Python, we'll convert it to/from numpy.ndarray. + */ +class vector2 { +public: + + double & operator[](int i) { + return _data[i]; + } + + double const & operator[](int i) const { + return _data[i]; + } + + double const * data() const { return _data; } + + vector2 operator+(vector2 const & other) const { + vector2 r; + r[0] = _data[0] + other[0]; + r[1] = _data[1] + other[1]; + return r; + } + + vector2 operator-(vector2 const & other) const { + vector2 r; + r[0] = _data[0] - other[0]; + r[1] = _data[1] - other[1]; + return r; + } + +private: + double _data[2]; +}; + +/** + * Matrix-vector multiplication. + */ +vector2 operator*(matrix2 const & m, vector2 const & v) { + vector2 r; + r[0] = m(0, 0) * v[0] + m(0, 1) * v[1]; + r[1] = m(1, 0) * v[0] + m(1, 1) * v[1]; + return r; +} + +/** + * Vector inner product. + */ +double dot(vector2 const & v1, vector2 const & v2) { + return v1[0] * v2[0] + v1[1] * v2[1]; +} + +/** + * This class represents a simple 2-d Gaussian (Normal) distribution, defined by a + * mean vector 'mu' and a covariance matrix 'sigma'. + */ +class bivariate_gaussian { +public: + + vector2 const & get_mu() const { return _mu; } + + matrix2 const & get_sigma() const { return _sigma; } + + /** + * Evaluate the density of the distribution at a point defined by a two-element vector. + */ + double operator()(vector2 const & p) const { + vector2 u = _cholesky * (p - _mu); + return 0.5 * _cholesky(0, 0) * _cholesky(1, 1) * std::exp(-0.5 * dot(u, u)) / M_PI; + } + + /** + * Evaluate the density of the distribution at an (x, y) point. + */ + double operator()(double x, double y) const { + vector2 p; + p[0] = x; + p[1] = y; + return operator()(p); + } + + /** + * Construct from a mean vector and covariance matrix. + */ + bivariate_gaussian(vector2 const & mu, matrix2 const & sigma) + : _mu(mu), _sigma(sigma), _cholesky(compute_inverse_cholesky(sigma)) + {} + +private: + + /** + * This evaluates the inverse of the Cholesky factorization of a 2x2 matrix; + * it's just a shortcut in evaluating the density. + */ + static matrix2 compute_inverse_cholesky(matrix2 const & m) { + matrix2 l; + // First do cholesky factorization: l l^t = m + l(0, 0) = std::sqrt(m(0, 0)); + l(0, 1) = m(0, 1) / l(0, 0); + l(1, 1) = std::sqrt(m(1, 1) - l(0,1) * l(0,1)); + // Now do forward-substitution (in-place) to invert: + l(0, 0) = 1.0 / l(0, 0); + l(1, 0) = l(0, 1) = -l(0, 1) / l(1, 1); + l(1, 1) = 1.0 / l(1, 1); + return l; + } + + vector2 _mu; + matrix2 _sigma; + matrix2 _cholesky; + +}; + +/* + * We have a two options for wrapping get_mu and get_sigma into NumPy-returning Python methods: + * - we could deep-copy the data, making totally new NumPy arrays; + * - we could make NumPy arrays that point into the existing memory. + * The latter is often preferable, especially if the arrays are large, but it's dangerous unless + * the reference counting is correct: the returned NumPy array needs to hold a reference that + * keeps the memory it points to from being deallocated as long as it is alive. This is what the + * "owner" argument to from_data does - the NumPy array holds a reference to the owner, keeping it + * from being destroyed. + * + * Note that this mechanism isn't completely safe for data members that can have their internal + * storage reallocated. A std::vector, for instance, can be invalidated when it is resized, + * so holding a Python reference to a C++ class that holds a std::vector may not be a guarantee + * that the memory in the std::vector will remain valid. + */ + +/** + * These two functions are custom wrappers for get_mu and get_sigma, providing the shallow-copy + * conversion with reference counting described above. + * + * It's also worth noting that these return NumPy arrays that cannot be modified in Python; + * the const overloads of vector::data() and matrix::data() return const references, + * and passing a const pointer to from_data causes NumPy's 'writeable' flag to be set to false. + */ +static bn::ndarray py_get_mu(bp::object const & self) { + vector2 const & mu = bp::extract<bivariate_gaussian const &>(self)().get_mu(); + return bn::from_data( + mu.data(), + bn::dtype::get_builtin<double>(), + bp::make_tuple(2), + bp::make_tuple(sizeof(double)), + self + ); +} +static bn::ndarray py_get_sigma(bp::object const & self) { + matrix2 const & sigma = bp::extract<bivariate_gaussian const &>(self)().get_sigma(); + return bn::from_data( + sigma.data(), + bn::dtype::get_builtin<double>(), + bp::make_tuple(2, 2), + bp::make_tuple(2 * sizeof(double), sizeof(double)), + self + ); +} + +/** + * To allow the constructor to work, we need to define some from-Python converters from NumPy arrays + * to the matrix/vector types. The rvalue-from-python functionality is not well-documented in Boost.Python + * itself; you can learn more from boost/python/converter/rvalue_from_python_data.hpp. + */ + +/** + * We start with two functions that just copy a NumPy array into matrix/vector objects. These will be used + * in the templated converted below. The first just uses the operator[] overloads provided by + * bp::object. + */ +static void copy_ndarray_to_mv2(bn::ndarray const & array, vector2 & vec) { + vec[0] = bp::extract<double>(array[0]); + vec[1] = bp::extract<double>(array[1]); +} + +/** + * Here, we'll take the alternate approach of using the strides to access the array's memory directly. + * This can be much faster for large arrays. + */ +static void copy_ndarray_to_mv2(bn::ndarray const & array, matrix2 & mat) { + // Unfortunately, get_strides() can't be inlined, so it's best to call it once up-front. + Py_intptr_t const * strides = array.get_strides(); + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 2; ++j) { + mat(i, j) = *reinterpret_cast<double const *>(array.get_data() + i * strides[0] + j * strides[1]); + } + } +} + +/** + * Here's the actual converter. Because we've separated the differences into the above functions, + * we can write a single template class that works for both matrix2 and vector2. + */ +template <typename T, int N> +struct mv2_from_python { + + /** + * Register the converter. + */ + mv2_from_python() { + bp::converter::registry::push_back( + &convertible, + &construct, + bp::type_id< T >() + ); + } + + /** + * Test to see if we can convert this to the desired type; if not return zero. + * If we can convert, returned pointer can be used by construct(). + */ + static void * convertible(PyObject * p) { + try { + bp::object obj(bp::handle<>(bp::borrowed(p))); + std::auto_ptr<bn::ndarray> array( + new bn::ndarray( + bn::from_object(obj, bn::dtype::get_builtin<double>(), N, N, bn::ndarray::V_CONTIGUOUS) + ) + ); + if (array->shape(0) != 2) return 0; + if (N == 2 && array->shape(1) != 2) return 0; + return array.release(); + } catch (bp::error_already_set & err) { + bp::handle_exception(); + return 0; + } + } + + /** + * Finish the conversion by initializing the C++ object into memory prepared by Boost.Python. + */ + static void construct(PyObject * obj, bp::converter::rvalue_from_python_stage1_data * data) { + // Extract the array we passed out of the convertible() member function. + std::auto_ptr<bn::ndarray> array(reinterpret_cast<bn::ndarray*>(data->convertible)); + // Find the memory block Boost.Python has prepared for the result. + typedef bp::converter::rvalue_from_python_storage<T> storage_t; + storage_t * storage = reinterpret_cast<storage_t*>(data); + // Use placement new to initialize the result. + T * m_or_v = new (storage->storage.bytes) T(); + // Fill the result with the values from the NumPy array. + copy_ndarray_to_mv2(*array, *m_or_v); + // Finish up. + data->convertible = storage->storage.bytes; + } + +}; + + +BOOST_PYTHON_MODULE(gaussian) { + bn::initialize(); + + // Register the from-python converters + mv2_from_python< vector2, 1 >(); + mv2_from_python< matrix2, 2 >(); + + typedef double (bivariate_gaussian::*call_vector)(vector2 const &) const; + + bp::class_<bivariate_gaussian>("bivariate_gaussian", bp::init<bivariate_gaussian const &>()) + + // Declare the constructor (wouldn't work without the from-python converters). + .def(bp::init< vector2 const &, matrix2 const & >()) + + // Use our custom reference-counting getters + .add_property("mu", &py_get_mu) + .add_property("sigma", &py_get_sigma) + + // First overload accepts a two-element array argument + .def("__call__", (call_vector)&bivariate_gaussian::operator()) + + // This overload works like a binary NumPy universal function: you can pass + // in scalars or arrays, and the C++ function will automatically be called + // on each element of an array argument. + .def("__call__", bn::binary_ufunc<bivariate_gaussian,double,double,double>::make()) + ; +} diff --git a/src/boost/libs/python/example/numpy/ndarray.cpp b/src/boost/libs/python/example/numpy/ndarray.cpp new file mode 100644 index 000000000..d7b57aa73 --- /dev/null +++ b/src/boost/libs/python/example/numpy/ndarray.cpp @@ -0,0 +1,71 @@ +// Copyright Ankit Daftery 2011-2012. +// 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) + +/** + * @brief An example to show how to create ndarrays using arbitrary Python sequences. + * + * The Python sequence could be any object whose __array__ method returns an array, or any + * (nested) sequence. This example also shows how to create arrays using both unit and + * non-unit strides. + */ + +#include <boost/python/numpy.hpp> +#include <iostream> + +namespace p = boost::python; +namespace np = boost::python::numpy; + +#if _MSC_VER +using boost::uint8_t; +#endif + +int main(int argc, char **argv) +{ + // Initialize the Python runtime. + Py_Initialize(); + // Initialize NumPy + np::initialize(); + // Create an ndarray from a simple tuple + p::object tu = p::make_tuple('a','b','c') ; + np::ndarray example_tuple = np::array (tu) ; + // and from a list + p::list l ; + np::ndarray example_list = np::array (l) ; + // Optionally, you can also specify a dtype + np::dtype dt = np::dtype::get_builtin<int>(); + np::ndarray example_list1 = np::array (l,dt); + // You can also create an array by supplying data.First,create an integer array + int data[] = {1,2,3,4} ; + // Create a shape, and strides, needed by the function + p::tuple shape = p::make_tuple(4) ; + p::tuple stride = p::make_tuple(4) ; + // The function also needs an owner, to keep track of the data array passed. Passing none is dangerous + p::object own ; + // The from_data function takes the data array, datatype,shape,stride and owner as arguments + // and returns an ndarray + np::ndarray data_ex = np::from_data(data,dt,shape,stride,own); + // Print the ndarray we created + std::cout << "Single dimensional array ::" << std::endl << p::extract < char const * > (p::str(data_ex)) << std::endl ; + // Now lets make an 3x2 ndarray from a multi-dimensional array using non-unit strides + // First lets create a 3x4 array of 8-bit integers + uint8_t mul_data[][4] = {{1,2,3,4},{5,6,7,8},{1,3,5,7}}; + // Now let's create an array of 3x2 elements, picking the first and third elements from each row + // For that, the shape will be 3x2 + shape = p::make_tuple(3,2) ; + // The strides will be 4x2 i.e. 4 bytes to go to the next desired row, and 2 bytes to go to the next desired column + stride = p::make_tuple(4,2) ; + // Get the numpy dtype for the built-in 8-bit integer data type + np::dtype dt1 = np::dtype::get_builtin<uint8_t>(); + // First lets create and print out the ndarray as is + np::ndarray mul_data_ex = np::from_data(mul_data,dt1, p::make_tuple(3,4),p::make_tuple(4,1),p::object()); + std::cout << "Original multi dimensional array :: " << std::endl << p::extract < char const * > (p::str(mul_data_ex)) << std::endl ; + // Now create the new ndarray using the shape and strides + mul_data_ex = np::from_data(mul_data,dt1, shape,stride,p::object()); + // Print out the array we created using non-unit strides + std::cout << "Selective multidimensional array :: "<<std::endl << p::extract < char const * > (p::str(mul_data_ex)) << std::endl ; + +} + + diff --git a/src/boost/libs/python/example/numpy/simple.cpp b/src/boost/libs/python/example/numpy/simple.cpp new file mode 100644 index 000000000..ad598bde4 --- /dev/null +++ b/src/boost/libs/python/example/numpy/simple.cpp @@ -0,0 +1,32 @@ +// Copyright 2011 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) + +#include <boost/python/numpy.hpp> +#include <iostream> + +namespace p = boost::python; +namespace np = boost::python::numpy; + +int main(int argc, char **argv) +{ + // Initialize the Python runtime. + Py_Initialize(); + // Initialize NumPy + np::initialize(); + // Create a 3x3 shape... + p::tuple shape = p::make_tuple(3, 3); + // ...as well as a type for C++ float + np::dtype dtype = np::dtype::get_builtin<float>(); + // Construct an array with the above shape and type + np::ndarray a = np::zeros(shape, dtype); + // Construct an empty array with the above shape and dtype as well + np::ndarray b = np::empty(shape,dtype); + // Print the array + std::cout << "Original array:\n" << p::extract<char const *>(p::str(a)) << std::endl; + // Reshape the array into a 1D array + a = a.reshape(p::make_tuple(9)); + // Print it again. + std::cout << "Reshaped array:\n" << p::extract<char const *>(p::str(a)) << std::endl; +} diff --git a/src/boost/libs/python/example/numpy/ufunc.cpp b/src/boost/libs/python/example/numpy/ufunc.cpp new file mode 100644 index 000000000..5fb692045 --- /dev/null +++ b/src/boost/libs/python/example/numpy/ufunc.cpp @@ -0,0 +1,86 @@ +// Copyright Ankit Daftery 2011-2012. +// 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) + +/** + * @brief An example to demonstrate use of universal functions or ufuncs + * + * + * @todo Calling the overloaded () operator is in a roundabout manner, find a simpler way + * None of the methods like np::add, np::multiply etc are supported as yet + */ + +#include <boost/python/numpy.hpp> +#include <iostream> + +namespace p = boost::python; +namespace np = boost::python::numpy; + + +// Create the structs necessary to implement the ufuncs +// The typedefs *must* be made + +struct UnarySquare +{ + typedef double argument_type; + typedef double result_type; + + double operator()(double r) const { return r * r;} +}; + +struct BinarySquare +{ + typedef double first_argument_type; + typedef double second_argument_type; + typedef double result_type; + + double operator()(double a,double b) const { return (a*a + b*b) ; } +}; + +int main(int argc, char **argv) +{ + // Initialize the Python runtime. + Py_Initialize(); + // Initialize NumPy + np::initialize(); + // Expose the struct UnarySquare to Python as a class, and let ud be the class object + p::object ud = p::class_<UnarySquare, boost::shared_ptr<UnarySquare> >("UnarySquare") + .def("__call__", np::unary_ufunc<UnarySquare>::make()); + // Let inst be an instance of the class ud + p::object inst = ud(); + // Use the "__call__" method to call the overloaded () operator and print the value + std::cout << "Square of unary scalar 1.0 is " << p::extract <char const * > (p::str(inst.attr("__call__")(1.0))) << std::endl ; + // Create an array in C++ + int arr[] = {1,2,3,4} ; + // ..and use it to create the ndarray in Python + np::ndarray demo_array = np::from_data(arr, np::dtype::get_builtin<int>() , p::make_tuple(4), p::make_tuple(4), p::object()); + // Print out the demo array + std::cout << "Demo array is " << p::extract <char const * > (p::str(demo_array)) << std::endl ; + // Call the "__call__" method to perform the operation and assign the value to result_array + p::object result_array = inst.attr("__call__")(demo_array) ; + // Print the resultant array + std::cout << "Square of demo array is " << p::extract <char const * > (p::str(result_array)) << std::endl ; + // Lets try the same with a list + p::list li ; + li.append(3); + li.append(7); + // Print out the demo list + std::cout << "Demo list is " << p::extract <char const * > (p::str(li)) << std::endl ; + // Call the ufunc for the list + result_array = inst.attr("__call__")(li) ; + // And print the list out + std::cout << "Square of demo list is " << p::extract <char const * > (p::str(result_array)) << std::endl ; + // Now lets try Binary ufuncs + // Expose the struct BinarySquare to Python as a class, and let ud be the class object + ud = p::class_<BinarySquare, boost::shared_ptr<BinarySquare> >("BinarySquare") + .def("__call__", np::binary_ufunc<BinarySquare>::make()); + // Again initialise inst as an instance of the class ud + inst = ud(); + // Print the two input listsPrint the two input lists + std::cout << "The two input list for binary ufunc are " << std::endl << p::extract <char const * > (p::str(demo_array)) << std::endl << p::extract <char const * > (p::str(demo_array)) << std::endl ; + // Call the binary ufunc taking demo_array as both inputs + result_array = inst.attr("__call__")(demo_array,demo_array) ; + std::cout << "Square of list with binary ufunc is " << p::extract <char const * > (p::str(result_array)) << std::endl ; +} + diff --git a/src/boost/libs/python/example/numpy/wrap.cpp b/src/boost/libs/python/example/numpy/wrap.cpp new file mode 100644 index 000000000..33f71c85a --- /dev/null +++ b/src/boost/libs/python/example/numpy/wrap.cpp @@ -0,0 +1,135 @@ +// Copyright Jim Bosch 2011-2012. +// 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) + +/** + * A simple example showing how to wrap a couple of C++ functions that + * operate on 2-d arrays into Python functions that take NumPy arrays + * as arguments. + * + * If you find have a lot of such functions to wrap, you may want to + * create a C++ array type (or use one of the many existing C++ array + * libraries) that maps well to NumPy arrays and create Boost.Python + * converters. There's more work up front than the approach here, + * but much less boilerplate per function. See the "Gaussian" example + * included with Boost.NumPy for an example of custom converters, or + * take a look at the "ndarray" project on GitHub for a more complete, + * high-level solution. + * + * Note that we're using embedded Python here only to make a convenient + * self-contained example; you could just as easily put the wrappers + * in a regular C++-compiled module and imported them in regular + * Python. Again, see the Gaussian demo for an example. + */ + +#include <boost/python/numpy.hpp> +#include <boost/scoped_array.hpp> +#include <iostream> + +namespace p = boost::python; +namespace np = boost::python::numpy; + +// This is roughly the most efficient way to write a C/C++ function that operates +// on a 2-d NumPy array - operate directly on the array by incrementing a pointer +// with the strides. +void fill1(double * array, int rows, int cols, int row_stride, int col_stride) { + double * row_iter = array; + double n = 0.0; // just a counter we'll fill the array with. + for (int i = 0; i < rows; ++i, row_iter += row_stride) { + double * col_iter = row_iter; + for (int j = 0; j < cols; ++j, col_iter += col_stride) { + *col_iter = ++n; + } + } +} + +// Here's a simple wrapper function for fill1. It requires that the passed +// NumPy array be exactly what we're looking for - no conversion from nested +// sequences or arrays with other data types, because we want to modify it +// in-place. +void wrap_fill1(np::ndarray const & array) { + if (array.get_dtype() != np::dtype::get_builtin<double>()) { + PyErr_SetString(PyExc_TypeError, "Incorrect array data type"); + p::throw_error_already_set(); + } + if (array.get_nd() != 2) { + PyErr_SetString(PyExc_TypeError, "Incorrect number of dimensions"); + p::throw_error_already_set(); + } + fill1(reinterpret_cast<double*>(array.get_data()), + array.shape(0), array.shape(1), + array.strides(0) / sizeof(double), array.strides(1) / sizeof(double)); +} + +// Another fill function that takes a double**. This is less efficient, because +// it's not the native NumPy data layout, but it's common enough in C/C++ that +// it's worth its own example. This time we don't pass the strides, and instead +// in wrap_fill2 we'll require the C_CONTIGUOUS bitflag, which guarantees that +// the column stride is 1 and the row stride is the number of columns. That +// restricts the arrays that can be passed to fill2 (it won't work on most +// subarray views or transposes, for instance). +void fill2(double ** array, int rows, int cols) { + double n = 0.0; // just a counter we'll fill the array with. + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + array[i][j] = ++n; + } + } +} +// Here's the wrapper for fill2; it's a little more complicated because we need +// to check the flags and create the array of pointers. +void wrap_fill2(np::ndarray const & array) { + if (array.get_dtype() != np::dtype::get_builtin<double>()) { + PyErr_SetString(PyExc_TypeError, "Incorrect array data type"); + p::throw_error_already_set(); + } + if (array.get_nd() != 2) { + PyErr_SetString(PyExc_TypeError, "Incorrect number of dimensions"); + p::throw_error_already_set(); + } + if (!(array.get_flags() & np::ndarray::C_CONTIGUOUS)) { + PyErr_SetString(PyExc_TypeError, "Array must be row-major contiguous"); + p::throw_error_already_set(); + } + double * iter = reinterpret_cast<double*>(array.get_data()); + int rows = array.shape(0); + int cols = array.shape(1); + boost::scoped_array<double*> ptrs(new double*[rows]); + for (int i = 0; i < rows; ++i, iter += cols) { + ptrs[i] = iter; + } + fill2(ptrs.get(), array.shape(0), array.shape(1)); +} + +BOOST_PYTHON_MODULE(example) { + np::initialize(); // have to put this in any module that uses Boost.NumPy + p::def("fill1", wrap_fill1); + p::def("fill2", wrap_fill2); +} + +int main(int argc, char **argv) +{ + // This line makes our module available to the embedded Python intepreter. +# if PY_VERSION_HEX >= 0x03000000 + PyImport_AppendInittab("example", &PyInit_example); +# else + PyImport_AppendInittab("example", &initexample); +# endif + // Initialize the Python runtime. + Py_Initialize(); + + PyRun_SimpleString( + "import example\n" + "import numpy\n" + "z1 = numpy.zeros((5,6), dtype=float)\n" + "z2 = numpy.zeros((4,3), dtype=float)\n" + "example.fill1(z1)\n" + "example.fill2(z2)\n" + "print z1\n" + "print z2\n" + ); + Py_Finalize(); +} + + diff --git a/src/boost/libs/python/example/quickstart/Jamfile b/src/boost/libs/python/example/quickstart/Jamfile new file mode 100644 index 000000000..6dd351301 --- /dev/null +++ b/src/boost/libs/python/example/quickstart/Jamfile @@ -0,0 +1,35 @@ +# Copyright Stefan Seefeld 2016. +# 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 python ; +import testing ; + +project quickstart + : requirements + <location>. + ; + +# Declare a Python extension called hello. +python-extension extending : extending.cpp ; + +# Declare an executable called embedding that embeds Python +exe embedding : embedding.cpp /python//python ; + +# Declare a test of the extension module +testing.make-test run-pyd : extending test_extending.py : : test_ext ; + +# Declare a test of the embedding application +testing.run embedding embedding.cpp + : # any ordinary arguments + : script.py # any arguments that should be treated as relative paths + : # requirements + : test_embed ; # name of test + +# Create a "test" target that runs all the tests +alias test : test_ext test_embed ; + +# make sure the tests don't run by default +explicit test_ext test_embed test ; + diff --git a/src/boost/libs/python/example/quickstart/embedding.cpp b/src/boost/libs/python/example/quickstart/embedding.cpp new file mode 100644 index 000000000..65bcd16a0 --- /dev/null +++ b/src/boost/libs/python/example/quickstart/embedding.cpp @@ -0,0 +1,154 @@ +// Copyright Stefan Seefeld 2005. +// 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 <boost/python.hpp> + +#include <boost/detail/lightweight_test.hpp> +#include <iostream> + +namespace python = boost::python; + +// An abstract base class +class Base : public boost::noncopyable +{ +public: + virtual ~Base() {}; + virtual std::string hello() = 0; +}; + +// C++ derived class +class CppDerived : public Base +{ +public: + virtual ~CppDerived() {} + virtual std::string hello() { return "Hello from C++!";} +}; + +// Familiar Boost.Python wrapper class for Base +struct BaseWrap : Base, python::wrapper<Base> +{ + virtual std::string hello() + { +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + // workaround for VC++ 6.x or 7.0, see + // http://boost.org/libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions + return python::call<std::string>(this->get_override("hello").ptr()); +#else + return this->get_override("hello")(); +#endif + } +}; + +// Pack the Base class wrapper into a module +BOOST_PYTHON_MODULE(embedded_hello) +{ + python::class_<BaseWrap, boost::noncopyable> base("Base"); +} + + +void exec_test() +{ + std::cout << "registering extension module embedded_hello..." << std::endl; + + // Register the module with the interpreter + if (PyImport_AppendInittab("embedded_hello", initembedded_hello) == -1) + throw std::runtime_error("Failed to add embedded_hello to the interpreter's " + "builtin modules"); + + std::cout << "defining Python class derived from Base..." << std::endl; + + // Retrieve the main module + python::object main = python::import("__main__"); + + // Retrieve the main module's namespace + python::object global(main.attr("__dict__")); + + // Define the derived class in Python. + python::object result = python::exec( + "from embedded_hello import * \n" + "class PythonDerived(Base): \n" + " def hello(self): \n" + " return 'Hello from Python!' \n", + global, global); + + python::object PythonDerived = global["PythonDerived"]; + + // Creating and using instances of the C++ class is as easy as always. + CppDerived cpp; + BOOST_TEST(cpp.hello() == "Hello from C++!"); + + std::cout << "testing derived class from C++..." << std::endl; + + // But now creating and using instances of the Python class is almost + // as easy! + python::object py_base = PythonDerived(); + Base& py = python::extract<Base&>(py_base) BOOST_EXTRACT_WORKAROUND; + + // Make sure the right 'hello' method is called. + BOOST_TEST(py.hello() == "Hello from Python!"); + + std::cout << "success!" << std::endl; +} + +void exec_file_test(std::string const &script) +{ + std::cout << "running file " << script << "..." << std::endl; + + // Run a python script in an empty environment. + python::dict global; + python::object result = python::exec_file(script.c_str(), global, global); + + // Extract an object the script stored in the global dictionary. + BOOST_TEST(python::extract<int>(global["number"]) == 42); + + std::cout << "success!" << std::endl; +} + +void exec_test_error() +{ + std::cout << "intentionally causing a python exception..." << std::endl; + + // Execute a statement that raises a python exception. + python::dict global; + python::object result = python::exec("print unknown \n", global, global); + + std::cout << "Oops! This statement should be skipped due to an exception" << std::endl; +} + +int main(int argc, char **argv) +{ + BOOST_TEST(argc == 2); + std::string script = argv[1]; + // Initialize the interpreter + Py_Initialize(); + + bool error_expected = false; + + if ( + python::handle_exception(exec_test) + || python::handle_exception(boost::bind(exec_file_test, script)) + || ( + (error_expected = true) + && python::handle_exception(exec_test_error) + ) + + ) + { + if (PyErr_Occurred()) + { + if (!error_expected) + BOOST_ERROR("Python Error detected"); + PyErr_Print(); + } + else + { + BOOST_ERROR("A C++ exception was thrown for which " + "there was no exception translator registered."); + } + } + + // Boost.Python doesn't support Py_Finalize yet, so don't call it! + return boost::report_errors(); +} diff --git a/src/boost/libs/python/example/quickstart/extending.cpp b/src/boost/libs/python/example/quickstart/extending.cpp new file mode 100644 index 000000000..a539d3b4b --- /dev/null +++ b/src/boost/libs/python/example/quickstart/extending.cpp @@ -0,0 +1,41 @@ +// Copyright Ralf W. Grosse-Kunstleve 2002-2004. 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 <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <iostream> +#include <string> + +namespace { // Avoid cluttering the global namespace. + + // A friendly class. + class hello + { + public: + hello(const std::string& country) { this->country = country; } + std::string greet() const { return "Hello from " + country; } + private: + std::string country; + }; + + // A function taking a hello object as an argument. + std::string invite(const hello& w) { + return w.greet() + "! Please come soon!"; + } +} + +BOOST_PYTHON_MODULE(extending) +{ + using namespace boost::python; + class_<hello>("hello", init<std::string>()) + // Add a regular member function. + .def("greet", &hello::greet) + // Add invite() as a member of hello! + .def("invite", invite) + ; + + // Also add invite() as a regular function to the module. + def("invite", invite); +} diff --git a/src/boost/libs/python/example/quickstart/script.py b/src/boost/libs/python/example/quickstart/script.py new file mode 100644 index 000000000..c3e034ba8 --- /dev/null +++ b/src/boost/libs/python/example/quickstart/script.py @@ -0,0 +1,7 @@ +#! /usr/bin/env python +# Copyright Stefan Seefeld 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) + +print('Hello World !') +number = 42 diff --git a/src/boost/libs/python/example/quickstart/test_extending.py b/src/boost/libs/python/example/quickstart/test_extending.py new file mode 100644 index 000000000..938c7b904 --- /dev/null +++ b/src/boost/libs/python/example/quickstart/test_extending.py @@ -0,0 +1,37 @@ +#! /usr/bin/env python +# Copyright Ralf W. Grosse-Kunstleve 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) + +# Using the doctest module here to ensure that the results are as expected. +r'''>>> from extending import * + >>> hi = hello('California') + >>> hi.greet() + 'Hello from California' + >>> invite(hi) + 'Hello from California! Please come soon!' + >>> hi.invite() + 'Hello from California! Please come soon!' + + >>> class wordy(hello): + ... def greet(self): + ... return hello.greet(self) + ', where the weather is fine' + ... + >>> hi2 = wordy('Florida') + >>> hi2.greet() + 'Hello from Florida, where the weather is fine' + >>> invite(hi2) + 'Hello from Florida! Please come soon!' +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_extending + return doctest.testmod(test_extending, verbose=True) + +if __name__ == '__main__': + import sys + sys.exit(run()[0]) + diff --git a/src/boost/libs/python/example/tutorial/Jamfile b/src/boost/libs/python/example/tutorial/Jamfile new file mode 100644 index 000000000..a32272e7f --- /dev/null +++ b/src/boost/libs/python/example/tutorial/Jamfile @@ -0,0 +1,19 @@ +# Copyright Stefan Seefeld 2016. +# 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 python ; + +project tutorial + : requirements + <location>. + ; + +python-extension hello_ext : hello.cpp ; + +run-test hello : hello_ext hello.py ; + +alias test : hello ; +explicit test ; + diff --git a/src/boost/libs/python/example/tutorial/hello.cpp b/src/boost/libs/python/example/tutorial/hello.cpp new file mode 100644 index 000000000..d5114312b --- /dev/null +++ b/src/boost/libs/python/example/tutorial/hello.cpp @@ -0,0 +1,20 @@ +// Copyright Joel de Guzman 2002-2004. 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) +// Hello World Example from the tutorial +// [Joel de Guzman 10/9/2002] + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> + +char const* greet() +{ + return "hello, world"; +} + +BOOST_PYTHON_MODULE(hello_ext) +{ + using namespace boost::python; + def("greet", greet); +} + diff --git a/src/boost/libs/python/example/tutorial/hello.py b/src/boost/libs/python/example/tutorial/hello.py new file mode 100755 index 000000000..31f75565d --- /dev/null +++ b/src/boost/libs/python/example/tutorial/hello.py @@ -0,0 +1,8 @@ +#! /usr/bin/env python +# Copyright Joel de Guzman 2002-2007. 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) +# Hello World Example from the tutorial + +import hello_ext +print(hello_ext.greet()) diff --git a/src/boost/libs/python/fabscript b/src/boost/libs/python/fabscript new file mode 100644 index 000000000..054ed90e5 --- /dev/null +++ b/src/boost/libs/python/fabscript @@ -0,0 +1,82 @@ +# -*- python -*- +# +# Copyright (c) 2016 Stefan Seefeld +# All rights reserved. +# +# 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) + +from faber.feature import set +from faber.types import cxx +from faber.tools.compiler import cxxflags, define, include +from faber.tools.python import python +from faber.config import report, cxx_checks +from faber.config.try_run import try_run + +features += include('include') +features += define('BOOST_ALL_NO_LIB') # disable auto-linking +boost_include = options.get_with('boost-include') +if boost_include: + features += include(boost_include) +python = python.instance() +py_suffix = '{}{}'.format(*python.version.split('.')[:2]) +features |= set(python.include, python.linkpath, python.libs) + +class has_numpy(try_run): + + src = r""" +// If defined, enforces linking against PythonXXd.lib, which +// is usually not included in Python environments. +#undef _DEBUG +#include "Python.h" +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +#include "numpy/arrayobject.h" + +#if PY_VERSION_HEX >= 0x03000000 +void *initialize() { import_array();} +#else +void initialize() { import_array();} +#endif + +int main() +{ + int result = 0; + Py_Initialize(); + initialize(); + if (PyErr_Occurred()) + { + result = 1; + } + else + { + npy_intp dims = 2; + PyObject * a = PyArray_SimpleNew(1, &dims, NPY_INT); + if (!a) result = 1; + Py_DECREF(a); + } + Py_Finalize(); + return result; +} +""" + def __init__(self, features=()): + + inc = '' + try: + inc = python.check_python('import numpy; print(numpy.get_include())') + features |= include(inc) + except Exception: + # ignore errors, the check will fail during compilation... + pass + try_run.__init__(self, 'has_numpy', has_numpy.src, cxx, features, + if_=(include(inc), define('HAS_NUMPY'))) + +checks = [cxx_checks.has_cxx11(features, define('HAS_CXX11')), + has_numpy(features)] +config = report('config', checks) + +src = module('src', features=config.use) +test = module('test', features=config.use) +doc = module('doc', features=config.use) + +default = src.default diff --git a/src/boost/libs/python/index.html b/src/boost/libs/python/index.html new file mode 100644 index 000000000..1e1a27531 --- /dev/null +++ b/src/boost/libs/python/index.html @@ -0,0 +1,13 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> + <head> + <meta http-equiv="refresh" content="0; URL=doc/index.html"> + </head> + <body> + Automatic redirection failed, click this + <a href="doc/index.html">link</a> <hr> + <p>© Copyright Stefan Seefeld, 2015</p> + <p>Distributed under the Boost Software License, Version 1.0. (See accompanying + file <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)</p> + </body> +</html> diff --git a/src/boost/libs/python/meta/libraries.json b/src/boost/libs/python/meta/libraries.json new file mode 100644 index 000000000..e2f2a0547 --- /dev/null +++ b/src/boost/libs/python/meta/libraries.json @@ -0,0 +1,14 @@ +{ + "key": "python", + "name": "Python", + "authors": [ + "Dave Abrahams" + ], + "description": "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.", + "category": [ + "Inter-language" + ], + "maintainers": [ + "Stefan Seefeld <stefan -at- seefeld.name>" + ] +} diff --git a/src/boost/libs/python/src/converter/arg_to_python_base.cpp b/src/boost/libs/python/src/converter/arg_to_python_base.cpp new file mode 100644 index 000000000..d872314a7 --- /dev/null +++ b/src/boost/libs/python/src/converter/arg_to_python_base.cpp @@ -0,0 +1,28 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/converter/arg_to_python_base.hpp> +#include <boost/python/errors.hpp> +#include <boost/python/converter/registrations.hpp> +#include <boost/python/handle.hpp> +#include <boost/python/refcount.hpp> + +namespace boost { namespace python { namespace converter { + +namespace detail +{ + arg_to_python_base::arg_to_python_base( + void const volatile* source, registration const& converters) +# if !defined(BOOST_MSVC) || BOOST_MSVC <= 1300 || _MSC_FULL_VER > 13102179 + : handle<> +# else + : m_ptr +# endif + (converters.to_python(source)) + { + } +} + +}}} // namespace boost::python::converter diff --git a/src/boost/libs/python/src/converter/builtin_converters.cpp b/src/boost/libs/python/src/converter/builtin_converters.cpp new file mode 100644 index 000000000..ee2d5b479 --- /dev/null +++ b/src/boost/libs/python/src/converter/builtin_converters.cpp @@ -0,0 +1,592 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/handle.hpp> +#include <boost/python/type_id.hpp> +#include <boost/python/errors.hpp> +#include <boost/python/refcount.hpp> + +#include <boost/python/detail/config.hpp> +#include <boost/python/detail/wrap_python.hpp> + +#include <boost/python/converter/builtin_converters.hpp> +#include <boost/python/converter/rvalue_from_python_data.hpp> +#include <boost/python/converter/registry.hpp> +#include <boost/python/converter/registrations.hpp> +#include <boost/python/converter/shared_ptr_deleter.hpp> +#include <boost/python/converter/pytype_function.hpp> + +#include <boost/cast.hpp> +#include <string> +#include <complex> + +namespace boost { namespace python { namespace converter { + +shared_ptr_deleter::shared_ptr_deleter(handle<> owner) + : owner(owner) +{} + +shared_ptr_deleter::~shared_ptr_deleter() {} + +void shared_ptr_deleter::operator()(void const*) +{ + owner.reset(); +} + +namespace +{ + + // An lvalue conversion function which extracts a char const* from a + // Python String. +#if PY_VERSION_HEX < 0x03000000 + void* convert_to_cstring(PyObject* obj) + { + return PyString_Check(obj) ? PyString_AsString(obj) : 0; + } +#elif PY_VERSION_HEX < 0x03070000 + void* convert_to_cstring(PyObject* obj) + { + return PyUnicode_Check(obj) ? _PyUnicode_AsString(obj) : 0; + } +#else + void* convert_to_cstring(PyObject* obj) + { + return PyUnicode_Check(obj) ? const_cast<void*>(reinterpret_cast<const void*>(_PyUnicode_AsString(obj))) : 0; + } +#endif + + // Given a target type and a SlotPolicy describing how to perform a + // given conversion, registers from_python converters which use the + // SlotPolicy to extract the type. + template <class T, class SlotPolicy> + struct slot_rvalue_from_python + { + public: + slot_rvalue_from_python() + { + registry::insert( + &slot_rvalue_from_python<T,SlotPolicy>::convertible + , &slot_rvalue_from_python<T,SlotPolicy>::construct + , type_id<T>() + , &SlotPolicy::get_pytype + ); + } + + private: + static void* convertible(PyObject* obj) + { + unaryfunc* slot = SlotPolicy::get_slot(obj); + return slot && *slot ? slot : 0; + } + + static void construct(PyObject* obj, rvalue_from_python_stage1_data* data) + { + // Get the (intermediate) source object + unaryfunc creator = *static_cast<unaryfunc*>(data->convertible); + handle<> intermediate(creator(obj)); + + // Get the location in which to construct + void* storage = ((rvalue_from_python_storage<T>*)data)->storage.bytes; +# ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4244) +# endif + new (storage) T( SlotPolicy::extract(intermediate.get()) ); + +# ifdef _MSC_VER +# pragma warning(pop) +# endif + // record successful construction + data->convertible = storage; + } + }; + + // identity_unaryfunc/py_object_identity -- manufacture a unaryfunc + // "slot" which just returns its argument. + extern "C" PyObject* identity_unaryfunc(PyObject* x) + { + Py_INCREF(x); + return x; + } + unaryfunc py_object_identity = identity_unaryfunc; + +#if PY_VERSION_HEX >= 0x03000000 + // As in Python 3 there is only one integer type, we can have much + // simplified logic. + // XXX(bhy) maybe the code will work with 2.6 or even 2.5? + struct int_rvalue_from_python_base + { + static unaryfunc* get_slot(PyObject* obj) + { + return PyLong_Check(obj) ? &py_object_identity : 0; + } + static PyTypeObject const* get_pytype() {return &PyLong_Type;} + }; + + template <class T> + struct signed_int_rvalue_from_python : int_rvalue_from_python_base + { + static T extract(PyObject* intermediate) + { + long x = PyLong_AsLong(intermediate); + if (PyErr_Occurred()) + throw_error_already_set(); + return numeric_cast<T>(x); + } + }; + + template <class T> + struct unsigned_int_rvalue_from_python : int_rvalue_from_python_base + { + static T extract(PyObject* intermediate) + { + unsigned long x = PyLong_AsUnsignedLong(intermediate); + if (PyErr_Occurred()) + throw_error_already_set(); + return numeric_cast<T>(x); + } + }; +#else // PY_VERSION_HEX >= 0x03000000 + // A SlotPolicy for extracting signed integer types from Python objects + struct signed_int_rvalue_from_python_base + { + static unaryfunc* get_slot(PyObject* obj) + { + PyNumberMethods* number_methods = obj->ob_type->tp_as_number; + if (number_methods == 0) + return 0; + + return ( +#if PY_VERSION_HEX >= 0x02040000 && defined(BOOST_PYTHON_BOOL_INT_STRICT) + !PyBool_Check(obj) && +#endif + (PyInt_Check(obj) || PyLong_Check(obj))) + + ? &number_methods->nb_int : 0; + } + static PyTypeObject const* get_pytype() { return &PyInt_Type;} + }; + + template <class T> + struct signed_int_rvalue_from_python : signed_int_rvalue_from_python_base + { + static T extract(PyObject* intermediate) + { + long x = PyInt_AsLong(intermediate); + if (PyErr_Occurred()) + throw_error_already_set(); + return numeric_cast<T>(x); + } + }; + + // A SlotPolicy for extracting unsigned integer types from Python objects + struct unsigned_int_rvalue_from_python_base + { + static unaryfunc* get_slot(PyObject* obj) + { + PyNumberMethods* number_methods = obj->ob_type->tp_as_number; + if (number_methods == 0) + return 0; + + return ( +#if PY_VERSION_HEX >= 0x02040000 && defined(BOOST_PYTHON_BOOL_INT_STRICT) + !PyBool_Check(obj) && +#endif + (PyInt_Check(obj) || PyLong_Check(obj))) + ? &py_object_identity : 0; + } + static PyTypeObject const* get_pytype() { return &PyInt_Type;} + }; + + template <class T> + struct unsigned_int_rvalue_from_python : unsigned_int_rvalue_from_python_base + { + static T extract(PyObject* intermediate) + { + if (PyLong_Check(intermediate)) { + // PyLong_AsUnsignedLong() checks for negative overflow, so no + // need to check it here. + unsigned long result = PyLong_AsUnsignedLong(intermediate); + if (PyErr_Occurred()) + throw_error_already_set(); + return numeric_cast<T>(result); + } else { + // None of PyInt_AsUnsigned*() functions check for negative + // overflow, so use PyInt_AS_LONG instead and check if number is + // negative, issuing the exception appropriately. + long result = PyInt_AS_LONG(intermediate); + if (PyErr_Occurred()) + throw_error_already_set(); + if (result < 0) { + PyErr_SetString(PyExc_OverflowError, "can't convert negative" + " value to unsigned"); + throw_error_already_set(); + } + return numeric_cast<T>(result); + } + } + }; +#endif // PY_VERSION_HEX >= 0x03000000 + +// Checking Python's macro instead of Boost's - we don't seem to get +// the config right all the time. Furthermore, Python's is defined +// when long long is absent but __int64 is present. + +#ifdef HAVE_LONG_LONG + // A SlotPolicy for extracting long long types from Python objects + + struct long_long_rvalue_from_python_base + { + static unaryfunc* get_slot(PyObject* obj) + { +#if PY_VERSION_HEX >= 0x03000000 + return PyLong_Check(obj) ? &py_object_identity : 0; +#else + PyNumberMethods* number_methods = obj->ob_type->tp_as_number; + if (number_methods == 0) + return 0; + + // Return the identity conversion slot to avoid creating a + // new object. We'll handle that in the extract function + if (PyInt_Check(obj)) + return &number_methods->nb_int; + else if (PyLong_Check(obj)) + return &number_methods->nb_long; + else + return 0; +#endif + } + static PyTypeObject const* get_pytype() { return &PyLong_Type;} + }; + + struct long_long_rvalue_from_python : long_long_rvalue_from_python_base + { + static BOOST_PYTHON_LONG_LONG extract(PyObject* intermediate) + { +#if PY_VERSION_HEX < 0x03000000 + if (PyInt_Check(intermediate)) + { + return PyInt_AS_LONG(intermediate); + } + else +#endif + { + BOOST_PYTHON_LONG_LONG result = PyLong_AsLongLong(intermediate); + + if (PyErr_Occurred()) + throw_error_already_set(); + + return result; + } + } + }; + + struct unsigned_long_long_rvalue_from_python : long_long_rvalue_from_python_base + { + static unsigned BOOST_PYTHON_LONG_LONG extract(PyObject* intermediate) + { +#if PY_VERSION_HEX < 0x03000000 + if (PyInt_Check(intermediate)) + { + return numeric_cast<unsigned BOOST_PYTHON_LONG_LONG>(PyInt_AS_LONG(intermediate)); + } + else +#endif + { + unsigned BOOST_PYTHON_LONG_LONG result = PyLong_AsUnsignedLongLong(intermediate); + + if (PyErr_Occurred()) + throw_error_already_set(); + + return result; + } + } + }; +#endif + + // A SlotPolicy for extracting bool from a Python object + struct bool_rvalue_from_python + { + static unaryfunc* get_slot(PyObject* obj) + { +#if PY_VERSION_HEX >= 0x03000000 + return obj == Py_None || PyLong_Check(obj) ? &py_object_identity : 0; +#elif PY_VERSION_HEX >= 0x02040000 && defined(BOOST_PYTHON_BOOL_INT_STRICT) + return obj == Py_None || PyBool_Check(obj) ? &py_object_identity : 0; +#else + return obj == Py_None || PyInt_Check(obj) ? &py_object_identity : 0; +#endif + } + + static bool extract(PyObject* intermediate) + { + return PyObject_IsTrue(intermediate); + } + + static PyTypeObject const* get_pytype() + { +#if PY_VERSION_HEX >= 0x02030000 + return &PyBool_Type; +#else + return &PyInt_Type; +#endif + } + }; + + // A SlotPolicy for extracting floating types from Python objects. + struct float_rvalue_from_python + { + static unaryfunc* get_slot(PyObject* obj) + { + PyNumberMethods* number_methods = obj->ob_type->tp_as_number; + if (number_methods == 0) + return 0; + + // For integer types, return the tp_int conversion slot to avoid + // creating a new object. We'll handle that below +#if PY_VERSION_HEX < 0x03000000 + if (PyInt_Check(obj)) + return &number_methods->nb_int; +#endif + + return (PyLong_Check(obj) || PyFloat_Check(obj)) + ? &number_methods->nb_float : 0; + } + + static double extract(PyObject* intermediate) + { +#if PY_VERSION_HEX < 0x03000000 + if (PyInt_Check(intermediate)) + { + return PyInt_AS_LONG(intermediate); + } + else +#endif + { + return PyFloat_AS_DOUBLE(intermediate); + } + } + static PyTypeObject const* get_pytype() { return &PyFloat_Type;} + }; + +#if PY_VERSION_HEX >= 0x03000000 + unaryfunc py_unicode_as_string_unaryfunc = PyUnicode_AsUTF8String; +#endif + + // A SlotPolicy for extracting C++ strings from Python objects. + struct string_rvalue_from_python + { + // If the underlying object is "string-able" this will succeed + static unaryfunc* get_slot(PyObject* obj) + { +#if PY_VERSION_HEX >= 0x03000000 + return (PyUnicode_Check(obj)) ? &py_unicode_as_string_unaryfunc : + PyBytes_Check(obj) ? &py_object_identity : 0; +#else + return (PyString_Check(obj)) ? &obj->ob_type->tp_str : 0; + +#endif + }; + + // Remember that this will be used to construct the result object +#if PY_VERSION_HEX >= 0x03000000 + static std::string extract(PyObject* intermediate) + { + return std::string(PyBytes_AsString(intermediate),PyBytes_Size(intermediate)); + } + static PyTypeObject const* get_pytype() { return &PyUnicode_Type;} +#else + static std::string extract(PyObject* intermediate) + { + return std::string(PyString_AsString(intermediate),PyString_Size(intermediate)); + } + static PyTypeObject const* get_pytype() { return &PyString_Type;} +#endif + }; + +#if defined(Py_USING_UNICODE) && !defined(BOOST_NO_STD_WSTRING) + // encode_string_unaryfunc/py_encode_string -- manufacture a unaryfunc + // "slot" which encodes a Python string using the default encoding + extern "C" PyObject* encode_string_unaryfunc(PyObject* x) + { + return PyUnicode_FromEncodedObject( x, 0, 0 ); + } + unaryfunc py_encode_string = encode_string_unaryfunc; + + // A SlotPolicy for extracting C++ strings from Python objects. + struct wstring_rvalue_from_python + { + // If the underlying object is "string-able" this will succeed + static unaryfunc* get_slot(PyObject* obj) + { + return PyUnicode_Check(obj) + ? &py_object_identity +#if PY_VERSION_HEX >= 0x03000000 + : PyBytes_Check(obj) +#else + : PyString_Check(obj) +#endif + ? &py_encode_string + : 0; + }; + + // Remember that this will be used to construct the result object + static std::wstring extract(PyObject* intermediate) + { + // On Windows, with Python >= 3.3, PyObject_Length cannot be used to get + // the size of the wchar_t string, because it will count the number of + // *code points*, but some characters not on the BMP will use two UTF-16 + // *code units* (surrogate pairs). + // This is not a problem on Unix, since wchar_t is 32-bit. +#if defined(_WIN32) && PY_VERSION_HEX >= 0x03030000 + BOOST_STATIC_ASSERT(sizeof(wchar_t) == 2); + + Py_ssize_t size = 0; + wchar_t *buf = PyUnicode_AsWideCharString(intermediate, &size); + if (buf == NULL) { + boost::python::throw_error_already_set(); + } + std::wstring result(buf, size); + PyMem_Free(buf); +#else + std::wstring result(::PyObject_Length(intermediate), L' '); + if (!result.empty()) + { + int err = PyUnicode_AsWideChar( +#if PY_VERSION_HEX < 0x03020000 + (PyUnicodeObject *) +#endif + intermediate + , &result[0] + , result.size()); + + if (err == -1) + throw_error_already_set(); + } +#endif + return result; + } + static PyTypeObject const* get_pytype() { return &PyUnicode_Type;} + }; +#endif + + struct complex_rvalue_from_python + { + static unaryfunc* get_slot(PyObject* obj) + { + if (PyComplex_Check(obj)) + return &py_object_identity; + else + return float_rvalue_from_python::get_slot(obj); + } + + static std::complex<double> extract(PyObject* intermediate) + { + if (PyComplex_Check(intermediate)) + { + return std::complex<double>( + PyComplex_RealAsDouble(intermediate) + , PyComplex_ImagAsDouble(intermediate)); + } +#if PY_VERSION_HEX < 0x03000000 + else if (PyInt_Check(intermediate)) + { + return PyInt_AS_LONG(intermediate); + } +#endif + else + { + return PyFloat_AS_DOUBLE(intermediate); + } + } + static PyTypeObject const* get_pytype() { return &PyComplex_Type;} + }; +} + +BOOST_PYTHON_DECL PyObject* do_return_to_python(char x) +{ +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_FromStringAndSize(&x, 1); +#else + return PyString_FromStringAndSize(&x, 1); +#endif +} + +BOOST_PYTHON_DECL PyObject* do_return_to_python(char const* x) +{ +#if PY_VERSION_HEX >= 0x03000000 + return x ? PyUnicode_FromString(x) : boost::python::detail::none(); +#else + return x ? PyString_FromString(x) : boost::python::detail::none(); +#endif +} + +BOOST_PYTHON_DECL PyObject* do_return_to_python(PyObject* x) +{ + return x ? x : boost::python::detail::none(); +} + +BOOST_PYTHON_DECL PyObject* do_arg_to_python(PyObject* x) +{ + if (x == 0) + return boost::python::detail::none(); + + Py_INCREF(x); + return x; +} + +#define REGISTER_INT_CONVERTERS(signedness, U) \ + slot_rvalue_from_python< \ + signedness U \ + ,signedness##_int_rvalue_from_python<signedness U> \ + >() + +#define REGISTER_INT_CONVERTERS2(U) \ + REGISTER_INT_CONVERTERS(signed, U); \ + REGISTER_INT_CONVERTERS(unsigned, U) + +void initialize_builtin_converters() +{ + // booleans + slot_rvalue_from_python<bool,bool_rvalue_from_python>(); + + // integer types + REGISTER_INT_CONVERTERS2(char); + REGISTER_INT_CONVERTERS2(short); + REGISTER_INT_CONVERTERS2(int); + REGISTER_INT_CONVERTERS2(long); + +// using Python's macro instead of Boost's - we don't seem to get the +// config right all the time. +# ifdef HAVE_LONG_LONG + slot_rvalue_from_python<signed BOOST_PYTHON_LONG_LONG,long_long_rvalue_from_python>(); + slot_rvalue_from_python<unsigned BOOST_PYTHON_LONG_LONG,unsigned_long_long_rvalue_from_python>(); +# endif + + // floating types + slot_rvalue_from_python<float,float_rvalue_from_python>(); + slot_rvalue_from_python<double,float_rvalue_from_python>(); + slot_rvalue_from_python<long double,float_rvalue_from_python>(); + + slot_rvalue_from_python<std::complex<float>,complex_rvalue_from_python>(); + slot_rvalue_from_python<std::complex<double>,complex_rvalue_from_python>(); + slot_rvalue_from_python<std::complex<long double>,complex_rvalue_from_python>(); + + // Add an lvalue converter for char which gets us char const* +#if PY_VERSION_HEX < 0x03000000 + registry::insert(convert_to_cstring,type_id<char>(),&converter::wrap_pytype<&PyString_Type>::get_pytype); +#else + registry::insert(convert_to_cstring,type_id<char>(),&converter::wrap_pytype<&PyUnicode_Type>::get_pytype); +#endif + + // Register by-value converters to std::string, std::wstring +#if defined(Py_USING_UNICODE) && !defined(BOOST_NO_STD_WSTRING) + slot_rvalue_from_python<std::wstring, wstring_rvalue_from_python>(); +# endif + slot_rvalue_from_python<std::string, string_rvalue_from_python>(); + +} + +}}} // namespace boost::python::converter diff --git a/src/boost/libs/python/src/converter/from_python.cpp b/src/boost/libs/python/src/converter/from_python.cpp new file mode 100644 index 000000000..9678be1cb --- /dev/null +++ b/src/boost/libs/python/src/converter/from_python.cpp @@ -0,0 +1,303 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/converter/from_python.hpp> +#include <boost/python/converter/registrations.hpp> +#include <boost/python/converter/rvalue_from_python_data.hpp> + +#include <boost/python/object/find_instance.hpp> + +#include <boost/python/handle.hpp> +#include <boost/python/detail/raw_pyobject.hpp> +#include <boost/python/cast.hpp> + +#include <vector> +#include <algorithm> + +namespace boost { namespace python { namespace converter { + +// rvalue_from_python_stage1 -- do the first stage of a conversion +// from a Python object to a C++ rvalue. +// +// source - the Python object to be converted +// converters - the registry entry for the target type T +// +// Postcondition: where x is the result, one of: +// +// 1. x.convertible == 0, indicating failure +// +// 2. x.construct == 0, x.convertible is the address of an object of +// type T. Indicates a successful lvalue conversion +// +// 3. where y is of type rvalue_from_python_data<T>, +// x.construct(source, y) constructs an object of type T +// in y.storage.bytes and then sets y.convertible == y.storage.bytes, +// or else throws an exception and has no effect. +BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1( + PyObject* source + , registration const& converters) +{ + rvalue_from_python_stage1_data data; + + // First check to see if it's embedded in an extension class + // instance, as a special case. + data.convertible = objects::find_instance_impl(source, converters.target_type, converters.is_shared_ptr); + data.construct = 0; + if (!data.convertible) + { + for (rvalue_from_python_chain const* chain = converters.rvalue_chain; + chain != 0; + chain = chain->next) + { + void* r = chain->convertible(source); + if (r != 0) + { + data.convertible = r; + data.construct = chain->construct; + break; + } + } + } + return data; +} + +// rvalue_result_from_python -- return the address of a C++ object which +// can be used as the result of calling a Python function. +// +// src - the Python object to be converted +// +// data - a reference to the base part of a +// rvalue_from_python_data<T> object, where T is the +// target type of the conversion. +// +// Requires: data.convertible == ®istered<T>::converters +// +BOOST_PYTHON_DECL void* rvalue_result_from_python( + PyObject* src, rvalue_from_python_stage1_data& data) +{ + // Retrieve the registration + // Cast in two steps for less-capable compilers + void const* converters_ = data.convertible; + registration const& converters = *static_cast<registration const*>(converters_); + + // Look for an eligible converter + data = rvalue_from_python_stage1(src, converters); + return rvalue_from_python_stage2(src, data, converters); +} + +BOOST_PYTHON_DECL void* rvalue_from_python_stage2( + PyObject* source, rvalue_from_python_stage1_data& data, registration const& converters) +{ + if (!data.convertible) + { + handle<> msg( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromFormat +#else + ::PyString_FromFormat +#endif + ( + "No registered converter was able to produce a C++ rvalue of type %s from this Python object of type %s" + , converters.target_type.name() + , source->ob_type->tp_name + )); + + PyErr_SetObject(PyExc_TypeError, msg.get()); + throw_error_already_set(); + } + + // If a construct function was registered (i.e. we found an + // rvalue conversion), call it now. + if (data.construct != 0) + data.construct(source, &data); + + // Return the address of the resulting C++ object + return data.convertible; +} + +BOOST_PYTHON_DECL void* get_lvalue_from_python( + PyObject* source + , registration const& converters) +{ + // Check to see if it's embedded in a class instance + void* x = objects::find_instance_impl(source, converters.target_type); + if (x) + return x; + + lvalue_from_python_chain const* chain = converters.lvalue_chain; + for (;chain != 0; chain = chain->next) + { + void* r = chain->convert(source); + if (r != 0) + return r; + } + return 0; +} + +namespace +{ + // Prevent looping in implicit conversions. This could/should be + // much more efficient, but will work for now. + typedef std::vector<rvalue_from_python_chain const*> visited_t; + static visited_t visited; + + inline bool visit(rvalue_from_python_chain const* chain) + { + visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain); + if (p != visited.end() && *p == chain) + return false; + visited.insert(p, chain); + return true; + } + + // RAII class for managing global visited marks. + struct unvisit + { + unvisit(rvalue_from_python_chain const* chain) + : chain(chain) {} + + ~unvisit() + { + visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain); + assert(p != visited.end()); + visited.erase(p); + } + private: + rvalue_from_python_chain const* chain; + }; +} + + +BOOST_PYTHON_DECL bool implicit_rvalue_convertible_from_python( + PyObject* source + , registration const& converters) +{ + if (objects::find_instance_impl(source, converters.target_type)) + return true; + + rvalue_from_python_chain const* chain = converters.rvalue_chain; + + if (!visit(chain)) + return false; + + unvisit protect(chain); + + for (;chain != 0; chain = chain->next) + { + if (chain->convertible(source)) + return true; + } + + return false; +} + +namespace +{ + void throw_no_lvalue_from_python(PyObject* source, registration const& converters, char const* ref_type) + { + handle<> msg( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromFormat +#else + ::PyString_FromFormat +#endif + ( + "No registered converter was able to extract a C++ %s to type %s" + " from this Python object of type %s" + , ref_type + , converters.target_type.name() + , source->ob_type->tp_name + )); + + PyErr_SetObject(PyExc_TypeError, msg.get()); + + throw_error_already_set(); + } + + void* lvalue_result_from_python( + PyObject* source + , registration const& converters + , char const* ref_type) + { + handle<> holder(source); + if (source->ob_refcnt <= 1) + { + handle<> msg( +#if PY_VERSION_HEX >= 0x3000000 + ::PyUnicode_FromFormat +#else + ::PyString_FromFormat +#endif + ( + "Attempt to return dangling %s to object of type: %s" + , ref_type + , converters.target_type.name())); + + PyErr_SetObject(PyExc_ReferenceError, msg.get()); + + throw_error_already_set(); + } + + void* result = get_lvalue_from_python(source, converters); + if (!result) + (throw_no_lvalue_from_python)(source, converters, ref_type); + return result; + } + +} + +BOOST_PYTHON_DECL void throw_no_pointer_from_python(PyObject* source, registration const& converters) +{ + (throw_no_lvalue_from_python)(source, converters, "pointer"); +} + +BOOST_PYTHON_DECL void throw_no_reference_from_python(PyObject* source, registration const& converters) +{ + (throw_no_lvalue_from_python)(source, converters, "reference"); +} + +BOOST_PYTHON_DECL void* reference_result_from_python( + PyObject* source + , registration const& converters) +{ + return (lvalue_result_from_python)(source, converters, "reference"); +} + +BOOST_PYTHON_DECL void* pointer_result_from_python( + PyObject* source + , registration const& converters) +{ + if (source == Py_None) + { + Py_DECREF(source); + return 0; + } + return (lvalue_result_from_python)(source, converters, "pointer"); +} + +BOOST_PYTHON_DECL void void_result_from_python(PyObject* o) +{ + Py_DECREF(expect_non_null(o)); +} + +} // namespace boost::python::converter + +BOOST_PYTHON_DECL PyObject* +pytype_check(PyTypeObject* type_, PyObject* source) +{ + if (!PyObject_IsInstance(source, python::upcast<PyObject>(type_))) + { + ::PyErr_Format( + PyExc_TypeError + , "Expecting an object of type %s; got an object of type %s instead" + , type_->tp_name + , source->ob_type->tp_name + ); + throw_error_already_set(); + } + return source; +} + +}} // namespace boost::python diff --git a/src/boost/libs/python/src/converter/registry.cpp b/src/boost/libs/python/src/converter/registry.cpp new file mode 100644 index 000000000..aa20c3f68 --- /dev/null +++ b/src/boost/libs/python/src/converter/registry.cpp @@ -0,0 +1,306 @@ +// Copyright David Abrahams 2001. +// 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 <boost/python/converter/registry.hpp> +#include <boost/python/converter/registrations.hpp> +#include <boost/python/converter/builtin_converters.hpp> + +#include <set> +#include <stdexcept> + +#if defined(__APPLE__) && defined(__MACH__) && defined(__GNUC__) \ + && __GNUC__ == 3 && __GNUC_MINOR__ <= 4 && !defined(__APPLE_CC__) +# define BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND +#endif + +#if defined(BOOST_PYTHON_TRACE_REGISTRY) \ + || defined(BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND) +# include <iostream> +#endif + +namespace boost { namespace python { namespace converter { +BOOST_PYTHON_DECL PyTypeObject const* registration::expected_from_python_type() const +{ + if (this->m_class_object != 0) + return this->m_class_object; + + std::set<PyTypeObject const*> pool; + + for(rvalue_from_python_chain* r = rvalue_chain; r ; r=r->next) + if(r->expected_pytype) + pool.insert(r->expected_pytype()); + + //for now I skip the search for common base + if (pool.size()==1) + return *pool.begin(); + + return 0; + +} + +BOOST_PYTHON_DECL PyTypeObject const* registration::to_python_target_type() const +{ + if (this->m_class_object != 0) + return this->m_class_object; + + if (this->m_to_python_target_type != 0) + return this->m_to_python_target_type(); + + return 0; +} + +BOOST_PYTHON_DECL PyTypeObject* registration::get_class_object() const +{ + if (this->m_class_object == 0) + { + ::PyErr_Format( + PyExc_TypeError + , const_cast<char*>("No Python class registered for C++ class %s") + , this->target_type.name()); + + throw_error_already_set(); + } + + return this->m_class_object; +} + +BOOST_PYTHON_DECL PyObject* registration::to_python(void const volatile* source) const +{ + if (this->m_to_python == 0) + { + handle<> msg( +#if PY_VERSION_HEX >= 0x3000000 + ::PyUnicode_FromFormat +#else + ::PyString_FromFormat +#endif + ( + "No to_python (by-value) converter found for C++ type: %s" + , this->target_type.name() + ) + ); + + PyErr_SetObject(PyExc_TypeError, msg.get()); + + throw_error_already_set(); + } + + return source == 0 + ? incref(Py_None) + : this->m_to_python(const_cast<void*>(source)); +} + +namespace +{ + template< typename T > + void delete_node( T* node ) + { + if( !!node && !!node->next ) + delete_node( node->next ); + delete node; + } +} + +registration::~registration() +{ + delete_node(lvalue_chain); + delete_node(rvalue_chain); +} + + +namespace // <unnamed> +{ + typedef registration entry; + + typedef std::set<entry> registry_t; + +#ifndef BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND + registry_t& entries() + { + static registry_t registry; + +# ifndef BOOST_PYTHON_SUPPRESS_REGISTRY_INITIALIZATION + static bool builtin_converters_initialized = false; + if (!builtin_converters_initialized) + { + // Make this true early because registering the builtin + // converters will cause recursion. + builtin_converters_initialized = true; + + initialize_builtin_converters(); + } +# ifdef BOOST_PYTHON_TRACE_REGISTRY + std::cout << "registry: "; + for (registry_t::iterator p = registry.begin(); p != registry.end(); ++p) + { + std::cout << p->target_type << "; "; + } + std::cout << '\n'; +# endif +# endif + return registry; + } +#else + registry_t& static_registry() + { + static registry_t result; + return result; + } + + bool static_builtin_converters_initialized() + { + static bool result = false; + if (result == false) { + result = true; + std::cout << std::flush; + return false; + } + return true; + } + + registry_t& entries() + { +# ifndef BOOST_PYTHON_SUPPRESS_REGISTRY_INITIALIZATION + if (!static_builtin_converters_initialized()) + { + initialize_builtin_converters(); + } +# ifdef BOOST_PYTHON_TRACE_REGISTRY + std::cout << "registry: "; + for (registry_t::iterator p = static_registry().begin(); p != static_registry().end(); ++p) + { + std::cout << p->target_type << "; "; + } + std::cout << '\n'; +# endif +# endif + return static_registry(); + } +#endif // BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND + + entry* get(type_info type, bool is_shared_ptr = false) + { +# ifdef BOOST_PYTHON_TRACE_REGISTRY + registry_t::iterator p = entries().find(entry(type)); + + std::cout << "looking up " << type << ": " + << (p == entries().end() || p->target_type != type + ? "...NOT found\n" : "...found\n"); +# endif + std::pair<registry_t::const_iterator,bool> pos_ins + = entries().insert(entry(type,is_shared_ptr)); + +# if __MWERKS__ >= 0x3000 + // do a little invariant checking if a change was made + if ( pos_ins.second ) + assert(entries().invariants()); +# endif + return const_cast<entry*>(&*pos_ins.first); + } +} // namespace <unnamed> + +namespace registry +{ + void insert(to_python_function_t f, type_info source_t, PyTypeObject const* (*to_python_target_type)()) + { +# ifdef BOOST_PYTHON_TRACE_REGISTRY + std::cout << "inserting to_python " << source_t << "\n"; +# endif + entry* slot = get(source_t); + + assert(slot->m_to_python == 0); // we have a problem otherwise + if (slot->m_to_python != 0) + { + std::string msg = ( + std::string("to-Python converter for ") + + source_t.name() + + " already registered; second conversion method ignored." + ); + + if ( ::PyErr_Warn( NULL, const_cast<char*>(msg.c_str()) ) ) + { + throw_error_already_set(); + } + } + slot->m_to_python = f; + slot->m_to_python_target_type = to_python_target_type; + } + + // Insert an lvalue from_python converter + void insert(convertible_function convert, type_info key, PyTypeObject const* (*exp_pytype)()) + { +# ifdef BOOST_PYTHON_TRACE_REGISTRY + std::cout << "inserting lvalue from_python " << key << "\n"; +# endif + entry* found = get(key); + lvalue_from_python_chain *registration = new lvalue_from_python_chain; + registration->convert = convert; + registration->next = found->lvalue_chain; + found->lvalue_chain = registration; + + insert(convert, 0, key,exp_pytype); + } + + // Insert an rvalue from_python converter + void insert(convertible_function convertible + , constructor_function construct + , type_info key + , PyTypeObject const* (*exp_pytype)()) + { +# ifdef BOOST_PYTHON_TRACE_REGISTRY + std::cout << "inserting rvalue from_python " << key << "\n"; +# endif + entry* found = get(key); + rvalue_from_python_chain *registration = new rvalue_from_python_chain; + registration->convertible = convertible; + registration->construct = construct; + registration->expected_pytype = exp_pytype; + registration->next = found->rvalue_chain; + found->rvalue_chain = registration; + } + + // Insert an rvalue from_python converter + void push_back(convertible_function convertible + , constructor_function construct + , type_info key + , PyTypeObject const* (*exp_pytype)()) + { +# ifdef BOOST_PYTHON_TRACE_REGISTRY + std::cout << "push_back rvalue from_python " << key << "\n"; +# endif + rvalue_from_python_chain** found = &get(key)->rvalue_chain; + while (*found != 0) + found = &(*found)->next; + + rvalue_from_python_chain *registration = new rvalue_from_python_chain; + registration->convertible = convertible; + registration->construct = construct; + registration->expected_pytype = exp_pytype; + registration->next = 0; + *found = registration; + } + + registration const& lookup(type_info key) + { + return *get(key); + } + + registration const& lookup_shared_ptr(type_info key) + { + return *get(key, true); + } + + registration const* query(type_info type) + { + registry_t::iterator p = entries().find(entry(type)); +# ifdef BOOST_PYTHON_TRACE_REGISTRY + std::cout << "querying " << type + << (p == entries().end() || p->target_type != type + ? "...NOT found\n" : "...found\n"); +# endif + return (p == entries().end() || p->target_type != type) ? 0 : &*p; + } +} // namespace registry + +}}} // namespace boost::python::converter diff --git a/src/boost/libs/python/src/converter/type_id.cpp b/src/boost/libs/python/src/converter/type_id.cpp new file mode 100644 index 000000000..c6a8bf7a0 --- /dev/null +++ b/src/boost/libs/python/src/converter/type_id.cpp @@ -0,0 +1,212 @@ +// Copyright David Abrahams 2001. +// 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 <boost/python/type_id.hpp> +#include <boost/python/detail/decorated_type_id.hpp> +#include <utility> +#include <vector> +#include <algorithm> +#include <memory> +#include <cstdlib> +#include <cstring> + +#if defined(__QNXNTO__) +# include <ostream> +#else /* defined(__QNXNTO__) */ + +#if !defined(__GNUC__) || __GNUC__ >= 3 || __SGI_STL_PORT || __EDG_VERSION__ +# include <ostream> +#else +# include <ostream.h> +#endif + +# ifdef BOOST_PYTHON_HAVE_GCC_CP_DEMANGLE +# if defined(__GNUC__) && __GNUC__ >= 3 + +// http://lists.debian.org/debian-gcc/2003/09/msg00055.html notes +// that, in cxxabi.h of gcc-3.x for x < 4, this type is used before it +// is declared. +# if __GNUC__ == 3 && __GNUC_MINOR__ < 4 +class __class_type_info; +# endif + +# include <cxxabi.h> +# endif +# endif +#endif /* defined(__QNXNTO__) */ + +namespace boost { namespace python { + +# ifdef BOOST_PYTHON_HAVE_GCC_CP_DEMANGLE + +# if defined(__QNXNTO__) +namespace cxxabi { +extern "C" char* __cxa_demangle(char const*, char*, std::size_t*, int*); +} +# else /* defined(__QNXNTO__) */ + +# ifdef __GNUC__ +# if __GNUC__ < 3 + +namespace cxxabi = :: ; +extern "C" char* __cxa_demangle(char const*, char*, std::size_t*, int*); +# else + +namespace cxxabi = ::abi; // GCC 3.1 and later + +# if __GNUC__ == 3 && __GNUC_MINOR__ == 0 +namespace abi +{ + extern "C" char* __cxa_demangle(char const*, char*, std::size_t*, int*); +} +# endif /* __GNUC__ == 3 && __GNUC_MINOR__ == 0 */ +# endif /* __GNUC__ < 3 */ +# endif /* __GNUC__ */ +# endif /* defined(__QNXNTO__) */ + +namespace +{ + struct compare_first_cstring + { + template <class T> + bool operator()(T const& x, T const& y) + { + return std::strcmp(x.first,y.first) < 0; + } + }; + + struct free_mem + { + free_mem(char*p) + : p(p) {} + + ~free_mem() + { + std::free(p); + } + char* p; + }; +} + +bool cxxabi_cxa_demangle_is_broken() +{ + static bool was_tested = false; + static bool is_broken = false; + if (!was_tested) { + int status; + free_mem keeper(cxxabi::__cxa_demangle("b", 0, 0, &status)); + was_tested = true; + if (status == -2 || strcmp(keeper.p, "bool") != 0) { + is_broken = true; + } + } + return is_broken; +} + +namespace detail +{ + BOOST_PYTHON_DECL char const* gcc_demangle(char const* mangled) + { + typedef std::vector< + std::pair<char const*, char const*> + > mangling_map; + + static mangling_map demangler; + mangling_map::iterator p + = std::lower_bound( + demangler.begin(), demangler.end() + , std::make_pair(mangled, (char const*)0) + , compare_first_cstring()); + + if (p == demangler.end() || strcmp(p->first, mangled)) + { + int status; + free_mem keeper( + cxxabi::__cxa_demangle(mangled, 0, 0, &status) + ); + + assert(status != -3); // invalid argument error + + if (status == -1) + { + throw std::bad_alloc(); + } + else + { + char const* demangled + = status == -2 + // Invalid mangled name. Best we can do is to + // return it intact. + ? mangled + : keeper.p; + + // Ult Mundane, 2005 Aug 17 + // Contributed 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) + // The __cxa_demangle function is supposed to translate + // builtin types from their one-character mangled names, + // but it doesn't in gcc 3.3.5 and gcc 3.4.x. + if (cxxabi_cxa_demangle_is_broken() + && status == -2 && strlen(mangled) == 1) + { + // list from + // http://www.codesourcery.com/cxx-abi/abi.html + switch (mangled[0]) + { + case 'v': demangled = "void"; break; + case 'w': demangled = "wchar_t"; break; + case 'b': demangled = "bool"; break; + case 'c': demangled = "char"; break; + case 'a': demangled = "signed char"; break; + case 'h': demangled = "unsigned char"; break; + case 's': demangled = "short"; break; + case 't': demangled = "unsigned short"; break; + case 'i': demangled = "int"; break; + case 'j': demangled = "unsigned int"; break; + case 'l': demangled = "long"; break; + case 'm': demangled = "unsigned long"; break; + case 'x': demangled = "long long"; break; + case 'y': demangled = "unsigned long long"; break; + case 'n': demangled = "__int128"; break; + case 'o': demangled = "unsigned __int128"; break; + case 'f': demangled = "float"; break; + case 'd': demangled = "double"; break; + case 'e': demangled = "long double"; break; + case 'g': demangled = "__float128"; break; + case 'z': demangled = "..."; break; + } + } + + p = demangler.insert(p, std::make_pair(mangled, demangled)); + keeper.p = 0; + } + } + + return p->second; + } +} +# endif + +BOOST_PYTHON_DECL std::ostream& operator<<(std::ostream& os, type_info const& x) +{ + return os << x.name(); +} + +namespace detail +{ + BOOST_PYTHON_DECL std::ostream& operator<<(std::ostream& os, detail::decorated_type_info const& x) + { + os << x.m_base_type; + if (x.m_decoration & decorated_type_info::const_) + os << " const"; + if (x.m_decoration & decorated_type_info::volatile_) + os << " volatile"; + if (x.m_decoration & decorated_type_info::reference) + os << "&"; + return os; + } +} +}} // namespace boost::python::converter diff --git a/src/boost/libs/python/src/dict.cpp b/src/boost/libs/python/src/dict.cpp new file mode 100644 index 000000000..77d840d45 --- /dev/null +++ b/src/boost/libs/python/src/dict.cpp @@ -0,0 +1,184 @@ +// Copyright David Abrahams 2004. 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 <boost/python/dict.hpp> +#include <boost/python/extract.hpp> + +namespace boost { namespace python { namespace detail { +namespace +{ + // When returning list objects from methods, it may turn out that the + // derived class is returning something else, perhaps something not + // even derived from list. Since it is generally harmless for a + // Boost.Python wrapper object to hold an object of a different + // type, and because calling list() with an object may in fact + // perform a conversion, the least-bad alternative is to assume that + // we have a Python list object and stuff it into the list result. + list assume_list(object const& o) + { + return list(detail::borrowed_reference(o.ptr())); + } + + // No PyDict_CheckExact; roll our own. + inline bool check_exact(dict_base const* p) + { + return p->ptr()->ob_type == &PyDict_Type; + } +} + +detail::new_reference dict_base::call(object const& arg_) +{ + return (detail::new_reference)PyObject_CallFunction( + (PyObject*)&PyDict_Type, const_cast<char*>("(O)"), + arg_.ptr()); +} + +dict_base::dict_base() + : object(detail::new_reference(PyDict_New())) +{} + +dict_base::dict_base(object_cref data) + : object(call(data)) +{} + +void dict_base::clear() +{ + if (check_exact(this)) + PyDict_Clear(this->ptr()); + else + this->attr("clear")(); +} + +dict dict_base::copy() +{ + if (check_exact(this)) + { + return dict(detail::new_reference( + PyDict_Copy(this->ptr()))); + } + else + { + return dict(detail::borrowed_reference( + this->attr("copy")().ptr() + )); + } +} + +object dict_base::get(object_cref k) const +{ + if (check_exact(this)) + { + PyObject* result = PyDict_GetItem(this->ptr(),k.ptr()); + return object(detail::borrowed_reference(result ? result : Py_None)); + } + else + { + return this->attr("get")(k); + } +} + +object dict_base::get(object_cref k, object_cref d) const +{ + return this->attr("get")(k,d); +} + +bool dict_base::has_key(object_cref k) const +{ + return extract<bool>(this->contains(k)); +} + +list dict_base::items() const +{ + if (check_exact(this)) + { + return list(detail::new_reference( + PyDict_Items(this->ptr()))); + } + else + { + return assume_list(this->attr("items")()); + } +} + +object dict_base::iteritems() const +{ + return this->attr("iteritems")(); +} + +object dict_base::iterkeys() const +{ + return this->attr("iterkeys")(); +} + +object dict_base::itervalues() const +{ + return this->attr("itervalues")(); +} + +list dict_base::keys() const +{ + if (check_exact(this)) + { + return list(detail::new_reference( + PyDict_Keys(this->ptr()))); + } + else + { + return assume_list(this->attr("keys")()); + } +} + +tuple dict_base::popitem() +{ + return tuple(detail::borrowed_reference( + this->attr("popitem")().ptr() + )); +} + +object dict_base::setdefault(object_cref k) +{ + return this->attr("setdefault")(k); +} + +object dict_base::setdefault(object_cref k, object_cref d) +{ + return this->attr("setdefault")(k,d); +} + +void dict_base::update(object_cref other) +{ + if (check_exact(this)) + { + if (PyDict_Update(this->ptr(),other.ptr()) == -1) + throw_error_already_set(); + } + else + { + this->attr("update")(other); + } +} + +list dict_base::values() const +{ + if (check_exact(this)) + { + return list(detail::new_reference( + PyDict_Values(this->ptr()))); + } + else + { + return assume_list(this->attr("values")()); + } +} + +static struct register_dict_pytype_ptr +{ + register_dict_pytype_ptr() + { + const_cast<converter::registration &>( + converter::registry::lookup(boost::python::type_id<boost::python::dict>()) + ).m_class_object = &PyDict_Type; + } +}register_dict_pytype_ptr_; + +}}} // namespace boost::python diff --git a/src/boost/libs/python/src/errors.cpp b/src/boost/libs/python/src/errors.cpp new file mode 100644 index 000000000..34ea22f43 --- /dev/null +++ b/src/boost/libs/python/src/errors.cpp @@ -0,0 +1,105 @@ +// Copyright David Abrahams 2001. +// 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) + +#ifndef BOOST_PYTHON_SOURCE +# define BOOST_PYTHON_SOURCE +#endif + +#include <boost/python/errors.hpp> +#include <boost/cast.hpp> +#include <boost/python/detail/exception_handler.hpp> + +namespace boost { namespace python { + +error_already_set::~error_already_set() {} + +// IMPORTANT: this function may only be called from within a catch block! +BOOST_PYTHON_DECL bool handle_exception_impl(function0<void> f) +{ + try + { + if (detail::exception_handler::chain) + return detail::exception_handler::chain->handle(f); + f(); + return false; + } + catch(const boost::python::error_already_set&) + { + // The python error reporting has already been handled. + } + catch(const std::bad_alloc&) + { + PyErr_NoMemory(); + } + catch(const bad_numeric_cast& x) + { + PyErr_SetString(PyExc_OverflowError, x.what()); + } + catch(const std::out_of_range& x) + { + PyErr_SetString(PyExc_IndexError, x.what()); + } + catch(const std::invalid_argument& x) + { + PyErr_SetString(PyExc_ValueError, x.what()); + } + catch(const std::exception& x) + { + PyErr_SetString(PyExc_RuntimeError, x.what()); + } + catch(...) + { + PyErr_SetString(PyExc_RuntimeError, "unidentifiable C++ exception"); + } + return true; +} + +void BOOST_PYTHON_DECL throw_error_already_set() +{ + throw error_already_set(); +} + +namespace detail { + +bool exception_handler::operator()(function0<void> const& f) const +{ + if (m_next) + { + return m_next->handle(f); + } + else + { + f(); + return false; + } +} + +exception_handler::exception_handler(handler_function const& impl) + : m_impl(impl) + , m_next(0) +{ + if (chain != 0) + tail->m_next = this; + else + chain = this; + tail = this; +} + +exception_handler* exception_handler::chain; +exception_handler* exception_handler::tail; + +BOOST_PYTHON_DECL void register_exception_handler(handler_function const& f) +{ + // the constructor links the new object into a handler chain, so + // this object isn't actaully leaked (until, of course, the + // interpreter exits). + new exception_handler(f); +} + +} // namespace boost::python::detail + +}} // namespace boost::python + + diff --git a/src/boost/libs/python/src/exec.cpp b/src/boost/libs/python/src/exec.cpp new file mode 100644 index 000000000..171c6f418 --- /dev/null +++ b/src/boost/libs/python/src/exec.cpp @@ -0,0 +1,129 @@ +// Copyright Stefan Seefeld 2005. +// 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 <boost/python/exec.hpp> +#include <boost/python/borrowed.hpp> +#include <boost/python/dict.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/handle.hpp> + +namespace boost +{ +namespace python +{ + +object BOOST_PYTHON_DECL eval(str string, object global, object local) +{ + return eval(python::extract<char const *>(string), global, local); +} + +object BOOST_PYTHON_DECL eval(char const *string, object global, object local) +{ + // Set suitable default values for global and local dicts. + if (global.is_none()) + { + if (PyObject *g = PyEval_GetGlobals()) + global = object(detail::borrowed_reference(g)); + else + global = dict(); + } + if (local.is_none()) local = global; + // should be 'char const *' but older python versions don't use 'const' yet. + char *s = const_cast<char *>(string); + PyObject* result = PyRun_String(s, Py_eval_input, global.ptr(), local.ptr()); + if (!result) throw_error_already_set(); + return object(detail::new_reference(result)); +} + +object BOOST_PYTHON_DECL exec(str string, object global, object local) +{ + return exec(python::extract<char const *>(string), global, local); +} + +object BOOST_PYTHON_DECL exec(char const *string, object global, object local) +{ + // Set suitable default values for global and local dicts. + if (global.is_none()) + { + if (PyObject *g = PyEval_GetGlobals()) + global = object(detail::borrowed_reference(g)); + else + global = dict(); + } + if (local.is_none()) local = global; + // should be 'char const *' but older python versions don't use 'const' yet. + char *s = const_cast<char *>(string); + PyObject* result = PyRun_String(s, Py_file_input, global.ptr(), local.ptr()); + if (!result) throw_error_already_set(); + return object(detail::new_reference(result)); +} + +object BOOST_PYTHON_DECL exec_statement(str string, object global, object local) +{ + return exec_statement(python::extract<char const *>(string), global, local); +} + +object BOOST_PYTHON_DECL exec_statement(char const *string, object global, object local) +{ + // Set suitable default values for global and local dicts. + if (global.is_none()) + { + if (PyObject *g = PyEval_GetGlobals()) + global = object(detail::borrowed_reference(g)); + else + global = dict(); + } + if (local.is_none()) local = global; + // should be 'char const *' but older python versions don't use 'const' yet. + char *s = const_cast<char *>(string); + PyObject* result = PyRun_String(s, Py_single_input, global.ptr(), local.ptr()); + if (!result) throw_error_already_set(); + return object(detail::new_reference(result)); +} + +// Execute python source code from file filename. +// global and local are the global and local scopes respectively, +// used during execution. +object BOOST_PYTHON_DECL exec_file(str filename, object global, object local) +{ + return exec_file(python::extract<char const *>(filename), global, local); +} + +object BOOST_PYTHON_DECL exec_file(char const *filename, object global, object local) +{ + // Set suitable default values for global and local dicts. + if (global.is_none()) + { + if (PyObject *g = PyEval_GetGlobals()) + global = object(detail::borrowed_reference(g)); + else + global = dict(); + } + if (local.is_none()) local = global; + // should be 'char const *' but older python versions don't use 'const' yet. + char *f = const_cast<char *>(filename); + // Let python open the file to avoid potential binary incompatibilities. +#if PY_VERSION_HEX >= 0x03040000 + FILE *fs = _Py_fopen(f, "r"); +#elif PY_VERSION_HEX >= 0x03000000 + PyObject *fo = Py_BuildValue("s", f); + FILE *fs = _Py_fopen(fo, "r"); + Py_DECREF(fo); +#else + PyObject *pyfile = PyFile_FromString(f, const_cast<char*>("r")); + if (!pyfile) throw std::invalid_argument(std::string(f) + " : no such file"); + python::handle<> file(pyfile); + FILE *fs = PyFile_AsFile(file.get()); +#endif + PyObject* result = PyRun_File(fs, + f, + Py_file_input, + global.ptr(), local.ptr()); + if (!result) throw_error_already_set(); + return object(detail::new_reference(result)); +} + +} // namespace boost::python +} // namespace boost diff --git a/src/boost/libs/python/src/fabscript b/src/boost/libs/python/src/fabscript new file mode 100644 index 000000000..0ebeac609 --- /dev/null +++ b/src/boost/libs/python/src/fabscript @@ -0,0 +1,58 @@ +# -*- python -*- +# +# Copyright (c) 2016 Stefan Seefeld +# All rights reserved. +# +# 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) + +from faber.feature import set +from faber.artefacts.library import library +from faber.tools.compiler import define + +root = module('..') + +bpl = library('boost_python' + root.py_suffix, + ['list.cpp', + 'long.cpp', + 'dict.cpp', + 'tuple.cpp', + 'str.cpp', + 'slice.cpp', + 'converter/from_python.cpp', + 'converter/registry.cpp', + 'converter/type_id.cpp', + 'object/enum.cpp', + 'object/class.cpp', + 'object/function.cpp', + 'object/inheritance.cpp', + 'object/life_support.cpp', + 'object/pickle_support.cpp', + 'errors.cpp', + 'module.cpp', + 'converter/builtin_converters.cpp', + 'converter/arg_to_python_base.cpp', + 'object/iterator.cpp', + 'object/stl_iterator.cpp', + 'object_protocol.cpp', + 'object_operators.cpp', + 'wrapper.cpp', + 'import.cpp', + 'exec.cpp', + 'object/function_doc_signature.cpp'], + dependencies=root.config, + features=features + define('BOOST_PYTHON_SOURCE')) + +bnl = library('boost_numpy' + root.py_suffix, + ['numpy/dtype.cpp', + 'numpy/matrix.cpp', + 'numpy/ndarray.cpp', + 'numpy/numpy.cpp', + 'numpy/scalars.cpp', + 'numpy/ufunc.cpp', + bpl], + dependencies=root.config, + features=features + define('BOOST_NUMPY_SOURCE'), + condition=set.define.contains('HAS_NUMPY')) +default = [bpl, bnl] diff --git a/src/boost/libs/python/src/import.cpp b/src/boost/libs/python/src/import.cpp new file mode 100644 index 000000000..0add79eea --- /dev/null +++ b/src/boost/libs/python/src/import.cpp @@ -0,0 +1,25 @@ +// Copyright Stefan Seefeld 2005. +// 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 <boost/python/import.hpp> +#include <boost/python/borrowed.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/handle.hpp> + +namespace boost +{ +namespace python +{ + +object BOOST_PYTHON_DECL import(str name) +{ + // should be 'char const *' but older python versions don't use 'const' yet. + char *n = python::extract<char *>(name); + python::handle<> module(PyImport_ImportModule(n)); + return python::object(module); +} + +} // namespace boost::python +} // namespace boost diff --git a/src/boost/libs/python/src/list.cpp b/src/boost/libs/python/src/list.cpp new file mode 100644 index 000000000..77e616881 --- /dev/null +++ b/src/boost/libs/python/src/list.cpp @@ -0,0 +1,170 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/list.hpp> +#include <boost/python/ssize_t.hpp> + +namespace boost { namespace python { namespace detail { + + +detail::new_non_null_reference list_base::call(object const& arg_) +{ + return (detail::new_non_null_reference) + (expect_non_null)( + PyObject_CallFunction( + (PyObject*)&PyList_Type, const_cast<char*>("(O)"), + arg_.ptr())); +} + +list_base::list_base() + : object(detail::new_reference(PyList_New(0))) +{} + +list_base::list_base(object_cref sequence) + : object(list_base::call(sequence)) +{} + +void list_base::append(object_cref x) +{ + if (PyList_CheckExact(this->ptr())) + { + if (PyList_Append(this->ptr(), x.ptr()) == -1) + throw_error_already_set(); + } + else + { + this->attr("append")(x); + } +} + +//long list_base::count(object_cref value) const; + +void list_base::extend(object_cref sequence) +{ + this->attr("extend")(sequence); +} + +long list_base::index(object_cref value) const +{ + object result_obj(this->attr("index")(value)); +#if PY_VERSION_HEX >= 0x03000000 + ssize_t result = PyLong_AsSsize_t(result_obj.ptr()); +#else + long result = PyInt_AsLong(result_obj.ptr()); +#endif + if (result == -1) + throw_error_already_set(); + return result; +} + +void list_base::insert(ssize_t index, object_cref item) +{ + if (PyList_CheckExact(this->ptr())) + { + if (PyList_Insert(this->ptr(), index, item.ptr()) == -1) + throw_error_already_set(); + } + else + { + this->attr("insert")(index, item); + } +} + +void list_base::insert(object const& index, object_cref x) +{ +#if PY_VERSION_HEX >= 0x03000000 + ssize_t index_ = PyLong_AsSsize_t(index.ptr()); +#else + long index_ = PyInt_AsLong(index.ptr()); +#endif + if (index_ == -1 && PyErr_Occurred()) + throw_error_already_set(); + this->insert(index_, x); +} + +object list_base::pop() +{ + return this->attr("pop")(); +} + +object list_base::pop(ssize_t index) +{ + return this->pop(object(index)); +} + +object list_base::pop(object const& index) +{ + return this->attr("pop")(index); +} + +void list_base::remove(object_cref value) +{ + this->attr("remove")(value); +} + +void list_base::reverse() +{ + if (PyList_CheckExact(this->ptr())) + { + if (PyList_Reverse(this->ptr()) == -1) + throw_error_already_set(); + } + else + { + this->attr("reverse")(); + } +} + +void list_base::sort() +{ + if (PyList_CheckExact(this->ptr())) + { + if (PyList_Sort(this->ptr()) == -1) + throw_error_already_set(); + } + else + { + this->attr("sort")(); + } +} + +#if PY_VERSION_HEX >= 0x03000000 +void list_base::sort(args_proxy const &args, + kwds_proxy const &kwds) +{ + this->attr("sort")(args, kwds); +} +#else +void list_base::sort(object_cref cmpfunc) +{ + this->attr("sort")(cmpfunc); +} +#endif + +// For some reason, moving this to the end of the TU suppresses an ICE +// with vc6. +ssize_t list_base::count(object_cref value) const +{ + object result_obj(this->attr("count")(value)); +#if PY_VERSION_HEX >= 0x03000000 + ssize_t result = PyLong_AsSsize_t(result_obj.ptr()); +#else + long result = PyInt_AsLong(result_obj.ptr()); +#endif + if (result == -1) + throw_error_already_set(); + return result; +} + +static struct register_list_pytype_ptr +{ + register_list_pytype_ptr() + { + const_cast<converter::registration &>( + converter::registry::lookup(boost::python::type_id<boost::python::list>()) + ).m_class_object = &PyList_Type; + } +}register_list_pytype_ptr_; + +}}} // namespace boost::python diff --git a/src/boost/libs/python/src/long.cpp b/src/boost/libs/python/src/long.cpp new file mode 100644 index 000000000..1ec8ebc01 --- /dev/null +++ b/src/boost/libs/python/src/long.cpp @@ -0,0 +1,39 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/long.hpp> + +namespace boost { namespace python { namespace detail { + +new_non_null_reference long_base::call(object const& arg_) +{ + return (detail::new_non_null_reference)PyObject_CallFunction( + (PyObject*)&PyLong_Type, const_cast<char*>("(O)"), + arg_.ptr()); +} + +new_non_null_reference long_base::call(object const& arg_, object const& base) +{ + return (detail::new_non_null_reference)PyObject_CallFunction( + (PyObject*)&PyLong_Type, const_cast<char*>("(OO)"), + arg_.ptr(), base.ptr()); +} + +long_base::long_base() + : object( + detail::new_reference( + PyObject_CallFunction((PyObject*)&PyLong_Type, const_cast<char*>("()"))) + ) +{} + +long_base::long_base(object_cref arg) + : object(long_base::call(arg)) +{} + +long_base::long_base(object_cref arg, object_cref base) + : object(long_base::call(arg, base)) +{} + + +}}} // namespace boost::python diff --git a/src/boost/libs/python/src/module.cpp b/src/boost/libs/python/src/module.cpp new file mode 100644 index 000000000..962848199 --- /dev/null +++ b/src/boost/libs/python/src/module.cpp @@ -0,0 +1,73 @@ +// (C) Copyright David Abrahams 2000. +// 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) +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#include <boost/python/scope.hpp> +#include <boost/python/object/add_to_namespace.hpp> + +namespace boost { namespace python { namespace detail { + +namespace +{ + PyObject* init_module_in_scope(PyObject* m, void(*init_function)()) + { + if (m != 0) + { + // Create the current module scope + object m_obj(((borrowed_reference_t*)m)); + scope current_module(m_obj); + + handle_exception(init_function); + } + + return m; + } +} + +BOOST_PYTHON_DECL void scope_setattr_doc(char const* name, object const& x, char const* doc) +{ + // Use function::add_to_namespace to achieve overloading if + // appropriate. + scope current; + objects::add_to_namespace(current, name, x, doc); +} + +#if PY_VERSION_HEX >= 0x03000000 + +BOOST_PYTHON_DECL PyObject* init_module(PyModuleDef& moduledef, void(*init_function)()) +{ + return init_module_in_scope( + PyModule_Create(&moduledef), + init_function); +} + +#else + +namespace +{ + PyMethodDef initial_methods[] = { { 0, 0, 0, 0 } }; +} + +BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*init_function)()) +{ + return init_module_in_scope( + Py_InitModule(const_cast<char*>(name), initial_methods), + init_function); +} + +#endif + +}}} // namespace boost::python::detail + +namespace boost { namespace python { + +namespace detail +{ + BOOST_PYTHON_DECL PyObject* current_scope = 0; +} + +}} diff --git a/src/boost/libs/python/src/numpy/dtype.cpp b/src/boost/libs/python/src/numpy/dtype.cpp new file mode 100644 index 000000000..88a20a27b --- /dev/null +++ b/src/boost/libs/python/src/numpy/dtype.cpp @@ -0,0 +1,220 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// 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) + +#ifdef _MSC_VER +#include <boost/cstdint.hpp> +#endif +#define BOOST_PYTHON_NUMPY_INTERNAL +#include <boost/python/numpy/internal.hpp> + +#define DTYPE_FROM_CODE(code) \ + dtype(python::detail::new_reference(reinterpret_cast<PyObject*>(PyArray_DescrFromType(code)))) + +#define BUILTIN_INT_DTYPE(bits) \ + template <> struct builtin_int_dtype<bits, false> \ + { \ + static dtype get() { return DTYPE_FROM_CODE(NPY_INT ## bits);} \ + }; \ + template <> struct builtin_int_dtype<bits, true> \ + { \ + static dtype get() { return DTYPE_FROM_CODE(NPY_UINT ## bits);} \ + }; \ + template BOOST_NUMPY_DECL dtype get_int_dtype<bits, false>(); \ + template BOOST_NUMPY_DECL dtype get_int_dtype<bits, true>() + +#define BUILTIN_FLOAT_DTYPE(bits) \ + template <> struct builtin_float_dtype<bits> \ + { \ + static dtype get() { return DTYPE_FROM_CODE(NPY_FLOAT ## bits);} \ + }; \ + template BOOST_NUMPY_DECL dtype get_float_dtype<bits>() + +#define BUILTIN_COMPLEX_DTYPE(bits) \ + template <> struct builtin_complex_dtype<bits> \ + { \ + static dtype get() { return DTYPE_FROM_CODE(NPY_COMPLEX ## bits);} \ + }; \ + template BOOST_NUMPY_DECL dtype get_complex_dtype<bits>() + +namespace boost { namespace python { namespace converter { +NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArrayDescr_Type, numpy::dtype) +} // namespace boost::python::converter + +namespace numpy { +namespace detail { + +dtype builtin_dtype<bool,true>::get() { return DTYPE_FROM_CODE(NPY_BOOL); } + +template <int bits, bool isUnsigned> struct builtin_int_dtype; +template <int bits> struct builtin_float_dtype; +template <int bits> struct builtin_complex_dtype; + +template <int bits, bool isUnsigned> dtype get_int_dtype() { + return builtin_int_dtype<bits,isUnsigned>::get(); +} +template <int bits> dtype get_float_dtype() { return builtin_float_dtype<bits>::get(); } +template <int bits> dtype get_complex_dtype() { return builtin_complex_dtype<bits>::get(); } + +BUILTIN_INT_DTYPE(8); +BUILTIN_INT_DTYPE(16); +BUILTIN_INT_DTYPE(32); +BUILTIN_INT_DTYPE(64); +#ifdef NPY_FLOAT16 +BUILTIN_FLOAT_DTYPE(16); +#endif +BUILTIN_FLOAT_DTYPE(32); +BUILTIN_FLOAT_DTYPE(64); +BUILTIN_COMPLEX_DTYPE(64); +BUILTIN_COMPLEX_DTYPE(128); +#if NPY_BITSOF_LONGDOUBLE > NPY_BITSOF_DOUBLE +template <> struct builtin_float_dtype< NPY_BITSOF_LONGDOUBLE > { + static dtype get() { return DTYPE_FROM_CODE(NPY_LONGDOUBLE); } +}; +template dtype get_float_dtype< NPY_BITSOF_LONGDOUBLE >(); +template <> struct builtin_complex_dtype< 2 * NPY_BITSOF_LONGDOUBLE > { + static dtype get() { return DTYPE_FROM_CODE(NPY_CLONGDOUBLE); } +}; +template dtype get_complex_dtype< 2 * NPY_BITSOF_LONGDOUBLE >(); +#endif + +} // namespace detail + +python::detail::new_reference dtype::convert(object const & arg, bool align) +{ + PyArray_Descr* obj=NULL; + if (align) + { + if (PyArray_DescrAlignConverter(arg.ptr(), &obj) < 0) + throw_error_already_set(); + } + else + { + if (PyArray_DescrConverter(arg.ptr(), &obj) < 0) + throw_error_already_set(); + } + return python::detail::new_reference(reinterpret_cast<PyObject*>(obj)); +} + +int dtype::get_itemsize() const { return reinterpret_cast<PyArray_Descr*>(ptr())->elsize;} + +bool equivalent(dtype const & a, dtype const & b) { + // On Windows x64, the behaviour described on + // http://docs.scipy.org/doc/numpy/reference/c-api.array.html for + // PyArray_EquivTypes unfortunately does not extend as expected: + // "For example, on 32-bit platforms, NPY_LONG and NPY_INT are equivalent". + // This should also hold for 64-bit platforms (and does on Linux), but not + // on Windows. Implement an alternative: +#ifdef _MSC_VER + if (sizeof(long) == sizeof(int) && + // Manually take care of the type equivalence. + ((a == dtype::get_builtin<long>() || a == dtype::get_builtin<int>()) && + (b == dtype::get_builtin<long>() || b == dtype::get_builtin<int>()) || + (a == dtype::get_builtin<unsigned int>() || a == dtype::get_builtin<unsigned long>()) && + (b == dtype::get_builtin<unsigned int>() || b == dtype::get_builtin<unsigned long>()))) { + return true; + } else { + return PyArray_EquivTypes( + reinterpret_cast<PyArray_Descr*>(a.ptr()), + reinterpret_cast<PyArray_Descr*>(b.ptr()) + ); + } +#else + return PyArray_EquivTypes( + reinterpret_cast<PyArray_Descr*>(a.ptr()), + reinterpret_cast<PyArray_Descr*>(b.ptr()) + ); +#endif +} + +namespace +{ + +namespace pyconv = boost::python::converter; + +template <typename T> +class array_scalar_converter +{ +public: + + static PyTypeObject const * get_pytype() + { + // This implementation depends on the fact that get_builtin returns pointers to objects + // NumPy has declared statically, and that the typeobj member also refers to a static + // object. That means we don't need to do any reference counting. + // In fact, I'm somewhat concerned that increasing the reference count of any of these + // might cause leaks, because I don't think Boost.Python ever decrements it, but it's + // probably a moot point if everything is actually static. + return reinterpret_cast<PyArray_Descr*>(dtype::get_builtin<T>().ptr())->typeobj; + } + + static void * convertible(PyObject * obj) + { + if (obj->ob_type == get_pytype()) + { + return obj; + } + else + { + dtype dt(python::detail::borrowed_reference(obj->ob_type)); + if (equivalent(dt, dtype::get_builtin<T>())) + { + return obj; + } + } + return 0; + } + + static void convert(PyObject * obj, pyconv::rvalue_from_python_stage1_data* data) + { + void * storage = reinterpret_cast<pyconv::rvalue_from_python_storage<T>*>(data)->storage.bytes; + // We assume std::complex is a "standard layout" here and elsewhere; not guaranteed by + // C++03 standard, but true in every known implementation (and guaranteed by C++11). + PyArray_ScalarAsCtype(obj, reinterpret_cast<T*>(storage)); + data->convertible = storage; + } + + static void declare() + { + pyconv::registry::push_back(&convertible, &convert, python::type_id<T>() +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + , &get_pytype +#endif + ); + } + +}; + +} // anonymous + +void dtype::register_scalar_converters() +{ + array_scalar_converter<bool>::declare(); + array_scalar_converter<npy_uint8>::declare(); + array_scalar_converter<npy_int8>::declare(); + array_scalar_converter<npy_uint16>::declare(); + array_scalar_converter<npy_int16>::declare(); + array_scalar_converter<npy_uint32>::declare(); + array_scalar_converter<npy_int32>::declare(); +#ifdef _MSC_VER + // Since the npy_(u)int32 types are defined as long types and treated + // as being different from the int32 types, these converters must be declared + // explicitely. + array_scalar_converter<boost::uint32_t>::declare(); + array_scalar_converter<boost::int32_t>::declare(); +#endif + array_scalar_converter<npy_uint64>::declare(); + array_scalar_converter<npy_int64>::declare(); + array_scalar_converter<float>::declare(); + array_scalar_converter<double>::declare(); + array_scalar_converter< std::complex<float> >::declare(); + array_scalar_converter< std::complex<double> >::declare(); +#if NPY_BITSOF_LONGDOUBLE > NPY_BITSOF_DOUBLE + array_scalar_converter<long double>::declare(); + array_scalar_converter< std::complex<long double> >::declare(); +#endif +} + +}}} // namespace boost::python::numpy diff --git a/src/boost/libs/python/src/numpy/matrix.cpp b/src/boost/libs/python/src/numpy/matrix.cpp new file mode 100644 index 000000000..47d226163 --- /dev/null +++ b/src/boost/libs/python/src/numpy/matrix.cpp @@ -0,0 +1,63 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// 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) + +#define BOOST_PYTHON_NUMPY_INTERNAL +#include <boost/python/numpy/internal.hpp> +#include <boost/python/numpy/matrix.hpp> + +namespace boost { namespace python { namespace numpy +{ +namespace detail +{ +inline object get_matrix_type() +{ + object module = import("numpy"); + return module.attr("matrix"); +} +} // namespace boost::python::numpy::detail +} // namespace boost::python::numpy + +namespace converter +{ + +PyTypeObject const * object_manager_traits<numpy::matrix>::get_pytype() +{ + return reinterpret_cast<PyTypeObject*>(numpy::detail::get_matrix_type().ptr()); +} + +} // namespace boost::python::converter + +namespace numpy +{ + +object matrix::construct(object const & obj, dtype const & dt, bool copy) +{ + return numpy::detail::get_matrix_type()(obj, dt, copy); +} + +object matrix::construct(object const & obj, bool copy) +{ + return numpy::detail::get_matrix_type()(obj, object(), copy); +} + +matrix matrix::view(dtype const & dt) const +{ + return matrix(python::detail::new_reference + (PyObject_CallMethod(this->ptr(), const_cast<char*>("view"), const_cast<char*>("O"), dt.ptr()))); +} + +matrix matrix::copy() const +{ + return matrix(python::detail::new_reference + (PyObject_CallMethod(this->ptr(), const_cast<char*>("copy"), const_cast<char*>("")))); +} + +matrix matrix::transpose() const +{ + return matrix(extract<matrix>(ndarray::transpose())); +} + +}}} // namespace boost::python::numpy diff --git a/src/boost/libs/python/src/numpy/ndarray.cpp b/src/boost/libs/python/src/numpy/ndarray.cpp new file mode 100644 index 000000000..af09ecc33 --- /dev/null +++ b/src/boost/libs/python/src/numpy/ndarray.cpp @@ -0,0 +1,301 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// 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) + +#define BOOST_PYTHON_NUMPY_INTERNAL +#include <boost/python/numpy/internal.hpp> +#include <boost/scoped_array.hpp> + +namespace boost { namespace python { +namespace converter +{ +NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArray_Type, numpy::ndarray) +} // namespace boost::python::converter + +namespace numpy +{ +namespace detail +{ + +ndarray::bitflag numpy_to_bitflag(int const f) +{ + ndarray::bitflag r = ndarray::NONE; + if (f & NPY_ARRAY_C_CONTIGUOUS) r = (r | ndarray::C_CONTIGUOUS); + if (f & NPY_ARRAY_F_CONTIGUOUS) r = (r | ndarray::F_CONTIGUOUS); + if (f & NPY_ARRAY_ALIGNED) r = (r | ndarray::ALIGNED); + if (f & NPY_ARRAY_WRITEABLE) r = (r | ndarray::WRITEABLE); + return r; +} + +int bitflag_to_numpy(ndarray::bitflag f) +{ + int r = 0; + if (f & ndarray::C_CONTIGUOUS) r |= NPY_ARRAY_C_CONTIGUOUS; + if (f & ndarray::F_CONTIGUOUS) r |= NPY_ARRAY_F_CONTIGUOUS; + if (f & ndarray::ALIGNED) r |= NPY_ARRAY_ALIGNED; + if (f & ndarray::WRITEABLE) r |= NPY_ARRAY_WRITEABLE; + return r; +} + +bool is_c_contiguous(std::vector<Py_intptr_t> const & shape, + std::vector<Py_intptr_t> const & strides, + int itemsize) +{ + std::vector<Py_intptr_t>::const_reverse_iterator j = strides.rbegin(); + int total = itemsize; + for (std::vector<Py_intptr_t>::const_reverse_iterator i = shape.rbegin(); i != shape.rend(); ++i, ++j) + { + if (total != *j) return false; + total *= (*i); + } + return true; +} + +bool is_f_contiguous(std::vector<Py_intptr_t> const & shape, + std::vector<Py_intptr_t> const & strides, + int itemsize) +{ + std::vector<Py_intptr_t>::const_iterator j = strides.begin(); + int total = itemsize; + for (std::vector<Py_intptr_t>::const_iterator i = shape.begin(); i != shape.end(); ++i, ++j) + { + if (total != *j) return false; + total *= (*i); + } + return true; +} + +bool is_aligned(std::vector<Py_intptr_t> const & strides, + int itemsize) +{ + for (std::vector<Py_intptr_t>::const_iterator i = strides.begin(); i != strides.end(); ++i) + { + if (*i % itemsize) return false; + } + return true; +} + +inline PyArray_Descr * incref_dtype(dtype const & dt) +{ + Py_INCREF(dt.ptr()); + return reinterpret_cast<PyArray_Descr*>(dt.ptr()); +} + +ndarray from_data_impl(void * data, + dtype const & dt, + python::object const & shape, + python::object const & strides, + python::object const & owner, + bool writeable) +{ + std::vector<Py_intptr_t> shape_(len(shape)); + std::vector<Py_intptr_t> strides_(len(strides)); + if (shape_.size() != strides_.size()) + { + PyErr_SetString(PyExc_ValueError, "Length of shape and strides arrays do not match."); + python::throw_error_already_set(); + } + for (std::size_t i = 0; i < shape_.size(); ++i) + { + shape_[i] = python::extract<Py_intptr_t>(shape[i]); + strides_[i] = python::extract<Py_intptr_t>(strides[i]); + } + return from_data_impl(data, dt, shape_, strides_, owner, writeable); +} + +ndarray from_data_impl(void * data, + dtype const & dt, + std::vector<Py_intptr_t> const & shape, + std::vector<Py_intptr_t> const & strides, + python::object const & owner, + bool writeable) +{ + if (shape.size() != strides.size()) + { + PyErr_SetString(PyExc_ValueError, "Length of shape and strides arrays do not match."); + python::throw_error_already_set(); + } + int itemsize = dt.get_itemsize(); + int flags = 0; + if (writeable) flags |= NPY_ARRAY_WRITEABLE; + if (is_c_contiguous(shape, strides, itemsize)) flags |= NPY_ARRAY_C_CONTIGUOUS; + if (is_f_contiguous(shape, strides, itemsize)) flags |= NPY_ARRAY_F_CONTIGUOUS; + if (is_aligned(strides, itemsize)) flags |= NPY_ARRAY_ALIGNED; + ndarray r(python::detail::new_reference + (PyArray_NewFromDescr(&PyArray_Type, + incref_dtype(dt), + shape.size(), + const_cast<Py_intptr_t*>(&shape.front()), + const_cast<Py_intptr_t*>(&strides.front()), + data, + flags, + NULL))); + r.set_base(owner); + return r; +} + +} // namespace detail + +namespace { + int normalize_index(int n,int nlim) // wraps [-nlim:nlim) into [0:nlim), throw IndexError otherwise + { + if (n<0) + n += nlim; // negative indices work backwards from end + if (n < 0 || n >= nlim) + { + PyErr_SetObject(PyExc_IndexError, Py_None); + throw_error_already_set(); + } + return n; + } +} + +Py_intptr_t ndarray::shape(int n) const +{ + return get_shape()[normalize_index(n,get_nd())]; +} + +Py_intptr_t ndarray::strides(int n) const +{ + return get_strides()[normalize_index(n,get_nd())]; +} + +ndarray ndarray::view(dtype const & dt) const +{ + return ndarray(python::detail::new_reference + (PyObject_CallMethod(this->ptr(), const_cast<char*>("view"), const_cast<char*>("O"), dt.ptr()))); +} + +ndarray ndarray::astype(dtype const & dt) const +{ + return ndarray(python::detail::new_reference + (PyObject_CallMethod(this->ptr(), const_cast<char*>("astype"), const_cast<char*>("O"), dt.ptr()))); +} + +ndarray ndarray::copy() const +{ + return ndarray(python::detail::new_reference + (PyObject_CallMethod(this->ptr(), const_cast<char*>("copy"), const_cast<char*>("")))); +} + +dtype ndarray::get_dtype() const +{ + return dtype(python::detail::borrowed_reference(get_struct()->descr)); +} + +python::object ndarray::get_base() const +{ + if (get_struct()->base == NULL) return object(); + return python::object(python::detail::borrowed_reference(get_struct()->base)); +} + +void ndarray::set_base(object const & base) +{ + Py_XDECREF(get_struct()->base); + if (base.ptr()) + { + Py_INCREF(base.ptr()); + get_struct()->base = base.ptr(); + } + else + { + get_struct()->base = NULL; + } +} + +ndarray::bitflag ndarray::get_flags() const +{ + return numpy::detail::numpy_to_bitflag(get_struct()->flags); +} + +ndarray ndarray::transpose() const +{ + return ndarray(python::detail::new_reference + (PyArray_Transpose(reinterpret_cast<PyArrayObject*>(this->ptr()), NULL))); +} + +ndarray ndarray::squeeze() const +{ + return ndarray(python::detail::new_reference + (PyArray_Squeeze(reinterpret_cast<PyArrayObject*>(this->ptr())))); +} + +ndarray ndarray::reshape(python::tuple const & shape) const +{ + return ndarray(python::detail::new_reference + (PyArray_Reshape(reinterpret_cast<PyArrayObject*>(this->ptr()), shape.ptr()))); +} + +python::object ndarray::scalarize() const +{ + Py_INCREF(ptr()); + return python::object(python::detail::new_reference(PyArray_Return(reinterpret_cast<PyArrayObject*>(ptr())))); +} + +ndarray zeros(python::tuple const & shape, dtype const & dt) +{ + int nd = len(shape); + boost::scoped_array<Py_intptr_t> dims(new Py_intptr_t[nd]); + for (int n=0; n<nd; ++n) dims[n] = python::extract<Py_intptr_t>(shape[n]); + return ndarray(python::detail::new_reference + (PyArray_Zeros(nd, dims.get(), detail::incref_dtype(dt), 0))); +} + +ndarray zeros(int nd, Py_intptr_t const * shape, dtype const & dt) +{ + return ndarray(python::detail::new_reference + (PyArray_Zeros(nd, const_cast<Py_intptr_t*>(shape), detail::incref_dtype(dt), 0))); +} + +ndarray empty(python::tuple const & shape, dtype const & dt) +{ + int nd = len(shape); + boost::scoped_array<Py_intptr_t> dims(new Py_intptr_t[nd]); + for (int n=0; n<nd; ++n) dims[n] = python::extract<Py_intptr_t>(shape[n]); + return ndarray(python::detail::new_reference + (PyArray_Empty(nd, dims.get(), detail::incref_dtype(dt), 0))); +} + +ndarray empty(int nd, Py_intptr_t const * shape, dtype const & dt) +{ + return ndarray(python::detail::new_reference + (PyArray_Empty(nd, const_cast<Py_intptr_t*>(shape), detail::incref_dtype(dt), 0))); +} + +ndarray array(python::object const & obj) +{ + return ndarray(python::detail::new_reference + (PyArray_FromAny(obj.ptr(), NULL, 0, 0, NPY_ARRAY_ENSUREARRAY, NULL))); +} + +ndarray array(python::object const & obj, dtype const & dt) +{ + return ndarray(python::detail::new_reference + (PyArray_FromAny(obj.ptr(), detail::incref_dtype(dt), 0, 0, NPY_ARRAY_ENSUREARRAY, NULL))); +} + +ndarray from_object(python::object const & obj, dtype const & dt, int nd_min, int nd_max, ndarray::bitflag flags) +{ + int requirements = detail::bitflag_to_numpy(flags); + return ndarray(python::detail::new_reference + (PyArray_FromAny(obj.ptr(), + detail::incref_dtype(dt), + nd_min, nd_max, + requirements, + NULL))); +} + +ndarray from_object(python::object const & obj, int nd_min, int nd_max, ndarray::bitflag flags) +{ + int requirements = detail::bitflag_to_numpy(flags); + return ndarray(python::detail::new_reference + (PyArray_FromAny(obj.ptr(), + NULL, + nd_min, nd_max, + requirements, + NULL))); +} + +}}} // namespace boost::python::numpy diff --git a/src/boost/libs/python/src/numpy/numpy.cpp b/src/boost/libs/python/src/numpy/numpy.cpp new file mode 100644 index 000000000..3ae2295e3 --- /dev/null +++ b/src/boost/libs/python/src/numpy/numpy.cpp @@ -0,0 +1,34 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// 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) + +#define BOOST_PYTHON_NUMPY_INTERNAL_MAIN +#include <boost/python/numpy/internal.hpp> +#include <boost/python/numpy/dtype.hpp> + +namespace boost { namespace python { namespace numpy { + +#if PY_MAJOR_VERSION == 2 +static void wrap_import_array() +{ + import_array(); +} +#else +static void * wrap_import_array() +{ + import_array(); + return NULL; +} +#endif + +void initialize(bool register_scalar_converters) +{ + wrap_import_array(); + import_ufunc(); + if (register_scalar_converters) + dtype::register_scalar_converters(); +} + +}}} // namespace boost::python::numpy diff --git a/src/boost/libs/python/src/numpy/scalars.cpp b/src/boost/libs/python/src/numpy/scalars.cpp new file mode 100644 index 000000000..3947c06f2 --- /dev/null +++ b/src/boost/libs/python/src/numpy/scalars.cpp @@ -0,0 +1,36 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// 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) + +#define BOOST_PYTHON_NUMPY_INTERNAL +#include <boost/python/numpy/internal.hpp> + +namespace boost { namespace python { +namespace converter +{ +NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyVoidArrType_Type, numpy::void_) +} // namespace boost::python::converter + +namespace numpy +{ + +void_::void_(Py_ssize_t size) + : object(python::detail::new_reference + (PyObject_CallFunction((PyObject*)&PyVoidArrType_Type, const_cast<char*>("i"), size))) +{} + +void_ void_::view(dtype const & dt) const +{ + return void_(python::detail::new_reference + (PyObject_CallMethod(this->ptr(), const_cast<char*>("view"), const_cast<char*>("O"), dt.ptr()))); +} + +void_ void_::copy() const +{ + return void_(python::detail::new_reference + (PyObject_CallMethod(this->ptr(), const_cast<char*>("copy"), const_cast<char*>("")))); +} + +}}} // namespace boost::python::numpy diff --git a/src/boost/libs/python/src/numpy/ufunc.cpp b/src/boost/libs/python/src/numpy/ufunc.cpp new file mode 100644 index 000000000..173d7213e --- /dev/null +++ b/src/boost/libs/python/src/numpy/ufunc.cpp @@ -0,0 +1,65 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// 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) + +#define BOOST_PYTHON_NUMPY_INTERNAL +#include <boost/python/numpy/internal.hpp> +#include <boost/python/numpy/ufunc.hpp> + +namespace boost { namespace python { +namespace converter +{ +NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArrayMultiIter_Type, numpy::multi_iter) +} // namespace boost::python::converter + +namespace numpy +{ + +multi_iter make_multi_iter(object const & a1) +{ + return multi_iter(python::detail::new_reference(PyArray_MultiIterNew(1, a1.ptr()))); +} + + multi_iter make_multi_iter(object const & a1, object const & a2) +{ + return multi_iter(python::detail::new_reference(PyArray_MultiIterNew(2, a1.ptr(), a2.ptr()))); +} + +multi_iter make_multi_iter(object const & a1, object const & a2, object const & a3) +{ + return multi_iter(python::detail::new_reference(PyArray_MultiIterNew(3, a1.ptr(), a2.ptr(), a3.ptr()))); +} + +void multi_iter::next() +{ + PyArray_MultiIter_NEXT(ptr()); +} + +bool multi_iter::not_done() const +{ + return PyArray_MultiIter_NOTDONE(ptr()); +} + +char * multi_iter::get_data(int i) const +{ + return reinterpret_cast<char*>(PyArray_MultiIter_DATA(ptr(), i)); +} + +int multi_iter::get_nd() const +{ + return reinterpret_cast<PyArrayMultiIterObject*>(ptr())->nd; +} + +Py_intptr_t const * multi_iter::get_shape() const +{ + return reinterpret_cast<PyArrayMultiIterObject*>(ptr())->dimensions; +} + +Py_intptr_t multi_iter::shape(int n) const +{ + return reinterpret_cast<PyArrayMultiIterObject*>(ptr())->dimensions[n]; +} + +}}} // namespace boost::python::numpy diff --git a/src/boost/libs/python/src/object/class.cpp b/src/boost/libs/python/src/object/class.cpp new file mode 100644 index 000000000..9bb9683a3 --- /dev/null +++ b/src/boost/libs/python/src/object/class.cpp @@ -0,0 +1,764 @@ +// Copyright David Abrahams 2001. +// 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 <boost/python/detail/prefix.hpp> +#include <boost/mpl/lambda.hpp> // #including this first is an intel6 workaround + +#include <boost/python/object/class.hpp> +#include <boost/python/object/instance.hpp> +#include <boost/python/object/class_detail.hpp> +#include <boost/python/scope.hpp> +#include <boost/python/converter/registry.hpp> +#include <boost/python/object/find_instance.hpp> +#include <boost/python/object/pickle_support.hpp> +#include <boost/python/detail/map_entry.hpp> +#include <boost/python/object.hpp> +#include <boost/python/object_protocol.hpp> +#include <boost/detail/binary_search.hpp> +#include <boost/python/self.hpp> +#include <boost/python/dict.hpp> +#include <boost/python/str.hpp> +#include <boost/python/ssize_t.hpp> +#include <functional> +#include <vector> +#include <cstddef> +#include <new> +#include <structmember.h> + +namespace boost { namespace python { + +# ifdef BOOST_PYTHON_SELF_IS_CLASS +namespace self_ns +{ + self_t self; +} +# endif + +instance_holder::instance_holder() + : m_next(0) +{ +} + +instance_holder::~instance_holder() +{ +} + +extern "C" +{ + // This is copied from typeobject.c in the Python sources. Even though + // class_metatype_object doesn't set Py_TPFLAGS_HAVE_GC, that bit gets + // filled in by the base class initialization process in + // PyType_Ready(). However, tp_is_gc is *not* copied from the base + // type, making it assume that classes are GC-able even if (like + // class_type_object) they're statically allocated. + static int + type_is_gc(PyTypeObject *python_type) + { + return python_type->tp_flags & Py_TPFLAGS_HEAPTYPE; + } + + // This is also copied from the Python sources. We can't implement + // static_data as a subclass property effectively without it. + typedef struct { + PyObject_HEAD + PyObject *prop_get; + PyObject *prop_set; + PyObject *prop_del; + PyObject *prop_doc; + int getter_doc; + } propertyobject; + + // Copied from Python source and removed the part for setting docstring, + // since we don't have a setter for __doc__ and trying to set it will + // cause the init fail. + static int property_init(PyObject *self, PyObject *args, PyObject *kwds) + { + PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL; + static const char *kwlist[] = {"fget", "fset", "fdel", "doc", 0}; + propertyobject *prop = (propertyobject *)self; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property", + const_cast<char **>(kwlist), &get, &set, &del, &doc)) + return -1; + + if (get == Py_None) + get = NULL; + if (set == Py_None) + set = NULL; + if (del == Py_None) + del = NULL; + + Py_XINCREF(get); + Py_XINCREF(set); + Py_XINCREF(del); + Py_XINCREF(doc); + + prop->prop_get = get; + prop->prop_set = set; + prop->prop_del = del; + prop->prop_doc = doc; + prop->getter_doc = 0; + + return 0; + } + + + static PyObject * + static_data_descr_get(PyObject *self, PyObject * /*obj*/, PyObject * /*type*/) + { + propertyobject *gs = (propertyobject *)self; + + return PyObject_CallFunction(gs->prop_get, const_cast<char*>("()")); + } + + static int + static_data_descr_set(PyObject *self, PyObject * /*obj*/, PyObject *value) + { + propertyobject *gs = (propertyobject *)self; + PyObject *func, *res; + + if (value == NULL) + func = gs->prop_del; + else + func = gs->prop_set; + if (func == NULL) { + PyErr_SetString(PyExc_AttributeError, + value == NULL ? + "can't delete attribute" : + "can't set attribute"); + return -1; + } + if (value == NULL) + res = PyObject_CallFunction(func, const_cast<char*>("()")); + else + res = PyObject_CallFunction(func, const_cast<char*>("(O)"), value); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; + } +} + +static PyTypeObject static_data_object = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast<char*>("Boost.Python.StaticProperty"), + sizeof(propertyobject), + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT // | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, //&PyProperty_Type, /* tp_base */ + 0, /* tp_dict */ + static_data_descr_get, /* tp_descr_get */ + static_data_descr_set, /* tp_descr_set */ + 0, /* tp_dictoffset */ + property_init, /* tp_init */ + 0, /* tp_alloc */ + 0, // filled in with type_new /* tp_new */ + 0, // filled in with __PyObject_GC_Del /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +namespace objects +{ +#if PY_VERSION_HEX < 0x03000000 + // XXX Not sure why this run into compiling error in Python 3 + extern "C" + { + // This declaration needed due to broken Python 2.2 headers + extern DL_IMPORT(PyTypeObject) PyProperty_Type; + } +#endif + + BOOST_PYTHON_DECL PyObject* static_data() + { + if (static_data_object.tp_dict == 0) + { + Py_TYPE(&static_data_object) = &PyType_Type; + static_data_object.tp_base = &PyProperty_Type; + if (PyType_Ready(&static_data_object)) + return 0; + } + return upcast<PyObject>(&static_data_object); + } +} + +extern "C" +{ + // Ordinarily, descriptors have a certain assymetry: you can use + // them to read attributes off the class object they adorn, but + // writing the same attribute on the class object always replaces + // the descriptor in the class __dict__. In order to properly + // represent C++ static data members, we need to allow them to be + // written through the class instance. This function of the + // metaclass makes it possible. + static int + class_setattro(PyObject *obj, PyObject *name, PyObject* value) + { + // Must use "private" Python implementation detail + // _PyType_Lookup instead of PyObject_GetAttr because the + // latter will always end up calling the descr_get function on + // any descriptor it finds; we need the unadulterated + // descriptor here. + PyObject* a = _PyType_Lookup(downcast<PyTypeObject>(obj), name); + + // a is a borrowed reference or 0 + + // If we found a static data descriptor, call it directly to + // force it to set the static data member + if (a != 0 && PyObject_IsInstance(a, objects::static_data())) + return Py_TYPE(a)->tp_descr_set(a, obj, value); + else + return PyType_Type.tp_setattro(obj, name, value); + } +} + +static PyTypeObject class_metatype_object = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast<char*>("Boost.Python.class"), + PyType_Type.tp_basicsize, + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + class_setattro, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT // | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, //&PyType_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, // filled in with type_new /* tp_new */ + 0, // filled in with __PyObject_GC_Del /* tp_free */ + (inquiry)type_is_gc, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +// Install the instance data for a C++ object into a Python instance +// object. +void instance_holder::install(PyObject* self) throw() +{ + assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self)), &class_metatype_object)); + m_next = ((objects::instance<>*)self)->objects; + ((objects::instance<>*)self)->objects = this; +} + + +namespace objects +{ +// Get the metatype object for all extension classes. + BOOST_PYTHON_DECL type_handle class_metatype() + { + if (class_metatype_object.tp_dict == 0) + { + Py_TYPE(&class_metatype_object) = &PyType_Type; + class_metatype_object.tp_base = &PyType_Type; + if (PyType_Ready(&class_metatype_object)) + return type_handle(); + } + return type_handle(borrowed(&class_metatype_object)); + } + extern "C" + { + static void instance_dealloc(PyObject* inst) + { + instance<>* kill_me = (instance<>*)inst; + + for (instance_holder* p = kill_me->objects, *next; p != 0; p = next) + { + next = p->next(); + p->~instance_holder(); + instance_holder::deallocate(inst, dynamic_cast<void*>(p)); + } + + // Python 2.2.1 won't add weak references automatically when + // tp_itemsize > 0, so we need to manage that + // ourselves. Accordingly, we also have to clean up the + // weakrefs ourselves. + if (kill_me->weakrefs != NULL) + PyObject_ClearWeakRefs(inst); + + Py_XDECREF(kill_me->dict); + + Py_TYPE(inst)->tp_free(inst); + } + + static PyObject * + instance_new(PyTypeObject* type_, PyObject* /*args*/, PyObject* /*kw*/) + { + // Attempt to find the __instance_size__ attribute. If not present, no problem. + PyObject* d = type_->tp_dict; + PyObject* instance_size_obj = PyObject_GetAttrString(d, const_cast<char*>("__instance_size__")); + + ssize_t instance_size = instance_size_obj ? +#if PY_VERSION_HEX >= 0x03000000 + PyLong_AsSsize_t(instance_size_obj) : 0; +#else + PyInt_AsLong(instance_size_obj) : 0; +#endif + + if (instance_size < 0) + instance_size = 0; + + PyErr_Clear(); // Clear any errors that may have occurred. + + instance<>* result = (instance<>*)type_->tp_alloc(type_, instance_size); + if (result) + { + // Guido says we can use ob_size for any purpose we + // like, so we'll store the total size of the object + // there. A negative number indicates that the extra + // instance memory is not yet allocated to any holders. +#if PY_VERSION_HEX >= 0x02060000 + Py_SIZE(result) = +#else + result->ob_size = +#endif + -(static_cast<int>(offsetof(instance<>,storage) + instance_size)); + } + return (PyObject*)result; + } + + static PyObject* instance_get_dict(PyObject* op, void*) + { + instance<>* inst = downcast<instance<> >(op); + if (inst->dict == 0) + inst->dict = PyDict_New(); + return python::xincref(inst->dict); + } + + static int instance_set_dict(PyObject* op, PyObject* dict, void*) + { + instance<>* inst = downcast<instance<> >(op); + python::xdecref(inst->dict); + inst->dict = python::incref(dict); + return 0; + } + + } + + + static PyGetSetDef instance_getsets[] = { + {const_cast<char*>("__dict__"), instance_get_dict, instance_set_dict, NULL, 0}, + {0, 0, 0, 0, 0} + }; + + + static PyMemberDef instance_members[] = { + {const_cast<char*>("__weakref__"), T_OBJECT, offsetof(instance<>, weakrefs), 0, 0}, + {0, 0, 0, 0, 0} + }; + + static PyTypeObject class_type_object = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast<char*>("Boost.Python.instance"), + offsetof(instance<>,storage), /* tp_basicsize */ + 1, /* tp_itemsize */ + instance_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT // | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(instance<>,weakrefs), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + instance_members, /* tp_members */ + instance_getsets, /* tp_getset */ + 0, //&PyBaseObject_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(instance<>,dict), /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + instance_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif + }; + + BOOST_PYTHON_DECL type_handle class_type() + { + if (class_type_object.tp_dict == 0) + { + Py_TYPE(&class_type_object) = incref(class_metatype().get()); + class_type_object.tp_base = &PyBaseObject_Type; + if (PyType_Ready(&class_type_object)) + return type_handle(); +// class_type_object.tp_setattro = class_setattro; + } + return type_handle(borrowed(&class_type_object)); + } + + BOOST_PYTHON_DECL void* + find_instance_impl(PyObject* inst, type_info type, bool null_shared_ptr_only) + { + if (!Py_TYPE(Py_TYPE(inst)) || + !PyType_IsSubtype(Py_TYPE(Py_TYPE(inst)), &class_metatype_object)) + return 0; + + instance<>* self = reinterpret_cast<instance<>*>(inst); + + for (instance_holder* match = self->objects; match != 0; match = match->next()) + { + void* const found = match->holds(type, null_shared_ptr_only); + if (found) + return found; + } + return 0; + } + + object module_prefix() + { + return object( + PyObject_IsInstance(scope().ptr(), upcast<PyObject>(&PyModule_Type)) + ? object(scope().attr("__name__")) + : api::getattr(scope(), "__module__", str()) + ); + } + + namespace + { + // Find a registered class object corresponding to id. Return a + // null handle if no such class is registered. + inline type_handle query_class(type_info id) + { + converter::registration const* p = converter::registry::query(id); + return type_handle( + python::borrowed( + python::allow_null(p ? p->m_class_object : 0)) + ); + } + + // Find a registered class corresponding to id. If not found, + // throw an appropriate exception. + type_handle get_class(type_info id) + { + type_handle result(query_class(id)); + + if (result.get() == 0) + { + object report("extension class wrapper for base class "); + report = report + id.name() + " has not been created yet"; + PyErr_SetObject(PyExc_RuntimeError, report.ptr()); + throw_error_already_set(); + } + return result; + } + + // class_base constructor + // + // name - the name of the new Python class + // + // num_types - one more than the number of declared bases + // + // types - array of python::type_info, the first item + // corresponding to the class being created, and the + // rest corresponding to its declared bases. + // + inline object + new_class(char const* name, std::size_t num_types, type_info const* const types, char const* doc) + { + assert(num_types >= 1); + + // Build a tuple of the base Python type objects. If no bases + // were declared, we'll use our class_type() as the single base + // class. + ssize_t const num_bases = (std::max)(num_types - 1, static_cast<std::size_t>(1)); + handle<> bases(PyTuple_New(num_bases)); + + for (ssize_t i = 1; i <= num_bases; ++i) + { + type_handle c = (i >= static_cast<ssize_t>(num_types)) ? class_type() : get_class(types[i]); + // PyTuple_SET_ITEM steals this reference + PyTuple_SET_ITEM(bases.get(), static_cast<ssize_t>(i - 1), upcast<PyObject>(c.release())); + } + + // Call the class metatype to create a new class + dict d; + + object m = module_prefix(); + if (m) d["__module__"] = m; + + if (doc != 0) + d["__doc__"] = doc; + + object result = object(class_metatype())(name, bases, d); + assert(PyType_IsSubtype(Py_TYPE(result.ptr()), &PyType_Type)); + + if (scope().ptr() != Py_None) + scope().attr(name) = result; + + // For pickle. Will lead to informative error messages if pickling + // is not enabled. + result.attr("__reduce__") = object(make_instance_reduce_function()); + + return result; + } + } + + class_base::class_base( + char const* name, std::size_t num_types, type_info const* const types, char const* doc) + : object(new_class(name, num_types, types, doc)) + { + // Insert the new class object in the registry + converter::registration& converters = const_cast<converter::registration&>( + converter::registry::lookup(types[0])); + + // Class object is leaked, for now + converters.m_class_object = (PyTypeObject*)incref(this->ptr()); + } + + BOOST_PYTHON_DECL void copy_class_object(type_info const& src, type_info const& dst) + { + converter::registration& dst_converters + = const_cast<converter::registration&>(converter::registry::lookup(dst)); + + converter::registration const& src_converters = converter::registry::lookup(src); + + dst_converters.m_class_object = src_converters.m_class_object; + } + + void class_base::set_instance_size(std::size_t instance_size) + { + this->attr("__instance_size__") = instance_size; + } + + void class_base::add_property( + char const* name, object const& fget, char const* docstr) + { + object property( + (python::detail::new_reference) + PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast<char*>("Osss"), fget.ptr(), (char*)NULL, (char*)NULL, docstr)); + + this->setattr(name, property); + } + + void class_base::add_property( + char const* name, object const& fget, object const& fset, char const* docstr) + { + object property( + (python::detail::new_reference) + PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast<char*>("OOss"), fget.ptr(), fset.ptr(), (char*)NULL, docstr)); + + this->setattr(name, property); + } + + void class_base::add_static_property(char const* name, object const& fget) + { + object property( + (python::detail::new_reference) + PyObject_CallFunction(static_data(), const_cast<char*>("O"), fget.ptr()) + ); + + this->setattr(name, property); + } + + void class_base::add_static_property(char const* name, object const& fget, object const& fset) + { + object property( + (python::detail::new_reference) + PyObject_CallFunction(static_data(), const_cast<char*>("OO"), fget.ptr(), fset.ptr())); + + this->setattr(name, property); + } + + void class_base::setattr(char const* name, object const& x) + { + if (PyObject_SetAttrString(this->ptr(), const_cast<char*>(name), x.ptr()) < 0) + throw_error_already_set(); + } + + namespace + { + extern "C" PyObject* no_init(PyObject*, PyObject*) + { + ::PyErr_SetString(::PyExc_RuntimeError, const_cast<char*>("This class cannot be instantiated from Python")); + return NULL; + } + static ::PyMethodDef no_init_def = { + const_cast<char*>("__init__"), no_init, METH_VARARGS, + const_cast<char*>("Raises an exception\n" + "This class cannot be instantiated from Python\n") + }; + } + + void class_base::def_no_init() + { + handle<> f(::PyCFunction_New(&no_init_def, 0)); + this->setattr("__init__", object(f)); + } + + void class_base::enable_pickling_(bool getstate_manages_dict) + { + setattr("__safe_for_unpickling__", object(true)); + + if (getstate_manages_dict) + { + setattr("__getstate_manages_dict__", object(true)); + } + } + + namespace + { + PyObject* callable_check(PyObject* callable) + { + if (PyCallable_Check(expect_non_null(callable))) + return callable; + + ::PyErr_Format( + PyExc_TypeError + , const_cast<char*>("staticmethod expects callable object; got an object of type %s, which is not callable") + , Py_TYPE(callable)->tp_name + ); + + throw_error_already_set(); + return 0; + } + } + + void class_base::make_method_static(const char * method_name) + { + PyTypeObject* self = downcast<PyTypeObject>(this->ptr()); + dict d((handle<>(borrowed(self->tp_dict)))); + + object method(d[method_name]); + + this->attr(method_name) = object( + handle<>( + PyStaticMethod_New((callable_check)(method.ptr()) ) + )); + } + + BOOST_PYTHON_DECL type_handle registered_class_object(type_info id) + { + return query_class(id); + } +} // namespace objects + + +void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std::size_t holder_size) +{ + assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self_)), &class_metatype_object)); + objects::instance<>* self = (objects::instance<>*)self_; + + int total_size_needed = holder_offset + holder_size; + + if (-Py_SIZE(self) >= total_size_needed) + { + // holder_offset should at least point into the variable-sized part + assert(holder_offset >= offsetof(objects::instance<>,storage)); + + // Record the fact that the storage is occupied, noting where it starts + Py_SIZE(self) = holder_offset; + return (char*)self + holder_offset; + } + else + { + void* const result = PyMem_Malloc(holder_size); + if (result == 0) + throw std::bad_alloc(); + return result; + } +} + +void instance_holder::deallocate(PyObject* self_, void* storage) throw() +{ + assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self_)), &class_metatype_object)); + objects::instance<>* self = (objects::instance<>*)self_; + if (storage != (char*)self + Py_SIZE(self)) + { + PyMem_Free(storage); + } +} + +}} // namespace boost::python diff --git a/src/boost/libs/python/src/object/enum.cpp b/src/boost/libs/python/src/object/enum.cpp new file mode 100644 index 000000000..10122ad1d --- /dev/null +++ b/src/boost/libs/python/src/object/enum.cpp @@ -0,0 +1,252 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/object/enum_base.hpp> +#include <boost/python/cast.hpp> +#include <boost/python/scope.hpp> +#include <boost/python/object.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/dict.hpp> +#include <boost/python/str.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/object_protocol.hpp> +#include <structmember.h> + +namespace boost { namespace python { namespace objects { + +struct enum_object +{ +#if PY_VERSION_HEX >= 0x03000000 + PyLongObject base_object; +#else + PyIntObject base_object; +#endif + PyObject* name; +}; + +static PyMemberDef enum_members[] = { + {const_cast<char*>("name"), T_OBJECT_EX, offsetof(enum_object,name),READONLY, 0}, + {0, 0, 0, 0, 0} +}; + + +extern "C" +{ + static void + enum_dealloc(enum_object* self) + { + Py_XDECREF(self->name); + Py_TYPE(self)->tp_free((PyObject*)self); + } + + static PyObject* enum_repr(PyObject* self_) + { + PyObject *mod = PyObject_GetAttrString( self_, "__module__"); + object auto_free = object(handle<>(mod)); + enum_object* self = downcast<enum_object>(self_); + if (!self->name) + { + return +#if PY_VERSION_HEX >= 0x03000000 + PyUnicode_FromFormat("%S.%s(%ld)", mod, self_->ob_type->tp_name, PyLong_AsLong(self_)); +#else + PyString_FromFormat("%s.%s(%ld)", PyString_AsString(mod), self_->ob_type->tp_name, PyInt_AS_LONG(self_)); +#endif + } + else + { + PyObject* name = self->name; + if (name == 0) + return 0; + + return +#if PY_VERSION_HEX >= 0x03000000 + PyUnicode_FromFormat("%S.%s.%S", mod, self_->ob_type->tp_name, name); +#else + PyString_FromFormat("%s.%s.%s", + PyString_AsString(mod), self_->ob_type->tp_name, PyString_AsString(name)); +#endif + } + } + + static PyObject* enum_str(PyObject* self_) + { + enum_object* self = downcast<enum_object>(self_); + if (!self->name) + { +#if PY_VERSION_HEX >= 0x03000000 + return PyLong_Type.tp_str(self_); +#else + return PyInt_Type.tp_str(self_); +#endif + } + else + { + return incref(self->name); + } + } +} + +static PyTypeObject enum_type_object = { + PyVarObject_HEAD_INIT(NULL, 0) // &PyType_Type + const_cast<char*>("Boost.Python.enum"), + sizeof(enum_object), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) enum_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + enum_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + enum_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT +#if PY_VERSION_HEX < 0x03000000 + | Py_TPFLAGS_CHECKTYPES +#endif + | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + enum_members, /* tp_members */ + 0, /* tp_getset */ + 0, //&PyInt_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +object module_prefix(); + +namespace +{ + object new_enum_type(char const* name, char const *doc) + { + if (enum_type_object.tp_dict == 0) + { + Py_TYPE(&enum_type_object) = incref(&PyType_Type); +#if PY_VERSION_HEX >= 0x03000000 + enum_type_object.tp_base = &PyLong_Type; +#else + enum_type_object.tp_base = &PyInt_Type; +#endif + if (PyType_Ready(&enum_type_object)) + throw_error_already_set(); + } + + type_handle metatype(borrowed(&PyType_Type)); + type_handle base(borrowed(&enum_type_object)); + + // suppress the instance __dict__ in these enum objects. There + // may be a slicker way, but this'll do for now. + dict d; + d["__slots__"] = tuple(); + d["values"] = dict(); + d["names"] = dict(); + + object module_name = module_prefix(); + if (module_name) + d["__module__"] = module_name; + if (doc) + d["__doc__"] = doc; + + object result = (object(metatype))(name, make_tuple(base), d); + + scope().attr(name) = result; + + return result; + } +} + +enum_base::enum_base( + char const* name + , converter::to_python_function_t to_python + , converter::convertible_function convertible + , converter::constructor_function construct + , type_info id + , char const *doc + ) + : object(new_enum_type(name, doc)) +{ + converter::registration& converters + = const_cast<converter::registration&>( + converter::registry::lookup(id)); + + converters.m_class_object = downcast<PyTypeObject>(this->ptr()); + converter::registry::insert(to_python, id); + converter::registry::insert(convertible, construct, id); +} + +void enum_base::add_value(char const* name_, long value) +{ + // Convert name to Python string + object name(name_); + + // Create a new enum instance by calling the class with a value + object x = (*this)(value); + + // Store the object in the enum class + (*this).attr(name_) = x; + + dict d = extract<dict>(this->attr("values"))(); + d[value] = x; + + // Set the name field in the new enum instanec + enum_object* p = downcast<enum_object>(x.ptr()); + Py_XDECREF(p->name); + p->name = incref(name.ptr()); + + dict names_dict = extract<dict>(this->attr("names"))(); + names_dict[x.attr("name")] = x; +} + +void enum_base::export_values() +{ + dict d = extract<dict>(this->attr("names"))(); + list items = d.items(); + scope current; + + for (unsigned i = 0, max = len(items); i < max; ++i) + api::setattr(current, items[i][0], items[i][1]); + } + +PyObject* enum_base::to_python(PyTypeObject* type_, long x) +{ + object type((type_handle(borrowed(type_)))); + + dict d = extract<dict>(type.attr("values"))(); + object v = d.get(x, object()); + return incref( + (v == object() ? type(x) : v).ptr()); +} + +}}} // namespace boost::python::object diff --git a/src/boost/libs/python/src/object/function.cpp b/src/boost/libs/python/src/object/function.cpp new file mode 100644 index 000000000..9d4745d10 --- /dev/null +++ b/src/boost/libs/python/src/object/function.cpp @@ -0,0 +1,789 @@ +// Copyright David Abrahams 2001. +// 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 <boost/python/docstring_options.hpp> +#include <boost/python/object/function_object.hpp> +#include <boost/python/object/function_handle.hpp> +#include <boost/python/object/function_doc_signature.hpp> +#include <boost/python/errors.hpp> +#include <boost/python/str.hpp> +#include <boost/python/object_attributes.hpp> +#include <boost/python/args.hpp> +#include <boost/python/refcount.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/list.hpp> +#include <boost/python/ssize_t.hpp> + +#include <boost/python/detail/signature.hpp> +#include <boost/python/detail/none.hpp> +#include <boost/mpl/vector/vector10.hpp> + +#include <boost/bind.hpp> + +#include <algorithm> +#include <cstring> + +#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES +# include <cstdio> +#endif + +namespace boost { namespace python { + volatile bool docstring_options::show_user_defined_ = true; + volatile bool docstring_options::show_cpp_signatures_ = true; +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + volatile bool docstring_options::show_py_signatures_ = true; +#else + volatile bool docstring_options::show_py_signatures_ = false; +#endif +}} + +namespace boost { namespace python { namespace objects { + +py_function_impl_base::~py_function_impl_base() +{ +} + +unsigned py_function_impl_base::max_arity() const +{ + return this->min_arity(); +} + +extern PyTypeObject function_type; + +function::function( + py_function const& implementation +#if BOOST_WORKAROUND(__EDG_VERSION__, == 245) + , python::detail::keyword const* names_and_defaults +#else + , python::detail::keyword const* const names_and_defaults +#endif + , unsigned num_keywords + ) + : m_fn(implementation) + , m_nkeyword_values(0) +{ + if (names_and_defaults != 0) + { + unsigned int max_arity = m_fn.max_arity(); + unsigned int keyword_offset + = max_arity > num_keywords ? max_arity - num_keywords : 0; + + + ssize_t tuple_size = num_keywords ? max_arity : 0; + m_arg_names = object(handle<>(PyTuple_New(tuple_size))); + + if (num_keywords != 0) + { + for (unsigned j = 0; j < keyword_offset; ++j) + PyTuple_SET_ITEM(m_arg_names.ptr(), j, incref(Py_None)); + } + + for (unsigned i = 0; i < num_keywords; ++i) + { + tuple kv; + + python::detail::keyword const* const p = names_and_defaults + i; + if (p->default_value) + { + kv = make_tuple(p->name, p->default_value); + ++m_nkeyword_values; + } + else + { + kv = make_tuple(p->name); + } + + PyTuple_SET_ITEM( + m_arg_names.ptr() + , i + keyword_offset + , incref(kv.ptr()) + ); + } + } + + PyObject* p = this; + if (Py_TYPE(&function_type) == 0) + { + Py_TYPE(&function_type) = &PyType_Type; + ::PyType_Ready(&function_type); + } + + (void)( // warning suppression for GCC + PyObject_INIT(p, &function_type) + ); +} + +function::~function() +{ +} + +PyObject* function::call(PyObject* args, PyObject* keywords) const +{ + std::size_t n_unnamed_actual = PyTuple_GET_SIZE(args); + std::size_t n_keyword_actual = keywords ? PyDict_Size(keywords) : 0; + std::size_t n_actual = n_unnamed_actual + n_keyword_actual; + + function const* f = this; + + // Try overloads looking for a match + do + { + // Check for a plausible number of arguments + unsigned min_arity = f->m_fn.min_arity(); + unsigned max_arity = f->m_fn.max_arity(); + + if (n_actual + f->m_nkeyword_values >= min_arity + && n_actual <= max_arity) + { + // This will be the args that actually get passed + handle<>inner_args(allow_null(borrowed(args))); + + if (n_keyword_actual > 0 // Keyword arguments were supplied + || n_actual < min_arity) // or default keyword values are needed + { + if (f->m_arg_names.is_none()) + { + // this overload doesn't accept keywords + inner_args = handle<>(); + } + else + { + // "all keywords are none" is a special case + // indicating we will accept any number of keyword + // arguments + if (PyTuple_Size(f->m_arg_names.ptr()) == 0) + { + // no argument preprocessing + } + else + { + // build a new arg tuple, will adjust its size later + assert(max_arity <= static_cast<std::size_t>(ssize_t_max)); + inner_args = handle<>( + PyTuple_New(static_cast<ssize_t>(max_arity))); + + // Fill in the positional arguments + for (std::size_t i = 0; i < n_unnamed_actual; ++i) + PyTuple_SET_ITEM(inner_args.get(), i, incref(PyTuple_GET_ITEM(args, i))); + + // Grab remaining arguments by name from the keyword dictionary + std::size_t n_actual_processed = n_unnamed_actual; + + for (std::size_t arg_pos = n_unnamed_actual; arg_pos < max_arity ; ++arg_pos) + { + // Get the keyword[, value pair] corresponding + PyObject* kv = PyTuple_GET_ITEM(f->m_arg_names.ptr(), arg_pos); + + // If there were any keyword arguments, + // look up the one we need for this + // argument position + PyObject* value = n_keyword_actual + ? PyDict_GetItem(keywords, PyTuple_GET_ITEM(kv, 0)) + : 0; + + if (!value) + { + // Not found; check if there's a default value + if (PyTuple_GET_SIZE(kv) > 1) + value = PyTuple_GET_ITEM(kv, 1); + + if (!value) + { + // still not found; matching fails + PyErr_Clear(); + inner_args = handle<>(); + break; + } + } + else + { + ++n_actual_processed; + } + + PyTuple_SET_ITEM(inner_args.get(), arg_pos, incref(value)); + } + + if (inner_args.get()) + { + //check if we proccessed all the arguments + if(n_actual_processed < n_actual) + inner_args = handle<>(); + } + } + } + } + + // Call the function. Pass keywords in case it's a + // function accepting any number of keywords + PyObject* result = inner_args ? f->m_fn(inner_args.get(), keywords) : 0; + + // If the result is NULL but no error was set, m_fn failed + // the argument-matching test. + + // This assumes that all other error-reporters are + // well-behaved and never return NULL to python without + // setting an error. + if (result != 0 || PyErr_Occurred()) + return result; + } + f = f->m_overloads.get(); + } + while (f); + // None of the overloads matched; time to generate the error message + argument_error(args, keywords); + return 0; +} + +object function::signature(bool show_return_type) const +{ + py_function const& impl = m_fn; + + python::detail::signature_element const* return_type = impl.signature(); + python::detail::signature_element const* s = return_type + 1; + + list formal_params; + if (impl.max_arity() == 0) + formal_params.append("void"); + + for (unsigned n = 0; n < impl.max_arity(); ++n) + { + if (s[n].basename == 0) + { + formal_params.append("..."); + break; + } + + str param(s[n].basename); + if (s[n].lvalue) + param += " {lvalue}"; + + if (m_arg_names) // None or empty tuple will test false + { + object kv(m_arg_names[n]); + if (kv) + { + char const* const fmt = len(kv) > 1 ? " %s=%r" : " %s"; + param += fmt % kv; + } + } + + formal_params.append(param); + } + + if (show_return_type) + return "%s(%s) -> %s" % make_tuple( + m_name, str(", ").join(formal_params), return_type->basename); + return "%s(%s)" % make_tuple( + m_name, str(", ").join(formal_params)); +} + +object function::signatures(bool show_return_type) const +{ + list result; + for (function const* f = this; f; f = f->m_overloads.get()) { + result.append(f->signature(show_return_type)); + } + return result; +} + +void function::argument_error(PyObject* args, PyObject* /*keywords*/) const +{ + static handle<> exception( + PyErr_NewException(const_cast<char*>("Boost.Python.ArgumentError"), PyExc_TypeError, 0)); + + object message = "Python argument types in\n %s.%s(" + % make_tuple(this->m_namespace, this->m_name); + + list actual_args; + for (ssize_t i = 0; i < PyTuple_Size(args); ++i) + { + char const* name = PyTuple_GetItem(args, i)->ob_type->tp_name; + actual_args.append(str(name)); + } + message += str(", ").join(actual_args); + message += ")\ndid not match C++ signature:\n "; + message += str("\n ").join(signatures()); + +#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES + std::printf("\n--------\n%s\n--------\n", extract<const char*>(message)()); +#endif + PyErr_SetObject(exception.get(), message.ptr()); + throw_error_already_set(); +} + +void function::add_overload(handle<function> const& overload_) +{ + function* parent = this; + + while (parent->m_overloads) + parent = parent->m_overloads.get(); + + parent->m_overloads = overload_; + + // If we have no documentation, get the docs from the overload + if (!m_doc) + m_doc = overload_->m_doc; +} + +namespace +{ + char const* const binary_operator_names[] = + { + "add__", + "and__", + "div__", + "divmod__", + "eq__", + "floordiv__", + "ge__", + "gt__", + "le__", + "lshift__", + "lt__", + "mod__", + "mul__", + "ne__", + "or__", + "pow__", + "radd__", + "rand__", + "rdiv__", + "rdivmod__", + "rfloordiv__", + "rlshift__", + "rmod__", + "rmul__", + "ror__", + "rpow__", + "rrshift__", + "rshift__", + "rsub__", + "rtruediv__", + "rxor__", + "sub__", + "truediv__", + "xor__" + }; + + struct less_cstring + { + bool operator()(char const* x, char const* y) const + { + return BOOST_CSTD_::strcmp(x,y) < 0; + } + }; + + inline bool is_binary_operator(char const* name) + { + return name[0] == '_' + && name[1] == '_' + && std::binary_search( + &binary_operator_names[0] + , binary_operator_names + sizeof(binary_operator_names)/sizeof(*binary_operator_names) + , name + 2 + , less_cstring() + ); + } + + // Something for the end of the chain of binary operators + PyObject* not_implemented(PyObject*, PyObject*) + { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + handle<function> not_implemented_function() + { + + static object keeper( + function_object( + py_function(¬_implemented, mpl::vector1<void>(), 2) + , python::detail::keyword_range()) + ); + return handle<function>(borrowed(downcast<function>(keeper.ptr()))); + } +} + +void function::add_to_namespace( + object const& name_space, char const* name_, object const& attribute) +{ + add_to_namespace(name_space, name_, attribute, 0); +} + +namespace detail +{ + extern char py_signature_tag[]; + extern char cpp_signature_tag[]; +} + +void function::add_to_namespace( + object const& name_space, char const* name_, object const& attribute, char const* doc) +{ + str const name(name_); + PyObject* const ns = name_space.ptr(); + + if (attribute.ptr()->ob_type == &function_type) + { + function* new_func = downcast<function>(attribute.ptr()); + handle<> dict; + +#if PY_VERSION_HEX < 0x03000000 + // Old-style class gone in Python 3 + if (PyClass_Check(ns)) + dict = handle<>(borrowed(((PyClassObject*)ns)->cl_dict)); + else +#endif + if (PyType_Check(ns)) + dict = handle<>(borrowed(((PyTypeObject*)ns)->tp_dict)); + else + dict = handle<>(PyObject_GetAttrString(ns, const_cast<char*>("__dict__"))); + + if (dict == 0) + throw_error_already_set(); + + assert(!PyErr_Occurred()); + handle<> existing(allow_null(::PyObject_GetItem(dict.get(), name.ptr()))); + PyErr_Clear(); + + if (existing) + { + if (existing->ob_type == &function_type) + { + new_func->add_overload( + handle<function>( + borrowed( + downcast<function>(existing.get()) + ) + ) + ); + } + else if (existing->ob_type == &PyStaticMethod_Type) + { + char const* name_space_name = extract<char const*>(name_space.attr("__name__")); + + ::PyErr_Format( + PyExc_RuntimeError + , "Boost.Python - All overloads must be exported " + "before calling \'class_<...>(\"%s\").staticmethod(\"%s\")\'" + , name_space_name + , name_ + ); + throw_error_already_set(); + } + } + else if (is_binary_operator(name_)) + { + // Binary operators need an additional overload which + // returns NotImplemented, so that Python will try the + // __rxxx__ functions on the other operand. We add this + // when no overloads for the operator already exist. + new_func->add_overload(not_implemented_function()); + } + + // A function is named the first time it is added to a namespace. + if (new_func->name().is_none()) + new_func->m_name = name; + + assert(!PyErr_Occurred()); + handle<> name_space_name( + allow_null(::PyObject_GetAttrString(name_space.ptr(), const_cast<char*>("__name__")))); + PyErr_Clear(); + + if (name_space_name) + new_func->m_namespace = object(name_space_name); + } + + if (PyObject_SetAttr(ns, name.ptr(), attribute.ptr()) < 0) + throw_error_already_set(); + + object mutable_attribute(attribute); +/* + if (doc != 0 && docstring_options::show_user_defined_) + { + // Accumulate documentation + + if ( + PyObject_HasAttrString(mutable_attribute.ptr(), "__doc__") + && mutable_attribute.attr("__doc__")) + { + mutable_attribute.attr("__doc__") += "\n\n"; + mutable_attribute.attr("__doc__") += doc; + } + else { + mutable_attribute.attr("__doc__") = doc; + } + } + + if (docstring_options::show_signatures_) + { + if ( PyObject_HasAttrString(mutable_attribute.ptr(), "__doc__") + && mutable_attribute.attr("__doc__")) { + mutable_attribute.attr("__doc__") += ( + mutable_attribute.attr("__doc__")[-1] != "\n" ? "\n\n" : "\n"); + } + else { + mutable_attribute.attr("__doc__") = ""; + } + function* f = downcast<function>(attribute.ptr()); + mutable_attribute.attr("__doc__") += str("\n ").join(make_tuple( + "C++ signature:", f->signature(true))); + } + */ + str _doc; + + if (docstring_options::show_py_signatures_) + { + _doc += str(const_cast<const char*>(detail::py_signature_tag)); + } + if (doc != 0 && docstring_options::show_user_defined_) + _doc += doc; + + if (docstring_options::show_cpp_signatures_) + { + _doc += str(const_cast<const char*>(detail::cpp_signature_tag)); + } + if(_doc) + { + object mutable_attribute(attribute); + mutable_attribute.attr("__doc__")= _doc; + } +} + +BOOST_PYTHON_DECL void add_to_namespace( + object const& name_space, char const* name, object const& attribute) +{ + function::add_to_namespace(name_space, name, attribute, 0); +} + +BOOST_PYTHON_DECL void add_to_namespace( + object const& name_space, char const* name, object const& attribute, char const* doc) +{ + function::add_to_namespace(name_space, name, attribute, doc); +} + + +namespace +{ + struct bind_return + { + bind_return(PyObject*& result, function const* f, PyObject* args, PyObject* keywords) + : m_result(result) + , m_f(f) + , m_args(args) + , m_keywords(keywords) + {} + + void operator()() const + { + m_result = m_f->call(m_args, m_keywords); + } + + private: + PyObject*& m_result; + function const* m_f; + PyObject* m_args; + PyObject* m_keywords; + }; +} + +extern "C" +{ + // Stolen from Python's funcobject.c + static PyObject * + function_descr_get(PyObject *func, PyObject *obj, PyObject *type_) + { +#if PY_VERSION_HEX >= 0x03000000 + // The implement is different in Python 3 because of the removal of unbound method + if (obj == Py_None || obj == NULL) { + Py_INCREF(func); + return func; + } + return PyMethod_New(func, obj); +#else + if (obj == Py_None) + obj = NULL; + return PyMethod_New(func, obj, type_); +#endif + } + + static void + function_dealloc(PyObject* p) + { + delete static_cast<function*>(p); + } + + static PyObject * + function_call(PyObject *func, PyObject *args, PyObject *kw) + { + PyObject* result = 0; + handle_exception(bind_return(result, static_cast<function*>(func), args, kw)); + return result; + } + + // + // Here we're using the function's tp_getset rather than its + // tp_members to set up __doc__ and __name__, because tp_members + // really depends on having a POD object type (it relies on + // offsets). It might make sense to reformulate function as a POD + // at some point, but this is much more expedient. + // + static PyObject* function_get_doc(PyObject* op, void*) + { + function* f = downcast<function>(op); + list signatures = function_doc_signature_generator::function_doc_signatures(f); + if(!signatures) return python::detail::none(); + signatures.reverse(); + return python::incref( str("\n").join(signatures).ptr()); + } + + static int function_set_doc(PyObject* op, PyObject* doc, void*) + { + function* f = downcast<function>(op); + f->doc(doc ? object(python::detail::borrowed_reference(doc)) : object()); + return 0; + } + + static PyObject* function_get_name(PyObject* op, void*) + { + function* f = downcast<function>(op); + if (f->name().is_none()) +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_InternFromString("<unnamed Boost.Python function>"); +#else + return PyString_InternFromString("<unnamed Boost.Python function>"); +#endif + else + return python::incref(f->name().ptr()); + } + + // We add a dummy __class__ attribute in order to fool PyDoc into + // treating these as built-in functions and scanning their + // documentation + static PyObject* function_get_class(PyObject* /*op*/, void*) + { + return python::incref(upcast<PyObject>(&PyCFunction_Type)); + } + + static PyObject* function_get_module(PyObject* op, void*) + { + function* f = downcast<function>(op); + object const& ns = f->get_namespace(); + if (!ns.is_none()) { + return python::incref(ns.ptr()); + } + PyErr_SetString( + PyExc_AttributeError, const_cast<char*>( + "Boost.Python function __module__ unknown.")); + return 0; + } +} + +static PyGetSetDef function_getsetlist[] = { + {const_cast<char*>("__name__"), (getter)function_get_name, 0, 0, 0 }, + {const_cast<char*>("func_name"), (getter)function_get_name, 0, 0, 0 }, + {const_cast<char*>("__module__"), (getter)function_get_module, 0, 0, 0 }, + {const_cast<char*>("func_module"), (getter)function_get_module, 0, 0, 0 }, + {const_cast<char*>("__class__"), (getter)function_get_class, 0, 0, 0 }, // see note above + {const_cast<char*>("__doc__"), (getter)function_get_doc, (setter)function_set_doc, 0, 0}, + {const_cast<char*>("func_doc"), (getter)function_get_doc, (setter)function_set_doc, 0, 0}, + {NULL, 0, 0, 0, 0} /* Sentinel */ +}; + +PyTypeObject function_type = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast<char*>("Boost.Python.function"), + sizeof(function), + 0, + (destructor)function_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, //(reprfunc)func_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + function_call, /* tp_call */ + 0, /* tp_str */ + 0, // PyObject_GenericGetAttr, /* tp_getattro */ + 0, // PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT /* | Py_TPFLAGS_HAVE_GC */,/* tp_flags */ + 0, /* tp_doc */ + 0, // (traverseproc)func_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, //offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, // func_memberlist, /* tp_members */ + function_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + function_descr_get, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, //offsetof(PyFunctionObject, func_dict), /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +object function_object( + py_function const& f + , python::detail::keyword_range const& keywords) +{ + return python::object( + python::detail::new_non_null_reference( + new function( + f, keywords.first, keywords.second - keywords.first))); +} + +object function_object(py_function const& f) +{ + return function_object(f, python::detail::keyword_range()); +} + + +handle<> function_handle_impl(py_function const& f) +{ + return python::handle<>( + allow_null( + new function(f, 0, 0))); +} + +} // namespace objects + +namespace detail +{ + object BOOST_PYTHON_DECL make_raw_function(objects::py_function f) + { + static keyword k; + + return objects::function_object( + f + , keyword_range(&k,&k)); + } + void BOOST_PYTHON_DECL pure_virtual_called() + { + PyErr_SetString( + PyExc_RuntimeError, const_cast<char*>("Pure virtual function called")); + throw_error_already_set(); + } +} + +}} // namespace boost::python diff --git a/src/boost/libs/python/src/object/function_doc_signature.cpp b/src/boost/libs/python/src/object/function_doc_signature.cpp new file mode 100644 index 000000000..41695285a --- /dev/null +++ b/src/boost/libs/python/src/object/function_doc_signature.cpp @@ -0,0 +1,344 @@ +// Copyright Nikolay Mladenov 2007. +// 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) + +// boost::python::make_tuple below are for gcc 4.4 -std=c++0x compatibility +// (Intel C++ 10 and 11 with -std=c++0x don't need the full qualification). + +#include <boost/python/converter/registrations.hpp> +#include <boost/python/object/function_doc_signature.hpp> +#include <boost/python/errors.hpp> +#include <boost/python/str.hpp> +#include <boost/python/args.hpp> +#include <boost/python/tuple.hpp> + +#include <boost/python/detail/signature.hpp> + +#include <vector> + +namespace boost { namespace python { namespace objects { + + bool function_doc_signature_generator::arity_cmp( function const *f1, function const *f2 ) + { + return f1->m_fn.max_arity() < f2->m_fn.max_arity(); + } + + bool function_doc_signature_generator::are_seq_overloads( function const *f1, function const *f2 , bool check_docs) + { + py_function const & impl1 = f1->m_fn; + py_function const & impl2 = f2->m_fn; + + //the number of parameters differs by 1 + if (impl2.max_arity()-impl1.max_arity() != 1) + return false; + + // if check docs then f1 shold not have docstring or have the same docstring as f2 + if (check_docs && f2->doc() != f1->doc() && f1->doc()) + return false; + + python::detail::signature_element const* s1 = impl1.signature(); + python::detail::signature_element const* s2 = impl2.signature(); + + unsigned size = impl1.max_arity()+1; + + for (unsigned i = 0; i != size; ++i) + { + //check if the argument types are the same + if (s1[i].basename != s2[i].basename) + return false; + + //return type + if (!i) continue; + + //check if the argument default values are the same + bool f1_has_names = bool(f1->m_arg_names); + bool f2_has_names = bool(f2->m_arg_names); + if ( (f1_has_names && f2_has_names && f2->m_arg_names[i-1]!=f1->m_arg_names[i-1]) + || (f1_has_names && !f2_has_names) + || (!f1_has_names && f2_has_names && f2->m_arg_names[i-1]!=python::object()) + ) + return false; + } + return true; + } + + std::vector<function const*> function_doc_signature_generator::flatten(function const *f) + { + object name = f->name(); + + std::vector<function const*> res; + + while (f) { + + //this if takes out the not_implemented_function + if (f->name() == name) + res.push_back(f); + + f=f->m_overloads.get(); + } + + //std::sort(res.begin(),res.end(), &arity_cmp); + + return res; + } + std::vector<function const*> function_doc_signature_generator::split_seq_overloads( const std::vector<function const *> &funcs, bool split_on_doc_change) + { + std::vector<function const*> res; + + std::vector<function const*>::const_iterator fi = funcs.begin(); + + function const * last = *fi; + + while (++fi != funcs.end()){ + + //check if fi starts a new chain of overloads + if (!are_seq_overloads( last, *fi, split_on_doc_change )) + res.push_back(last); + + last = *fi; + } + + if (last) + res.push_back(last); + + return res; + } + + str function_doc_signature_generator::raw_function_pretty_signature(function const *f, size_t n_overloads, bool cpp_types ) + { + str res("object"); + + res = str("%s %s(%s)" % make_tuple( res, f->m_name, str("tuple args, dict kwds")) ); + + return res; + } + + const char * function_doc_signature_generator::py_type_str(const python::detail::signature_element &s) + { + if (s.basename==std::string("void")){ + static const char * none = "None"; + return none; + } + + PyTypeObject const * py_type = s.pytype_f?s.pytype_f():0; + if ( py_type ) + return py_type->tp_name; + else{ + static const char * object = "object"; + return object; + } + } + + str function_doc_signature_generator::parameter_string(py_function const &f, size_t n, object arg_names, bool cpp_types) + { + str param; + + python::detail::signature_element const * s = f.signature(); + if (cpp_types) + { + if(!n) + s = &f.get_return_type(); + if (s[n].basename == 0) + { + return str("..."); + } + + param = str(s[n].basename); + + if (s[n].lvalue) + param += " {lvalue}"; + + } + else + { + if (n) //we are processing an argument and trying to come up with a name for it + { + object kv; + if ( arg_names && (kv = arg_names[n-1]) ) + param = str( " (%s)%s" % make_tuple(py_type_str(s[n]),kv[0]) ); + else + param = str(" (%s)%s%d" % make_tuple(py_type_str(s[n]),"arg", n) ); + } + else //we are processing the return type + param = py_type_str(f.get_return_type()); + } + + //an argument - check for default value and append it + if(n && arg_names) + { + object kv(arg_names[n-1]); + if (kv && len(kv) == 2) + { + param = str("%s=%r" % make_tuple(param, kv[1])); + } + } + return param; + } + + str function_doc_signature_generator::pretty_signature(function const *f, size_t n_overloads, bool cpp_types ) + { + py_function + const& impl = f->m_fn; + ; + + + unsigned arity = impl.max_arity(); + + if(arity == unsigned(-1))// is this the proper raw function test? + { + return raw_function_pretty_signature(f,n_overloads,cpp_types); + } + + list formal_params; + + size_t n_extra_default_args=0; + + for (unsigned n = 0; n <= arity; ++n) + { + str param; + + formal_params.append( + parameter_string(impl, n, f->m_arg_names, cpp_types) + ); + + // find all the arguments with default values preceeding the arity-n_overloads + if (n && f->m_arg_names) + { + object kv(f->m_arg_names[n-1]); + + if (kv && len(kv) == 2) + { + //default argument preceeding the arity-n_overloads + if( n <= arity-n_overloads) + ++n_extra_default_args; + } + else + //argument without default, preceeding the arity-n_overloads + if( n <= arity-n_overloads) + n_extra_default_args = 0; + } + } + + n_overloads+=n_extra_default_args; + + if (!arity && cpp_types) + formal_params.append("void"); + + str ret_type (formal_params.pop(0)); + if (cpp_types ) + { + return str( + "%s %s(%s%s%s%s)" + % boost::python::make_tuple // workaround, see top + ( ret_type + , f->m_name + , str(",").join(formal_params.slice(0,arity-n_overloads)) + , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str() + , str(" [,").join(formal_params.slice(arity-n_overloads,arity)) + , std::string(n_overloads,']') + )); + }else{ + return str( + "%s(%s%s%s%s) -> %s" + % boost::python::make_tuple // workaround, see top + ( f->m_name + , str(",").join(formal_params.slice(0,arity-n_overloads)) + , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str() + , str(" [,").join(formal_params.slice(arity-n_overloads,arity)) + , std::string(n_overloads,']') + , ret_type + )); + } + + return str( + "%s %s(%s%s%s%s) %s" + % boost::python::make_tuple // workaround, see top + ( cpp_types?ret_type:str("") + , f->m_name + , str(",").join(formal_params.slice(0,arity-n_overloads)) + , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str() + , str(" [,").join(formal_params.slice(arity-n_overloads,arity)) + , std::string(n_overloads,']') + , cpp_types?str(""):ret_type + )); + + } + + namespace detail { + char py_signature_tag[] = "PY signature :"; + char cpp_signature_tag[] = "C++ signature :"; + } + + list function_doc_signature_generator::function_doc_signatures( function const * f) + { + list signatures; + std::vector<function const*> funcs = flatten( f); + std::vector<function const*> split_funcs = split_seq_overloads( funcs, true); + std::vector<function const*>::const_iterator sfi=split_funcs.begin(), fi; + size_t n_overloads=0; + for (fi=funcs.begin(); fi!=funcs.end(); ++fi) + { + if(*sfi == *fi){ + if((*fi)->doc()) + { + str func_doc = str((*fi)->doc()); + + int doc_len = len(func_doc); + + bool show_py_signature = doc_len >= int(sizeof(detail::py_signature_tag)/sizeof(char)-1) + && str(detail::py_signature_tag) == func_doc.slice(0, int(sizeof(detail::py_signature_tag)/sizeof(char))-1); + if(show_py_signature) + { + func_doc = str(func_doc.slice(int(sizeof(detail::py_signature_tag)/sizeof(char))-1, _)); + doc_len = len(func_doc); + } + + bool show_cpp_signature = doc_len >= int(sizeof(detail::cpp_signature_tag)/sizeof(char)-1) + && str(detail::cpp_signature_tag) == func_doc.slice( 1-int(sizeof(detail::cpp_signature_tag)/sizeof(char)), _); + + if(show_cpp_signature) + { + func_doc = str(func_doc.slice(_, 1-int(sizeof(detail::cpp_signature_tag)/sizeof(char)))); + doc_len = len(func_doc); + } + + str res="\n"; + str pad = "\n"; + + if(show_py_signature) + { + str sig = pretty_signature(*fi, n_overloads,false); + res+=sig; + if(doc_len || show_cpp_signature )res+=" :"; + pad+= str(" "); + } + + if(doc_len) + { + if(show_py_signature) + res+=pad; + res+= pad.join(func_doc.split("\n")); + } + + if( show_cpp_signature) + { + if(len(res)>1) + res+="\n"+pad; + res+=detail::cpp_signature_tag+pad+" "+pretty_signature(*fi, n_overloads,true); + } + + signatures.append(res); + } + ++sfi; + n_overloads = 0; + }else + ++n_overloads ; + } + + return signatures; + } + + +}}} + diff --git a/src/boost/libs/python/src/object/inheritance.cpp b/src/boost/libs/python/src/object/inheritance.cpp new file mode 100644 index 000000000..7dc9db1cd --- /dev/null +++ b/src/boost/libs/python/src/object/inheritance.cpp @@ -0,0 +1,495 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/object/inheritance.hpp> +#include <boost/python/type_id.hpp> +#include <boost/graph/breadth_first_search.hpp> +#if _MSC_FULL_VER >= 13102171 && _MSC_FULL_VER <= 13102179 +# include <boost/graph/reverse_graph.hpp> +#endif +#include <boost/graph/adjacency_list.hpp> +#include <boost/graph/reverse_graph.hpp> +#include <boost/property_map/property_map.hpp> +#include <boost/bind.hpp> +#include <boost/integer_traits.hpp> +#include <boost/tuple/tuple.hpp> +#include <boost/tuple/tuple_comparison.hpp> +#include <queue> +#include <vector> +#include <functional> + +// +// Procedure: +// +// The search is a BFS over the space of (type,address) pairs +// guided by the edges of the casting graph whose nodes +// correspond to classes, and whose edges are traversed by +// applying associated cast functions to an address. We use +// vertex distance to the goal node in the cast_graph to rate the +// paths. The vertex distance to any goal node is calculated on +// demand and outdated by the addition of edges to the graph. + +namespace boost { +namespace +{ + enum edge_cast_t { edge_cast = 8010 }; + template <class T> inline void unused_variable(const T&) { } +} + +// Install properties +BOOST_INSTALL_PROPERTY(edge, cast); + +namespace +{ + typedef void*(*cast_function)(void*); + + // + // Here we put together the low-level data structures of the + // casting graph representation. + // + typedef python::type_info class_id; + + // represents a graph of available casts + +#if 0 + struct cast_graph + : +#else + typedef +#endif + adjacency_list<vecS,vecS, bidirectionalS, no_property + + // edge index property allows us to look up edges in the connectivity matrix + , property<edge_index_t,std::size_t + + // The function which casts a void* from the edge's source type + // to its destination type. + , property<edge_cast_t,cast_function> > > +#if 0 + {}; +#else + cast_graph; +#endif + + typedef cast_graph::vertex_descriptor vertex_t; + typedef cast_graph::edge_descriptor edge_t; + + struct smart_graph + { + typedef std::vector<std::size_t>::const_iterator node_distance_map; + + typedef std::pair<cast_graph::out_edge_iterator + , cast_graph::out_edge_iterator> out_edges_t; + + // Return a map of the distances from any node to the given + // target node + node_distance_map distances_to(vertex_t target) const + { + std::size_t n = num_vertices(m_topology); + if (m_distances.size() != n * n) + { + m_distances.clear(); + m_distances.resize(n * n, (std::numeric_limits<std::size_t>::max)()); + m_known_vertices = n; + } + + std::vector<std::size_t>::iterator to_target = m_distances.begin() + n * target; + + // this node hasn't been used as a target yet + if (to_target[target] != 0) + { + typedef reverse_graph<cast_graph> reverse_cast_graph; + reverse_cast_graph reverse_topology(m_topology); + + to_target[target] = 0; + + breadth_first_search( + reverse_topology, target + , visitor( + make_bfs_visitor( + record_distances( + make_iterator_property_map( + to_target + , get(vertex_index, reverse_topology) +# ifdef BOOST_NO_STD_ITERATOR_TRAITS + , *to_target +# endif + ) + , on_tree_edge() + )))); + } + + return to_target; + } + + cast_graph& topology() { return m_topology; } + cast_graph const& topology() const { return m_topology; } + + smart_graph() + : m_known_vertices(0) + {} + + private: + cast_graph m_topology; + mutable std::vector<std::size_t> m_distances; + mutable std::size_t m_known_vertices; + }; + + smart_graph& full_graph() + { + static smart_graph x; + return x; + } + + smart_graph& up_graph() + { + static smart_graph x; + return x; + } + + // + // Our index of class types + // + using boost::python::objects::dynamic_id_function; + typedef tuples::tuple< + class_id // static type + , vertex_t // corresponding vertex + , dynamic_id_function // dynamic_id if polymorphic, or 0 + > + index_entry_interface; + typedef index_entry_interface::inherited index_entry; + enum { ksrc_static_t, kvertex, kdynamic_id }; + + typedef std::vector<index_entry> type_index_t; + + + type_index_t& type_index() + { + static type_index_t x; + return x; + } + + template <class Tuple> + struct select1st + { + typedef typename tuples::element<0, Tuple>::type result_type; + + result_type const& operator()(Tuple const& x) const + { + return tuples::get<0>(x); + } + }; + + // map a type to a position in the index + inline type_index_t::iterator type_position(class_id type) + { + typedef index_entry entry; + + return std::lower_bound( + type_index().begin(), type_index().end() + , boost::make_tuple(type, vertex_t(), dynamic_id_function(0)) + , boost::bind<bool>(std::less<class_id>() + , boost::bind<class_id>(select1st<entry>(), _1) + , boost::bind<class_id>(select1st<entry>(), _2))); + } + + inline index_entry* seek_type(class_id type) + { + type_index_t::iterator p = type_position(type); + if (p == type_index().end() || tuples::get<ksrc_static_t>(*p) != type) + return 0; + else + return &*p; + } + + // Get the entry for a type, inserting if necessary + inline type_index_t::iterator demand_type(class_id type) + { + type_index_t::iterator p = type_position(type); + + if (p != type_index().end() && tuples::get<ksrc_static_t>(*p) == type) + return p; + + vertex_t v = add_vertex(full_graph().topology()); + vertex_t v2 = add_vertex(up_graph().topology()); + unused_variable(v2); + assert(v == v2); + return type_index().insert(p, boost::make_tuple(type, v, dynamic_id_function(0))); + } + + // Map a two types to a vertex in the graph, inserting if necessary + typedef std::pair<type_index_t::iterator, type_index_t::iterator> + type_index_iterator_pair; + + inline type_index_iterator_pair + demand_types(class_id t1, class_id t2) + { + // be sure there will be no reallocation + type_index().reserve(type_index().size() + 2); + type_index_t::iterator first = demand_type(t1); + type_index_t::iterator second = demand_type(t2); + if (first == second) + ++first; + return std::make_pair(first, second); + } + + struct q_elt + { + q_elt(std::size_t distance + , void* src_address + , vertex_t target + , cast_function cast + ) + : distance(distance) + , src_address(src_address) + , target(target) + , cast(cast) + {} + + std::size_t distance; + void* src_address; + vertex_t target; + cast_function cast; + + bool operator<(q_elt const& rhs) const + { + return distance < rhs.distance; + } + }; + + // Optimization: + // + // Given p, src_t, dst_t + // + // Get a pointer pd to the most-derived object + // if it's polymorphic, dynamic_cast to void* + // otherwise pd = p + // + // Get the most-derived typeid src_td + // + // ptrdiff_t offset = p - pd + // + // Now we can keep a cache, for [src_t, offset, src_td, dst_t] of + // the cast transformation function to use on p and the next src_t + // in the chain. src_td, dst_t don't change throughout this + // process. In order to represent unreachability, when a pair is + // found to be unreachable, we stick a 0-returning "dead-cast" + // function in the cache. + + // This is needed in a few places below + inline void* identity_cast(void* p) + { + return p; + } + + void* search(smart_graph const& g, void* p, vertex_t src, vertex_t dst) + { + // I think this test was thoroughly bogus -- dwa + // If we know there's no path; bail now. + // if (src > g.known_vertices() || dst > g.known_vertices()) + // return 0; + + smart_graph::node_distance_map d(g.distances_to(dst)); + + if (d[src] == (std::numeric_limits<std::size_t>::max)()) + return 0; + + typedef property_map<cast_graph,edge_cast_t>::const_type cast_map; + cast_map casts = get(edge_cast, g.topology()); + + typedef std::pair<vertex_t,void*> search_state; + typedef std::vector<search_state> visited_t; + visited_t visited; + std::priority_queue<q_elt> q; + + q.push(q_elt(d[src], p, src, identity_cast)); + while (!q.empty()) + { + q_elt top = q.top(); + q.pop(); + + // Check to see if we have a real state + void* dst_address = top.cast(top.src_address); + if (dst_address == 0) + continue; + + if (top.target == dst) + return dst_address; + + search_state s(top.target,dst_address); + + visited_t::iterator pos = std::lower_bound( + visited.begin(), visited.end(), s); + + // If already visited, continue + if (pos != visited.end() && *pos == s) + continue; + + visited.insert(pos, s); // mark it + + // expand it: + smart_graph::out_edges_t edges = out_edges(s.first, g.topology()); + for (cast_graph::out_edge_iterator p = edges.first + , finish = edges.second + ; p != finish + ; ++p + ) + { + edge_t e = *p; + q.push(q_elt( + d[target(e, g.topology())] + , dst_address + , target(e, g.topology()) + , boost::get(casts, e))); + } + } + return 0; + } + + struct cache_element + { + typedef tuples::tuple< + class_id // source static type + , class_id // target type + , std::ptrdiff_t // offset within source object + , class_id // source dynamic type + >::inherited key_type; + + cache_element(key_type const& k) + : key(k) + , offset(0) + {} + + key_type key; + std::ptrdiff_t offset; + + BOOST_STATIC_CONSTANT( + std::ptrdiff_t, not_found = integer_traits<std::ptrdiff_t>::const_min); + + bool operator<(cache_element const& rhs) const + { + return this->key < rhs.key; + } + + bool unreachable() const + { + return offset == not_found; + } + }; + + enum { kdst_t = ksrc_static_t + 1, koffset, ksrc_dynamic_t }; + typedef std::vector<cache_element> cache_t; + + cache_t& cache() + { + static cache_t x; + return x; + } + + inline void* convert_type(void* const p, class_id src_t, class_id dst_t, bool polymorphic) + { + // Quickly rule out unregistered types + index_entry* src_p = seek_type(src_t); + if (src_p == 0) + return 0; + + index_entry* dst_p = seek_type(dst_t); + if (dst_p == 0) + return 0; + + // Look up the dynamic_id function and call it to get the dynamic + // info + boost::python::objects::dynamic_id_t dynamic_id = polymorphic + ? tuples::get<kdynamic_id>(*src_p)(p) + : std::make_pair(p, src_t); + + // Look in the cache first for a quickie address translation + std::ptrdiff_t offset = (char*)p - (char*)dynamic_id.first; + + cache_element seek(boost::make_tuple(src_t, dst_t, offset, dynamic_id.second)); + cache_t& c = cache(); + cache_t::iterator const cache_pos + = std::lower_bound(c.begin(), c.end(), seek); + + + // if found in the cache, we're done + if (cache_pos != c.end() && cache_pos->key == seek.key) + { + return cache_pos->offset == cache_element::not_found + ? 0 : (char*)p + cache_pos->offset; + } + + // If we are starting at the most-derived type, only look in the up graph + smart_graph const& g = polymorphic && dynamic_id.second != src_t + ? full_graph() : up_graph(); + + void* result = search( + g, p, tuples::get<kvertex>(*src_p) + , tuples::get<kvertex>(*dst_p)); + + // update the cache + c.insert(cache_pos, seek)->offset + = (result == 0) ? cache_element::not_found : (char*)result - (char*)p; + + return result; + } +} + +namespace python { namespace objects { + +BOOST_PYTHON_DECL void* find_dynamic_type(void* p, class_id src_t, class_id dst_t) +{ + return convert_type(p, src_t, dst_t, true); +} + +BOOST_PYTHON_DECL void* find_static_type(void* p, class_id src_t, class_id dst_t) +{ + return convert_type(p, src_t, dst_t, false); +} + +BOOST_PYTHON_DECL void add_cast( + class_id src_t, class_id dst_t, cast_function cast, bool is_downcast) +{ + // adding an edge will invalidate any record of unreachability in + // the cache. + static std::size_t expected_cache_len = 0; + cache_t& c = cache(); + if (c.size() > expected_cache_len) + { + c.erase(std::remove_if( + c.begin(), c.end(), + mem_fn(&cache_element::unreachable)) + , c.end()); + + // If any new cache entries get added, we'll have to do this + // again when the next edge is added + expected_cache_len = c.size(); + } + + type_index_iterator_pair types = demand_types(src_t, dst_t); + vertex_t src = tuples::get<kvertex>(*types.first); + vertex_t dst = tuples::get<kvertex>(*types.second); + + cast_graph* const g[2] = { &up_graph().topology(), &full_graph().topology() }; + + for (cast_graph*const* p = g + (is_downcast ? 1 : 0); p < g + 2; ++p) + { + edge_t e; + bool added; + + tie(e, added) = add_edge(src, dst, **p); + assert(added); + + put(get(edge_cast, **p), e, cast); + put(get(edge_index, **p), e, num_edges(full_graph().topology()) - 1); + } +} + +BOOST_PYTHON_DECL void register_dynamic_id_aux( + class_id static_id, dynamic_id_function get_dynamic_id) +{ + tuples::get<kdynamic_id>(*demand_type(static_id)) = get_dynamic_id; +} + +}}} // namespace boost::python::objects diff --git a/src/boost/libs/python/src/object/iterator.cpp b/src/boost/libs/python/src/object/iterator.cpp new file mode 100644 index 000000000..3f6c4adac --- /dev/null +++ b/src/boost/libs/python/src/object/iterator.cpp @@ -0,0 +1,39 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/object/iterator_core.hpp> +#include <boost/python/object/function_object.hpp> +#include <boost/bind.hpp> +#include <boost/mpl/vector/vector10.hpp> + +namespace boost { namespace python { namespace objects { + +namespace +{ + PyObject* identity(PyObject* args_, PyObject*) + { + PyObject* x = PyTuple_GET_ITEM(args_,0); + Py_INCREF(x); + return x; + } +} + +BOOST_PYTHON_DECL object const& identity_function() +{ + static object result( + function_object( + py_function(&identity, mpl::vector2<PyObject*,PyObject*>()) + ) + ); + return result; +} + +void stop_iteration_error() +{ + PyErr_SetObject(PyExc_StopIteration, Py_None); + throw_error_already_set(); +} + +}}} // namespace boost::python::objects diff --git a/src/boost/libs/python/src/object/life_support.cpp b/src/boost/libs/python/src/object/life_support.cpp new file mode 100644 index 000000000..b7e9aa861 --- /dev/null +++ b/src/boost/libs/python/src/object/life_support.cpp @@ -0,0 +1,121 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/object/life_support.hpp> +#include <boost/python/detail/none.hpp> +#include <boost/python/refcount.hpp> + +namespace boost { namespace python { namespace objects { + +struct life_support +{ + PyObject_HEAD + PyObject* patient; +}; + +extern "C" +{ + static void + life_support_dealloc(PyObject* self) + { + Py_XDECREF(((life_support*)self)->patient); + self->ob_type->tp_free(self); + } + + static PyObject * + life_support_call(PyObject *self, PyObject *arg, PyObject * /*kw*/) + { + // Let the patient die now + Py_XDECREF(((life_support*)self)->patient); + ((life_support*)self)->patient = 0; + // Let the weak reference die. This probably kills us. + Py_XDECREF(PyTuple_GET_ITEM(arg, 0)); + return ::boost::python::detail::none(); + } +} + +PyTypeObject life_support_type = { + PyVarObject_HEAD_INIT(NULL, 0)//(&PyType_Type) + const_cast<char*>("Boost.Python.life_support"), + sizeof(life_support), + 0, + life_support_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, //(reprfunc)func_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + life_support_call, /* tp_call */ + 0, /* tp_str */ + 0, // PyObject_GenericGetAttr, /* tp_getattro */ + 0, // PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT /* | Py_TPFLAGS_HAVE_GC */,/* tp_flags */ + 0, /* tp_doc */ + 0, // (traverseproc)func_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, //offsetof(PyLife_SupportObject, func_weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, // func_memberlist, /* tp_members */ + 0, //func_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, //offsetof(PyLife_SupportObject, func_dict), /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +PyObject* make_nurse_and_patient(PyObject* nurse, PyObject* patient) +{ + if (nurse == Py_None || nurse == patient) + return nurse; + + if (Py_TYPE(&life_support_type) == 0) + { + Py_TYPE(&life_support_type) = &PyType_Type; + PyType_Ready(&life_support_type); + } + + life_support* system = PyObject_New(life_support, &life_support_type); + if (!system) + return 0; + + system->patient = 0; + + // We're going to leak this reference, but don't worry; the + // life_support system decrements it when the nurse dies. + PyObject* weakref = PyWeakref_NewRef(nurse, (PyObject*)system); + + // weakref has either taken ownership, or we have to release it + // anyway + Py_DECREF(system); + if (!weakref) + return 0; + + system->patient = patient; + Py_XINCREF(patient); // hang on to the patient until death + return weakref; +} + +}}} // namespace boost::python::objects diff --git a/src/boost/libs/python/src/object/pickle_support.cpp b/src/boost/libs/python/src/object/pickle_support.cpp new file mode 100644 index 000000000..428c07b6c --- /dev/null +++ b/src/boost/libs/python/src/object/pickle_support.cpp @@ -0,0 +1,78 @@ +// (C) Copyright R.W. Grosse-Kunstleve 2002. +// 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 <boost/python/make_function.hpp> +#include <boost/python/object/class.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/list.hpp> +#include <boost/python/dict.hpp> +#include <boost/python/str.hpp> + +namespace boost { namespace python { + +namespace { + + tuple instance_reduce(object instance_obj) + { + list result; + object instance_class(instance_obj.attr("__class__")); + result.append(instance_class); + object none; + if (!getattr(instance_obj, "__safe_for_unpickling__", none)) + { + str type_name(getattr(instance_class, "__name__")); + str module_name(getattr(instance_class, "__module__", object(""))); + if (module_name) + module_name += "."; + + PyErr_SetObject( + PyExc_RuntimeError, + ( "Pickling of \"%s\" instances is not enabled" + " (http://www.boost.org/libs/python/doc/v2/pickle.html)" + % (module_name+type_name)).ptr() + ); + + throw_error_already_set(); + } + object getinitargs = getattr(instance_obj, "__getinitargs__", none); + tuple initargs; + if (!getinitargs.is_none()) { + initargs = tuple(getinitargs()); + } + result.append(initargs); + object getstate = getattr(instance_obj, "__getstate__", none); + object instance_dict = getattr(instance_obj, "__dict__", none); + long len_instance_dict = 0; + if (!instance_dict.is_none()) { + len_instance_dict = len(instance_dict); + } + if (!getstate.is_none()) { + if (len_instance_dict > 0) { + object getstate_manages_dict = getattr( + instance_obj, "__getstate_manages_dict__", none); + if (getstate_manages_dict.is_none()) { + PyErr_SetString(PyExc_RuntimeError, + "Incomplete pickle support" + " (__getstate_manages_dict__ not set)"); + throw_error_already_set(); + } + } + result.append(getstate()); + } + else if (len_instance_dict > 0) { + result.append(instance_dict); + } + return tuple(result); + } + +} // namespace + +object const& make_instance_reduce_function() +{ + static object result(&instance_reduce); + return result; +} + +}} // namespace boost::python diff --git a/src/boost/libs/python/src/object/stl_iterator.cpp b/src/boost/libs/python/src/object/stl_iterator.cpp new file mode 100644 index 000000000..e32d32145 --- /dev/null +++ b/src/boost/libs/python/src/object/stl_iterator.cpp @@ -0,0 +1,48 @@ +// Copyright Eric Niebler 2005. +// 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) +// +// Credits: +// Andreas Kl\:ockner for fixing increment() to handle +// error conditions. + +#include <boost/python/object.hpp> +#include <boost/python/handle.hpp> +#include <boost/python/object/stl_iterator_core.hpp> + +namespace boost { namespace python { namespace objects +{ + +stl_input_iterator_impl::stl_input_iterator_impl() + : it_() + , ob_() +{ +} + +stl_input_iterator_impl::stl_input_iterator_impl(boost::python::object const &ob) + : it_(ob.attr("__iter__")()) + , ob_() +{ + this->increment(); +} + +void stl_input_iterator_impl::increment() +{ + this->ob_ = boost::python::handle<>( + boost::python::allow_null(PyIter_Next(this->it_.ptr()))); + if (PyErr_Occurred()) + throw boost::python::error_already_set(); +} + +bool stl_input_iterator_impl::equal(stl_input_iterator_impl const &that) const +{ + return !this->ob_ == !that.ob_; +} + +boost::python::handle<> const &stl_input_iterator_impl::current() const +{ + return this->ob_; +} + +}}} // namespace boost::python::objects diff --git a/src/boost/libs/python/src/object_operators.cpp b/src/boost/libs/python/src/object_operators.cpp new file mode 100644 index 000000000..b993245fe --- /dev/null +++ b/src/boost/libs/python/src/object_operators.cpp @@ -0,0 +1,85 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/object_operators.hpp> +#include <boost/python/detail/raw_pyobject.hpp> + +namespace boost { namespace python { namespace api { + +# define BOOST_PYTHON_COMPARE_OP(op, opid) \ +BOOST_PYTHON_DECL object operator op(object const& l, object const& r) \ +{ \ + return object( \ + detail::new_reference( \ + PyObject_RichCompare( \ + l.ptr(), r.ptr(), opid)) \ + ); \ +} +BOOST_PYTHON_COMPARE_OP(>, Py_GT) +BOOST_PYTHON_COMPARE_OP(>=, Py_GE) +BOOST_PYTHON_COMPARE_OP(<, Py_LT) +BOOST_PYTHON_COMPARE_OP(<=, Py_LE) +BOOST_PYTHON_COMPARE_OP(==, Py_EQ) +BOOST_PYTHON_COMPARE_OP(!=, Py_NE) +# undef BOOST_PYTHON_COMPARE_OP + + +#define BOOST_PYTHON_BINARY_OPERATOR(op, name) \ +BOOST_PYTHON_DECL object operator op(object const& l, object const& r) \ +{ \ + return object( \ + detail::new_reference( \ + PyNumber_##name(l.ptr(), r.ptr())) \ + ); \ +} + +BOOST_PYTHON_BINARY_OPERATOR(+, Add) +BOOST_PYTHON_BINARY_OPERATOR(-, Subtract) +BOOST_PYTHON_BINARY_OPERATOR(*, Multiply) +#if PY_VERSION_HEX >= 0x03000000 +// We choose FloorDivide instead of TrueDivide to keep the semantic +// conform with C/C++'s '/' operator +BOOST_PYTHON_BINARY_OPERATOR(/, FloorDivide) +#else +BOOST_PYTHON_BINARY_OPERATOR(/, Divide) +#endif +BOOST_PYTHON_BINARY_OPERATOR(%, Remainder) +BOOST_PYTHON_BINARY_OPERATOR(<<, Lshift) +BOOST_PYTHON_BINARY_OPERATOR(>>, Rshift) +BOOST_PYTHON_BINARY_OPERATOR(&, And) +BOOST_PYTHON_BINARY_OPERATOR(^, Xor) +BOOST_PYTHON_BINARY_OPERATOR(|, Or) +#undef BOOST_PYTHON_BINARY_OPERATOR + +#define BOOST_PYTHON_INPLACE_OPERATOR(op, name) \ +BOOST_PYTHON_DECL object& operator op##=(object& l, object const& r) \ +{ \ + return l = object( \ + (detail::new_reference) \ + PyNumber_InPlace##name(l.ptr(), r.ptr())); \ +} + +BOOST_PYTHON_INPLACE_OPERATOR(+, Add) +BOOST_PYTHON_INPLACE_OPERATOR(-, Subtract) +BOOST_PYTHON_INPLACE_OPERATOR(*, Multiply) +#if PY_VERSION_HEX >= 0x03000000 +// Same reason as above for choosing FloorDivide instead of TrueDivide +BOOST_PYTHON_INPLACE_OPERATOR(/, FloorDivide) +#else +BOOST_PYTHON_INPLACE_OPERATOR(/, Divide) +#endif +BOOST_PYTHON_INPLACE_OPERATOR(%, Remainder) +BOOST_PYTHON_INPLACE_OPERATOR(<<, Lshift) +BOOST_PYTHON_INPLACE_OPERATOR(>>, Rshift) +BOOST_PYTHON_INPLACE_OPERATOR(&, And) +BOOST_PYTHON_INPLACE_OPERATOR(^, Xor) +BOOST_PYTHON_INPLACE_OPERATOR(|, Or) +#undef BOOST_PYTHON_INPLACE_OPERATOR + +object::object(handle<> const& x) + : object_base(python::incref(python::expect_non_null(x.get()))) +{} + +}}} // namespace boost::python diff --git a/src/boost/libs/python/src/object_protocol.cpp b/src/boost/libs/python/src/object_protocol.cpp new file mode 100644 index 000000000..95c8c73ee --- /dev/null +++ b/src/boost/libs/python/src/object_protocol.cpp @@ -0,0 +1,197 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/object_protocol.hpp> +#include <boost/python/errors.hpp> +#include <boost/python/object.hpp> +#include <boost/python/ssize_t.hpp> + +namespace boost { namespace python { namespace api { + +BOOST_PYTHON_DECL object getattr(object const& target, object const& key) +{ + return object(detail::new_reference(PyObject_GetAttr(target.ptr(), key.ptr()))); +} + +BOOST_PYTHON_DECL object getattr(object const& target, object const& key, object const& default_) +{ + PyObject* result = PyObject_GetAttr(target.ptr(), key.ptr()); + if (result == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) + { + PyErr_Clear(); + return default_; + } + return object(detail::new_reference(result)); +} + +BOOST_PYTHON_DECL void setattr(object const& target, object const& key, object const& value) +{ + if (PyObject_SetAttr(target.ptr(), key.ptr(), value.ptr()) == -1) + throw_error_already_set(); +} + +BOOST_PYTHON_DECL void delattr(object const& target, object const& key) +{ + if (PyObject_DelAttr(target.ptr(), key.ptr()) == -1) + throw_error_already_set(); +} + +BOOST_PYTHON_DECL object getattr(object const& target, char const* key) +{ + return object( + detail::new_reference( + PyObject_GetAttrString(target.ptr(), const_cast<char*>(key)) + )); +} + +BOOST_PYTHON_DECL object getattr(object const& target, char const* key, object const& default_) +{ + PyObject* result = PyObject_GetAttrString(target.ptr(), const_cast<char*>(key)); + if (result == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) + { + PyErr_Clear(); + return default_; + } + return object(detail::new_reference(result)); + +} +BOOST_PYTHON_DECL void setattr(object const& target, char const* key, object const& value) +{ + if (PyObject_SetAttrString( + target.ptr(), const_cast<char*>(key), value.ptr()) == -1 + ) + { + throw_error_already_set(); + } +} + +BOOST_PYTHON_DECL void delattr(object const& target, char const* key) +{ + if (PyObject_DelAttrString( + target.ptr(), const_cast<char*>(key)) == -1 + ) + { + throw_error_already_set(); + } +} + +BOOST_PYTHON_DECL object getitem(object const& target, object const& key) +{ + return object(detail::new_reference( + PyObject_GetItem(target.ptr(), key.ptr()))); +} + +BOOST_PYTHON_DECL void setitem(object const& target, object const& key, object const& value) +{ + if (PyObject_SetItem(target.ptr(), key.ptr(), value.ptr()) == -1) + throw_error_already_set(); +} + +BOOST_PYTHON_DECL void delitem(object const& target, object const& key) +{ + if (PyObject_DelItem(target.ptr(), key.ptr()) == -1) + throw_error_already_set(); +} + +namespace // slicing code copied directly out of the Python implementation +{ + #undef ISINT + #define ISINT(x) ((x) == NULL || PyInt_Check(x) || PyLong_Check(x)) + + static PyObject * + apply_slice(PyObject *u, PyObject *v, PyObject *w) /* return u[v:w] */ + { +#if PY_VERSION_HEX < 0x03000000 + PyTypeObject *tp = u->ob_type; + PySequenceMethods *sq = tp->tp_as_sequence; + + if (sq && sq->sq_slice && ISINT(v) && ISINT(w)) { + ssize_t ilow = 0, ihigh = ssize_t_max; + if (!_PyEval_SliceIndex(v, &ilow)) + return NULL; + if (!_PyEval_SliceIndex(w, &ihigh)) + return NULL; + return PySequence_GetSlice(u, ilow, ihigh); + } + else +#endif + { + PyObject *slice = PySlice_New(v, w, NULL); + if (slice != NULL) { + PyObject *res = PyObject_GetItem(u, slice); + Py_DECREF(slice); + return res; + } + else + return NULL; + } + } + + static int + assign_slice(PyObject *u, PyObject *v, PyObject *w, PyObject *x) + /* u[v:w] = x */ + { +#if PY_VERSION_HEX < 0x03000000 + PyTypeObject *tp = u->ob_type; + PySequenceMethods *sq = tp->tp_as_sequence; + + if (sq && sq->sq_slice && ISINT(v) && ISINT(w)) { + ssize_t ilow = 0, ihigh = ssize_t_max; + if (!_PyEval_SliceIndex(v, &ilow)) + return -1; + if (!_PyEval_SliceIndex(w, &ihigh)) + return -1; + if (x == NULL) + return PySequence_DelSlice(u, ilow, ihigh); + else + return PySequence_SetSlice(u, ilow, ihigh, x); + } + else +#endif + { + PyObject *slice = PySlice_New(v, w, NULL); + if (slice != NULL) { + int res; + if (x != NULL) + res = PyObject_SetItem(u, slice, x); + else + res = PyObject_DelItem(u, slice); + Py_DECREF(slice); + return res; + } + else + return -1; + } + } +} + +BOOST_PYTHON_DECL object getslice(object const& target, handle<> const& begin, handle<> const& end) +{ + return object( + detail::new_reference( + apply_slice(target.ptr(), begin.get(), end.get()))); +} + +BOOST_PYTHON_DECL void setslice(object const& target, handle<> const& begin, handle<> const& end, object const& value) +{ + if (assign_slice( + target.ptr(), begin.get(), end.get(), value.ptr()) == -1 + ) + { + throw_error_already_set(); + } +} + +BOOST_PYTHON_DECL void delslice(object const& target, handle<> const& begin, handle<> const& end) +{ + if (assign_slice( + target.ptr(), begin.get(), end.get(), 0) == -1 + ) + { + throw_error_already_set(); + } +} + +}}} // namespace boost::python::api diff --git a/src/boost/libs/python/src/slice.cpp b/src/boost/libs/python/src/slice.cpp new file mode 100644 index 000000000..ee55f9484 --- /dev/null +++ b/src/boost/libs/python/src/slice.cpp @@ -0,0 +1,37 @@ +#include "boost/python/slice.hpp" + +// Copyright (c) 2004 Jonathan Brandmeyer +// Use, modification and distribution are subject to 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) + + +namespace boost { namespace python { namespace detail { + +slice_base::slice_base(PyObject* start, PyObject* stop, PyObject* step) + : object(detail::new_reference( PySlice_New(start, stop, step))) +{ +} + +object +slice_base::start() const +{ + return object( detail::borrowed_reference( + ((PySliceObject*)this->ptr())->start)); +} + +object +slice_base::stop() const +{ + return object( detail::borrowed_reference( + ((PySliceObject*)this->ptr())->stop)); +} + +object +slice_base::step() const +{ + return object( detail::borrowed_reference( + ((PySliceObject*)this->ptr())->step)); +} + +} } } // !namespace boost::python::detail diff --git a/src/boost/libs/python/src/str.cpp b/src/boost/libs/python/src/str.cpp new file mode 100644 index 000000000..5122f7f57 --- /dev/null +++ b/src/boost/libs/python/src/str.cpp @@ -0,0 +1,419 @@ +// Copyright David Abrahams 2004. 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 <boost/python/str.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/ssize_t.hpp> + +namespace boost { namespace python { namespace detail { + +detail::new_reference str_base::call(object const& arg_) +{ + return (detail::new_reference)PyObject_CallFunction( +#if PY_VERSION_HEX >= 0x03000000 + (PyObject*)&PyUnicode_Type, +#else + (PyObject*)&PyString_Type, +#endif + const_cast<char*>("(O)"), + arg_.ptr()); +} + +str_base::str_base() + : object(detail::new_reference( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromString("") +#else + ::PyString_FromString("") +#endif + )) +{} + +str_base::str_base(const char* s) + : object(detail::new_reference( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromString(s) +#else + ::PyString_FromString(s) +#endif + )) +{} + +namespace { + + ssize_t str_size_as_py_ssize_t(std::size_t n) + { + if (n > static_cast<std::size_t>(ssize_t_max)) + { + throw std::range_error("str size > ssize_t_max"); + } + return static_cast<ssize_t>(n); + } + +} // namespace <anonymous> + +str_base::str_base(char const* start, char const* finish) + : object( + detail::new_reference( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromStringAndSize +#else + ::PyString_FromStringAndSize +#endif + (start, str_size_as_py_ssize_t(finish - start)) + ) + ) +{} + +str_base::str_base(char const* start, std::size_t length) // new str + : object( + detail::new_reference( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromStringAndSize +#else + ::PyString_FromStringAndSize +#endif + ( start, str_size_as_py_ssize_t(length) ) + ) + ) +{} + +str_base::str_base(object_cref other) + : object(str_base::call(other)) +{} + +#define BOOST_PYTHON_FORMAT_OBJECT(z, n, data) "O" +#define BOOST_PYTHON_OBJECT_PTR(z, n, data) , x##n .ptr() + +#define BOOST_PYTHON_DEFINE_STR_METHOD(name, arity) \ +str str_base:: name ( BOOST_PP_ENUM_PARAMS(arity, object_cref x) ) const \ +{ \ + return str(new_reference( \ + expect_non_null( \ + PyObject_CallMethod( \ + this->ptr(), const_cast<char*>( #name ), \ + const_cast<char*>( \ + "(" BOOST_PP_REPEAT(arity, BOOST_PYTHON_FORMAT_OBJECT, _) ")") \ + BOOST_PP_REPEAT_1(arity, BOOST_PYTHON_OBJECT_PTR, _))))); \ +} + +BOOST_PYTHON_DEFINE_STR_METHOD(capitalize, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(center, 1) + +long str_base::count(object_cref sub) const +{ + return extract<long>(this->attr("count")(sub)); +} + +long str_base::count(object_cref sub, object_cref start) const +{ + return extract<long>(this->attr("count")(sub,start)); +} + +long str_base::count(object_cref sub, object_cref start, object_cref end) const +{ + return extract<long>(this->attr("count")(sub,start,end)); +} + +#if PY_VERSION_HEX < 0x03000000 +object str_base::decode() const +{ + return this->attr("decode")(); +} + +object str_base::decode(object_cref encoding) const +{ + return this->attr("decode")(encoding); +} + +object str_base::decode(object_cref encoding, object_cref errors) const +{ + return this->attr("decode")(encoding,errors); +} +#endif + +object str_base::encode() const +{ + return this->attr("encode")(); +} + +object str_base::encode(object_cref encoding) const +{ + return this->attr("encode")(encoding); +} + +object str_base::encode(object_cref encoding, object_cref errors) const +{ + return this->attr("encode")(encoding,errors); +} + + +#if PY_VERSION_HEX >= 0x03000000 + #define _BOOST_PYTHON_ASLONG PyLong_AsLong +#else + #define _BOOST_PYTHON_ASLONG PyInt_AsLong +#endif + +bool str_base::endswith(object_cref suffix) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("endswith")(suffix).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::endswith(object_cref suffix, object_cref start) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("endswith")(suffix,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::endswith(object_cref suffix, object_cref start, object_cref end) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("endswith")(suffix,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +BOOST_PYTHON_DEFINE_STR_METHOD(expandtabs, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(expandtabs, 1) + +long str_base::find(object_cref sub) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("find")(sub).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::find(object_cref sub, object_cref start) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("find")(sub,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::find(object_cref sub, object_cref start, object_cref end) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("find")(sub,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::index(object_cref sub) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("index")(sub).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::index(object_cref sub, object_cref start) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("index")(sub,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::index(object_cref sub, object_cref start, object_cref end) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("index")(sub,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::isalnum() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("isalnum")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::isalpha() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("isalpha")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::isdigit() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("isdigit")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::islower() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("islower")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::isspace() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("isspace")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::istitle() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("istitle")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::isupper() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("isupper")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +BOOST_PYTHON_DEFINE_STR_METHOD(join, 1) +BOOST_PYTHON_DEFINE_STR_METHOD(ljust, 1) +BOOST_PYTHON_DEFINE_STR_METHOD(lower, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(lstrip, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(replace, 2) +BOOST_PYTHON_DEFINE_STR_METHOD(replace, 3) + +long str_base::rfind(object_cref sub) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rfind")(sub).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::rfind(object_cref sub, object_cref start) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rfind")(sub,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::rfind(object_cref sub, object_cref start, object_cref end) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rfind")(sub,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::rindex(object_cref sub) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rindex")(sub).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::rindex(object_cref sub, object_cref start) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rindex")(sub,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::rindex(object_cref sub, object_cref start, object_cref end) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rindex")(sub,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +BOOST_PYTHON_DEFINE_STR_METHOD(rjust, 1) +BOOST_PYTHON_DEFINE_STR_METHOD(rstrip, 0) + +list str_base::split() const +{ + return list(this->attr("split")()); +} + +list str_base::split(object_cref sep) const +{ + return list(this->attr("split")(sep)); +} + +list str_base::split(object_cref sep, object_cref maxsplit) const +{ + return list(this->attr("split")(sep,maxsplit)); +} + +list str_base::splitlines() const +{ + return list(this->attr("splitlines")()); +} + +list str_base::splitlines(object_cref keepends) const +{ + return list(this->attr("splitlines")(keepends)); +} + +bool str_base::startswith(object_cref prefix) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("startswith")(prefix).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::startswith(object_cref prefix, object_cref start) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("startswith")(prefix,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::startswith(object_cref prefix, object_cref start, object_cref end) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("startswith")(prefix,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +#undef _BOOST_PYTHON_ASLONG + +BOOST_PYTHON_DEFINE_STR_METHOD(strip, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(swapcase, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(title, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(translate, 1) +BOOST_PYTHON_DEFINE_STR_METHOD(translate, 2) +BOOST_PYTHON_DEFINE_STR_METHOD(upper, 0) + +static struct register_str_pytype_ptr +{ + register_str_pytype_ptr() + { + const_cast<converter::registration &>( + converter::registry::lookup(boost::python::type_id<boost::python::str>()) + ) +#if PY_VERSION_HEX >= 0x03000000 + .m_class_object = &PyUnicode_Type; +#else + .m_class_object = &PyString_Type; +#endif + } +}register_str_pytype_ptr_; + +}}} // namespace boost::python diff --git a/src/boost/libs/python/src/tuple.cpp b/src/boost/libs/python/src/tuple.cpp new file mode 100644 index 000000000..6719713b7 --- /dev/null +++ b/src/boost/libs/python/src/tuple.cpp @@ -0,0 +1,35 @@ +// Copyright David Abrahams 2004. +// 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 <boost/python/tuple.hpp> + +namespace boost { namespace python { namespace detail { + +detail::new_reference tuple_base::call(object const& arg_) +{ + return (detail::new_reference)PyObject_CallFunction( + (PyObject*)&PyTuple_Type, const_cast<char*>("(O)"), + arg_.ptr()); +} + +tuple_base::tuple_base() + : object(detail::new_reference(PyTuple_New(0))) +{} + +tuple_base::tuple_base(object_cref sequence) + : object(call(sequence)) +{} + +static struct register_tuple_pytype_ptr +{ + register_tuple_pytype_ptr() + { + const_cast<converter::registration &>( + converter::registry::lookup(boost::python::type_id<boost::python::tuple>()) + ).m_class_object = &PyTuple_Type; + } +}register_tuple_pytype_ptr_; + + +}}} // namespace boost::python diff --git a/src/boost/libs/python/src/wrapper.cpp b/src/boost/libs/python/src/wrapper.cpp new file mode 100644 index 000000000..f8feaef94 --- /dev/null +++ b/src/boost/libs/python/src/wrapper.cpp @@ -0,0 +1,66 @@ +// Copyright David Abrahams 2004. 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 <boost/python/wrapper.hpp> + +namespace boost { namespace python { + +namespace detail +{ + override wrapper_base::get_override( + char const* name + , PyTypeObject* class_object + ) const + { + if (this->m_self) + { + if (handle<> m = handle<>( + python::allow_null( + ::PyObject_GetAttrString( + this->m_self, const_cast<char*>(name)))) + ) + { + PyObject* borrowed_f = 0; + + if ( + PyMethod_Check(m.get()) + && ((PyMethodObject*)m.get())->im_self == this->m_self + && class_object->tp_dict != 0 + ) + { + borrowed_f = ::PyDict_GetItemString( + class_object->tp_dict, const_cast<char*>(name)); + + + } + if (borrowed_f != ((PyMethodObject*)m.get())->im_func) + return override(m); + } + } + return override(handle<>(detail::none())); + } +} + +#if 0 +namespace converter +{ + PyObject* BOOST_PYTHON_DECL do_polymorphic_ref_to_python( + python::detail::wrapper_base const volatile* x, type_info src + ) + { + if (x == 0) + { + ::PyErr_Format( + PyExc_TypeError + , "Attempting to returning pointer or reference to instance of %s\n" + "for which no corresponding Python object exists. Wrap this function" + "with a return return value policy" + ) + } + } + +} +#endif + +}} // namespace boost::python::detail diff --git a/src/boost/libs/python/test/Jamfile b/src/boost/libs/python/test/Jamfile new file mode 100644 index 000000000..9a5c75695 --- /dev/null +++ b/src/boost/libs/python/test/Jamfile @@ -0,0 +1,257 @@ +# 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) + +import python ; +import os ; +import ../../config/checks/config : requires ; + +lib socket ; + +use-project /boost/python : ../build ; +project /boost/python/test + : requirements + <toolset>gcc:<cxxflags>-Wextra + <target-os>qnxnto:<library>socket + ; + +local PY = ; +if [ python.configured ] +{ + PY = /python//python ; +} + +rule py-run ( sources * : input-file ? ) +{ + return [ run $(sources) /boost/python//boost_python $(PY) + : # args + : $(input-file) + : #requirements + <define>BOOST_PYTHON_SUPPRESS_REGISTRY_INITIALIZATION + + ] ; +} + +rule py-compile ( sources * ) +{ + return [ compile $(sources) /boost/python//boost_python ] ; +} + +rule py-compile-fail ( sources * ) +{ + return [ compile-fail $(sources) /boost/python//boost_python ] ; +} + +rule require-windows ( properties * ) +{ + if ! <target-os>windows in $(properties) + { + return <build>no ; + } +} + +if [ python.configured ] +{ +test-suite python + : + + [ + run exec.cpp /boost/python//boost_python/<link>static $(PY) + : # program args + : exec.py # input files + : # requirements + : # target-name + ] + + [ + run exec.cpp ../build//boost_python/<link>shared /python//python + : # program args + : exec.py + : # requirements + : exec-dynamic # target-name + ] + +# [ +# run import_.cpp ../build//boost_python /python//python +# : # program args +# : import_.py # input files +# : # requirements +# : # target-name +# ] + +[ +bpl-test crossmod_exception + : crossmod_exception.py crossmod_exception_a.cpp crossmod_exception_b.cpp +] + +[ bpl-test injected ] +[ bpl-test properties ] +[ bpl-test return_arg ] +[ bpl-test staticmethod ] +[ bpl-test boost_shared_ptr ] +[ bpl-test shared_ptr + : # sources + : [ requires cxx11_smart_ptr ] +] +[ bpl-test enable_shared_from_this ] +[ bpl-test andreas_beyer ] +[ bpl-test wrapper_held_type ] + +[ bpl-test polymorphism2_auto_ptr + : polymorphism2_auto_ptr.py polymorphism2.py polymorphism2_auto_ptr.cpp + : [ requires auto_ptr ] +] + +[ bpl-test polymorphism ] +[ bpl-test polymorphism2 ] + +[ bpl-test auto_ptr + : # files + : [ requires auto_ptr ] +] + +[ bpl-test minimal ] +[ bpl-test args ] +[ bpl-test raw_ctor ] +[ bpl-test enum : test_enum.py enum_ext.cpp ] +[ bpl-test exception_translator ] +[ bpl-test pearu1 : test_cltree.py cltree.cpp ] +[ bpl-test try : newtest.py m1.cpp m2.cpp ] +[ bpl-test const_argument ] +[ bpl-test keywords : keywords.cpp keywords_test.py ] + + +[ python-extension builtin_converters_ext : builtin_converters.cpp /boost/python//boost_python ] +[ bpl-test builtin_converters : test_builtin_converters.py builtin_converters_ext ] + + [ bpl-test test_pointer_adoption ] + [ bpl-test operators ] + [ bpl-test operators_wrapper ] + [ bpl-test callbacks ] + [ bpl-test defaults ] + +[ bpl-test object ] +[ bpl-test class ] +[ bpl-test list ] +[ bpl-test long ] +[ bpl-test dict ] +[ bpl-test tuple ] +[ bpl-test str ] +[ bpl-test slice ] + +[ bpl-test virtual_functions ] +[ bpl-test back_reference ] +[ bpl-test implicit ] +[ bpl-test data_members ] + +[ bpl-test ben_scott1 ] + +[ bpl-test bienstman1 ] +[ bpl-test bienstman2 ] +[ bpl-test bienstman3 ] + +[ bpl-test multi_arg_constructor + : # files + : # requirements + # A bug in the Win32 intel compilers causes compilation of one of our + # tests to take forever when debug symbols are enabled. This rule + # turns them off when added to the requirements section + <toolset>intel-win:<debug-symbols>off +] + +[ bpl-test iterator : iterator.py iterator.cpp input_iterator.cpp ] + +[ bpl-test stl_iterator : stl_iterator.py stl_iterator.cpp ] + +[ bpl-test extract ] + +[ +bpl-test crossmod_opaque + : crossmod_opaque.py crossmod_opaque_a.cpp crossmod_opaque_b.cpp +] +[ bpl-test opaque ] +[ bpl-test voidptr ] + +[ bpl-test pickle1 ] +[ bpl-test pickle2 ] +[ bpl-test pickle3 ] +[ bpl-test pickle4 ] + +[ bpl-test nested ] + +[ bpl-test docstring ] +[ bpl-test pytype_function ] + +[ bpl-test vector_indexing_suite ] + +[ bpl-test pointer_vector + : # files + : # requirements + # Turn off this test on HP CXX, as the test hangs when executing. + # Whenever the cause for the failure of the polymorphism test is found + # and fixed, this should be retested. + <toolset>hp_cxx:<build>no ] + +[ python-extension map_indexing_suite_ext + : map_indexing_suite.cpp int_map_indexing_suite.cpp a_map_indexing_suite.cpp + /boost/python//boost_python ] +[ bpl-test + map_indexing_suite : map_indexing_suite.py map_indexing_suite_ext ] + +[ run import_.cpp /boost/python//boost_python $(PY) : : import_.py ] + +# if $(TEST_BIENSTMAN_NON_BUGS) +# { +# bpl-test bienstman4 ; +# bpl-test bienstman5 ; +# } + +[ bpl-test calling_conventions : : <conditional>@require-windows ] +[ bpl-test calling_conventions_mf : : <conditional>@require-windows ] + +# --- unit tests of library components --- + +[ compile indirect_traits_test.cpp ] +[ run destroy_test.cpp ] +[ py-run pointer_type_id_test.cpp ] +[ py-run bases.cpp ] +[ run if_else.cpp ] +[ py-run pointee.cpp ] +[ run result.cpp ] + +[ compile string_literal.cpp ] +[ py-compile borrowed.cpp ] +[ py-compile object_manager.cpp ] +[ py-compile copy_ctor_mutates_rhs.cpp ] + +[ py-run upcast.cpp ] + +[ py-compile select_holder.cpp ] + +[ run select_from_python_test.cpp ../src/converter/type_id.cpp + : + : + : <define>BOOST_PYTHON_STATIC_LIB + <use>$(PY) + +] + + [ py-compile select_arg_to_python_test.cpp ] + +[ py-compile-fail ./raw_pyobject_fail1.cpp ] +[ py-compile-fail ./raw_pyobject_fail2.cpp ] +[ py-compile-fail ./as_to_python_function.cpp ] +[ py-compile-fail ./object_fail1.cpp ] + +# --- NumPy tests --- + +[ numpy-test numpy/dtype ] +[ numpy-test numpy/ufunc ] +[ numpy-test numpy/templates ] +[ numpy-test numpy/ndarray ] +[ numpy-test numpy/indexing ] +[ numpy-test numpy/shapes ] + + + ; +} diff --git a/src/boost/libs/python/test/a_map_indexing_suite.cpp b/src/boost/libs/python/test/a_map_indexing_suite.cpp new file mode 100644 index 000000000..07a0a6b97 --- /dev/null +++ b/src/boost/libs/python/test/a_map_indexing_suite.cpp @@ -0,0 +1,92 @@ +// Copyright Joel de Guzman 2004. 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 <boost/python/suite/indexing/map_indexing_suite.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/implicit.hpp> + +using namespace boost::python; + +struct A +{ + int value; + A() : value(0){}; + A(int v) : value(v) {}; +}; + +bool operator==(const A& v1, const A& v2) +{ + return (v1.value == v2.value); +} + +struct B +{ + A a; +}; + +// Converter from A to python int +struct AToPython +{ + static PyObject* convert(const A& s) + { + return boost::python::incref(boost::python::object((int)s.value).ptr()); + } +}; + +// Conversion from python int to A +struct AFromPython +{ + AFromPython() + { + boost::python::converter::registry::push_back( + &convertible, + &construct, + boost::python::type_id< A >()); + } + + static void* convertible(PyObject* obj_ptr) + { +#if PY_VERSION_HEX >= 0x03000000 + if (!PyLong_Check(obj_ptr)) return 0; +#else + if (!PyInt_Check(obj_ptr)) return 0; +#endif + return obj_ptr; + } + + static void construct( + PyObject* obj_ptr, + boost::python::converter::rvalue_from_python_stage1_data* data) + { + void* storage = ( + (boost::python::converter::rvalue_from_python_storage< A >*) + data)-> storage.bytes; + +#if PY_VERSION_HEX >= 0x03000000 + new (storage) A((int)PyLong_AsLong(obj_ptr)); +#else + new (storage) A((int)PyInt_AsLong(obj_ptr)); +#endif + data->convertible = storage; + } +}; + +void a_map_indexing_suite() +{ + + to_python_converter< A , AToPython >(); + AFromPython(); + + class_< std::map<int, A> >("AMap") + .def(map_indexing_suite<std::map<int, A>, true >()) + ; + + class_< B >("B") + .add_property("a", make_getter(&B::a, return_value_policy<return_by_value>()), + make_setter(&B::a, return_value_policy<return_by_value>())) + ; +} + + diff --git a/src/boost/libs/python/test/andreas_beyer.cpp b/src/boost/libs/python/test/andreas_beyer.cpp new file mode 100644 index 000000000..b28b15660 --- /dev/null +++ b/src/boost/libs/python/test/andreas_beyer.cpp @@ -0,0 +1,61 @@ +// 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) +#include <boost/python.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/shared_ptr.hpp> + +using namespace boost; + +class A : public enable_shared_from_this<A> { + public: + A() : val(0) {}; + int val; + typedef shared_ptr<A> A_ptr; + A_ptr self() { + A_ptr self; + self = shared_from_this(); + return self; + } + +}; + +class B { + public: + B() { + a = A::A_ptr(new A()); + } + void set(A::A_ptr _a) { + this->a = _a; + } + A::A_ptr get() { + return a; + } + A::A_ptr a; +}; + +template <class T> +void hold_python(shared_ptr<T>& x) +{ + x = python::extract<shared_ptr<T> >( python::object(x) ); +} + +A::A_ptr get_b_a(shared_ptr<B> b) +{ + hold_python(b->a); + return b->get(); +} + +BOOST_PYTHON_MODULE(andreas_beyer_ext) { + python::class_<A, noncopyable> ("A") + .def("self", &A::self) + .def_readwrite("val", &A::val) + ; + python::register_ptr_to_python< A::A_ptr >(); + + python::class_<B>("B") + .def("set", &B::set) +// .def("get", &B::get) + .def("get", get_b_a) + ; +} diff --git a/src/boost/libs/python/test/andreas_beyer.py b/src/boost/libs/python/test/andreas_beyer.py new file mode 100644 index 000000000..0c24969bd --- /dev/null +++ b/src/boost/libs/python/test/andreas_beyer.py @@ -0,0 +1,24 @@ +# Copyright David Abrahams 2004. 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) +''' + >>> from andreas_beyer_ext import * + >>> b=B() + >>> a=b.get() # let b create an A + >>> a2=b.get() + >>> assert id(a) == id(a2) +''' +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/args.cpp b/src/boost/libs/python/test/args.cpp new file mode 100644 index 000000000..592a8e505 --- /dev/null +++ b/src/boost/libs/python/test/args.cpp @@ -0,0 +1,99 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include "test_class.hpp" +#include <boost/python/def.hpp> +#include <boost/python/args.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/class.hpp> +#include <boost/python/overloads.hpp> +#include <boost/python/raw_function.hpp> +#include <boost/python/return_internal_reference.hpp> + +using namespace boost::python; + +#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) +# define make_tuple boost::python::make_tuple +#endif + +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) + +typedef test_class<> Y; + +struct X +{ + X(int a0 = 0, int a1 = 1) : inner0(a0), inner1(a1) {} + tuple f(int x = 1, double y = 4.25, char const* z = "wow") + { + return make_tuple(x, y, z); + } + + Y const& inner(bool n) const { return n ? inner1 : inner0; } + + Y inner0; + Y inner1; +}; + +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)); + +#if defined(BOOST_MSVC) && BOOST_MSVC <= 1200 + // MSVC6 gives a fatal error LNK1179: invalid or corrupt file: + // duplicate comdat error if we try to re-use the exact type of f + // here, so substitute long for int. + tuple (*f)(long,double,char const*) = 0; +#endif + def("f1", f, f_overloads("f1's docstring", args("x", "y", "z"))); + def("f2", f, f_overloads(args("x", "y", "z"))); + def("f3", f, f_overloads(args("x", "y", "z"), "f3's docstring")); + + class_<Y>("Y", init<int>(args("value"), "Y's docstring")) + .def("value", &Y::value) + .def("raw", raw_function(raw_func)) + ; + + class_<X>("X", "This is X's docstring", init<>(args("self"))) + .def(init<int, optional<int> >(args("self", "a0", "a1"))) + .def("f", &X::f + , "This is X.f's docstring" + , args("self","x", "y", "z")) + + // Just to prove that all the different argument combinations work + .def("inner0", &X::inner, return_internal_reference<>(), args("self", "n"), "docstring") + .def("inner1", &X::inner, return_internal_reference<>(), "docstring", args("self", "n")) + + .def("inner2", &X::inner, args("self", "n"), return_internal_reference<>(), "docstring") + .def("inner3", &X::inner, "docstring", return_internal_reference<>(), args("self", "n")) + + .def("inner4", &X::inner, args("self", "n"), "docstring", return_internal_reference<>()) + .def("inner5", &X::inner, "docstring", args("self", "n"), return_internal_reference<>()) + + .def("f1", &X::f, X_f_overloads(args("self", "x", "y", "z"))) + .def("f2", &X::f, X_f_overloads(args("self", "x", "y", "z"), "f2's docstring")) + .def("f2", &X::f, X_f_overloads(args("x", "y", "z"), "f2's docstring")) + ; + + def("inner", &X::inner, "docstring", args("self", "n"), return_internal_reference<>()); +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/args.py b/src/boost/libs/python/test/args.py new file mode 100644 index 000000000..e884c06be --- /dev/null +++ b/src/boost/libs/python/test/args.py @@ -0,0 +1,148 @@ +# Copyright David Abrahams 2004. 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) +from __future__ import print_function +""" +>>> from args_ext import * + +>>> raw(3, 4, foo = 'bar', baz = 42) +((3, 4), {'foo': 'bar', 'baz': 42}) + + Prove that we can handle empty keywords and non-keywords + +>>> raw(3, 4) +((3, 4), {}) + +>>> raw(foo = 'bar') +((), {'foo': 'bar'}) + +>>> f(x= 1, y = 3, z = 'hello') +(1, 3.0, 'hello') + +>>> f(z = 'hello', x = 3, y = 2.5) +(3, 2.5, 'hello') + +>>> f(1, z = 'hi', y = 3) +(1, 3.0, 'hi') + +>>> try: f(1, 2, 'hello', bar = 'baz') +... except TypeError: pass +... else: print('expected an exception: unknown keyword') + + + Exercise the functions using default stubs + +>>> f1(z = 'nix', y = .125, x = 2) +(2, 0.125, 'nix') +>>> f1(y = .125, x = 2) +(2, 0.125, 'wow') +>>> f1(x = 2) +(2, 4.25, 'wow') +>>> f1() +(1, 4.25, 'wow') + +>>> f2(z = 'nix', y = .125, x = 2) +(2, 0.125, 'nix') +>>> f2(y = .125, x = 2) +(2, 0.125, 'wow') +>>> f2(x = 2) +(2, 4.25, 'wow') +>>> f2() +(1, 4.25, 'wow') + +>>> f3(z = 'nix', y = .125, x = 2) +(2, 0.125, 'nix') +>>> f3(y = .125, x = 2) +(2, 0.125, 'wow') +>>> f3(x = 2) +(2, 4.25, 'wow') +>>> f3() +(1, 4.25, 'wow') + + Member function tests + +>>> q = X() +>>> q.f(x= 1, y = 3, z = 'hello') +(1, 3.0, 'hello') + +>>> q.f(z = 'hello', x = 3, y = 2.5) +(3, 2.5, 'hello') + +>>> q.f(1, z = 'hi', y = 3) +(1, 3.0, 'hi') + +>>> try: q.f(1, 2, 'hello', bar = 'baz') +... except TypeError: pass +... else: print('expected an exception: unknown keyword') + + Exercise member functions using default stubs + +>>> q.f1(z = 'nix', y = .125, x = 2) +(2, 0.125, 'nix') +>>> q.f1(y = .125, x = 2) +(2, 0.125, 'wow') +>>> q.f1(x = 2) +(2, 4.25, 'wow') +>>> q.f1() +(1, 4.25, 'wow') +>>> q.f2.__doc__.splitlines()[1] +'f2( (X)self [, (int)x [, (float)y [, (str)z]]]) -> tuple :' + +>>> q.f2.__doc__.splitlines()[2] +" f2's docstring" + +>>> X.f.__doc__.splitlines()[1:5] +['f( (X)self, (int)x, (float)y, (str)z) -> tuple :', " This is X.f's docstring", '', ' C++ signature :'] + +>>> xfuncs = (X.inner0, X.inner1, X.inner2, X.inner3, X.inner4, X.inner5) +>>> for f in xfuncs: +... print(f(q,1).value(), end=' ') +... print(f(q, n = 1).value(), end=' ') +... print(f(q, n = 0).value(), end=' ') +... print(f.__doc__.splitlines()[1:5]) +1 1 0 ['inner0( (X)self, (bool)n) -> Y :', ' docstring', '', ' C++ signature :'] +1 1 0 ['inner1( (X)self, (bool)n) -> Y :', ' docstring', '', ' C++ signature :'] +1 1 0 ['inner2( (X)self, (bool)n) -> Y :', ' docstring', '', ' C++ signature :'] +1 1 0 ['inner3( (X)self, (bool)n) -> Y :', ' docstring', '', ' C++ signature :'] +1 1 0 ['inner4( (X)self, (bool)n) -> Y :', ' docstring', '', ' C++ signature :'] +1 1 0 ['inner5( (X)self, (bool)n) -> Y :', ' docstring', '', ' C++ signature :'] + +>>> x = X(a1 = 44, a0 = 22) +>>> x.inner0(0).value() +22 +>>> x.inner0(1).value() +44 + +>>> x = X(a0 = 7) +>>> x.inner0(0).value() +7 +>>> x.inner0(1).value() +1 + +>>> inner(n = 1, self = q).value() +1 + +>>> y = Y(value = 33) +>>> y.raw(this = 1, that = 'the other')[1] +{'this': 1, 'that': 'the other'} + +""" +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print("running...") + import sys + status = run()[0] + if (status == 0): print("Done.") + import args_ext + help(args_ext) + sys.exit(status) + + + diff --git a/src/boost/libs/python/test/as_to_python_function.cpp b/src/boost/libs/python/test/as_to_python_function.cpp new file mode 100644 index 000000000..cc083890a --- /dev/null +++ b/src/boost/libs/python/test/as_to_python_function.cpp @@ -0,0 +1,13 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/converter/as_to_python_function.hpp> + +struct hopefully_illegal +{ + static PyObject* convert(int&); +}; + +PyObject* x = boost::python::converter::as_to_python_function<int, hopefully_illegal>::convert(0); diff --git a/src/boost/libs/python/test/auto_ptr.cpp b/src/boost/libs/python/test/auto_ptr.cpp new file mode 100644 index 000000000..0f61e96dc --- /dev/null +++ b/src/boost/libs/python/test/auto_ptr.cpp @@ -0,0 +1,90 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include "test_class.hpp" +#include <boost/python/class.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/def.hpp> +#include <boost/python/implicit.hpp> + +#include <boost/detail/workaround.hpp> + +#include <memory> + +using namespace boost::python; + +typedef test_class<> X; + +struct Y : X +{ + Y(int n) : X(n) {}; +}; + +int look(std::auto_ptr<X> const& x) +{ + return (x.get()) ? x->value() : -1; +} + +int steal(std::auto_ptr<X> x) +{ + return x->value(); +} + +int maybe_steal(std::auto_ptr<X>& x, bool doit) +{ + int n = x->value(); + if (doit) + x.release(); + return n; +} + +std::auto_ptr<X> make() +{ + return std::auto_ptr<X>(new X(77)); +} + +std::auto_ptr<X> callback(object f) +{ + std::auto_ptr<X> x(new X(77)); + return call<std::auto_ptr<X> >(f.ptr(), x); +} + +std::auto_ptr<X> extract_(object o) +{ + return extract<std::auto_ptr<X>&>(o) +#if BOOST_MSVC <= 1300 + () +#endif + ; +} + +BOOST_PYTHON_MODULE(auto_ptr_ext) +{ + class_<X, std::auto_ptr<X>, boost::noncopyable>("X", init<int>()) + .def("value", &X::value) + ; + + class_<Y, std::auto_ptr<Y>, bases<X>, boost::noncopyable>("Y", init<int>()) + ; + + // VC6 auto_ptrs do not have converting constructors +#if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, < 306) + scope().attr("broken_auto_ptr") = 1; +#else + scope().attr("broken_auto_ptr") = 0; + implicitly_convertible<std::auto_ptr<Y>, std::auto_ptr<X> >(); +#endif + + def("look", look); + def("steal", steal); + def("maybe_steal", maybe_steal); + def("make", make); + def("callback", callback); + def("extract", extract_); +} + +#include "module_tail.cpp" + diff --git a/src/boost/libs/python/test/auto_ptr.py b/src/boost/libs/python/test/auto_ptr.py new file mode 100644 index 000000000..12e977d06 --- /dev/null +++ b/src/boost/libs/python/test/auto_ptr.py @@ -0,0 +1,100 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from auto_ptr_ext import * +>>> x = X(42) +>>> x.value() +42 +>>> look(x), look(x) +(42, 42) + +>>> maybe_steal(x, 0) +42 +>>> look(x) +42 + +>>> maybe_steal(x, 1) +42 +>>> broken_auto_ptr and -1 or look(x) +-1 + +>>> x = X(69) +>>> steal(x) +69 +>>> broken_auto_ptr and -1 or look(x) +-1 + +>>> if not broken_auto_ptr: +... try: x.value() +... except TypeError: pass +... else: print('expected a TypeError exception') + +>>> x = make() +>>> look(x) +77 + +>>> z = callback(lambda z: z) +>>> z.value() +77 + +>>> extract(x).value() +77 + +# +# Test derived to base conversions +# + +>>> y = Y(42) +>>> y.value() +42 + +>>> try: maybe_steal(y, 0) +... except TypeError: pass +... else: print('expected a TypeError exception') + +>>> y.value() +42 + +>>> broken_auto_ptr and 42 or steal(y) +42 + +>>> if not broken_auto_ptr: +... try: y.value() +... except TypeError: pass +... else: print('expected a TypeError exception') + +>>> print(look.__doc__.splitlines()[1]) +look( (X)arg1) -> int : + +>>> print(steal.__doc__.splitlines()[1]) +steal( (X)arg1) -> int : + +>>> print(maybe_steal.__doc__.splitlines()[1]) +maybe_steal( (X)arg1, (bool)arg2) -> int : + +>>> print(make.__doc__.splitlines()[1]) +make() -> X : + +>>> print(callback.__doc__.splitlines()[1]) +callback( (object)arg1) -> X : + +>>> print(extract.__doc__.splitlines()[1]) +extract( (object)arg1) -> X : + +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/back_reference.cpp b/src/boost/libs/python/test/back_reference.cpp new file mode 100644 index 000000000..266ed2912 --- /dev/null +++ b/src/boost/libs/python/test/back_reference.cpp @@ -0,0 +1,112 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/has_back_reference.hpp> +#include <boost/python/back_reference.hpp> +#include <boost/ref.hpp> +#include <boost/utility.hpp> +#include <memory> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> +#include <boost/python/copy_const_reference.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/mpl/bool.hpp> + +// This test shows that a class can be wrapped "as itself" but also +// acquire a back-reference iff has_back_reference<> is appropriately +// specialized. +using namespace boost::python; + +struct X +{ + explicit X(int x) : x(x), magic(7654321) { ++counter; } + X(X const& rhs) : x(rhs.x), magic(7654321) { ++counter; } + virtual ~X() { BOOST_ASSERT(magic == 7654321); magic = 6666666; x = 9999; --counter; } + + void set(int _x) { BOOST_ASSERT(magic == 7654321); this->x = _x; } + int value() const { BOOST_ASSERT(magic == 7654321); return x; } + static int count() { return counter; } + private: + void operator=(X const&); + private: + int x; + long magic; + static int counter; +}; + +int X::counter; + +struct Y : X +{ + Y(PyObject* self, int x) : X(x), self(self) {} + Y(PyObject* self, Y const& rhs) : X(rhs), self(self) {} + private: + Y(Y const&); + PyObject* self; +}; + +struct Z : X +{ + Z(PyObject* self, int x) : X(x), self(self) {} + Z(PyObject* self, Z const& rhs) : X(rhs), self(self) {} + private: + Z(Z const&); + PyObject* self; +}; + +Y const& copy_Y(Y const& y) { return y; } +Z const& copy_Z(Z const& z) { return z; } + +namespace boost { namespace python +{ + template <> + struct has_back_reference<Y> + : mpl::true_ + { + }; + + template <> + struct has_back_reference<Z> + : mpl::true_ + { + }; +}} + +// prove that back_references get initialized with the right PyObject* +object y_identity(back_reference<Y const&> y) +{ + return y.source(); +} + +// prove that back_references contain the right value +bool y_equality(back_reference<Y const&> y1, Y const& y2) +{ + return &y1.get() == &y2; +} + +BOOST_PYTHON_MODULE(back_reference_ext) +{ + def("copy_Y", copy_Y, return_value_policy<copy_const_reference>()); + def("copy_Z", copy_Z, return_value_policy<copy_const_reference>()); + def("x_instances", &X::count); + + class_<Y>("Y", init<int>()) + .def("value", &Y::value) + .def("set", &Y::set) + ; + + class_<Z,std::auto_ptr<Z> >("Z", init<int>()) + .def("value", &Z::value) + .def("set", &Z::set) + ; + + def("y_identity", y_identity); + def("y_equality", y_equality); + +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/back_reference.py b/src/boost/libs/python/test/back_reference.py new file mode 100644 index 000000000..4a283a3e3 --- /dev/null +++ b/src/boost/libs/python/test/back_reference.py @@ -0,0 +1,37 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from back_reference_ext import * +>>> y = Y(3) +>>> z = Z(4) +>>> x_instances() +2 +>>> y2 = copy_Y(y) +>>> x_instances() +3 +>>> z2 = copy_Z(z) +>>> x_instances() +4 +>>> assert y_identity(y) is y +>>> y_equality(y, y) +1 + +>>> print(y_identity.__doc__.splitlines()[1]) +y_identity( (Y)arg1) -> object : +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/bases.cpp b/src/boost/libs/python/test/bases.cpp new file mode 100644 index 000000000..4e00f5448 --- /dev/null +++ b/src/boost/libs/python/test/bases.cpp @@ -0,0 +1,62 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/bases.hpp> +#include <boost/static_assert.hpp> +#include <boost/python/detail/type_traits.hpp> + +struct A; +struct B; + +template <class X, class Y, class Z> +struct choose_bases + : boost::python::detail::select_bases< + X + , typename boost::python::detail::select_bases< + Y + , typename boost::python::detail::select_bases<Z>::type + >::type> +{ + +}; + +int main() +{ + BOOST_STATIC_ASSERT((boost::python::detail::specifies_bases< + boost::python::bases<A,B> >::value)); + + BOOST_STATIC_ASSERT((!boost::python::detail::specifies_bases< + boost::python::bases<A,B>& >::value)); + + BOOST_STATIC_ASSERT((!boost::python::detail::specifies_bases< + void* >::value)); + + BOOST_STATIC_ASSERT((!boost::python::detail::specifies_bases< + int >::value)); + + BOOST_STATIC_ASSERT((!boost::python::detail::specifies_bases< + int[5] >::value)); + + typedef boost::python::detail::select_bases< + int + , boost::python::detail::select_bases<char*>::type > collected1; + + BOOST_STATIC_ASSERT((boost::python::detail::is_same<collected1::type,boost::python::bases<> >::value)); + BOOST_STATIC_ASSERT((boost::python::detail::is_same<choose_bases<int,char*,long>::type,boost::python::bases<> >::value)); + + typedef boost::python::detail::select_bases< + int + , boost::python::detail::select_bases< + boost::python::bases<A,B> + , boost::python::detail::select_bases< + A + >::type + >::type + > collected2; + + BOOST_STATIC_ASSERT((boost::python::detail::is_same<collected2::type,boost::python::bases<A,B> >::value)); + BOOST_STATIC_ASSERT((boost::python::detail::is_same<choose_bases<int,boost::python::bases<A,B>,long>::type,boost::python::bases<A,B> >::value)); + + return 0; +} diff --git a/src/boost/libs/python/test/ben_scott1.cpp b/src/boost/libs/python/test/ben_scott1.cpp new file mode 100644 index 000000000..5a675e230 --- /dev/null +++ b/src/boost/libs/python/test/ben_scott1.cpp @@ -0,0 +1,54 @@ +// Copyright David Abrahams 2004. 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 <boost/python.hpp> +#include <iostream> +using namespace boost::python; +using namespace boost; + +struct Product {}; +typedef shared_ptr<Product> ProductPtr; + + +struct Creator +{ + virtual ~Creator() {} + virtual ProductPtr create() = 0; +}; + + +struct Factory +{ + void reg(Creator* c) { mC = c; } + ProductPtr create() + { + std::cout << "Name: " << (typeid(*mC)).name() << std::endl; + return mC->create(); + } + +private: + Creator* mC; +}; + +struct CreatorWrap : public Creator +{ + CreatorWrap(PyObject* self) : mSelf(self) {} + ProductPtr create() { return call_method<ProductPtr>(mSelf, "create"); } + PyObject* mSelf; +}; + +BOOST_PYTHON_MODULE(ben_scott1_ext) +{ + class_<Product, ProductPtr>("Product"); + + class_<Creator, CreatorWrap, noncopyable>("Creator") + .def("create", &CreatorWrap::create) + ; + + class_<Factory>("Factory") + .def("reg", &Factory::reg, with_custodian_and_ward<1,2>()) + .def("create", &Factory::create) + ; +} + +#include "../test/module_tail.cpp" diff --git a/src/boost/libs/python/test/ben_scott1.py b/src/boost/libs/python/test/ben_scott1.py new file mode 100644 index 000000000..79130757a --- /dev/null +++ b/src/boost/libs/python/test/ben_scott1.py @@ -0,0 +1,17 @@ +# Copyright David Abrahams 2004. 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) +# This regression test checks that call_method<T>(...) where T is a +# non-reference, non-pointer type that happens to be held inside the +# result object (and thus is found as an lvalue) works. +from ben_scott1_ext import * + +class CreatorImpl(Creator): + def create(self): + return Product() + +factory = Factory() +c = CreatorImpl() +factory.reg(c) + +a = factory.create() diff --git a/src/boost/libs/python/test/bienstman1.cpp b/src/boost/libs/python/test/bienstman1.cpp new file mode 100644 index 000000000..dc0065784 --- /dev/null +++ b/src/boost/libs/python/test/bienstman1.cpp @@ -0,0 +1,40 @@ +// Copyright David Abrahams 2004. 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/reference_existing_object.hpp> +#include <boost/python/return_value_policy.hpp> + +struct A {}; + +struct V +{ + virtual ~V() {}; // silence compiler warningsa + virtual void f() = 0; + + const A* inside() {return &a;} + + A a; +}; + +const A* outside(const V& v) {return &v.a;} + +BOOST_PYTHON_MODULE(bienstman1_ext) +{ + using namespace boost::python; + using boost::shared_ptr; + using boost::python::return_value_policy; + using boost::python::reference_existing_object; + + class_<A>("A"); + + class_<V, boost::noncopyable>("V", no_init) + .def("inside", &V::inside, + return_value_policy<reference_existing_object>()) + .def("outside", outside, + return_value_policy<reference_existing_object>()) + ; +} + diff --git a/src/boost/libs/python/test/bienstman1.py b/src/boost/libs/python/test/bienstman1.py new file mode 100644 index 000000000..16dc47b2d --- /dev/null +++ b/src/boost/libs/python/test/bienstman1.py @@ -0,0 +1,23 @@ +# Copyright David Abrahams 2004. 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) +''' +# Try to reproduce a Numeric interaction bug if Numeric is installed. +>>> from bienstman1_ext import * +>>> try: from Numeric import * +... except: pass +''' +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/bienstman2.cpp b/src/boost/libs/python/test/bienstman2.cpp new file mode 100644 index 000000000..10f99923d --- /dev/null +++ b/src/boost/libs/python/test/bienstman2.cpp @@ -0,0 +1,28 @@ +// Copyright David Abrahams 2004. 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> + +struct C {}; + +struct D {}; + +struct E +{ + const D fe (const C&) {return D();} + const D fe2(const C&, const C&) {return D();} +}; + +BOOST_PYTHON_MODULE(bienstman2_ext) +{ + using namespace boost::python; + + class_<C>("C"); + class_<D>("D"); + class_<E>("E") + .def("fe", &E::fe) // this compiles. + .def("fe2", &E::fe2) // this doesn't... well, now it does ;-) + ; +} diff --git a/src/boost/libs/python/test/bienstman2.py b/src/boost/libs/python/test/bienstman2.py new file mode 100644 index 000000000..931fae8f7 --- /dev/null +++ b/src/boost/libs/python/test/bienstman2.py @@ -0,0 +1,20 @@ +# Copyright David Abrahams 2004. 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 bienstman2_ext +''' +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/bienstman3.cpp b/src/boost/libs/python/test/bienstman3.cpp new file mode 100644 index 000000000..d765b303d --- /dev/null +++ b/src/boost/libs/python/test/bienstman3.cpp @@ -0,0 +1,26 @@ +// Copyright David Abrahams 2004. 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> + +struct V +{ + virtual ~V() {}; // silence compiler warningsa + virtual void f() = 0; +}; + +struct B +{ + B(const V&) {} +}; + +BOOST_PYTHON_MODULE(bienstman3_ext) +{ + using namespace boost::python; + + class_<V, boost::noncopyable>("V", no_init); + class_<B>("B", init<const V&>()); + +} diff --git a/src/boost/libs/python/test/bienstman3.py b/src/boost/libs/python/test/bienstman3.py new file mode 100644 index 000000000..d0d250aea --- /dev/null +++ b/src/boost/libs/python/test/bienstman3.py @@ -0,0 +1,30 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from bienstman3_ext import * + +>>> try: +... V() +... except RuntimeError as x: +... print(x) +... else: +... print('expected an exception') +... +This class cannot be instantiated from Python + +''' +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/bienstman4.cpp b/src/boost/libs/python/test/bienstman4.cpp new file mode 100644 index 000000000..34b9e211f --- /dev/null +++ b/src/boost/libs/python/test/bienstman4.cpp @@ -0,0 +1,39 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/implicit.hpp> +#include <boost/mpl/list.hpp> + +struct Type1 {}; + +struct Term {Term(Type1 const&) {} }; + +struct Expression {void add(Term const&) {} }; + +BOOST_PYTHON_MODULE(bienstman4_ext) +{ + using namespace boost::python; + using boost::mpl::list; + + implicitly_convertible<Type1,Term>(); + + class_<Expression>("Expression") + .def("add", &Expression::add) + ; + + class_<Type1>("T1") + ; + + class_<Term>("Term", init<Type1&>()) + ; + + Type1 t1; + Expression e; + e.add(t1); +} + diff --git a/src/boost/libs/python/test/bienstman4.py b/src/boost/libs/python/test/bienstman4.py new file mode 100644 index 000000000..eea33ba2a --- /dev/null +++ b/src/boost/libs/python/test/bienstman4.py @@ -0,0 +1,23 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from bienstman4_ext import * +>>> t1 = T1() +>>> e = Expression() +>>> e.add(t1) +''' +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/bienstman5.cpp b/src/boost/libs/python/test/bienstman5.cpp new file mode 100644 index 000000000..657dadd12 --- /dev/null +++ b/src/boost/libs/python/test/bienstman5.cpp @@ -0,0 +1,23 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/mpl/list.hpp> + +#include <complex> + +struct M {M(const std::complex<double>&) {} }; + +BOOST_PYTHON_MODULE(bienstman5_ext) +{ + using namespace boost::python; + + class_<M>("M", init<std::complex<double> const&>()) + ; +} + + diff --git a/src/boost/libs/python/test/bienstman5.py b/src/boost/libs/python/test/bienstman5.py new file mode 100644 index 000000000..a6735d942 --- /dev/null +++ b/src/boost/libs/python/test/bienstman5.py @@ -0,0 +1,21 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from bienstman5_ext import * +>>> m = M(1j) +''' +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/boost_shared_ptr.cpp b/src/boost/libs/python/test/boost_shared_ptr.cpp new file mode 100644 index 000000000..57e50aa3c --- /dev/null +++ b/src/boost/libs/python/test/boost_shared_ptr.cpp @@ -0,0 +1,20 @@ +// Copyright David Abrahams 2002. +// Copyright Stefan Seefeld 2016. +// 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 <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/call_method.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/def.hpp> +#include <boost/shared_ptr.hpp> +#include <memory> + +using boost::shared_ptr; +#define MODULE boost_shared_ptr_ext + +#include "shared_ptr.hpp" +#include "module_tail.cpp" + diff --git a/src/boost/libs/python/test/boost_shared_ptr.py b/src/boost/libs/python/test/boost_shared_ptr.py new file mode 100644 index 000000000..31a2ad3d2 --- /dev/null +++ b/src/boost/libs/python/test/boost_shared_ptr.py @@ -0,0 +1,130 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from boost_shared_ptr_ext import * + + Test that shared_ptr<Derived> can be converted to shared_ptr<Base> + +>>> Y.store(YYY(42)) + +>>> x = X(17) +>>> null_x = null(x) +>>> null_x # should be None +>>> identity(null_x) # should also be None + +>>> a = New(1) +>>> A.call_f(a) +1 +>>> New(0) + +>>> type(factory(3)) +<class 'boost_shared_ptr_ext.Y'> +>>> type(factory(42)) +<class 'boost_shared_ptr_ext.YY'> + +>>> class P(Z): +... def v(self): +... return -Z.v(self); +... def __del__(self): +... print('bye') +... +>>> p = P(12) +>>> p.value() +12 +>>> p.v() +-12 +>>> look(p) +12 +>>> try: modify(p) +... except TypeError: pass +... else: 'print(expected a TypeError)' +>>> look(None) +-1 +>>> store(p) +>>> del p +>>> Z.get().v() +-12 +>>> Z.count() +1 +>>> Z.look_store() +12 +>>> Z.release() +bye +>>> Z.count() +0 + +>>> z = Z(13) +>>> z.value() +13 +>>> z.v() +13 +>>> try: modify(z) +... except TypeError: pass +... else: 'print(expected a TypeError)' + +>>> Z.get() # should be None +>>> store(z) +>>> assert Z.get() is z # show that deleter introspection works +>>> del z +>>> Z.get().value() +13 +>>> Z.count() +1 +>>> Z.look_store() +13 +>>> Z.release() +>>> Z.count() +0 + +>>> x = X(17) +>>> x.value() +17 +>>> look(x) +17 +>>> try: modify(x) +... except TypeError: pass +... else: 'print(expected a TypeError)' +>>> look(None) +-1 +>>> store(x) +>>> del x +>>> X.count() +1 +>>> X.look_store() +17 +>>> X.release() +>>> X.count() +0 + + +>>> y = Y(19) +>>> y.value() +19 +>>> modify(y) +>>> look(y) +-1 +>>> store(Y(23)) +>>> Y.count() +1 +>>> Y.look_store() +23 +>>> Y.release() +>>> Y.count() +0 +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/borrowed.cpp b/src/boost/libs/python/test/borrowed.cpp new file mode 100644 index 000000000..2c1bd1b7a --- /dev/null +++ b/src/boost/libs/python/test/borrowed.cpp @@ -0,0 +1,33 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/detail/wrap_python.hpp> +#include <boost/python/borrowed.hpp> +#include <boost/static_assert.hpp> + +using namespace boost::python; + +template <class T> +void assert_borrowed_ptr(T const&) +{ + BOOST_STATIC_ASSERT(boost::python::detail::is_borrowed_ptr<T>::value); +} + +template <class T> +void assert_not_borrowed_ptr(T const&) +{ + BOOST_STATIC_ASSERT(!boost::python::detail::is_borrowed_ptr<T>::value); +} + +int main() +{ + assert_borrowed_ptr(borrowed((PyObject*)0)); + assert_borrowed_ptr(borrowed((PyTypeObject*)0)); + assert_borrowed_ptr((detail::borrowed<PyObject> const*)0); + assert_borrowed_ptr((detail::borrowed<PyObject> volatile*)0); + assert_borrowed_ptr((detail::borrowed<PyObject> const volatile*)0); + assert_not_borrowed_ptr((PyObject*)0); + assert_not_borrowed_ptr(0); + return 0; +} diff --git a/src/boost/libs/python/test/builtin_converters.cpp b/src/boost/libs/python/test/builtin_converters.cpp new file mode 100644 index 000000000..f66e61bd8 --- /dev/null +++ b/src/boost/libs/python/test/builtin_converters.cpp @@ -0,0 +1,152 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <complex> +#include <boost/python/handle.hpp> +#include <boost/python/cast.hpp> +#include <boost/python/object.hpp> +#include <boost/python/detail/wrap_python.hpp> + +template <class T> +struct by_value +{ + static T rewrap(T x) + { + return x; + } + static int size(void) + { + return sizeof(T); + } +}; + +template <class T> +struct by_const_reference +{ + static T rewrap(T const& x) + { + return x; + } +}; + +template <class T> +struct by_reference +{ + static T rewrap(T& x) + { + return x; + } +}; + +using boost::python::def; +using boost::python::handle; +using boost::python::object; +using boost::python::borrowed; + +// Used to test that arbitrary handle<>s can be returned +handle<PyTypeObject> get_type(handle<> x) +{ + return handle<PyTypeObject>(borrowed(x->ob_type)); +} + +handle<> return_null_handle() +{ + return handle<>(); +} + +char const* rewrap_value_mutable_cstring(char* x) { return x; } + +object identity_(object x) { return x; } + +BOOST_PYTHON_MODULE(builtin_converters_ext) +{ + def("get_type", get_type); + def("return_null_handle", return_null_handle); + +// These methods are used solely for getting some C++ type sizes + def("bool_size", by_value<bool>::size); + def("char_size", by_value<char>::size); + def("int_size", by_value<int>::size); + def("short_size", by_value<short>::size); + def("long_size", by_value<long>::size); +#ifdef HAVE_LONG_LONG + def("long_long_size", by_value<BOOST_PYTHON_LONG_LONG>::size); +#endif + + def("rewrap_value_bool", by_value<bool>::rewrap); + def("rewrap_value_char", by_value<char>::rewrap); + def("rewrap_value_signed_char", by_value<signed char>::rewrap); + def("rewrap_value_unsigned_char", by_value<unsigned char>::rewrap); + def("rewrap_value_int", by_value<int>::rewrap); + def("rewrap_value_unsigned_int", by_value<unsigned int>::rewrap); + def("rewrap_value_short", by_value<short>::rewrap); + def("rewrap_value_unsigned_short", by_value<unsigned short>::rewrap); + def("rewrap_value_long", by_value<long>::rewrap); + def("rewrap_value_unsigned_long", by_value<unsigned long>::rewrap); +// using Python's macro instead of Boost's - we don't seem to get the +// config right all the time. +#ifdef HAVE_LONG_LONG + def("rewrap_value_long_long", by_value<BOOST_PYTHON_LONG_LONG>::rewrap); + def("rewrap_value_unsigned_long_long", by_value<unsigned BOOST_PYTHON_LONG_LONG>::rewrap); +# endif + def("rewrap_value_float", by_value<float>::rewrap); + def("rewrap_value_double", by_value<double>::rewrap); + def("rewrap_value_long_double", by_value<long double>::rewrap); + def("rewrap_value_complex_float", by_value<std::complex<float> >::rewrap); + def("rewrap_value_complex_double", by_value<std::complex<double> >::rewrap); + def("rewrap_value_complex_long_double", by_value<std::complex<long double> >::rewrap); + def("rewrap_value_wstring", +# if defined(BOOST_NO_STD_WSTRING) || !defined(Py_USING_UNICODE) + identity_ +# else + by_value<std::wstring>::rewrap +# endif + ); + def("rewrap_value_string", +# if defined(BOOST_NO_STD_WSTRING) || !defined(Py_USING_UNICODE) + identity_ +# else + by_value<std::wstring>::rewrap +# endif + ); + def("rewrap_value_string", by_value<std::string>::rewrap); + def("rewrap_value_cstring", by_value<char const*>::rewrap); + def("rewrap_value_handle", by_value<handle<> >::rewrap); + def("rewrap_value_object", by_value<object>::rewrap); + + // Expose this to illustrate our failings ;-). See test_builtin_converters.py + def("rewrap_value_mutable_cstring", rewrap_value_mutable_cstring); + + + def("rewrap_const_reference_bool", by_const_reference<bool>::rewrap); + def("rewrap_const_reference_char", by_const_reference<char>::rewrap); + def("rewrap_const_reference_signed_char", by_const_reference<signed char>::rewrap); + def("rewrap_const_reference_unsigned_char", by_const_reference<unsigned char>::rewrap); + def("rewrap_const_reference_int", by_const_reference<int>::rewrap); + def("rewrap_const_reference_unsigned_int", by_const_reference<unsigned int>::rewrap); + def("rewrap_const_reference_short", by_const_reference<short>::rewrap); + def("rewrap_const_reference_unsigned_short", by_const_reference<unsigned short>::rewrap); + def("rewrap_const_reference_long", by_const_reference<long>::rewrap); + def("rewrap_const_reference_unsigned_long", by_const_reference<unsigned long>::rewrap); +// using Python's macro instead of Boost's - we don't seem to get the +// config right all the time. +# ifdef HAVE_LONG_LONG + def("rewrap_const_reference_long_long", by_const_reference<BOOST_PYTHON_LONG_LONG>::rewrap); + def("rewrap_const_reference_unsigned_long_long", by_const_reference<unsigned BOOST_PYTHON_LONG_LONG>::rewrap); +# endif + def("rewrap_const_reference_float", by_const_reference<float>::rewrap); + def("rewrap_const_reference_double", by_const_reference<double>::rewrap); + def("rewrap_const_reference_long_double", by_const_reference<long double>::rewrap); + def("rewrap_const_reference_complex_float", by_const_reference<std::complex<float> >::rewrap); + def("rewrap_const_reference_complex_double", by_const_reference<std::complex<double> >::rewrap); + def("rewrap_const_reference_complex_long_double", by_const_reference<std::complex<long double> >::rewrap); + def("rewrap_const_reference_string", by_const_reference<std::string>::rewrap); + def("rewrap_const_reference_cstring", by_const_reference<char const*>::rewrap); + def("rewrap_const_reference_handle", by_const_reference<handle<> >::rewrap); + def("rewrap_const_reference_object", by_const_reference<object>::rewrap); + def("rewrap_reference_object", by_reference<object>::rewrap); +} + diff --git a/src/boost/libs/python/test/callbacks.cpp b/src/boost/libs/python/test/callbacks.cpp new file mode 100644 index 000000000..66bd35240 --- /dev/null +++ b/src/boost/libs/python/test/callbacks.cpp @@ -0,0 +1,150 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/ref.hpp> +#include <boost/python/ptr.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/python/reference_existing_object.hpp> +#include <boost/python/call.hpp> +#include <boost/python/object.hpp> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> + +using namespace boost::python; +BOOST_STATIC_ASSERT(converter::is_object_manager<handle<> >::value); + +int apply_int_int(PyObject* f, int x) +{ + return call<int>(f, x); +} + +void apply_void_int(PyObject* f, int x) +{ + call<void>(f, x); +} + +struct X +{ + explicit X(int x) : x(x), magic(7654321) { ++counter; } + X(X const& rhs) : x(rhs.x), magic(7654321) { ++counter; } + ~X() { BOOST_ASSERT(magic == 7654321); magic = 6666666; x = 9999; --counter; } + + void set(int _x) { BOOST_ASSERT(magic == 7654321); this->x = _x; } + int value() const { BOOST_ASSERT(magic == 7654321); return x; } + static int count() { return counter; } + private: + void operator=(X const&); + private: + int x; + long magic; + static int counter; +}; + +X apply_X_X(PyObject* f, X x) +{ + return call<X>(f, x); +} + +void apply_void_X_ref(PyObject* f, X& x) +{ + call<void>(f, boost::ref(x)); +} + +X& apply_X_ref_handle(PyObject* f, handle<> obj) +{ + return call<X&>(f, obj); +} + +X* apply_X_ptr_handle_cref(PyObject* f, handle<> const& obj) +{ + return call<X*>(f, obj); +} + +void apply_void_X_cref(PyObject* f, X const& x) +{ + call<void>(f, boost::cref(x)); +} + +void apply_void_X_ptr(PyObject* f, X* x) +{ + call<void>(f, ptr(x)); +} + +void apply_void_X_deep_ptr(PyObject* f, X* x) +{ + call<void>(f, x); +} + +char const* apply_cstring_cstring(PyObject* f, char const* s) +{ + return call<char const*>(f, s); +} + +char const* apply_cstring_pyobject(PyObject* f, PyObject* s) +{ + return call<char const*>(f, borrowed(s)); +} + +char apply_char_char(PyObject* f, char c) +{ + return call<char>(f, c); +} + +char const* apply_to_string_literal(PyObject* f) +{ + return call<char const*>(f, "hello, world"); +} + +handle<> apply_to_own_type(handle<> x) +{ + // Tests that we can return handle<> from a callback and that we + // can pass arbitrary handle<T>. + return call<handle<> >(x.get(), type_handle(borrowed(x->ob_type))); +} + +object apply_object_object(PyObject* f, object x) +{ + return call<object>(f, x); +} + +int X::counter; + +BOOST_PYTHON_MODULE(callbacks_ext) +{ + def("apply_object_object", apply_object_object); + def("apply_to_own_type", apply_to_own_type); + def("apply_int_int", apply_int_int); + def("apply_void_int", apply_void_int); + def("apply_X_X", apply_X_X); + def("apply_void_X_ref", apply_void_X_ref); + def("apply_void_X_cref", apply_void_X_cref); + def("apply_void_X_ptr", apply_void_X_ptr); + def("apply_void_X_deep_ptr", apply_void_X_deep_ptr); + + def("apply_X_ptr_handle_cref", apply_X_ptr_handle_cref + , return_value_policy<reference_existing_object>()); + + def("apply_X_ref_handle", apply_X_ref_handle + , return_value_policy<reference_existing_object>()); + + def("apply_cstring_cstring", apply_cstring_cstring); + def("apply_cstring_pyobject", apply_cstring_pyobject); + def("apply_char_char", apply_char_char); + def("apply_to_string_literal", apply_to_string_literal); + + + class_<X>("X", init<int>()) + .def(init<X const&>()) + .def("value", &X::value) + .def("set", &X::set) + ; + + def("x_count", &X::count); +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/callbacks.py b/src/boost/libs/python/test/callbacks.py new file mode 100644 index 000000000..cf876a89d --- /dev/null +++ b/src/boost/libs/python/test/callbacks.py @@ -0,0 +1,147 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from callbacks_ext import * + +>>> def double(x): +... return x + x +... +>>> apply_int_int(double, 42) +84 +>>> apply_void_int(double, 42) + +>>> def identity(x): +... return x + +Once we have array conversion support, this test will fail. Er, +succeed<wink>: + +>>> try: apply_to_string_literal(identity) +... except ReferenceError: pass # expected +... else: print('expected an exception!') + +>>> try: apply_X_ref_handle(lambda ignored:X(42), None) +... except ReferenceError: pass # expected +... else: print('expected an exception!') + +>>> x = X(42) +>>> x.y = X(7) +>>> apply_X_ref_handle(lambda z:z.y, x).value() +7 + +>>> x = apply_X_X(identity, X(42)) +>>> x.value() +42 +>>> x_count() +1 +>>> del x +>>> x_count() +0 + +>>> def increment(x): +... x.set(x.value() + 1) +... +>>> x = X(42) +>>> apply_void_X_ref(increment, x) +>>> x.value() +43 + +>>> apply_void_X_cref(increment, x) +>>> x.value() # const-ness is not respected, sorry! +44 + +>>> last_x = 1 +>>> def decrement(x): +... global last_x +... last_x = x +... if x is not None: +... x.set(x.value() - 1) + +>>> apply_void_X_ptr(decrement, x) +>>> x.value() +43 +>>> last_x.value() +43 +>>> increment(last_x) +>>> x.value() +44 +>>> last_x.value() +44 + +>>> apply_void_X_ptr(decrement, None) +>>> assert last_x is None +>>> x.value() +44 + +>>> last_x = 1 +>>> apply_void_X_deep_ptr(decrement, None) +>>> assert last_x is None +>>> x.value() +44 + +>>> apply_void_X_deep_ptr(decrement, x) +>>> x.value() +44 +>>> last_x.value() +43 + +>>> y = apply_X_ref_handle(identity, x) +>>> assert y.value() == x.value() +>>> increment(x) +>>> assert y.value() == x.value() + +>>> y = apply_X_ptr_handle_cref(identity, x) +>>> assert y.value() == x.value() +>>> increment(x) +>>> assert y.value() == x.value() + +>>> y = apply_X_ptr_handle_cref(identity, None) +>>> y + +>>> def new_x(ignored): +... return X(666) +... +>>> try: apply_X_ref_handle(new_x, 1) +... except ReferenceError: pass +... else: print('no error') + +>>> try: apply_X_ptr_handle_cref(new_x, 1) +... except ReferenceError: pass +... else: print('no error') + +>>> try: apply_cstring_cstring(identity, 'hello') +... except ReferenceError: pass +... else: print('no error') + +>>> apply_char_char(identity, 'x') +'x' + +>>> apply_cstring_pyobject(identity, 'hello') +'hello' + +>>> apply_cstring_pyobject(identity, None) + + +>>> apply_char_char(identity, 'x') +'x' + +>>> assert apply_to_own_type(identity) is type(identity) + +>>> assert apply_object_object(identity, identity) is identity +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/calling_conventions.cpp b/src/boost/libs/python/test/calling_conventions.cpp new file mode 100644 index 000000000..c1c2b5a41 --- /dev/null +++ b/src/boost/libs/python/test/calling_conventions.cpp @@ -0,0 +1,160 @@ +// +// adapted from bind_stdcall_test.cpp - test for bind.hpp + __stdcall (free functions) +// The purpose of this simple test is to determine if a function can be +// called from Python with the various existing calling conventions +// +// Copyright (c) 2001 Peter Dimov and Multi Media Ltd. +// +// 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) +// + +#if !defined(TEST_INCLUDE_RECURSION) + +#define TEST_INCLUDE_RECURSION + +//------------------------------------------------------------------------------ +// this section is the main body of the test extension module + +#if defined(_WIN32) && !defined(_WIN64) +# define BOOST_PYTHON_ENABLE_CDECL +# define BOOST_PYTHON_ENABLE_STDCALL +# define BOOST_PYTHON_ENABLE_FASTCALL +#endif +#include <boost/preprocessor/cat.hpp> +#include <boost/preprocessor/stringize.hpp> +#include <boost/python.hpp> +using namespace boost::python; + +// first define test functions for every calling convention + +#define TEST_DECLARE_FUNCTIONS + +#define TESTED_CALLING_CONVENTION __cdecl +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __stdcall +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __fastcall +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#undef TEST_DECLARE_FUNCTIONS + +// then create a module wrapping the defined functions for every calling convention + +BOOST_PYTHON_MODULE( calling_conventions_ext ) +{ + +#define TEST_WRAP_FUNCTIONS + +#define TESTED_CALLING_CONVENTION __cdecl +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __stdcall +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __fastcall +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#undef TEST_WRAP_FUNCTIONS + +} + +#else // !defined(TEST_INCLUDE_RECURSION) + +//------------------------------------------------------------------------------ +// this section defines the functions to be wrapped + +# if defined(TEST_DECLARE_FUNCTIONS) + +# if !defined(TESTED_CALLING_CONVENTION) +# error "One calling convention must be defined" +# endif // !defined(TESTED_CALLING_CONVENTION) + +namespace BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION) { + + long TESTED_CALLING_CONVENTION f_0() + { + return 17041L; + } + + long TESTED_CALLING_CONVENTION f_1(long a) + { + return a; + } + + long TESTED_CALLING_CONVENTION f_2(long a, long b) + { + return a + 10 * b; + } + + long TESTED_CALLING_CONVENTION f_3(long a, long b, long c) + { + return a + 10 * b + 100 * c; + } + + long TESTED_CALLING_CONVENTION f_4(long a, long b, long c, long d) + { + return a + 10 * b + 100 * c + 1000 * d; + } + + long TESTED_CALLING_CONVENTION f_5(long a, long b, long c, long d, long e) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e; + } + + long TESTED_CALLING_CONVENTION f_6(long a, long b, long c, long d, long e, long f) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e + 100000 * f; + } + + long TESTED_CALLING_CONVENTION f_7(long a, long b, long c, long d, long e, long f, long g) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e + 100000 * f + 1000000 * g; + } + + long TESTED_CALLING_CONVENTION f_8(long a, long b, long c, long d, long e, long f, long g, long h) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e + 100000 * f + 1000000 * g + 10000000 * h; + } + + long TESTED_CALLING_CONVENTION f_9(long a, long b, long c, long d, long e, long f, long g, long h, long i) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e + 100000 * f + 1000000 * g + 10000000 * h + 100000000 * i; + } + +} // namespace test##TESTED_CALLING_CONVENTION + +# endif // defined(TEST_DECLARE_FUNCTIONS) + +//------------------------------------------------------------------------------ +// this section wraps the functions + +# if defined(TEST_WRAP_FUNCTIONS) + +# if !defined(TESTED_CALLING_CONVENTION) +# error "One calling convention must be defined" +# endif // !defined(TESTED_CALLING_CONVENTION) + + def("f_0" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_0); + def("f_1" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_1); + def("f_2" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_2); + def("f_3" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_3); + def("f_4" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_4); + def("f_5" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_5); + def("f_6" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_6); + def("f_7" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_7); + def("f_8" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_8); + def("f_9" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_9); + +# endif // defined(TEST_WRAP_FUNCTIONS) + +#endif // !defined(TEST_INCLUDE_RECURSION) diff --git a/src/boost/libs/python/test/calling_conventions.py b/src/boost/libs/python/test/calling_conventions.py new file mode 100644 index 000000000..c57142448 --- /dev/null +++ b/src/boost/libs/python/test/calling_conventions.py @@ -0,0 +1,81 @@ +# Copyright Nicolas Lelong, 2010. 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) +""" +>>> from calling_conventions_ext import * +>>> f_0__cdecl() +17041 +>>> f_1__cdecl(1) +1 +>>> f_2__cdecl(1, 2) +21 +>>> f_3__cdecl(1, 2, 3) +321 +>>> f_4__cdecl(1, 2, 3, 4) +4321 +>>> f_5__cdecl(1, 2, 3, 4, 5) +54321 +>>> f_6__cdecl(1, 2, 3, 4, 5, 6) +654321 +>>> f_7__cdecl(1, 2, 3, 4, 5, 6, 7) +7654321 +>>> f_8__cdecl(1, 2, 3, 4, 5, 6, 7, 8) +87654321 +>>> f_9__cdecl(1, 2, 3, 4, 5, 6, 7, 8, 9) +987654321 +>>> f_0__stdcall() +17041 +>>> f_1__stdcall(1) +1 +>>> f_2__stdcall(1, 2) +21 +>>> f_3__stdcall(1, 2, 3) +321 +>>> f_4__stdcall(1, 2, 3, 4) +4321 +>>> f_5__stdcall(1, 2, 3, 4, 5) +54321 +>>> f_6__stdcall(1, 2, 3, 4, 5, 6) +654321 +>>> f_7__stdcall(1, 2, 3, 4, 5, 6, 7) +7654321 +>>> f_8__stdcall(1, 2, 3, 4, 5, 6, 7, 8) +87654321 +>>> f_9__stdcall(1, 2, 3, 4, 5, 6, 7, 8, 9) +987654321 +>>> f_0__fastcall() +17041 +>>> f_1__fastcall(1) +1 +>>> f_2__fastcall(1, 2) +21 +>>> f_3__fastcall(1, 2, 3) +321 +>>> f_4__fastcall(1, 2, 3, 4) +4321 +>>> f_5__fastcall(1, 2, 3, 4, 5) +54321 +>>> f_6__fastcall(1, 2, 3, 4, 5, 6) +654321 +>>> f_7__fastcall(1, 2, 3, 4, 5, 6, 7) +7654321 +>>> f_8__fastcall(1, 2, 3, 4, 5, 6, 7, 8) +87654321 +>>> f_9__fastcall(1, 2, 3, 4, 5, 6, 7, 8, 9) +987654321 +""" + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/calling_conventions_mf.cpp b/src/boost/libs/python/test/calling_conventions_mf.cpp new file mode 100644 index 000000000..83a97acfe --- /dev/null +++ b/src/boost/libs/python/test/calling_conventions_mf.cpp @@ -0,0 +1,161 @@ +// +// adapted from bind_stdcall_mf_test.cpp - test for bind.hpp + __stdcall (free functions) +// The purpose of this simple test is to determine if a function can be +// called from Python with the various existing calling conventions +// +// Copyright (c) 2001 Peter Dimov and Multi Media Ltd. +// +// 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) +// + +#if !defined(TEST_INCLUDE_RECURSION) + +#define TEST_INCLUDE_RECURSION + +//------------------------------------------------------------------------------ +// this section is the main body of the test extension module + +#if defined(_WIN32) && !defined(_WIN64) +# define BOOST_PYTHON_ENABLE_CDECL +# define BOOST_PYTHON_ENABLE_STDCALL +# define BOOST_PYTHON_ENABLE_FASTCALL +#endif +#include <boost/preprocessor/cat.hpp> +#include <boost/preprocessor/stringize.hpp> +#include <boost/python.hpp> +using namespace boost::python; + +// first define test functions for every calling convention + +#define TEST_DECLARE_FUNCTIONS + +#define TESTED_CALLING_CONVENTION __cdecl +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __stdcall +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __fastcall +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#undef TEST_DECLARE_FUNCTIONS + +// then create a module wrapping the defined functions for every calling convention + +BOOST_PYTHON_MODULE( calling_conventions_mf_ext ) +{ + +#define TEST_WRAP_FUNCTIONS + +#define TESTED_CALLING_CONVENTION __cdecl +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __stdcall +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __fastcall +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#undef TEST_WRAP_FUNCTIONS + +} + +#else // !defined(TEST_INCLUDE_RECURSION) + +//------------------------------------------------------------------------------ +// this section defines the functions to be wrapped + +# if defined(TEST_DECLARE_FUNCTIONS) + +# if !defined(TESTED_CALLING_CONVENTION) +# error "One calling convention must be defined" +# endif // !defined(TESTED_CALLING_CONVENTION) + +namespace BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION) { + +struct X +{ + mutable unsigned int hash; + + X(): hash(0) {} + + void TESTED_CALLING_CONVENTION f0() { f1(17); } + void TESTED_CALLING_CONVENTION g0() const { g1(17); } + + void TESTED_CALLING_CONVENTION f1(int a1) { hash = (hash * 17041 + a1) % 32768; } + void TESTED_CALLING_CONVENTION g1(int a1) const { hash = (hash * 17041 + a1 * 2) % 32768; } + + void TESTED_CALLING_CONVENTION f2(int a1, int a2) { f1(a1); f1(a2); } + void TESTED_CALLING_CONVENTION g2(int a1, int a2) const { g1(a1); g1(a2); } + + void TESTED_CALLING_CONVENTION f3(int a1, int a2, int a3) { f2(a1, a2); f1(a3); } + void TESTED_CALLING_CONVENTION g3(int a1, int a2, int a3) const { g2(a1, a2); g1(a3); } + + void TESTED_CALLING_CONVENTION f4(int a1, int a2, int a3, int a4) { f3(a1, a2, a3); f1(a4); } + void TESTED_CALLING_CONVENTION g4(int a1, int a2, int a3, int a4) const { g3(a1, a2, a3); g1(a4); } + + void TESTED_CALLING_CONVENTION f5(int a1, int a2, int a3, int a4, int a5) { f4(a1, a2, a3, a4); f1(a5); } + void TESTED_CALLING_CONVENTION g5(int a1, int a2, int a3, int a4, int a5) const { g4(a1, a2, a3, a4); g1(a5); } + + void TESTED_CALLING_CONVENTION f6(int a1, int a2, int a3, int a4, int a5, int a6) { f5(a1, a2, a3, a4, a5); f1(a6); } + void TESTED_CALLING_CONVENTION g6(int a1, int a2, int a3, int a4, int a5, int a6) const { g5(a1, a2, a3, a4, a5); g1(a6); } + + void TESTED_CALLING_CONVENTION f7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) { f6(a1, a2, a3, a4, a5, a6); f1(a7); } + void TESTED_CALLING_CONVENTION g7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) const { g6(a1, a2, a3, a4, a5, a6); g1(a7); } + + void TESTED_CALLING_CONVENTION f8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) { f7(a1, a2, a3, a4, a5, a6, a7); f1(a8); } + void TESTED_CALLING_CONVENTION g8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) const { g7(a1, a2, a3, a4, a5, a6, a7); g1(a8); } +}; + +} // namespace BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION) + +# endif // defined(TEST_DECLARE_FUNCTIONS) + +//------------------------------------------------------------------------------ +// this section wraps the functions + +# if defined(TEST_WRAP_FUNCTIONS) + +# if !defined(TESTED_CALLING_CONVENTION) +# error "One calling convention must be defined" +# endif // !defined(TESTED_CALLING_CONVENTION) + +{ + + typedef BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::X X; + + class_<X>("X" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION)) + .def("f0", &X::f0) + .def("g0", &X::g0) + .def("f1", &X::f1) + .def("g1", &X::g1) + .def("f2", &X::f2) + .def("g2", &X::g2) + .def("f3", &X::f3) + .def("g3", &X::g3) + .def("f4", &X::f4) + .def("g4", &X::g4) + .def("f5", &X::f5) + .def("g5", &X::g5) + .def("f6", &X::f6) + .def("g6", &X::g6) + .def("f7", &X::f7) + .def("g7", &X::g7) + .def("f8", &X::f8) + .def("g8", &X::g8) + .def_readonly("hash", &X::hash) + ; + +} + +# endif // defined(TEST_WRAP_FUNCTIONS) + +#endif // !defined(TEST_INCLUDE_RECURSION) diff --git a/src/boost/libs/python/test/calling_conventions_mf.py b/src/boost/libs/python/test/calling_conventions_mf.py new file mode 100644 index 000000000..7e28484b9 --- /dev/null +++ b/src/boost/libs/python/test/calling_conventions_mf.py @@ -0,0 +1,84 @@ +# Copyright Nicolas Lelong, 2010. 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) +""" +>>> from calling_conventions_mf_ext import * +>>> x = X__cdecl() +>>> x.f0() +>>> x.g0() +>>> x.f1(1) +>>> x.g1(1) +>>> x.f2(1, 2) +>>> x.g2(1, 2) +>>> x.f3(1, 2, 3) +>>> x.g3(1, 2, 3) +>>> x.f4(1, 2, 3, 4) +>>> x.g4(1, 2, 3, 4) +>>> x.f5(1, 2, 3, 4, 5) +>>> x.g5(1, 2, 3, 4, 5) +>>> x.f6(1, 2, 3, 4, 5, 6) +>>> x.g6(1, 2, 3, 4, 5, 6) +>>> x.f7(1, 2, 3, 4, 5, 6, 7) +>>> x.g7(1, 2, 3, 4, 5, 6, 7) +>>> x.f8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.g8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.hash +2155 +>>> x = X__stdcall() +>>> x.f0() +>>> x.g0() +>>> x.f1(1) +>>> x.g1(1) +>>> x.f2(1, 2) +>>> x.g2(1, 2) +>>> x.f3(1, 2, 3) +>>> x.g3(1, 2, 3) +>>> x.f4(1, 2, 3, 4) +>>> x.g4(1, 2, 3, 4) +>>> x.f5(1, 2, 3, 4, 5) +>>> x.g5(1, 2, 3, 4, 5) +>>> x.f6(1, 2, 3, 4, 5, 6) +>>> x.g6(1, 2, 3, 4, 5, 6) +>>> x.f7(1, 2, 3, 4, 5, 6, 7) +>>> x.g7(1, 2, 3, 4, 5, 6, 7) +>>> x.f8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.g8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.hash +2155 +>>> x = X__fastcall() +>>> x.f0() +>>> x.g0() +>>> x.f1(1) +>>> x.g1(1) +>>> x.f2(1, 2) +>>> x.g2(1, 2) +>>> x.f3(1, 2, 3) +>>> x.g3(1, 2, 3) +>>> x.f4(1, 2, 3, 4) +>>> x.g4(1, 2, 3, 4) +>>> x.f5(1, 2, 3, 4, 5) +>>> x.g5(1, 2, 3, 4, 5) +>>> x.f6(1, 2, 3, 4, 5, 6) +>>> x.g6(1, 2, 3, 4, 5, 6) +>>> x.f7(1, 2, 3, 4, 5, 6, 7) +>>> x.g7(1, 2, 3, 4, 5, 6, 7) +>>> x.f8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.g8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.hash +2155 +""" + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/class.cpp b/src/boost/libs/python/test/class.cpp new file mode 100644 index 000000000..078bebdf6 --- /dev/null +++ b/src/boost/libs/python/test/class.cpp @@ -0,0 +1,28 @@ +// 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/object.hpp> +#include <boost/python/class.hpp> + +using namespace boost::python; + +struct X +{ + int x; + X(int n) : x(n) { } +}; + +int x_function(X& x) +{ return x.x; +} + + +BOOST_PYTHON_MODULE(class_ext) +{ + class_<X>("X", init<int>()); + def("x_function", x_function); +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/class.py b/src/boost/libs/python/test/class.py new file mode 100644 index 000000000..15594a105 --- /dev/null +++ b/src/boost/libs/python/test/class.py @@ -0,0 +1,40 @@ +# 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) +''' +>>> from class_ext import * + +Ensure sanity: + + >>> x = X(42) + >>> x_function(x) + 42 + +Demonstrate extraction in the presence of metaclass changes: + + >>> class MetaX(X.__class__): + ... def __new__(cls, *args): + ... return super(MetaX, cls).__new__(cls, *args) + >>> class XPlusMetatype(X): + ... __metaclass__ = MetaX + >>> x = XPlusMetatype(42) + >>> x_function(x) + 42 + + +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/cltree.cpp b/src/boost/libs/python/test/cltree.cpp new file mode 100644 index 000000000..518ae37fe --- /dev/null +++ b/src/boost/libs/python/test/cltree.cpp @@ -0,0 +1,74 @@ +// Copyright David Abrahams 2005. 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/utility.hpp> + +/* Non-modifiable definitions */ + +class basic { +public: + basic() { name = "cltree.basic"; } + std::string repr() { return name+"()"; } +protected: + std::string name; +}; + +class constant: public basic { +public: + constant() { name = "cltree.constant"; } +}; + +class symbol: public basic { +public: + symbol() { name = "cltree.symbol"; } +}; + +class variable: public basic { +public: + variable() { name = "cltree.variable"; } +}; + +/* EOF: Non-modifiable definitions */ + +class symbol_wrapper: public symbol { +public: + symbol_wrapper(PyObject* /*self*/): symbol() { + name = "cltree.wrapped_symbol"; + } +}; + +class variable_wrapper: public variable { +public: + variable_wrapper(PyObject* /*self*/): variable() { + name = "cltree.wrapped_variable"; + } + + // This constructor is introduced only because cannot use + // boost::noncopyable, see below. + variable_wrapper(PyObject* /*self*/,variable v): variable(v) {} + +}; + +BOOST_PYTHON_MODULE(cltree) +{ + boost::python::class_<basic>("basic") + .def("__repr__",&basic::repr) + ; + + boost::python::class_<constant, boost::python::bases<basic>, boost::noncopyable>("constant") + ; + + + boost::python::class_<symbol, symbol_wrapper, boost::noncopyable>("symbol") + ; + + boost::python::class_<variable, boost::python::bases<basic>, variable_wrapper>("variable") + ; +} + +#include "module_tail.cpp" + diff --git a/src/boost/libs/python/test/complicated.hpp b/src/boost/libs/python/test/complicated.hpp new file mode 100644 index 000000000..5ff19aea0 --- /dev/null +++ b/src/boost/libs/python/test/complicated.hpp @@ -0,0 +1,38 @@ +// Copyright David Abrahams 2001. +// 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) +#ifndef COMPLICATED_DWA20011215_HPP +# define COMPLICATED_DWA20011215_HPP +# include <iostream> + +# include "simple_type.hpp" + +struct complicated +{ + complicated(simple const&, int = 0); + ~complicated(); + + int get_n() const; + + char* s; + int n; +}; + +inline complicated::complicated(simple const&s, int _n) + : s(s.s), n(_n) +{ + std::cout << "constructing complicated: " << this->s << ", " << _n << std::endl; +} + +inline complicated::~complicated() +{ + std::cout << "destroying complicated: " << this->s << ", " << n << std::endl; +} + +inline int complicated::get_n() const +{ + return n; +} + +#endif // COMPLICATED_DWA20011215_HPP diff --git a/src/boost/libs/python/test/const_argument.cpp b/src/boost/libs/python/test/const_argument.cpp new file mode 100644 index 000000000..279c3dc1a --- /dev/null +++ b/src/boost/libs/python/test/const_argument.cpp @@ -0,0 +1,28 @@ +/* Copyright 2004 Jonathan Brandmeyer + * Use, modification and distribution are subject to 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) + * + * The purpose of this test is to determine if a function can be called from + * Python with a const value type as an argument, and whether or not the + * presence of a prototype without the cv-qualifier will work around the + * compiler's bug. + */ +#include <boost/python.hpp> +using namespace boost::python; + + +#if BOOST_WORKAROUND(BOOST_MSVC, == 1200) +bool accept_const_arg( object ); +#endif + +bool accept_const_arg( const object ) +{ + return true; +} + + +BOOST_PYTHON_MODULE( const_argument_ext ) +{ + def( "accept_const_arg", accept_const_arg ); +} diff --git a/src/boost/libs/python/test/const_argument.py b/src/boost/libs/python/test/const_argument.py new file mode 100644 index 000000000..1d241953b --- /dev/null +++ b/src/boost/libs/python/test/const_argument.py @@ -0,0 +1,23 @@ +# Copyright Jonathan Brandmeyer, 2004. 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) +""" +>>> from const_argument_ext import * +>>> accept_const_arg(1) +1 +""" + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/copy_ctor_mutates_rhs.cpp b/src/boost/libs/python/test/copy_ctor_mutates_rhs.cpp new file mode 100644 index 000000000..41eac495e --- /dev/null +++ b/src/boost/libs/python/test/copy_ctor_mutates_rhs.cpp @@ -0,0 +1,23 @@ +// Copyright David Abrahams 2003. +// 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 <boost/python/detail/copy_ctor_mutates_rhs.hpp> +#include <boost/static_assert.hpp> +#include <memory> +#include <string> + +struct foo +{ + operator std::auto_ptr<int>&() const; +}; + +int main() +{ + using namespace boost::python::detail; + BOOST_STATIC_ASSERT(!copy_ctor_mutates_rhs<int>::value); + BOOST_STATIC_ASSERT(copy_ctor_mutates_rhs<std::auto_ptr<int> >::value); + BOOST_STATIC_ASSERT(!copy_ctor_mutates_rhs<std::string>::value); + BOOST_STATIC_ASSERT(!copy_ctor_mutates_rhs<foo>::value); + return 0; +} diff --git a/src/boost/libs/python/test/crossmod_exception.py b/src/boost/libs/python/test/crossmod_exception.py new file mode 100644 index 000000000..4820f29e9 --- /dev/null +++ b/src/boost/libs/python/test/crossmod_exception.py @@ -0,0 +1,19 @@ +# Copyright (C) 2003 Rational Discovery LLC. 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) + +print("running...") + +import crossmod_exception_a +import crossmod_exception_b + +try: + crossmod_exception_b.tossit() +except IndexError: + pass +try: + crossmod_exception_a.tossit() +except IndexError: + pass + +print("Done.") diff --git a/src/boost/libs/python/test/crossmod_exception_a.cpp b/src/boost/libs/python/test/crossmod_exception_a.cpp new file mode 100644 index 000000000..9526129af --- /dev/null +++ b/src/boost/libs/python/test/crossmod_exception_a.cpp @@ -0,0 +1,18 @@ +// Copyright (C) 2003 Rational Discovery LLC +// 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 <boost/python.hpp> + +namespace python = boost::python; + +void tossit(){ + PyErr_SetString(PyExc_IndexError,"a-blah!"); + throw python::error_already_set(); +} + +BOOST_PYTHON_MODULE(crossmod_exception_a) +{ + python::def("tossit",tossit); +} diff --git a/src/boost/libs/python/test/crossmod_exception_b.cpp b/src/boost/libs/python/test/crossmod_exception_b.cpp new file mode 100644 index 000000000..e2ea491ca --- /dev/null +++ b/src/boost/libs/python/test/crossmod_exception_b.cpp @@ -0,0 +1,18 @@ +// Copyright (C) 2003 Rational Discovery LLC +// 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 <boost/python.hpp> + +namespace python = boost::python; + +void tossit(){ + PyErr_SetString(PyExc_IndexError,"b-blah!"); + throw python::error_already_set(); +} + +BOOST_PYTHON_MODULE(crossmod_exception_b) +{ + python::def("tossit",tossit); +} diff --git a/src/boost/libs/python/test/crossmod_opaque.py b/src/boost/libs/python/test/crossmod_opaque.py new file mode 100644 index 000000000..533ac16fe --- /dev/null +++ b/src/boost/libs/python/test/crossmod_opaque.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Copyright Gottfried Ganßauge 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) + +if __name__ == '__main__': + print("running...") + + import crossmod_opaque_a + import crossmod_opaque_b + + crossmod_opaque_a.get() + crossmod_opaque_b.get() + + print("Done.") diff --git a/src/boost/libs/python/test/crossmod_opaque_a.cpp b/src/boost/libs/python/test/crossmod_opaque_a.cpp new file mode 100644 index 000000000..62ed43311 --- /dev/null +++ b/src/boost/libs/python/test/crossmod_opaque_a.cpp @@ -0,0 +1,26 @@ +// Copyright Gottfried Ganßauge 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) +# include <boost/python/return_opaque_pointer.hpp> +# include <boost/python/def.hpp> +# include <boost/python/module.hpp> +# include <boost/python/return_value_policy.hpp> + +typedef struct opaque_ *opaque; + +opaque the_op = ((opaque) 0x47110815); + +opaque get() { return the_op; } + +BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(opaque_) + +namespace bpl = boost::python; + +BOOST_PYTHON_MODULE(crossmod_opaque_a) +{ + bpl::def ( + "get", + &::get, + bpl::return_value_policy<bpl::return_opaque_pointer>()); +} diff --git a/src/boost/libs/python/test/crossmod_opaque_b.cpp b/src/boost/libs/python/test/crossmod_opaque_b.cpp new file mode 100644 index 000000000..3d661339c --- /dev/null +++ b/src/boost/libs/python/test/crossmod_opaque_b.cpp @@ -0,0 +1,26 @@ +// Copyright Gottfried Ganßauge 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) +# include <boost/python/return_opaque_pointer.hpp> +# include <boost/python/def.hpp> +# include <boost/python/module.hpp> +# include <boost/python/return_value_policy.hpp> + +typedef struct opaque_ *opaque; + +opaque the_op = ((opaque) 0x47110815); + +opaque get() { return the_op; } + +BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(opaque_) + +namespace bpl = boost::python; + +BOOST_PYTHON_MODULE(crossmod_opaque_b) +{ + bpl::def ( + "get", + &::get, + bpl::return_value_policy<bpl::return_opaque_pointer>()); +} diff --git a/src/boost/libs/python/test/data_members.cpp b/src/boost/libs/python/test/data_members.cpp new file mode 100644 index 000000000..6d2cc7bd4 --- /dev/null +++ b/src/boost/libs/python/test/data_members.cpp @@ -0,0 +1,132 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/python/return_by_value.hpp> +#include "test_class.hpp" + +#if defined(_AIX) && defined(__EDG_VERSION__) && __EDG_VERSION__ < 245 +# include <iostream> // works around a KCC intermediate code generation bug +#endif + + +using namespace boost::python; + +typedef test_class<> X; + +struct Y : test_class<1> +{ + Y(int v) : test_class<1>(v) {} + Y& operator=(Y const& rhs) { x = rhs.x; return *this; } + bool q; +}; + +double get_fair_value(X const& x) { return x.value(); } + + +struct VarBase +{ + VarBase(std::string name_) : name(name_) {} + + std::string const name; + std::string get_name1() const { return name; } + +}; + +struct Var : VarBase +{ + Var(std::string name_) : VarBase(name_), value(), name2(name.c_str()), y(6) {} + std::string const& get_name2() const { return name; } + float value; + char const* name2; + Y y; + + static int static1; + static Y static2; +}; + +int Var::static1 = 0; +Y Var::static2(0); + +// Compilability regression tests +namespace boost_python_test +{ + struct trivial + { + trivial() : value(123) {} + double value; + }; + + struct Color3 + { + static const Color3 black; + }; + + const Color3 Color3::black +#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + = {} +#endif + ; + + void compilability_test() + { + class_<trivial>("trivial") + .add_property("property", make_getter(&trivial::value, return_value_policy<return_by_value>())) + .def_readonly("readonly", &trivial::value) + ; + + class_< Color3 >("Color3", init< const Color3 & >()) + .def_readonly("BLACK", &Color3::black) // line 17 + ; + } +} + +BOOST_PYTHON_MODULE(data_members_ext) +{ + using namespace boost_python_test; + class_<X>("X", init<int>()) + .def("value", &X::value) + .def("set", &X::set) + .def_readonly("x", &X::x) + .add_property("fair_value", get_fair_value) + ; + + class_<Y>("Y", init<int>()) + .def("value", &Y::value) + .def("set", &Y::set) + .def_readwrite("x", &Y::x) + .def_readwrite("q", &Y::q) + ; + + class_<Var>("Var", init<std::string>()) + .def_readonly("name", &Var::name) + .def_readonly("name2", &Var::name2) + .def_readwrite("value", &Var::value) + .def_readonly("y", &Var::y) + + // Test return_by_value for plain values and for + // pointers... return_by_value was implemented as a + // side-effect of implementing data member support, so it made + // sense to add the test here. + .def("get_name1", &Var::get_name1, return_value_policy<return_by_value>()) + .def("get_name2", &Var::get_name2, return_value_policy<return_by_value>()) + + .add_property("name3", &Var::get_name1) + + // Test static data members + .def_readonly("ro1a", &Var::static1) + .def_readonly("ro1b", Var::static1) + .def_readwrite("rw1a", &Var::static1) + .def_readwrite("rw1b", Var::static1) + + .def_readonly("ro2a", &Var::static2) + .def_readonly("ro2b", Var::static2) + .def_readwrite("rw2a", &Var::static2) + .def_readwrite("rw2b", Var::static2) + ; +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/data_members.py b/src/boost/libs/python/test/data_members.py new file mode 100644 index 000000000..74b655eb5 --- /dev/null +++ b/src/boost/libs/python/test/data_members.py @@ -0,0 +1,215 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from data_members_ext import * + + ---- Test static data members --- + +>>> v = Var('slim shady') + +>>> Var.ro2a.x +0 +>>> Var.ro2b.x +0 +>>> Var.rw2a.x +0 +>>> Var.rw2b.x +0 +>>> v.ro2a.x +0 +>>> v.ro2b.x +0 +>>> v.rw2a.x +0 +>>> v.rw2b.x +0 +>>> Var.rw2a.x = 777 +>>> Var.ro2a.x +777 +>>> Var.ro2b.x +777 +>>> Var.rw2a.x +777 +>>> Var.rw2b.x +777 +>>> v.ro2a.x +777 +>>> v.ro2b.x +777 +>>> v.rw2a.x +777 +>>> v.rw2b.x +777 +>>> Var.rw2b = Y(888) + +>>> y = Y(99) +>>> y.q = True +>>> y.q +True +>>> y.q = False +>>> y.q +False + +>>> Var.ro2a.x +888 +>>> Var.ro2b.x +888 +>>> Var.rw2a.x +888 +>>> Var.rw2b.x +888 +>>> v.ro2a.x +888 +>>> v.ro2b.x +888 +>>> v.rw2a.x +888 +>>> v.rw2b.x +888 +>>> v.rw2b.x = 999 +>>> Var.ro2a.x +999 +>>> Var.ro2b.x +999 +>>> Var.rw2a.x +999 +>>> Var.rw2b.x +999 +>>> v.ro2a.x +999 +>>> v.ro2b.x +999 +>>> v.rw2a.x +999 +>>> v.rw2b.x +999 + + +>>> Var.ro1a +0 +>>> Var.ro1b +0 +>>> Var.rw1a +0 +>>> Var.rw1b +0 +>>> v.ro1a +0 +>>> v.ro1b +0 +>>> v.rw1a +0 +>>> v.rw1b +0 +>>> Var.rw1a = 777 +>>> Var.ro1a +777 +>>> Var.ro1b +777 +>>> Var.rw1a +777 +>>> Var.rw1b +777 +>>> v.ro1a +777 +>>> v.ro1b +777 +>>> v.rw1a +777 +>>> v.rw1b +777 +>>> Var.rw1b = 888 +>>> Var.ro1a +888 +>>> Var.ro1b +888 +>>> Var.rw1a +888 +>>> Var.rw1b +888 +>>> v.ro1a +888 +>>> v.ro1b +888 +>>> v.rw1a +888 +>>> v.rw1b +888 +>>> v.rw1b = 999 +>>> Var.ro1a +999 +>>> Var.ro1b +999 +>>> Var.rw1a +999 +>>> Var.rw1b +999 +>>> v.ro1a +999 +>>> v.ro1b +999 +>>> v.rw1a +999 +>>> v.rw1b +999 + + + + ----------------- + +>>> x = X(42) +>>> x.x +42 +>>> try: x.x = 77 +... except AttributeError: pass +... else: print('no error') + +>>> x.fair_value +42.0 +>>> y = Y(69) +>>> y.x +69 +>>> y.x = 77 +>>> y.x +77 + +>>> v = Var("pi") +>>> v.value = 3.14 +>>> v.name +'pi' +>>> v.name2 +'pi' + +>>> v.get_name1() +'pi' + +>>> v.get_name2() +'pi' + +>>> v.y.x +6 +>>> v.y.x = -7 +>>> v.y.x +-7 + +>>> v.name3 +'pi' + + +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/defaults.cpp b/src/boost/libs/python/test/defaults.cpp new file mode 100644 index 000000000..6d87e5d6e --- /dev/null +++ b/src/boost/libs/python/test/defaults.cpp @@ -0,0 +1,173 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/def.hpp> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/list.hpp> +#include <boost/python/overloads.hpp> +#include <boost/python/return_internal_reference.hpp> + +#if defined(_AIX) && defined(__EDG_VERSION__) && __EDG_VERSION__ < 245 +# include <iostream> // works around a KCC intermediate code generation bug +#endif + +using namespace boost::python; +namespace bpl = boost::python; + +char const* const format = "int(%s); char(%s); string(%s); double(%s); "; + +/////////////////////////////////////////////////////////////////////////////// +// +// Overloaded functions +// +/////////////////////////////////////////////////////////////////////////////// +object +bar(int a, char b, std::string c, double d) +{ + return format % bpl::make_tuple(a, b, c, d); +} + +object +bar(int a, char b, std::string c) +{ + return format % bpl::make_tuple(a, b, c, 0.0); +} + +object +bar(int a, char b) +{ + return format % bpl::make_tuple(a, b, "default", 0.0); +} + +object +bar(int a) +{ + return format % bpl::make_tuple(a, 'D', "default", 0.0); +} + +BOOST_PYTHON_FUNCTION_OVERLOADS(bar_stubs, bar, 1, 4) + +/////////////////////////////////////////////////////////////////////////////// +// +// Functions with default arguments +// +/////////////////////////////////////////////////////////////////////////////// +object +foo(int a, char b = 'D', std::string c = "default", double d = 0.0) +{ + return format % bpl::make_tuple(a, b, c, d); +} + +BOOST_PYTHON_FUNCTION_OVERLOADS(foo_stubs, foo, 1, 4) + +/////////////////////////////////////////////////////////////////////////////// +// +// Overloaded member functions with default arguments +// +/////////////////////////////////////////////////////////////////////////////// +struct Y { + + Y() {} + + object + get_state() const + { + return format % bpl::make_tuple(a, b, c, d); + } + + int a; char b; std::string c; double d; +}; + + +struct X { + + X() {} + + X(int a, char b = 'D', std::string c = "constructor", double d = 0.0) + : state(format % bpl::make_tuple(a, b, c, d)) + {} + + X(std::string s, bool b) + : state("Got exactly two arguments from constructor: string(%s); bool(%s); " % bpl::make_tuple(s, b*1)) + {} + + object + bar(int a, char b = 'D', std::string c = "default", double d = 0.0) const + { + return format % bpl::make_tuple(a, b, c, d); + } + + Y const& + bar2(int a = 0, char b = 'D', std::string c = "default", double d = 0.0) + { + // tests zero arg member function and return_internal_reference policy + y.a = a; + y.b = b; + y.c = c; + y.d = d; + return y; + } + + object + foo(int a, bool b=false) const + { + return "int(%s); bool(%s); " % bpl::make_tuple(a, b*1); + } + + object + foo(std::string a, bool b=false) const + { + return "string(%s); bool(%s); " % bpl::make_tuple(a, b*1); + } + + object + foo(list a, list b, bool c=false) const + { + return "list(%s); list(%s); bool(%s); " % bpl::make_tuple(a, b, c*1); + } + + object + get_state() const + { + return state; + } + + Y y; + object state; +}; + +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_bar_stubs, bar, 1, 4) +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_bar_stubs2, bar2, 0, 4) +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_foo_2_stubs, foo, 1, 2) +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_foo_3_stubs, foo, 2, 3) + +/////////////////////////////////////////////////////////////////////////////// + +BOOST_PYTHON_MODULE(defaults_ext) +{ + def("foo", foo, foo_stubs()); + def("bar", (object(*)(int, char, std::string, double))0, bar_stubs()); + + class_<Y>("Y", init<>("doc of Y init")) // this should work + .def("get_state", &Y::get_state) + ; + + class_<X>("X",no_init) + + .def(init<optional<int, char, std::string, double> >("doc of init", args("self", "a", "b", "c", "d"))) + .def(init<std::string, bool>(args("self", "s", "b"))[default_call_policies()]) // what's a good policy here? + .def("get_state", &X::get_state) + .def("bar", &X::bar, X_bar_stubs()) + .def("bar2", &X::bar2, X_bar_stubs2("doc of X::bar2")[return_internal_reference<>()]) + .def("foo", (object(X::*)(std::string, bool) const)0, X_foo_2_stubs()) + .def("foo", (object(X::*)(int, bool) const)0, X_foo_2_stubs()) + .def("foo", (object(X::*)(list, list, bool) const)0, X_foo_3_stubs()) + ; +} + +#include "module_tail.cpp" + diff --git a/src/boost/libs/python/test/defaults.py b/src/boost/libs/python/test/defaults.py new file mode 100644 index 000000000..cf3cfd38f --- /dev/null +++ b/src/boost/libs/python/test/defaults.py @@ -0,0 +1,140 @@ +# Copyright David Abrahams 2004. 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) +""" +>>> from defaults_ext import * +>>> bar(1) +'int(1); char(D); string(default); double(0.0); ' + +>>> bar(2, 'X') +'int(2); char(X); string(default); double(0.0); ' + +>>> bar(3, 'Y', "Hello World") +'int(3); char(Y); string(Hello World); double(0.0); ' + +>>> bar(4, 'Z', "Hi There", 3.3) +'int(4); char(Z); string(Hi There); double(3.3); ' + +>>> foo(1) +'int(1); char(D); string(default); double(0.0); ' + +>>> foo(2, 'X') +'int(2); char(X); string(default); double(0.0); ' + +>>> foo(3, 'Y', "Hello World") +'int(3); char(Y); string(Hello World); double(0.0); ' + +>>> foo(4, 'Z', "Hi There", 3.3) +'int(4); char(Z); string(Hi There); double(3.3); ' + +>>> x = X() +>>> x.bar(1) +'int(1); char(D); string(default); double(0.0); ' + +>>> x.bar(2, 'X') +'int(2); char(X); string(default); double(0.0); ' + +>>> x.bar(3, 'Y', "Hello World") +'int(3); char(Y); string(Hello World); double(0.0); ' + +>>> x.bar(4, 'Z', "Hi There", 3.3) +'int(4); char(Z); string(Hi There); double(3.3); ' + +>>> x.foo(5) +'int(5); bool(0); ' + +>>> x.foo(6, 0) +'int(6); bool(0); ' + +>>> x.foo(7, 1) +'int(7); bool(1); ' + +>>> x.foo("A") +'string(A); bool(0); ' + +>>> x.foo("B", False) +'string(B); bool(0); ' + +>>> x.foo("C", True) +'string(C); bool(1); ' + +>>> x.foo([0,1,2], [2,3,4]) +'list([0, 1, 2]); list([2, 3, 4]); bool(0); ' + +>>> x.foo([0,1,2], [2,3,4], False) +'list([0, 1, 2]); list([2, 3, 4]); bool(0); ' + +>>> x.foo([0,1,2], [2,3,4], True) +'list([0, 1, 2]); list([2, 3, 4]); bool(1); ' + +>>> x = X(1) +>>> x.get_state() +'int(1); char(D); string(constructor); double(0.0); ' + +>>> x = X(1, 'X') +>>> x.get_state() +'int(1); char(X); string(constructor); double(0.0); ' + +>>> x = X(1, 'X', "Yabadabadoo") +>>> x.get_state() +'int(1); char(X); string(Yabadabadoo); double(0.0); ' + +>>> x = X(1, 'X', "Phoenix", 3.65) +>>> x.get_state() +'int(1); char(X); string(Phoenix); double(3.65); ' + +>>> x.bar2().get_state() +'int(0); char(D); string(default); double(0.0); ' + +>>> x.bar2(1).get_state() +'int(1); char(D); string(default); double(0.0); ' + +>>> x.bar2(1, 'K').get_state() +'int(1); char(K); string(default); double(0.0); ' + +>>> x.bar2(1, 'K', "Kim").get_state() +'int(1); char(K); string(Kim); double(0.0); ' + +>>> x.bar2(1, 'K', "Kim", 9.9).get_state() +'int(1); char(K); string(Kim); double(9.9); ' + +>>> x = X("Phoenix", 1) +>>> x.get_state() +'Got exactly two arguments from constructor: string(Phoenix); bool(1); ' + +>>> def selected_doc(obj, *args): +... doc = obj.__doc__.splitlines() +... return "\\n".join(["|"+doc[i] for i in args]) + +>>> print(selected_doc(X.__init__, 1, 2, 4, 7, 9)) +|__init__( (object)self [, (int)a [, (str)b [, (str)c [, (float)d]]]]) -> None : +| doc of init +| C++ signature : +|__init__( (object)self, (str)s, (bool)b) -> None : +| C++ signature : + +>>> print(selected_doc(Y.__init__, 1, 2, 4)) +|__init__( (object)arg1) -> None : +| doc of Y init +| C++ signature : + +>>> print(selected_doc(X.bar2, 1, 2, 4)) +|bar2( (X)arg1 [, (int)arg2 [, (str)arg3 [, (str)arg4 [, (float)arg5]]]]) -> Y : +| doc of X::bar2 +| C++ signature : + +""" +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/destroy_test.cpp b/src/boost/libs/python/test/destroy_test.cpp new file mode 100644 index 000000000..57501604b --- /dev/null +++ b/src/boost/libs/python/test/destroy_test.cpp @@ -0,0 +1,58 @@ +// Copyright David Abrahams 2004. 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 <boost/python/detail/destroy.hpp> + +#include <boost/detail/lightweight_test.hpp> + +int count; +int marks[] = { + -1 + , -1, -1 + , -1, -1, -1, -1 + , -1 +}; +int* kills = marks; + +struct foo +{ + foo() : n(count++) {} + ~foo() + { + *kills++ = n; + } + int n; + + // This used to cause compiler errors with MSVC 9.0. + foo& operator~(); + foo& T(); +}; + +void assert_destructions(int n) +{ + for (int i = 0; i < n; ++i) + BOOST_TEST(marks[i] == i); + BOOST_TEST(marks[n] == -1); +} + +int main() +{ + assert_destructions(0); + + foo* f1 = new foo; + boost::python::detail::destroy_referent<foo const volatile&>(f1); + assert_destructions(1); + + foo* f2 = new foo[2]; + typedef foo x[2]; + + boost::python::detail::destroy_referent<x const&>(f2); + assert_destructions(3); + + typedef foo y[2][2]; + x* f3 = new y; + boost::python::detail::destroy_referent<y&>(f3); + assert_destructions(7); + + return boost::report_errors(); +} diff --git a/src/boost/libs/python/test/dict.cpp b/src/boost/libs/python/test/dict.cpp new file mode 100644 index 000000000..375905d69 --- /dev/null +++ b/src/boost/libs/python/test/dict.cpp @@ -0,0 +1,91 @@ +// Copyright David Abrahams 2004. 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 <boost/python/module.hpp> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> + +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/dict.hpp> +#include <exception> +#include <string> + +using namespace boost::python; + +object new_dict() +{ + return dict(); +} + +object data_dict() +{ + dict tmp1; + tmp1["key1"] = "value1"; + + dict tmp2; + tmp2["key2"] = "value2"; + tmp1[1] = tmp2; + return tmp1; +} + +object dict_from_sequence(object sequence) +{ + return dict(sequence); +} + +object dict_keys(dict data) +{ + return data.keys(); +} + +object dict_values(dict data) +{ + return data.values(); +} + +object dict_items(dict data) +{ + return data.items(); +} + +void work_with_dict(dict data1, dict data2) +{ + if (!data1.has_key("k1")) { + throw std::runtime_error("dict does not have key 'k1'"); + } + data1.update(data2); +} + +void test_templates(object print) +{ + std::string key = "key"; + + dict tmp; + tmp[1] = "a test string"; + print(tmp.get(1)); + //print(tmp[1]); + tmp[1.5] = 13; + print(tmp.get(1.5)); + print(tmp.get(44)); + print(tmp); + print(tmp.get(2,"default")); + print(tmp.setdefault(3,"default")); + + BOOST_ASSERT(!tmp.has_key(key)); + //print(tmp[3]); +} + +BOOST_PYTHON_MODULE(dict_ext) +{ + def("new_dict", new_dict); + def("data_dict", data_dict); + def("dict_keys", dict_keys); + def("dict_values", dict_values); + def("dict_items", dict_items); + def("dict_from_sequence", dict_from_sequence); + def("work_with_dict", work_with_dict); + def("test_templates", test_templates); +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/dict.py b/src/boost/libs/python/test/dict.py new file mode 100644 index 000000000..72c37d99e --- /dev/null +++ b/src/boost/libs/python/test/dict.py @@ -0,0 +1,46 @@ +# Copyright David Abrahams 2004. 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) +from __future__ import print_function +""" +>>> from dict_ext import * +>>> def printer(*args): +... for x in args: print(x, end='') +... print('') +... +>>> print(new_dict()) +{} +>>> print(data_dict()) +{1: {'key2': 'value2'}, 'key1': 'value1'} +>>> tmp = data_dict() +>>> print(dict_keys(tmp)) +[1, 'key1'] +>>> print(dict_values(tmp)) +[{'key2': 'value2'}, 'value1'] +>>> print(dict_items(tmp)) +[(1, {'key2': 'value2'}), ('key1', 'value1')] +>>> print(dict_from_sequence([(1,1),(2,2),(3,3)])) +{1: 1, 2: 2, 3: 3} +>>> test_templates(printer) #doctest: +NORMALIZE_WHITESPACE +a test string +13 +None +{1.5: 13, 1: 'a test string'} +default +default +""" + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/docstring.cpp b/src/boost/libs/python/test/docstring.cpp new file mode 100644 index 000000000..c6cc0252b --- /dev/null +++ b/src/boost/libs/python/test/docstring.cpp @@ -0,0 +1,116 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/operators.hpp> +#include <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/docstring_options.hpp> +#include <boost/python/scope.hpp> +#include <boost/python/manage_new_object.hpp> +#include "test_class.hpp" + +// Just use math.h here; trying to use std::pow() causes too much +// trouble for non-conforming compilers and libraries. +#include <math.h> + +using namespace boost::python; + +typedef test_class<> X; + +X* create(int x) +{ + return new X(x); +} + +unsigned long fact(unsigned long n) +{ + return n <= 1 ? n : n * fact(n - 1); +} + +BOOST_PYTHON_MODULE(docstring_ext) +{ + scope().attr("__doc__") = + "A simple test module for documentation strings\n" + "Exercised by docstring.py" + ; + + class_<X>("X", + "A simple class wrapper around a C++ int\n" + "includes some error-checking" + + , init<int>( + "this is the __init__ function\n" + "its documentation has two lines." + , args("self", "value") + ) + + ) + .def("value", &X::value, + "gets the value of the object" + , args("self")) + .def( "value", &X::value, + "also gets the value of the object" + , args("self")) + ; + + def("create", create, return_value_policy<manage_new_object>(), + "creates a new X object", args("value")); + + def("fact", fact, "compute the factorial", args("n")); + + { + docstring_options doc_options; + doc_options.disable_user_defined(); + def("fact_usr_off_1", fact, "usr off 1", args("n")); + doc_options.enable_user_defined(); + def("fact_usr_on_1", fact, "usr on 1", args("n")); + doc_options.disable_user_defined(); + def("fact_usr_off_2", fact, "usr off 2", args("n")); + } + def("fact_usr_on_2", fact, "usr on 2", args("n")); + + { + docstring_options doc_options(true, false); + def("fact_sig_off_1", fact, "sig off 1", args("n")); + doc_options.enable_signatures(); + def("fact_sig_on_1", fact, "sig on 1", args("n")); + doc_options.disable_signatures(); + def("fact_sig_off_2", fact, "sig off 2", args("n")); + } + def("fact_sig_on_2", fact, "sig on 2", args("n")); + + { + docstring_options doc_options(false); + def("fact_usr_off_sig_off_1", fact, "usr off sig off 1", args("n")); + { + docstring_options nested_doc_options; + def("fact_usr_on_sig_on_1", fact, "usr on sig on 1", args("n")); + nested_doc_options.disable_all(); + nested_doc_options.enable_user_defined(); + def("fact_usr_on_sig_off_1", fact, "usr on sig off 1", args("n")); + nested_doc_options.enable_all(); + def("fact_usr_on_sig_on_2", fact, "usr on sig on 2", args("n")); + } + def("fact_usr_off_sig_off_2", fact, "usr off sig off 2", args("n")); + } + + { + docstring_options doc_options(true); + doc_options.disable_cpp_signatures(); + def("fact_usr_on_psig_on_csig_off_1", fact, "usr on psig on csig off 1", args("n")); + doc_options.enable_cpp_signatures(); + doc_options.disable_py_signatures(); + def("fact_usr_on_psig_off_csig_on_1", fact, "usr on psig off csig on 1", args("n")); + doc_options.enable_py_signatures(); + doc_options.disable_user_defined(); + doc_options.disable_cpp_signatures(); + def("fact_usr_off_psig_on_csig_off_1", fact, "usr off psig on csig off 1", args("n")); + doc_options.enable_cpp_signatures(); + doc_options.disable_py_signatures(); + def("fact_usr_off_psig_off_csig_on_1", fact, "usr off psig off csig on 1", args("n")); + } +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/docstring.py b/src/boost/libs/python/test/docstring.py new file mode 100644 index 000000000..2727bd6d5 --- /dev/null +++ b/src/boost/libs/python/test/docstring.py @@ -0,0 +1,153 @@ +# Copyright David Abrahams & Ralf W. Grosse-Kunsteve 2004-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) +''' +>>> from docstring_ext import * + +>>> def selected_doc(obj, *args): +... doc = obj.__doc__.splitlines() +... return "\\n".join(["|"+doc[i] for i in args]) + +>>> print(selected_doc(X.__init__, 1, 2, 3, 4, 5)) +|__init__( (object)self, (int)value) -> None : +| this is the __init__ function +| its documentation has two lines. +| +| C++ signature : + +>>> print(selected_doc(X.value, 1, 2, 4, 7, 8, 10)) +|value( (X)self) -> int : +| gets the value of the object +| C++ signature : +|value( (X)self) -> int : +| also gets the value of the object +| C++ signature : + +>>> print(selected_doc(create, 1, 2, 3, 4)) +|create( (int)value) -> X : +| creates a new X object +| +| C++ signature : + +>>> print(selected_doc(fact, 1, 2, 3, 4)) +|fact( (int)n) -> int : +| compute the factorial +| +| C++ signature : + +>>> len(fact_usr_off_1.__doc__.splitlines()) +5 +>>> print(selected_doc(fact_usr_off_1, 1, 3)) +|fact_usr_off_1( (int)n) -> int : +| C++ signature : +>>> len(fact_usr_on_1.__doc__.splitlines()) +6 +>>> print(selected_doc(fact_usr_on_1, 1, 2, 4)) +|fact_usr_on_1( (int)n) -> int : +| usr on 1 +| C++ signature : +>>> len(fact_usr_off_2.__doc__.splitlines()) +5 +>>> print(selected_doc(fact_usr_off_2, 1, 3)) +|fact_usr_off_2( (int)n) -> int : +| C++ signature : +>>> len(fact_usr_on_2.__doc__.splitlines()) +6 +>>> print(selected_doc(fact_usr_on_2, 1, 2, 4)) +|fact_usr_on_2( (int)n) -> int : +| usr on 2 +| C++ signature : + + +>>> len(fact_sig_off_1.__doc__.splitlines()) +2 +>>> print(selected_doc(fact_sig_off_1, 1)) +|sig off 1 +>>> len(fact_sig_on_1.__doc__.splitlines()) +6 +>>> print(selected_doc(fact_sig_on_1, 1, 2, 4)) +|fact_sig_on_1( (int)n) -> int : +| sig on 1 +| C++ signature : + +>>> len(fact_sig_off_2.__doc__.splitlines()) +2 +>>> print(selected_doc(fact_sig_off_2, 1)) +|sig off 2 +>>> len(fact_sig_on_2.__doc__.splitlines()) +6 +>>> print(selected_doc(fact_sig_on_2, 1, 2, 4)) +|fact_sig_on_2( (int)n) -> int : +| sig on 2 +| C++ signature : + + +>>> print(fact_usr_off_sig_off_1.__doc__) +None +>>> len(fact_usr_on_sig_on_1.__doc__.splitlines()) +6 +>>> print(selected_doc(fact_usr_on_sig_on_1, 1, 2, 4)) +|fact_usr_on_sig_on_1( (int)n) -> int : +| usr on sig on 1 +| C++ signature : + +>>> len(fact_usr_on_sig_off_1.__doc__.splitlines()) +2 +>>> print(selected_doc(fact_usr_on_sig_off_1, 1)) +|usr on sig off 1 +>>> len(fact_usr_on_sig_on_2.__doc__.splitlines()) +6 +>>> print(selected_doc(fact_usr_on_sig_on_2, 1, 2, 4)) +|fact_usr_on_sig_on_2( (int)n) -> int : +| usr on sig on 2 +| C++ signature : + +>>> print(selected_doc(fact_usr_on_psig_on_csig_off_1, 1, 2)) +|fact_usr_on_psig_on_csig_off_1( (int)n) -> int : +| usr on psig on csig off 1 + +>>> print(selected_doc(fact_usr_on_psig_off_csig_on_1, 1, 3)) +|usr on psig off csig on 1 +|C++ signature : + +>>> print(fact_usr_off_psig_on_csig_off_1.__doc__.splitlines()[1]) +fact_usr_off_psig_on_csig_off_1( (int)n) -> int + +>>> print(selected_doc(fact_usr_off_psig_off_csig_on_1,1)) +|C++ signature : + + +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + + import docstring_ext + + result = doctest.testmod(sys.modules.get(__name__)) + + import pydoc + import re + docmodule = lambda m: re.sub(".\10", "", pydoc.text.docmodule(m)) + try: + print('printing module help:') + print(docmodule(docstring_ext)) + except object as x: + print('********* failed **********') + print(x) + result = list(result) + result[0] += 1 + return tuple(result) + + return result + +if __name__ == '__main__': + print("running...") + import sys + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/enable_shared_from_this.cpp b/src/boost/libs/python/test/enable_shared_from_this.cpp new file mode 100644 index 000000000..c246284a1 --- /dev/null +++ b/src/boost/libs/python/test/enable_shared_from_this.cpp @@ -0,0 +1,48 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/call_method.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/def.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/shared_ptr.hpp> +#include "test_class.hpp" + +#include <memory> + +using namespace boost::python; +using boost::shared_ptr; + +class Test; +typedef shared_ptr<Test> TestPtr; + +class Test : public boost::enable_shared_from_this<Test> { +public: + static TestPtr construct() { + return TestPtr(new Test); + } + + void act() { + TestPtr kungFuDeathGrip(shared_from_this()); + } + + void take(TestPtr t) { + } +}; + +BOOST_PYTHON_MODULE(enable_shared_from_this_ext) +{ + class_<Test, TestPtr, boost::noncopyable>("Test") + .def("construct", &Test::construct).staticmethod("construct") + .def("act", &Test::act) + .def("take", &Test::take) + ; +} + +#include "module_tail.cpp" + + diff --git a/src/boost/libs/python/test/enable_shared_from_this.py b/src/boost/libs/python/test/enable_shared_from_this.py new file mode 100644 index 000000000..d7ac7a999 --- /dev/null +++ b/src/boost/libs/python/test/enable_shared_from_this.py @@ -0,0 +1,26 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from enable_shared_from_this_ext import * + +>>> x = Test.construct() +>>> x.take(x) +>>> x.act() +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) + diff --git a/src/boost/libs/python/test/enum_ext.cpp b/src/boost/libs/python/test/enum_ext.cpp new file mode 100644 index 000000000..74224f1d7 --- /dev/null +++ b/src/boost/libs/python/test/enum_ext.cpp @@ -0,0 +1,55 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/enum.hpp> +#include <boost/python/def.hpp> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#if BOOST_WORKAROUND(__MWERKS__, <= 0x2407) +#include <boost/python/detail/type_traits.hpp> +# include <boost/mpl/bool.hpp> +#endif +using namespace boost::python; + +enum color { red = 1, green = 2, blue = 4, blood = 1 }; + +#if BOOST_WORKAROUND(__MWERKS__, <= 0x2407) +namespace boost // Pro7 has a hard time detecting enums +{ + template <> struct boost::python::detail::is_enum<color> : boost::mpl::true_ {}; +} +#endif + +color identity_(color x) { return x; } + +struct colorized { + colorized() : x(red) {} + color x; +}; + +BOOST_PYTHON_MODULE(enum_ext) +{ + enum_<color>("color") + .value("red", red) + .value("green", green) + .value("blue", blue) + .value("blood", blood) + .export_values() + ; + + def("identity", identity_); + +#if BOOST_WORKAROUND(__MWERKS__, <=0x2407) + color colorized::*px = &colorized::x; + class_<colorized>("colorized") + .def_readwrite("x", px) + ; +#else + class_<colorized>("colorized") + .def_readwrite("x", &colorized::x) + ; +#endif +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/exception_translator.cpp b/src/boost/libs/python/test/exception_translator.cpp new file mode 100644 index 000000000..1e91c9296 --- /dev/null +++ b/src/boost/libs/python/test/exception_translator.cpp @@ -0,0 +1,28 @@ +// Copyright David Abrahams 2004. 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/exception_translator.hpp> + +struct error {}; + +void translate(error const& /*e*/) +{ + PyErr_SetString(PyExc_RuntimeError, "!!!error!!!"); +} + +void throw_error() +{ + throw error(); + +} + +BOOST_PYTHON_MODULE(exception_translator_ext) +{ + using namespace boost::python; + register_exception_translator<error>(&translate); + + def("throw_error", throw_error); +} + diff --git a/src/boost/libs/python/test/exception_translator.py b/src/boost/libs/python/test/exception_translator.py new file mode 100644 index 000000000..1d80aba3a --- /dev/null +++ b/src/boost/libs/python/test/exception_translator.py @@ -0,0 +1,27 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from exception_translator_ext import * +>>> try: +... throw_error(); +... except RuntimeError as x: +... print(x) +... else: +... print('Expected a RuntimeError!') +!!!error!!! +''' +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/exec.cpp b/src/boost/libs/python/test/exec.cpp new file mode 100644 index 000000000..72ff571bd --- /dev/null +++ b/src/boost/libs/python/test/exec.cpp @@ -0,0 +1,197 @@ +// Copyright Stefan Seefeld 2005. +// 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 <boost/python.hpp> + +#include <boost/detail/lightweight_test.hpp> +#include <iostream> + + +namespace python = boost::python; + +// An abstract base class +class Base : public boost::noncopyable +{ +public: + virtual ~Base() {}; + virtual std::string hello() = 0; +}; + +// C++ derived class +class CppDerived : public Base +{ +public: + virtual ~CppDerived() {} + virtual std::string hello() { return "Hello from C++!";} +}; + +// Familiar Boost.Python wrapper class for Base +struct BaseWrap : Base, python::wrapper<Base> +{ + virtual std::string hello() + { +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + // workaround for VC++ 6.x or 7.0, see + // http://boost.org/libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions + return python::call<std::string>(this->get_override("hello").ptr()); +#else + return this->get_override("hello")(); +#endif + } +}; + +// Pack the Base class wrapper into a module +BOOST_PYTHON_MODULE(embedded_hello) +{ + python::class_<BaseWrap, boost::noncopyable> base("Base"); +} + + +void eval_test() +{ + python::object result = python::eval("'abcdefg'.upper()"); + std::string value = python::extract<std::string>(result) BOOST_EXTRACT_WORKAROUND; + BOOST_TEST(value == "ABCDEFG"); +} + +void exec_test() +{ + // Retrieve the main module + python::object main = python::import("__main__"); + + // Retrieve the main module's namespace + python::object global(main.attr("__dict__")); + + // Define the derived class in Python. + python::object result = python::exec( + "from embedded_hello import * \n" + "class PythonDerived(Base): \n" + " def hello(self): \n" + " return 'Hello from Python!' \n", + global, global); + + python::object PythonDerived = global["PythonDerived"]; + + // Creating and using instances of the C++ class is as easy as always. + CppDerived cpp; + BOOST_TEST(cpp.hello() == "Hello from C++!"); + + // But now creating and using instances of the Python class is almost + // as easy! + python::object py_base = PythonDerived(); + Base& py = python::extract<Base&>(py_base) BOOST_EXTRACT_WORKAROUND; + + // Make sure the right 'hello' method is called. + BOOST_TEST(py.hello() == "Hello from Python!"); +} + +void exec_file_test(std::string const &script) +{ + // Run a python script in an empty environment. + python::dict global; + python::object result = python::exec_file(script.c_str(), global, global); + + // Extract an object the script stored in the global dictionary. + BOOST_TEST(python::extract<int>(global["number"]) == 42); +} + +void exec_test_error() +{ + // Execute a statement that raises a python exception. + python::dict global; + python::object result = python::exec("print(unknown) \n", global, global); +} + +void exercise_embedding_html() +{ + using namespace boost::python; + /* code from: libs/python/doc/tutorial/doc/tutorial.qbk + (generates libs/python/doc/tutorial/doc/html/python/embedding.html) + */ + 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); +} + +void check_pyerr(bool pyerr_expected=false) +{ + if (PyErr_Occurred()) + { + if (!pyerr_expected) { + BOOST_ERROR("Python Error detected"); + PyErr_Print(); + } + else { + PyErr_Clear(); + } + } + else + { + BOOST_ERROR("A C++ exception was thrown for which " + "there was no exception handler registered."); + } +} + +int main(int argc, char **argv) +{ + BOOST_TEST(argc == 2 || argc == 3); + std::string script = argv[1]; + + // Register the module with the interpreter + if (PyImport_AppendInittab(const_cast<char*>("embedded_hello"), +#if PY_VERSION_HEX >= 0x03000000 + PyInit_embedded_hello +#else + initembedded_hello +#endif + ) == -1) + { + BOOST_ERROR("Failed to add embedded_hello to the interpreter's " + "builtin modules"); + } + + // Initialize the interpreter + Py_Initialize(); + + if (python::handle_exception(eval_test)) { + check_pyerr(); + } + else if(python::handle_exception(exec_test)) { + check_pyerr(); + } + else if (python::handle_exception(boost::bind(exec_file_test, script))) { + check_pyerr(); + } + + if (python::handle_exception(exec_test_error)) + { + check_pyerr(/*pyerr_expected*/ true); + } + else + { + BOOST_ERROR("Python exception expected, but not seen."); + } + + if (argc > 2) { + // The main purpose is to test compilation. Since this test generates + // a file and I (rwgk) am uncertain about the side-effects, run it only + // if explicitly requested. + exercise_embedding_html(); + } + + // Boost.Python doesn't support Py_Finalize yet. + // Py_Finalize(); + return boost::report_errors(); +} + +// Including this file makes sure +// that on Windows, any crashes (e.g. null pointer dereferences) invoke +// the debugger immediately, rather than being translated into structured +// exceptions that can interfere with debugging. +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/exec.py b/src/boost/libs/python/test/exec.py new file mode 100644 index 000000000..c7bf28f35 --- /dev/null +++ b/src/boost/libs/python/test/exec.py @@ -0,0 +1,6 @@ +# Copyright Stefan Seefeld 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) + +if 1: + number = 42 diff --git a/src/boost/libs/python/test/extract.cpp b/src/boost/libs/python/test/extract.cpp new file mode 100644 index 000000000..40584a077 --- /dev/null +++ b/src/boost/libs/python/test/extract.cpp @@ -0,0 +1,143 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/extract.hpp> +#include <boost/python/list.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/reference_existing_object.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/python/implicit.hpp> +#include <string> +#include <boost/lexical_cast.hpp> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> +#include "test_class.hpp" + +using namespace boost::python; + +typedef test_class<> X; + +bool extract_bool(object x) { return extract<bool>(x); } + +boost::python::list extract_list(object x) +{ + extract<list> get_list((x)); + + // Make sure we always have the right idea about whether it's a list + bool is_list_1 = get_list.check(); + bool is_list_2 = PyObject_IsInstance(x.ptr(), (PyObject*)&PyList_Type); + if (is_list_1 != is_list_2) { + throw std::runtime_error("is_list_1 == is_list_2 failure."); + } + return get_list(); +} + +char const* extract_cstring(object x) +{ + return extract<char const*>(x); +} + +std::string extract_string(object x) +{ + std::string s = extract<std::string>(x); + return s; +} + +std::string const& extract_string_cref(object x) +{ +#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 +# pragma warning(push) +# pragma warning(disable:4172) // msvc lies about returning a reference to temporary +#elif defined(_MSC_VER) && defined(__ICL) && __ICL <= 900 +# pragma warning(push) +# pragma warning(disable:473) // intel/win32 does too +#endif + + return extract<std::string const&>(x); + +#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 || defined(_MSC_VER) && defined(__ICL) && __ICL <= 800 +# pragma warning(pop) +#endif +} + +X extract_X(object x) +{ + return extract<X>(x); +} + +X* extract_X_ptr(object x) { return extract<X*>(x); } + +X& extract_X_ref(object x) +{ + extract<X&> get_x(x); + return get_x; +} + +int double_X(object n) +{ + extract<X> x(n); + return x().value() + x().value(); +} + +bool check_bool(object x) { return extract<bool>(x).check(); } +bool check_list(object x) { return extract<list>(x).check(); } +bool check_cstring(object x) { return extract<char const*>(x).check(); } +bool check_string(object x) { return extract<std::string>(x).check(); } +bool check_string_cref(object x) { return extract<std::string const&>(x).check(); } +bool check_X(object x) { return extract<X>(x).check(); } +bool check_X_ptr(object x) { return extract<X*>(x).check(); } +bool check_X_ref(object x) { return extract<X&>(x).check(); } + +std::string x_rep(X const& x) +{ + return "X(" + boost::lexical_cast<std::string>(x.value()) + ")"; +} + +BOOST_PYTHON_MODULE(extract_ext) +{ + implicitly_convertible<int, X>(); + + def("extract_bool", extract_bool); + def("extract_list", extract_list); + def("extract_cstring", extract_cstring); + def("extract_string", extract_string); + def("extract_string_cref", extract_string_cref, return_value_policy<reference_existing_object>()); + def("extract_X", extract_X); + def("extract_X_ptr", extract_X_ptr, return_value_policy<reference_existing_object>()); + def("extract_X_ref", extract_X_ref, return_value_policy<reference_existing_object>()); + + def("check_bool", check_bool); + def("check_list", check_list); + def("check_cstring", check_cstring); + def("check_string", check_string); + def("check_string_cref", check_string_cref); + def("check_X", check_X); + def("check_X_ptr", check_X_ptr); + def("check_X_ref", check_X_ref); + + def("double_X", double_X); + + def("count_Xs", &X::count); + ; + + object x_class( + class_<X>("X", init<int>()) + .def( "__repr__", x_rep)); + + // Instantiate an X object through the Python interface + object x_obj = x_class(3); + + // Get the C++ object out of the Python object + X const& x = extract<X&>(x_obj); + if (x.value() != 3) { + throw std::runtime_error("x.value() == 3 failure."); + } +} + + +#include "module_tail.cpp" + diff --git a/src/boost/libs/python/test/extract.py b/src/boost/libs/python/test/extract.py new file mode 100644 index 000000000..feda93a1d --- /dev/null +++ b/src/boost/libs/python/test/extract.py @@ -0,0 +1,107 @@ +# Copyright David Abrahams 2004. 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) +''' + >>> from extract_ext import * + +Just about anything has a truth value in Python + + >>> assert check_bool(None) + >>> extract_bool(None) + 0 + + >>> assert check_bool(2) + >>> extract_bool(2) + 1 + + >>> assert not check_bool('') + +Check that object manager types work properly. These are a different +case because they wrap Python objects instead of being wrapped by them. + + >>> assert not check_list(2) + >>> try: x = extract_list(2) + ... except TypeError as x: + ... if str(x) != 'Expecting an object of type list; got an object of type int instead': + ... print(x) + ... else: + ... print('expected an exception, got', x, 'instead') + +Can't extract a list from a tuple. Use list(x) to convert a sequence +to a list: + + >>> assert not check_list((1, 2, 3)) + >>> assert check_list([1, 2, 3]) + >>> extract_list([1, 2, 3]) + [1, 2, 3] + +Can get a char const* from a Python string: + + >>> assert check_cstring('hello') + >>> extract_cstring('hello') + 'hello' + +Can't get a char const* from a Python int: + + >>> assert not check_cstring(1) + >>> try: x = extract_cstring(1) + ... except TypeError: pass + ... else: + ... print('expected an exception, got', x, 'instead') + +Extract an std::string (class) rvalue from a native Python type + + >>> assert check_string('hello') + >>> extract_string('hello') + 'hello' + +Constant references are not treated as rvalues for the purposes of +extract: + + >>> assert not check_string_cref('hello') + +We can extract lvalues where appropriate: + + >>> x = X(42) + >>> check_X(x) + 1 + >>> extract_X(x) + X(42) + + >>> check_X_ptr(x) + 1 + >>> extract_X_ptr(x) + X(42) + >>> extract_X_ref(x) + X(42) + +Demonstrate that double-extraction of an rvalue works, and all created +copies of the object are destroyed: + + >>> n = count_Xs() + >>> double_X(333) + 666 + >>> count_Xs() - n + 0 + +General check for cleanliness: + + >>> del x + >>> count_Xs() + 0 +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/fabscript b/src/boost/libs/python/test/fabscript new file mode 100644 index 000000000..1989cc0d1 --- /dev/null +++ b/src/boost/libs/python/test/fabscript @@ -0,0 +1,173 @@ +# -*- python -*- +# +# Copyright (c) 2016 Stefan Seefeld +# All rights reserved. +# +# 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) + +from faber import platform +from faber.feature import set +from faber.tools.compiler import runpath +from faber.tools.python import python, pythonpath +from faber.artefacts.object import object +from faber.artefacts.binary import binary +from faber.artefacts.python import extension +from faber.test import test, report, fail + +src = module('..src') + +python_libs=python.instance().libs +features |= runpath(src.bpl.path, base='') + +def extension_test(name, ext=[], script=None, np=False, + features=features, condition=None): + """Create a Python extension test `name`. + Arguments: + * name: the name of the test. + * ext: extensions to be compiled, <name> if none are given. + * script: the test script to execute, <name>.py if none is given. + * np: if true, add boost_numpy to sources + * features: pre-defined features + * condition: any condition under which to run the test + Return: + * the test artefact""" + + features=features.copy() + extensions = [] + libs = [src.bnl, src.bpl] if np else [src.bpl] + for e in ext or [name]: + if type(e) is str: # build from a single source file + n = e if e != name else e + '_ext' + s = [e + '.cpp'] + else: # build from a list of source files + n = e[0] if e[0] != name else e[0] + '_ext' + s = [n + '.cpp' for n in e] + e = extension(n, s + libs, features=features) + features |= pythonpath(e.path, base='') + extensions.append(e) + if not script: + script = name+'.py' + return test(name, script, run=python.run, dependencies=extensions, + features=features, condition=condition) + +tests = [] +for t in [('injected',), + ('properties',), + ('return_arg',), + ('staticmethod',), + ('boost_shared_ptr',), + ('enable_shared_from_this',), + ('andreas_beyer',), + ('polymorphism',), + ('polymorphism2',), + ('wrapper_held_type',), + ('minimal',), + ('args',), + ('raw_ctor',), + ('exception_translator',), + ('test_enum', ['enum_ext']), + ('test_cltree', ['cltree']), + ('newtest', ['m1', 'm2']), + ('const_argument',), + ('keywords_test', ['keywords']), + ('test_pointer_adoption',), + ('operators',), + ('operators_wrapper',), + ('callbacks',), + ('defaults',), + ('object',), + ('list',), + ('long',), + ('dict',), + ('tuple',), + ('str',), + ('slice',), + ('virtual_functions',), + ('back_reference',), + ('implicit',), + ('data_members',), + ('ben_scott1',), + ('bienstman1',), + ('bienstman2',), + ('bienstman3',), + ('multi_arg_constructor',), + ('iterator', ['iterator', 'input_iterator']), + ('stl_iterator',), + ('extract',), + ('crossmod_opaque', ['crossmod_opaque_a', 'crossmod_opaque_b']), + ('opaque',), + ('voidptr',), + ('pickle1',), + ('pickle2',), + ('pickle3',), + ('pickle4',), + ('nested',), + ('docstring',), + ('pytype_function',), + ('vector_indexing_suite',), + ('pointer_vector',), + ('builtin_converters', [], 'test_builtin_converters.py'), + ('map_indexing_suite', + [['map_indexing_suite', 'int_map_indexing_suite', 'a_map_indexing_suite']])]: + tests.append(extension_test(*t)) + +tests.append(extension_test('shared_ptr', + condition=set.define.contains('HAS_CXX11'))) +tests.append(extension_test('polymorphism2_auto_ptr', + condition=set.define.contains('HAS_CXX11').not_())) +tests.append(extension_test('auto_ptr', + condition=set.define.contains('HAS_CXX11'))) + +import_ = binary('import_', ['import_.cpp', src.bpl], features=features|python_libs) +if platform.os == 'Windows': + command = """set PATH=$(runpath);%PATH% +$(>[1]) $(>[2])""" +else: + command = 'LD_LIBRARY_PATH=$(runpath) $(>[1]) $(>[2])' + +tests.append(test('import', [import_, 'import_.py'], + run=action('run', command), + features=features)) + +tests.append(extension_test('calling_conventions', + condition=platform.os == 'Windows')) +tests.append(extension_test('calling_conventions_mf', + condition=platform.os == 'Windows')) + +for t in ['destroy_test', + 'pointer_type_id_test', + 'bases', + 'pointee', + 'if_else', + 'pointee', + 'result', + 'upcast', + 'select_from_python_test']: + tests.append(test(t, binary(t, [t + '.cpp', src.bpl], features=features), features=features, run=True)) +for t in ['indirect_traits_test', + 'string_literal', + 'borrowed', + 'object_manager', + 'copy_ctor_mutates_rhs', + 'select_holder', + 'select_arg_to_python_test']: + tests.append(test(t, object(t, [t + '.cpp'], features=features))) + +for t in ['raw_pyobject_fail1', + 'raw_pyobject_fail2', + 'as_to_python_function', + 'object_fail1']: + tests.append(test(t, object(t, [t + '.cpp'], features=features), expected=fail)) + +for t in ['numpy/dtype', + 'numpy/ufunc', + 'numpy/templates', + 'numpy/ndarray', + 'numpy/indexing', + 'numpy/shapes']: + tests.append(extension_test(t, np=True, + condition=set.define.contains('HAS_NUMPY'))) + +default = report('report', tests, fail_on_failures=True) diff --git a/src/boost/libs/python/test/if_else.cpp b/src/boost/libs/python/test/if_else.cpp new file mode 100644 index 000000000..60cc53192 --- /dev/null +++ b/src/boost/libs/python/test/if_else.cpp @@ -0,0 +1,44 @@ +// Copyright David Abrahams 2002. +// 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 <boost/static_assert.hpp> +#include <boost/python/detail/if_else.hpp> +#include <boost/python/detail/type_traits.hpp> + + typedef char c1; + typedef char c2[2]; + typedef char c3[3]; + typedef char c4[4]; + +template <unsigned size> +struct choose +{ + typedef typename boost::python::detail::if_< + (sizeof(c1) == size) + >::template then< + c1 + >::template elif< + (sizeof(c2) == size) + >::template then< + c2 + >::template elif< + (sizeof(c3) == size) + >::template then< + c3 + >::template elif< + (sizeof(c4) == size) + >::template then< + c4 + >::template else_<void*>::type type; +}; + +int main() +{ + BOOST_STATIC_ASSERT((boost::python::detail::is_same<choose<1>::type,c1>::value)); + BOOST_STATIC_ASSERT((boost::python::detail::is_same<choose<2>::type,c2>::value)); + BOOST_STATIC_ASSERT((boost::python::detail::is_same<choose<3>::type,c3>::value)); + BOOST_STATIC_ASSERT((boost::python::detail::is_same<choose<4>::type,c4>::value)); + BOOST_STATIC_ASSERT((boost::python::detail::is_same<choose<5>::type,void*>::value)); + return 0; +} diff --git a/src/boost/libs/python/test/implicit.cpp b/src/boost/libs/python/test/implicit.cpp new file mode 100644 index 000000000..a1bae59e8 --- /dev/null +++ b/src/boost/libs/python/test/implicit.cpp @@ -0,0 +1,48 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/class.hpp> +#include <boost/python/implicit.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include "test_class.hpp" + +using namespace boost::python; + +typedef test_class<> X; + +int x_value(X const& x) +{ + return x.value(); +} + +X make_x(int n) { return X(n); } + + +// foo/bar -- a regression for a vc7 bug workaround +struct bar {}; +struct foo +{ + virtual ~foo() {}; // silence compiler warnings + virtual void f() = 0; + operator bar() const { return bar(); } +}; + +BOOST_PYTHON_MODULE(implicit_ext) +{ + implicitly_convertible<foo,bar>(); + implicitly_convertible<int,X>(); + + def("x_value", x_value); + def("make_x", make_x); + + class_<X>("X", init<int>()) + .def("value", &X::value) + .def("set", &X::set) + ; + + implicitly_convertible<X,int>(); +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/implicit.py b/src/boost/libs/python/test/implicit.py new file mode 100644 index 000000000..f2aa3e1d3 --- /dev/null +++ b/src/boost/libs/python/test/implicit.py @@ -0,0 +1,44 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from implicit_ext import * +>>> x_value(X(42)) +42 +>>> x_value(42) +42 +>>> x = make_x(X(42)) +>>> x.value() +42 +>>> try: make_x('fool') +... except TypeError: pass +... else: print('no error') + +>>> print(x_value.__doc__.splitlines()[1]) +x_value( (X)arg1) -> int : + +>>> print(make_x.__doc__.splitlines()[1]) +make_x( (object)arg1) -> X : + +>>> print(X.value.__doc__.splitlines()[1]) +value( (X)arg1) -> int : + +>>> print(X.set.__doc__.splitlines()[1]) +set( (X)arg1, (object)arg2) -> None : + +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/import_.cpp b/src/boost/libs/python/test/import_.cpp new file mode 100644 index 000000000..3e21de0ba --- /dev/null +++ b/src/boost/libs/python/test/import_.cpp @@ -0,0 +1,70 @@ +// Copyright Stefan Seefeld 2007. +// 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 <boost/python.hpp> + +#include <boost/detail/lightweight_test.hpp> +#include <boost/bind.hpp> +#include <iostream> +#include <sstream> + +namespace bpl = boost::python; + +void import_test(char const *py_file_path) +{ + // Retrieve the main module + bpl::object main = bpl::import("__main__"); + + // Retrieve the main module's namespace + bpl::object global(main.attr("__dict__")); + + // Inject search path for import_ module + + bpl::str script( + "import sys, os.path\n" + "path = os.path.dirname(%r)\n" + "sys.path.insert(0, path)" + % bpl::str(py_file_path)); + + bpl::object result = bpl::exec(script, global, global); + + // Retrieve the main module + bpl::object import_ = bpl::import("import_"); + int value = bpl::extract<int>(import_.attr("value")) BOOST_EXTRACT_WORKAROUND; + std::cout << value << std::endl; + BOOST_TEST(value == 42); +} + +int main(int argc, char **argv) +{ + BOOST_TEST(argc == 2); + + // Initialize the interpreter + Py_Initialize(); + + if (bpl::handle_exception(boost::bind(import_test,argv[1]))) + { + if (PyErr_Occurred()) + { + BOOST_ERROR("Python Error detected"); + PyErr_Print(); + } + else + { + BOOST_ERROR("A C++ exception was thrown for which " + "there was no exception handler registered."); + } + } + + // Boost.Python doesn't support Py_Finalize yet. + // Py_Finalize(); + return boost::report_errors(); +} + +// Including this file makes sure +// that on Windows, any crashes (e.g. null pointer dereferences) invoke +// the debugger immediately, rather than being translated into structured +// exceptions that can interfere with debugging. +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/import_.py b/src/boost/libs/python/test/import_.py new file mode 100644 index 000000000..48de6e5ec --- /dev/null +++ b/src/boost/libs/python/test/import_.py @@ -0,0 +1,5 @@ +# Copyright Stefan Seefeld 2007. 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) + +value = 42 diff --git a/src/boost/libs/python/test/indirect_traits_test.cpp b/src/boost/libs/python/test/indirect_traits_test.cpp new file mode 100644 index 000000000..da4cc2456 --- /dev/null +++ b/src/boost/libs/python/test/indirect_traits_test.cpp @@ -0,0 +1,116 @@ +// Copyright David Abrahams 2004. 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 <stdio.h> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/python/detail/indirect_traits.hpp> +#include <boost/mpl/assert.hpp> + +//#define print(expr) printf("%s ==> %s\n", #expr, expr) + +// not all the compilers can handle an incomplete class type here. +struct X {}; + +using namespace boost::python::indirect_traits; + +typedef void (X::*pmf)(); + +BOOST_MPL_ASSERT((is_reference_to_function<int (&)()>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_function<int (*)()>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_function<int&>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_function<pmf>)); + +BOOST_MPL_ASSERT_NOT((is_pointer_to_function<int (&)()>)); +BOOST_MPL_ASSERT((is_pointer_to_function<int (*)()>)); +BOOST_MPL_ASSERT_NOT((is_pointer_to_function<int (*&)()>)); +BOOST_MPL_ASSERT_NOT((is_pointer_to_function<int (*const&)()>)); +BOOST_MPL_ASSERT_NOT((is_pointer_to_function<pmf>)); + +BOOST_MPL_ASSERT_NOT((is_reference_to_function_pointer<int (&)()>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_function_pointer<int (*)()>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_function_pointer<int&>)); +BOOST_MPL_ASSERT((is_reference_to_function_pointer<int (*&)()>)); +BOOST_MPL_ASSERT((is_reference_to_function_pointer<int (*const&)()>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_function_pointer<pmf>)); + +BOOST_MPL_ASSERT((is_reference_to_pointer<int*&>)); +BOOST_MPL_ASSERT((is_reference_to_pointer<int* const&>)); +BOOST_MPL_ASSERT((is_reference_to_pointer<int*volatile&>)); +BOOST_MPL_ASSERT((is_reference_to_pointer<int*const volatile&>)); +BOOST_MPL_ASSERT((is_reference_to_pointer<int const*&>)); +BOOST_MPL_ASSERT((is_reference_to_pointer<int const* const&>)); +BOOST_MPL_ASSERT((is_reference_to_pointer<int const*volatile&>)); +BOOST_MPL_ASSERT((is_reference_to_pointer<int const*const volatile&>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_pointer<pmf>)); + +BOOST_MPL_ASSERT_NOT((is_reference_to_pointer<int const volatile>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_pointer<int>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_pointer<int*>)); + +BOOST_MPL_ASSERT_NOT((is_reference_to_const<int*&>)); +BOOST_MPL_ASSERT((is_reference_to_const<int* const&>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_const<int*volatile&>)); +BOOST_MPL_ASSERT((is_reference_to_const<int*const volatile&>)); + +BOOST_MPL_ASSERT_NOT((is_reference_to_const<int const volatile>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_const<int>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_const<int*>)); + +BOOST_MPL_ASSERT((is_reference_to_non_const<int*&>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_non_const<int* const&>)); +BOOST_MPL_ASSERT((is_reference_to_non_const<int*volatile&>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_non_const<int*const volatile&>)); + +BOOST_MPL_ASSERT_NOT((is_reference_to_non_const<int const volatile>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_non_const<int>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_non_const<int*>)); + +BOOST_MPL_ASSERT_NOT((is_reference_to_volatile<int*&>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_volatile<int* const&>)); +BOOST_MPL_ASSERT((is_reference_to_volatile<int*volatile&>)); +BOOST_MPL_ASSERT((is_reference_to_volatile<int*const volatile&>)); + +BOOST_MPL_ASSERT_NOT((is_reference_to_volatile<int const volatile>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_volatile<int>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_volatile<int*>)); + +namespace tt = boost::python::indirect_traits; + +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_class<int>)); +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_class<int&>)); +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_class<int*>)); + + +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_class<pmf>)); +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_class<pmf const&>)); + +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_class<X>)); + +BOOST_MPL_ASSERT((tt::is_reference_to_class<X&>)); +BOOST_MPL_ASSERT((tt::is_reference_to_class<X const&>)); +BOOST_MPL_ASSERT((tt::is_reference_to_class<X volatile&>)); +BOOST_MPL_ASSERT((tt::is_reference_to_class<X const volatile&>)); + +BOOST_MPL_ASSERT_NOT((is_pointer_to_class<int>)); +BOOST_MPL_ASSERT_NOT((is_pointer_to_class<int*>)); +BOOST_MPL_ASSERT_NOT((is_pointer_to_class<int&>)); + +BOOST_MPL_ASSERT_NOT((is_pointer_to_class<X>)); +BOOST_MPL_ASSERT_NOT((is_pointer_to_class<X&>)); +BOOST_MPL_ASSERT_NOT((is_pointer_to_class<pmf>)); +BOOST_MPL_ASSERT_NOT((is_pointer_to_class<pmf const>)); +BOOST_MPL_ASSERT((is_pointer_to_class<X*>)); +BOOST_MPL_ASSERT((is_pointer_to_class<X const*>)); +BOOST_MPL_ASSERT((is_pointer_to_class<X volatile*>)); +BOOST_MPL_ASSERT((is_pointer_to_class<X const volatile*>)); + +BOOST_MPL_ASSERT((tt::is_reference_to_member_function_pointer<pmf&>)); +BOOST_MPL_ASSERT((tt::is_reference_to_member_function_pointer<pmf const&>)); +BOOST_MPL_ASSERT((tt::is_reference_to_member_function_pointer<pmf volatile&>)); +BOOST_MPL_ASSERT((tt::is_reference_to_member_function_pointer<pmf const volatile&>)); +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_member_function_pointer<pmf[2]>)); +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_member_function_pointer<pmf(&)[2]>)); +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_member_function_pointer<pmf>)); + diff --git a/src/boost/libs/python/test/injected.cpp b/src/boost/libs/python/test/injected.cpp new file mode 100644 index 000000000..73e1e14ba --- /dev/null +++ b/src/boost/libs/python/test/injected.cpp @@ -0,0 +1,39 @@ +// Copyright David Abrahams 2003. +// 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 <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include "test_class.hpp" +#include <memory> +#include <boost/shared_ptr.hpp> +#include <boost/python/make_constructor.hpp> +#include <boost/python/args.hpp> + +using namespace boost::python; + +typedef test_class<> X; + +X* empty() { return new X(1000); } + +std::auto_ptr<X> sum(int a, int b) { return std::auto_ptr<X>(new X(a+b)); } + +boost::shared_ptr<X> product(int a, int b, int c) +{ + return boost::shared_ptr<X>(new X(a*b*c)); +} + +BOOST_PYTHON_MODULE(injected_ext) +{ + class_<X>("X", init<int>()) + .def("__init__", make_constructor(empty)) + .def("__init__", make_constructor(sum)) + .def("__init__", make_constructor(product + , default_call_policies() + , ( arg_("a"), arg_("b"), arg_("c")) + ), + "this is product's docstring") + .def("value", &X::value) + ; +} diff --git a/src/boost/libs/python/test/injected.py b/src/boost/libs/python/test/injected.py new file mode 100644 index 000000000..c50215048 --- /dev/null +++ b/src/boost/libs/python/test/injected.py @@ -0,0 +1,28 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from injected_ext import * +>>> X(3,5).value() - (3+5) +0 +>>> X(a=3,b=5,c=7).value() - (3*5*7) +0 +>>> X().value() +1000 +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) + diff --git a/src/boost/libs/python/test/input_iterator.cpp b/src/boost/libs/python/test/input_iterator.cpp new file mode 100644 index 000000000..70b994186 --- /dev/null +++ b/src/boost/libs/python/test/input_iterator.cpp @@ -0,0 +1,48 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/iterator.hpp> +#include <boost/iterator/transform_iterator.hpp> +#include <list> + +using namespace boost::python; + +typedef std::list<int> list_int; + +// Prove that we can handle InputIterators which return rvalues. +struct doubler +{ + typedef int result_type; + int operator()(int x) const { return x * 2; } +}; + +typedef boost::transform_iterator<doubler, list_int::iterator> doubling_iterator; +typedef std::pair<doubling_iterator,doubling_iterator> list_range2; + +list_range2 range2(list_int& x) +{ + return list_range2( + boost::make_transform_iterator<doubler>(x.begin(), doubler()) + , boost::make_transform_iterator<doubler>(x.end(), doubler())); +} + +// We do this in a separate module from iterators_ext (iterators.cpp) +// to work around an MSVC6 linker bug, which causes it to complain +// about a "duplicate comdat" if the input iterator is instantiated in +// the same module with the others. +BOOST_PYTHON_MODULE(input_iterator) +{ + def("range2", &::range2); + + class_<list_range2>("list_range2") + // We can wrap InputIterators which return by-value + .def("__iter__" + , range(&list_range2::first, &list_range2::second)) + ; +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/int_map_indexing_suite.cpp b/src/boost/libs/python/test/int_map_indexing_suite.cpp new file mode 100644 index 000000000..397850131 --- /dev/null +++ b/src/boost/libs/python/test/int_map_indexing_suite.cpp @@ -0,0 +1,16 @@ +// Copyright David Abrahams 2004. 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 <boost/python/class.hpp> +#include <boost/python/suite/indexing/map_indexing_suite.hpp> + +void int_map_indexing_suite() +{ + using namespace boost::python; + + // Compile check only... + class_<std::map<int, int> >("IntMap") + .def(map_indexing_suite<std::map<int, int> >()) + ; +} diff --git a/src/boost/libs/python/test/iterator.cpp b/src/boost/libs/python/test/iterator.cpp new file mode 100644 index 000000000..458ba2926 --- /dev/null +++ b/src/boost/libs/python/test/iterator.cpp @@ -0,0 +1,137 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/return_internal_reference.hpp> +#include <boost/python/copy_non_const_reference.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/python/iterator.hpp> +#include <list> +#include <utility> +#include <iterator> +#include <algorithm> + +using namespace boost::python; + +typedef std::list<int> list_int; +typedef std::list<list_int> list_list; + + +void push_back(list_int& x, int y) +{ + x.push_back(y); +} + +void push_list_back(list_list& x, list_int const& y) +{ + x.push_back(y); +} + +int back(list_int& x) +{ + return x.back(); +} + +typedef std::pair<list_int::iterator,list_int::iterator> list_range; + +struct list_range2 : list_range +{ + list_int::iterator& begin() { return this->first; } + list_int::iterator& end() { return this->second; } +}; + +list_range range(list_int& x) +{ + return list_range(x.begin(), x.end()); +} + +struct two_lists +{ + two_lists() + { + int primes[] = { 2, 3, 5, 7, 11, 13 }; + std::copy(primes, primes + sizeof(primes)/sizeof(*primes), std::back_inserter(one)); + int evens[] = { 2, 4, 6, 8, 10, 12 }; + std::copy(evens, evens + sizeof(evens)/sizeof(*evens), std::back_inserter(two)); + } + + struct two_start + { + typedef list_int::iterator result_type; + result_type operator()(two_lists& ll) const { return ll.two.begin(); } + }; + friend struct two_start; + + list_int::iterator one_begin() { return one.begin(); } + list_int::iterator two_begin() { return two.begin(); } + + list_int::iterator one_end() { return one.end(); } + list_int::iterator two_end() { return two.end(); } + +private: + list_int one; + list_int two; +}; + +BOOST_PYTHON_MODULE(iterator_ext) +{ + using boost::python::iterator; // gcc 2.96 bug workaround + def("range", &::range); + + class_<list_int>("list_int") + .def("push_back", push_back) + .def("back", back) + .def("__iter__", iterator<list_int>()) + ; + + class_<list_range>("list_range") + + // We can specify data members + .def("__iter__" + , range(&list_range::first, &list_range::second)) + ; + + // No runtime tests for this one yet + class_<list_range2>("list_range2") + + // We can specify member functions returning a non-const reference + .def("__iter__", range(&list_range2::begin, &list_range2::end)) + ; + + class_<two_lists>("two_lists") + + // We can spcify member functions + .add_property( + "primes" + , range(&two_lists::one_begin, &two_lists::one_end)) + + // Prove that we can explicitly specify call policies + .add_property( + "evens" + , range<return_value_policy<copy_non_const_reference> >( + &two_lists::two_begin, &two_lists::two_end)) + + // Prove that we can specify call policies and target + .add_property( + "twosies" + , range<return_value_policy<copy_non_const_reference>, two_lists>( + // And we can use adaptable function objects when + // partial specialization is available. +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + two_lists::two_start() +# else + &two_lists::two_begin +# endif + , &two_lists::two_end)) + ; + + class_<list_list>("list_list") + .def("push_back", push_list_back) + .def("__iter__", iterator<list_list,return_internal_reference<> >()) + ; +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/iterator.py b/src/boost/libs/python/test/iterator.py new file mode 100644 index 000000000..314a35676 --- /dev/null +++ b/src/boost/libs/python/test/iterator.py @@ -0,0 +1,78 @@ +# Copyright David Abrahams 2004. 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) +from __future__ import print_function +''' +>>> from iterator_ext import * +>>> from input_iterator import * +>>> x = list_int() +>>> x.push_back(1) +>>> x.back() +1 +>>> x.push_back(3) +>>> x.push_back(5) +>>> for y in x: +... print(y) +1 +3 +5 +>>> z = range(x) +>>> for y in z: +... print(y) +1 +3 +5 + + Range2 wraps a transform_iterator which doubles the elements it + traverses. This proves we can wrap input iterators + +>>> z2 = range2(x) +>>> for y in z2: +... print(y) +2 +6 +10 + +>>> l2 = two_lists() +>>> for y in l2.primes: +... print(y) +2 +3 +5 +7 +11 +13 +>>> for y in l2.evens: +... print(y) +2 +4 +6 +8 +10 +12 +>>> ll = list_list() +>>> ll.push_back(x) +>>> x.push_back(7) +>>> ll.push_back(x) +>>> for a in ll: #doctest: +NORMALIZE_WHITESPACE +... for b in a: +... print(b, end='') +... print('') +... +1 3 5 +1 3 5 7 +''' +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/keywords.cpp b/src/boost/libs/python/test/keywords.cpp new file mode 100644 index 000000000..39bac0627 --- /dev/null +++ b/src/boost/libs/python/test/keywords.cpp @@ -0,0 +1,118 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python.hpp> +#include <string> + +struct Foo +{ + Foo( + int a = 0 + , double b = 0 + , const std::string &n = std::string() + ) : + a_(a) + , b_(b) + , n_(n) + {} + + void set(int a=0, double b=0, const std::string &n=std::string()) + { + a_ = a; + b_ = b; + n_ = n; + } + + int geta() const { return a_; } + + double getb() const { return b_; } + + std::string getn() const { return n_; } + +private: + int a_; + double b_; + std::string n_; +}; + +struct Bar +{ + Bar( + int a = 0 + , double b = 0 + , const std::string &n = std::string() + ) : + a_(a) + , b_(b) + , n_(n) + {} + + void set(int a=0, double b=0, const std::string &n=std::string()) + { + a_ = a; + b_ = b; + n_ = n; + } + + void seta(int a) + { + a_ = a; + } + + int geta() const { return a_; } + + double getb() const { return b_; } + + std::string getn() const { return n_; } + +private: + int a_; + double b_; + std::string n_; +}; + +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(bar_set, Bar::set, 0,3) + +using namespace boost::python; +BOOST_PYTHON_MODULE(keywords) +{ +#if BOOST_WORKAROUND(__GNUC__, == 2) + using boost::python::arg; +#endif + + class_<Foo>( + "Foo" + , init<int, double, const std::string&>( + ( arg("a") = 0 + , arg("b") = 0.0 + , arg("n") = std::string() + ) + )) + + .def("set", &Foo::set, (arg("a") = 0, arg("b") = 0.0, arg("n") = std::string()) ) + + .def("set2", &Foo::set, (arg("a"), "b", "n") ) + + .def("a", &Foo::geta) + .def("b", &Foo::getb) + .def("n", &Foo::getn) + ; + + class_<Bar>("Bar" + , init<optional<int, double, const std::string &> >() + ) + .def("set", &Bar::set, bar_set()) + .def("set2", &Bar::set, bar_set("set2's docstring")) + .def("seta", &Bar::seta, arg("a")) + + .def("a", &Bar::geta) + .def("b", &Bar::getb) + .def("n", &Bar::getn) + ; + +} + + + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/keywords_test.py b/src/boost/libs/python/test/keywords_test.py new file mode 100644 index 000000000..bac7d17c1 --- /dev/null +++ b/src/boost/libs/python/test/keywords_test.py @@ -0,0 +1,106 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from keywords import * +>>> f = Foo() +>>> f.a(), f.b(), f.n() +(0, 0.0, '') +>>> f = Foo(1) +>>> f.a(), f.b(), f.n() +(1, 0.0, '') +>>> f = Foo(1,1.0) +>>> f.a(), f.b(), f.n() +(1, 1.0, '') +>>> f = Foo(1,1.0,"1") +>>> f.a(), f.b(), f.n() +(1, 1.0, '1') +>>> f = Foo(a=1) +>>> f.a(), f.b(), f.n() +(1, 0.0, '') +>>> f = Foo(b=1) +>>> f.a(), f.b(), f.n() +(0, 1.0, '') +>>> f = Foo(n="1") +>>> f.a(), f.b(), f.n() +(0, 0.0, '1') +>>> f = Foo(1,n="1") +>>> f.a(), f.b(), f.n() +(1, 0.0, '1') +>>> f.set() +>>> f.a(), f.b(), f.n() +(0, 0.0, '') +>>> f.set(1) +>>> f.a(), f.b(), f.n() +(1, 0.0, '') +>>> f.set(1,1.0) +>>> f.a(), f.b(), f.n() +(1, 1.0, '') +>>> f.set(1,1.0,"1") +>>> f.a(), f.b(), f.n() +(1, 1.0, '1') +>>> f.set(a=1) +>>> f.a(), f.b(), f.n() +(1, 0.0, '') +>>> f.set(b=1) +>>> f.a(), f.b(), f.n() +(0, 1.0, '') +>>> f.set(n="1") +>>> f.a(), f.b(), f.n() +(0, 0.0, '1') +>>> f.set(1,n="1") +>>> f.a(), f.b(), f.n() +(1, 0.0, '1') +>>> f.set2(b=2.0,n="2",a=2) +>>> f.a(), f.b(), f.n() +(2, 2.0, '2') + +# lets see how badly we've broken the 'regular' functions +>>> f = Bar() +>>> f.a(), f.b(), f.n() +(0, 0.0, '') +>>> f = Bar(1) +>>> f.a(), f.b(), f.n() +(1, 0.0, '') +>>> f = Bar(1,1.0) +>>> f.a(), f.b(), f.n() +(1, 1.0, '') +>>> f = Bar(1,1.0,"1") +>>> f.a(), f.b(), f.n() +(1, 1.0, '1') +>>> f.set() +>>> f.a(), f.b(), f.n() +(0, 0.0, '') +>>> f.set(1) +>>> f.a(), f.b(), f.n() +(1, 0.0, '') +>>> f.set(1,1.0) +>>> f.a(), f.b(), f.n() +(1, 1.0, '') +>>> f.set(1,1.0,"1") +>>> f.a(), f.b(), f.n() +(1, 1.0, '1') +>>> f.set2.__doc__.splitlines()[1] +'set2( (Bar)arg1 [, (int)arg2 [, (float)arg3 [, (str)arg4]]]) -> None :' +>>> f.set2.__doc__.splitlines()[2] +" set2's docstring" +''' + + + + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) + diff --git a/src/boost/libs/python/test/list.cpp b/src/boost/libs/python/test/list.cpp new file mode 100644 index 000000000..3e9fcbe66 --- /dev/null +++ b/src/boost/libs/python/test/list.cpp @@ -0,0 +1,154 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/list.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/dict.hpp> +#include <boost/python/make_function.hpp> +#include <boost/lexical_cast.hpp> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> +#include "test_class.hpp" + +using namespace boost::python; + +object new_list() +{ + return list(); +} + +list listify(object x) +{ + return list(x); +} + +object listify_string(char const* s) +{ + return list(s); +} + +std::string x_rep(test_class<> const& x) +{ + return "X(" + boost::lexical_cast<std::string>(x.value()) + ")"; +} + +object apply_object_list(object f, list x) +{ + return f(x); +} + +list apply_list_list(object f, list x) +{ + return call<list>(f.ptr(), x); +} + +void append_object(list& x, object y) +{ + x.append(y); +} + +void append_list(list& x, list const& y) +{ + x.append(y); +} + +typedef test_class<> X; + +int notcmp(object const& x, object const& y) +{ + return y < x ? -1 : y > x ? 1 : 0; +} + +void exercise(list x, object y, object print) +{ + x.append(y); + x.append(5); + x.append(X(3)); + + print("after append:"); + print(x); + + print("number of", y, "instances:", x.count(y)); + + print("number of 5s:", x.count(5)); + + x.extend("xyz"); + print("after extend:"); + print(x); + print("index of", y, "is:", x.index(y)); + print("index of 'l' is:", x.index("l")); + + x.insert(4, 666); + print("after inserting 666:"); + print(x); + print("inserting with object as index:"); + x.insert(x[x.index(5)], "---"); + print(x); + + print("popping..."); + x.pop(); + print(x); + x.pop(x[x.index(5)]); + print(x); + x.pop(x.index(5)); + print(x); + + print("removing", y); + x.remove(y); + print(x); + print("removing", 666); + x.remove(666); + print(x); + + print("reversing..."); + x.reverse(); + print(x); + + print("sorted:"); + x.pop(2); // make sorting predictable + x.pop(2); // remove [1,2] so the list is sortable in py3k + x.sort(); + print(x); + + print("reverse sorted:"); +#if PY_VERSION_HEX >= 0x03000000 + x.sort(*tuple(), **dict(make_tuple(make_tuple("reverse", true)))); +#else + x.sort(¬cmp); +#endif + print(x); + + list w; + w.append(5); + w.append(6); + w += "hi"; + BOOST_ASSERT(w[0] == 5); + BOOST_ASSERT(w[1] == 6); + BOOST_ASSERT(w[2] == 'h'); + BOOST_ASSERT(w[3] == 'i'); +} + +BOOST_PYTHON_MODULE(list_ext) +{ + def("new_list", new_list); + def("listify", listify); + def("listify_string", listify_string); + def("apply_object_list", apply_object_list); + def("apply_list_list", apply_list_list); + + def("append_object", append_object); + def("append_list", append_list); + + def("exercise", exercise); + + class_<X>("X", init<int>()) + .def( "__repr__", x_rep) + ; +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/list.py b/src/boost/libs/python/test/list.py new file mode 100644 index 000000000..913032db8 --- /dev/null +++ b/src/boost/libs/python/test/list.py @@ -0,0 +1,119 @@ +# Copyright David Abrahams 2004. 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) +from __future__ import print_function +''' +>>> from list_ext import * + +>>> new_list() +[] + +>>> listify((1,2,3)) +[1, 2, 3] + +>>> letters = listify_string('hello') +>>> letters +['h', 'e', 'l', 'l', 'o'] + +>>> X(22) +X(22) + +>>> def identity(x): +... return x +>>> assert apply_object_list(identity, letters) is letters + + 5 is not convertible to a list + +>>> try: result = apply_object_list(identity, 5) +... except TypeError: pass +... else: print('expected an exception, got', result, 'instead') + +>>> assert apply_list_list(identity, letters) is letters + + 5 is not convertible to a list as a return value + +>>> try: result = apply_list_list(len, letters) +... except TypeError: pass +... else: print('expected an exception, got', result, 'instead') + +>>> append_object(letters, '.') +>>> letters +['h', 'e', 'l', 'l', 'o', '.'] + + tuples do not automatically convert to lists when passed as arguments + +>>> try: append_list(letters, (1,2)) +... except TypeError: pass +... else: print('expected an exception') + +>>> append_list(letters, [1,2]) +>>> letters +['h', 'e', 'l', 'l', 'o', '.', [1, 2]] + + Check that subclass functions are properly called + +>>> class mylist(list): +... def append(self, o): +... list.append(self, o) +... if not hasattr(self, 'nappends'): +... self.nappends = 1 +... else: +... self.nappends += 1 +... +>>> l2 = mylist() +>>> append_object(l2, 'hello') +>>> append_object(l2, 'world') +>>> l2 +['hello', 'world'] +>>> l2.nappends +2 + +>>> def printer(*args): +... for x in args: print( x,) +... print('') +... + +>>> y = X(42) +>>> exercise(letters, y, printer) #doctest: +NORMALIZE_WHITESPACE +after append: +['h', 'e', 'l', 'l', 'o', '.', [1, 2], X(42), 5, X(3)] +number of X(42) instances: 1 +number of 5s: 1 +after extend: +['h', 'e', 'l', 'l', 'o', '.', [1, 2], X(42), 5, X(3), 'x', 'y', 'z'] +index of X(42) is: 7 +index of 'l' is: 2 +after inserting 666: +['h', 'e', 'l', 'l', 666, 'o', '.', [1, 2], X(42), 5, X(3), 'x', 'y', 'z'] +inserting with object as index: +['h', 'e', 'l', 'l', 666, '---', 'o', '.', [1, 2], X(42), 5, X(3), 'x', 'y', 'z'] +popping... +['h', 'e', 'l', 'l', 666, '---', 'o', '.', [1, 2], X(42), 5, X(3), 'x', 'y'] +['h', 'e', 'l', 'l', 666, 'o', '.', [1, 2], X(42), 5, X(3), 'x', 'y'] +['h', 'e', 'l', 'l', 666, 'o', '.', [1, 2], X(42), X(3), 'x', 'y'] +removing X(42) +['h', 'e', 'l', 'l', 666, 'o', '.', [1, 2], X(3), 'x', 'y'] +removing 666 +['h', 'e', 'l', 'l', 'o', '.', [1, 2], X(3), 'x', 'y'] +reversing... +['y', 'x', X(3), [1, 2], '.', 'o', 'l', 'l', 'e', 'h'] +sorted: +['.', 'e', 'h', 'l', 'l', 'o', 'x', 'y'] +reverse sorted: +['y', 'x', 'o', 'l', 'l', 'h', 'e', '.'] +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/long.cpp b/src/boost/libs/python/test/long.cpp new file mode 100644 index 000000000..61e4518ff --- /dev/null +++ b/src/boost/libs/python/test/long.cpp @@ -0,0 +1,63 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/long.hpp> +#include <boost/python/class.hpp> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> + +using namespace boost::python; + +object new_long() +{ + return long_(); +} + +long_ longify(object x) +{ + return long_(x); +} + +object longify_string(char const* s) +{ + return long_(s); +} + +char const* is_long1(long_& x) +{ + long_ y = x; + x += 50; + BOOST_ASSERT(x == y + 50); + return "yes"; +} + +int is_long2(char const*) +{ + return 0; +} + +// tests for accepting objects (and derived classes) in constructors +// from "Milind Patil" <milind_patil-at-hotmail.com> + +struct Y +{ + Y(boost::python::long_) {} +}; + +BOOST_PYTHON_MODULE(long_ext) +{ + def("new_long", new_long); + def("longify", longify); + def("longify_string", longify_string); + def("is_long", is_long1); + def("is_long", is_long2); + + class_< Y >("Y", init< boost::python::long_ >()) + ; +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/long.py b/src/boost/libs/python/test/long.py new file mode 100644 index 000000000..f63923632 --- /dev/null +++ b/src/boost/libs/python/test/long.py @@ -0,0 +1,36 @@ +# Copyright David Abrahams 2004. 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 sys +if (sys.version_info.major >= 3): + long = int +''' +>>> from long_ext import * +>>> print(new_long()) +0 +>>> print(longify(42)) +42 +>>> print(longify_string('300')) +300 +>>> is_long(long(20)) +'yes' +>>> is_long('20') +0 + +>>> x = Y(long(4294967295)) +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/m1.cpp b/src/boost/libs/python/test/m1.cpp new file mode 100644 index 000000000..a873bc35d --- /dev/null +++ b/src/boost/libs/python/test/m1.cpp @@ -0,0 +1,344 @@ +// Copyright David Abrahams 2001. +// 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 <boost/python/def.hpp> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/lvalue_from_pytype.hpp> +#include <boost/python/copy_const_reference.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/python/to_python_converter.hpp> +#include <boost/python/errors.hpp> +#include <boost/python/manage_new_object.hpp> +#include <boost/python/converter/pytype_function.hpp> +#include <string.h> +#include "simple_type.hpp" +#include "complicated.hpp" + +// Declare some straightforward extension types +extern "C" void +dealloc(PyObject* self) +{ + PyObject_Del(self); +} + +// Noddy is a type we got from one of the Python sample files +struct NoddyObject : PyObject +{ + int x; +}; + +PyTypeObject NoddyType = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast<char*>("Noddy"), + sizeof(NoddyObject), + 0, + dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +// Create a Noddy containing 42 +PyObject* new_noddy() +{ + NoddyObject* noddy = PyObject_New(NoddyObject, &NoddyType); + noddy->x = 42; + return (PyObject*)noddy; +} + +// Simple is a wrapper around a struct simple, which just contains a char* +struct SimpleObject +{ + PyObject_HEAD + simple x; +}; + +struct extract_simple_object +{ + static simple& execute(SimpleObject& o) { return o.x; } +}; + +PyTypeObject SimpleType = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast<char*>("Simple"), + sizeof(SimpleObject), + 0, + dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +// Create a Simple containing "hello, world" +PyObject* new_simple() +{ + SimpleObject* simple = PyObject_New(SimpleObject, &SimpleType); + simple->x.s = const_cast<char*>("hello, world"); + return (PyObject*)simple; +} + +// +// Declare some wrappers/unwrappers to test the low-level conversion +// mechanism. +// +using boost::python::to_python_converter; + +// Wrap a simple by copying it into a Simple +struct simple_to_python + : to_python_converter<simple, simple_to_python, true> + //, boost::python::converter::wrap_pytype<&SimpleType> +{ + static PyObject* convert(simple const& x) + { + SimpleObject* p = PyObject_New(SimpleObject, &SimpleType); + p->x = x; + return (PyObject*)p; + } + static PyTypeObject const *get_pytype(){return &SimpleType; } +}; + +struct int_from_noddy +{ + static int& execute(NoddyObject& p) + { + return p.x; + } +}; + +// +// Some C++ functions to expose to Python +// + +// Returns the length of s's held string +int f(simple const& s) +{ + return strlen(s.s); +} + +int f_mutable_ref(simple& s) +{ + return strlen(s.s); +} + +int f_mutable_ptr(simple* s) +{ + return strlen(s->s); +} + +int f_const_ptr(simple const* s) +{ + return strlen(s->s); +} + +int f2(SimpleObject const& s) +{ + return strlen(s.x.s); +} + +// A trivial passthru function for simple objects +simple const& g(simple const& x) +{ + return x; +} + +struct A +{ + A() : x(0) {} + virtual ~A() {} + char const* name() { return "A"; } + int x; +}; + +struct B : A +{ + B() : x(1) {} + static char const* name(B*) { return "B"; } + int x; +}; + +struct C : A +{ + C() : x(2) {} + char const* name() { return "C"; } + virtual ~C() {} + int x; +}; + +struct D : B, C +{ + D() : x(3) {} + char const* name() { return "D"; } + int x; +}; + +A take_a(A const& a) { return a; } +B take_b(B& b) { return b; } +C take_c(C* c) { return *c; } +D take_d(D* const& d) { return *d; } + +D take_d_shared_ptr(boost::shared_ptr<D> d) { return *d; } + +boost::shared_ptr<A> d_factory() { return boost::shared_ptr<B>(new D); } + +struct Unregistered {}; +Unregistered make_unregistered(int) { return Unregistered(); } + +Unregistered* make_unregistered2(int) { return new Unregistered; } + +BOOST_PYTHON_MODULE(m1) +{ + using namespace boost::python; + using boost::shared_ptr; + + simple_to_python(); + + lvalue_from_pytype<int_from_noddy,&NoddyType>(); + + lvalue_from_pytype< +#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // doesn't support non-type member pointer parameters + extract_member<SimpleObject, simple, &SimpleObject::x> +#else + extract_simple_object +#endif + , &SimpleType + >(); + + lvalue_from_pytype<extract_identity<SimpleObject>,&SimpleType>(); + + def("new_noddy", new_noddy); + def("new_simple", new_simple); + + def("make_unregistered", make_unregistered); + def("make_unregistered2", make_unregistered2, return_value_policy<manage_new_object>()); + + // Expose f() in all its variations + def("f", f); + def("f_mutable_ref", f_mutable_ref); + def("f_mutable_ptr", f_mutable_ptr); + def("f_const_ptr", f_const_ptr); + + def("f2", f2); + + // Expose g() + def("g", g , return_value_policy<copy_const_reference>() + ); + + def("take_a", take_a); + def("take_b", take_b); + def("take_c", take_c); + def("take_d", take_d); + + + def("take_d_shared_ptr", take_d_shared_ptr); + def("d_factory", d_factory); + + class_<A, shared_ptr<A> >("A") + .def("name", &A::name) + ; + + // sequence points don't ensure that "A" is constructed before "B" + // or "C" below if we make them part of the same chain + class_<B,bases<A> >("B") + .def("name", &B::name) + ; + + class_<C,bases<A> >("C") + .def("name", &C::name) + ; + + class_<D, bases<B,C> >("D") + .def("name", &D::name) + ; + + class_<complicated>("complicated", + init<simple const&,int>()) + .def(init<simple const&>()) + .def("get_n", &complicated::get_n) + ; +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/m2.cpp b/src/boost/libs/python/test/m2.cpp new file mode 100644 index 000000000..5bcdea604 --- /dev/null +++ b/src/boost/libs/python/test/m2.cpp @@ -0,0 +1,108 @@ +// Copyright David Abrahams 2001. +// 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) + +// This module exercises the converters exposed in m1 at a low level +// by exposing raw Python extension functions that use wrap<> and +// unwrap<> objects. +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/copy_non_const_reference.hpp> +#include <boost/python/copy_const_reference.hpp> +#include <boost/python/return_value_policy.hpp> +#include "simple_type.hpp" + +#if PY_VERSION_HEX >= 0x03000000 +# define PyString_FromString PyUnicode_FromString +# define PyInt_FromLong PyLong_FromLong +#endif + +// Get a simple (by value) from the argument, and return the +// string it holds. +PyObject* unwrap_simple(simple x) +{ + return PyString_FromString(x.s); +} + +// Likewise, but demands that its possible to get a non-const +// reference to the simple. +PyObject* unwrap_simple_ref(simple& x) +{ + return PyString_FromString(x.s); +} + +// Likewise, with a const reference to the simple object. +PyObject* unwrap_simple_const_ref(simple const& x) +{ + return PyString_FromString(x.s); +} + +// Get an int (by value) from the argument, and convert it to a +// Python Int. +PyObject* unwrap_int(int x) +{ + return PyInt_FromLong(x); +} + +// Get a non-const reference to an int from the argument +PyObject* unwrap_int_ref(int& x) +{ + return PyInt_FromLong(x); +} + +// Get a const reference to an int from the argument. +PyObject* unwrap_int_const_ref(int const& x) +{ + return PyInt_FromLong(x); +} + +#if PY_VERSION_HEX >= 0x03000000 +# undef PyString_FromString +# undef PyInt_FromLong +#endif + +// rewrap<T> extracts a T from the argument, then converts the T back +// to a PyObject* and returns it. +template <class T> +struct rewrap +{ + static T f(T x) { return x; } +}; + +BOOST_PYTHON_MODULE(m2) +{ + using boost::python::return_value_policy; + using boost::python::copy_const_reference; + using boost::python::copy_non_const_reference; + using boost::python::def; + + def("unwrap_int", unwrap_int); + def("unwrap_int_ref", unwrap_int_ref); + def("unwrap_int_const_ref", unwrap_int_const_ref); + def("unwrap_simple", unwrap_simple); + def("unwrap_simple_ref", unwrap_simple_ref); + def("unwrap_simple_const_ref", unwrap_simple_const_ref); + + def("wrap_int", &rewrap<int>::f); + + def("wrap_int_ref", &rewrap<int&>::f + , return_value_policy<copy_non_const_reference>() + ); + + def("wrap_int_const_ref", &rewrap<int const&>::f + , return_value_policy<copy_const_reference>() + ); + + def("wrap_simple", &rewrap<simple>::f); + + def("wrap_simple_ref", &rewrap<simple&>::f + , return_value_policy<copy_non_const_reference>() + ); + + def("wrap_simple_const_ref", &rewrap<simple const&>::f + , return_value_policy<copy_const_reference>() + ); +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/map_indexing_suite.cpp b/src/boost/libs/python/test/map_indexing_suite.cpp new file mode 100644 index 000000000..b8771cf41 --- /dev/null +++ b/src/boost/libs/python/test/map_indexing_suite.cpp @@ -0,0 +1,68 @@ +// Copyright Joel de Guzman 2004. 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 <boost/python/suite/indexing/map_indexing_suite.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/implicit.hpp> + +using namespace boost::python; + +struct X // a container element +{ + std::string s; + X():s("default") {} + X(std::string s):s(s) {} + std::string repr() const { return s; } + void reset() { s = "reset"; } + void foo() { s = "foo"; } + bool operator==(X const& x) const { return s == x.s; } + bool operator!=(X const& x) const { return s != x.s; } +}; + +std::string x_value(X const& x) +{ + return "gotya " + x.s; +} + + +BOOST_PYTHON_MODULE(map_indexing_suite_ext) +{ + class_<X>("X") + .def(init<>()) + .def(init<X>()) + .def(init<std::string>()) + .def("__repr__", &X::repr) + .def("reset", &X::reset) + .def("foo", &X::foo) + ; + + def("x_value", x_value); + implicitly_convertible<std::string, X>(); + + class_<std::map<std::string, X> >("XMap") + .def(map_indexing_suite<std::map<std::string, X> >()) + ; + + void int_map_indexing_suite(); // moved to int_map_indexing_suite.cpp to + int_map_indexing_suite(); // avoid MSVC 6/7 internal structure overflow + +#if 0 + // Compile check only... + class_<std::map<int, int> >("IntMap") + .def(map_indexing_suite<std::map<int, int> >()) + ; +#endif + + // Some more.. + class_<std::map<std::string, boost::shared_ptr<X> > >("TestMap") + .def(map_indexing_suite<std::map<std::string, boost::shared_ptr<X> >, true>()) + ; + + void a_map_indexing_suite(); // moved to a_map_indexing_suite.cpp to + a_map_indexing_suite(); // avoid MSVC 6/7 internal structure overflow + +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/map_indexing_suite.py b/src/boost/libs/python/test/map_indexing_suite.py new file mode 100644 index 000000000..a5750a833 --- /dev/null +++ b/src/boost/libs/python/test/map_indexing_suite.py @@ -0,0 +1,243 @@ +# Copyright Joel de Guzman 2004. 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) +from __future__ import print_function +''' + +##################################################################### +# Check an object that we will use as container element +##################################################################### + +>>> from map_indexing_suite_ext import * +>>> assert "map_indexing_suite_IntMap_entry" in dir() +>>> assert "map_indexing_suite_TestMap_entry" in dir() +>>> assert "map_indexing_suite_XMap_entry" in dir() +>>> assert "map_indexing_suite_AMap_entry" in dir() +>>> x = X('hi') +>>> x +hi +>>> x.reset() # a member function that modifies X +>>> x +reset +>>> x.foo() # another member function that modifies X +>>> x +foo + +# test that a string is implicitly convertible +# to an X +>>> x_value('bochi bochi') +'gotya bochi bochi' + +##################################################################### +# Iteration +##################################################################### +>>> def print_xmap(xmap): +... s = '[ ' +... for x in xmap: +... s += repr(x) +... s += ' ' +... s += ']' +... print(s) + +##################################################################### +# Setting (adding entries) +##################################################################### +>>> xm = XMap() +>>> xm['joel'] = 'apple' +>>> xm['tenji'] = 'orange' +>>> xm['mariel'] = 'grape' +>>> xm['tutit'] = 'banana' +>>> xm['kim'] = 'kiwi' + +>>> print_xmap(xm) +[ (joel, apple) (kim, kiwi) (mariel, grape) (tenji, orange) (tutit, banana) ] + +##################################################################### +# Changing an entry +##################################################################### +>>> xm['joel'] = 'pineapple' +>>> print_xmap(xm) +[ (joel, pineapple) (kim, kiwi) (mariel, grape) (tenji, orange) (tutit, banana) ] + +##################################################################### +# Deleting an entry +##################################################################### +>>> del xm['joel'] +>>> print_xmap(xm) +[ (kim, kiwi) (mariel, grape) (tenji, orange) (tutit, banana) ] + +##################################################################### +# adding an entry +##################################################################### +>>> xm['joel'] = 'apple' +>>> print_xmap(xm) +[ (joel, apple) (kim, kiwi) (mariel, grape) (tenji, orange) (tutit, banana) ] + +##################################################################### +# Indexing +##################################################################### +>>> len(xm) +5 +>>> xm['joel'] +apple +>>> xm['tenji'] +orange +>>> xm['mariel'] +grape +>>> xm['tutit'] +banana +>>> xm['kim'] +kiwi + +##################################################################### +# Calling a mutating function of a container element +##################################################################### +>>> xm['joel'].reset() +>>> xm['joel'] +reset + +##################################################################### +# Copying a container element +##################################################################### +>>> x = X(xm['mariel']) +>>> x +grape +>>> x.foo() +>>> x +foo +>>> xm['mariel'] # should not be changed to 'foo' +grape + +##################################################################### +# Referencing a container element +##################################################################### +>>> x = xm['mariel'] +>>> x +grape +>>> x.foo() +>>> x +foo +>>> xm['mariel'] # should be changed to 'foo' +foo + +>>> xm['mariel'] = 'grape' # take it back +>>> xm['joel'] = 'apple' # take it back + +##################################################################### +# Contains +##################################################################### +>>> assert 'joel' in xm +>>> assert 'mariel' in xm +>>> assert 'tenji' in xm +>>> assert 'tutit' in xm +>>> assert 'kim' in xm +>>> assert not 'X' in xm +>>> assert not 12345 in xm + +##################################################################### +# Some references to the container elements +##################################################################### + +>>> z0 = xm['joel'] +>>> z1 = xm['mariel'] +>>> z2 = xm['tenji'] +>>> z3 = xm['tutit'] +>>> z4 = xm['kim'] + +>>> z0 # proxy +apple +>>> z1 # proxy +grape +>>> z2 # proxy +orange +>>> z3 # proxy +banana +>>> z4 # proxy +kiwi + +##################################################################### +# Delete some container element +##################################################################### + +>>> del xm['tenji'] +>>> print_xmap(xm) +[ (joel, apple) (kim, kiwi) (mariel, grape) (tutit, banana) ] + +>>> del xm['tutit'] +>>> print_xmap(xm) +[ (joel, apple) (kim, kiwi) (mariel, grape) ] + +##################################################################### +# Show that the references are still valid +##################################################################### +>>> z0 # proxy +apple +>>> z1 # proxy +grape +>>> z2 # proxy detached +orange +>>> z3 # proxy detached +banana +>>> z4 # proxy +kiwi + +##################################################################### +# Show that iteration allows mutable access to the elements +##################################################################### +>>> for x in xm: +... x.data().reset() +>>> print_xmap(xm) +[ (joel, reset) (kim, reset) (mariel, reset) ] + +##################################################################### +# Some more... +##################################################################### + +>>> tm = TestMap() +>>> tm["joel"] = X("aaa") +>>> tm["kimpo"] = X("bbb") +>>> print_xmap(tm) +[ (joel, aaa) (kimpo, bbb) ] +>>> for el in tm: #doctest: +NORMALIZE_WHITESPACE +... print(el.key(), end='') +... dom = el.data() +joel kimpo + +##################################################################### +# Test custom converter... +##################################################################### + +>>> am = AMap() +>>> am[3] = 4 +>>> am[3] +4 +>>> for i in am: +... i.data() +4 + +##################################################################### +# END.... +##################################################################### + +''' + + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argxm = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print('running...') + import sys + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) + + + + + diff --git a/src/boost/libs/python/test/minimal.cpp b/src/boost/libs/python/test/minimal.cpp new file mode 100644 index 000000000..5efee26bc --- /dev/null +++ b/src/boost/libs/python/test/minimal.cpp @@ -0,0 +1,16 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> + +#if defined(_AIX) && defined(__EDG_VERSION__) && __EDG_VERSION__ < 245 +# include <iostream> // works around a KCC intermediate code generation bug +#endif + +BOOST_PYTHON_MODULE(minimal_ext) +{ +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/minimal.py b/src/boost/libs/python/test/minimal.py new file mode 100644 index 000000000..ee75e3705 --- /dev/null +++ b/src/boost/libs/python/test/minimal.py @@ -0,0 +1,7 @@ +# Copyright David Abrahams 2004. 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) +print("IMPORTING minimal_ext") +import minimal_ext +print("DONE IMPORTING minimal_ext") + diff --git a/src/boost/libs/python/test/module_tail.cpp b/src/boost/libs/python/test/module_tail.cpp new file mode 100644 index 000000000..f9cdca189 --- /dev/null +++ b/src/boost/libs/python/test/module_tail.cpp @@ -0,0 +1,58 @@ +// Copyright David Abrahams 2001. +// 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) + +#if defined(_WIN32) +# ifdef __MWERKS__ +# pragma ANSI_strict off +# endif +# include <windows.h> +# ifdef __MWERKS__ +# pragma ANSI_strict reset +# endif + +# ifdef _MSC_VER +# include <eh.h> // for _set_se_translator() +# pragma warning(push) +# pragma warning(disable:4297) +# pragma warning(disable:4535) +extern "C" void straight_to_debugger(unsigned int, EXCEPTION_POINTERS*) +{ + throw; +} +extern "C" void (*old_translator)(unsigned, EXCEPTION_POINTERS*) + = _set_se_translator(straight_to_debugger); +# pragma warning(pop) +# endif + +#endif // _WIN32 + +#include <exception> +#include <boost/python/extract.hpp> +#include <boost/python/str.hpp> +struct test_failure : std::exception +{ + test_failure(char const* expr, char const* /*function*/, char const* file, unsigned line) + : msg(file + boost::python::str(":%s:") % line + ": Boost.Python assertion failure: " + expr) + {} + + ~test_failure() throw() {} + + char const* what() const throw() + { + return boost::python::extract<char const*>(msg)(); + } + + boost::python::str msg; +}; + +namespace boost +{ + +void assertion_failed(char const * expr, char const * function, char const * file, long line) +{ + throw ::test_failure(expr,function, file, line); +} + +} // namespace boost diff --git a/src/boost/libs/python/test/multi_arg_constructor.cpp b/src/boost/libs/python/test/multi_arg_constructor.cpp new file mode 100644 index 000000000..7d49bb556 --- /dev/null +++ b/src/boost/libs/python/test/multi_arg_constructor.cpp @@ -0,0 +1,27 @@ +// Copyright David Abrahams 2004. 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> + +struct A +{ + A(const double, const double, const double, const double, const double + , const double, const double + , const double, const double + ) {} +}; + +BOOST_PYTHON_MODULE(multi_arg_constructor_ext) +{ + using namespace boost::python; + + class_<A>( + "A" + , init<double, double, double, double, double, double, double, double, double>() + ) + ; + +} + diff --git a/src/boost/libs/python/test/multi_arg_constructor.py b/src/boost/libs/python/test/multi_arg_constructor.py new file mode 100644 index 000000000..5d8b4a516 --- /dev/null +++ b/src/boost/libs/python/test/multi_arg_constructor.py @@ -0,0 +1,21 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from multi_arg_constructor_ext import * +>>> a = A(1.0, 2, 3, 4, 5, 6, 7.0, 8.1, 9.3) +''' +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/nested.cpp b/src/boost/libs/python/test/nested.cpp new file mode 100644 index 000000000..de656d2b8 --- /dev/null +++ b/src/boost/libs/python/test/nested.cpp @@ -0,0 +1,51 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/operators.hpp> +#include <boost/python/scope.hpp> +#include "test_class.hpp" +#if __GNUC__ != 2 +# include <ostream> +#else +# include <ostream.h> +#endif + +typedef test_class<> X; +typedef test_class<1> Y; + +std::ostream& operator<<(std::ostream& s, X const& x) +{ + return s << x.value(); +} + +std::ostream& operator<<(std::ostream& s, Y const& x) +{ + return s << x.value(); +} + + +BOOST_PYTHON_MODULE(nested_ext) +{ + using namespace boost::python; + + // Establish X as the current scope. + scope x_class + = class_<X>("X", init<int>()) + .def(str(self)) + ; + + + // Y will now be defined in the current scope + class_<Y>("Y", init<int>()) + .def(str(self)) + ; +} + + +#include "module_tail.cpp" + + + diff --git a/src/boost/libs/python/test/nested.py b/src/boost/libs/python/test/nested.py new file mode 100644 index 000000000..720790173 --- /dev/null +++ b/src/boost/libs/python/test/nested.py @@ -0,0 +1,40 @@ +# Copyright David Abrahams 2004. 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) +''' + >>> from nested_ext import * + + >>> X + <class 'nested_ext.X'> + + >>> X.__module__ + 'nested_ext' + + >>> X.__name__ + 'X' + + >>> X.Y + <class 'nested_ext.Y'> + + >>> X.Y.__module__ + 'nested_ext' + + >>> X.Y.__name__ + 'Y' + +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/newtest.py b/src/boost/libs/python/test/newtest.py new file mode 100644 index 000000000..b878d5192 --- /dev/null +++ b/src/boost/libs/python/test/newtest.py @@ -0,0 +1,206 @@ +# Copyright David Abrahams 2004. 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) +""" +>>> from m1 import * + +>>> from m2 import * + + Prove that we get an appropriate error from trying to return a type + for which we have no registered to_python converter + +>>> def check_unregistered(f, msgprefix): +... try: +... f(1) +... except TypeError as x: +... if not str(x).startswith(msgprefix): +... print(str(x)) +... else: +... print('expected a TypeError') +... +>>> check_unregistered(make_unregistered, 'No to_python (by-value) converter found for C++ type') +>>> check_unregistered(make_unregistered2, 'No Python class registered for C++ class') + +>>> n = new_noddy() +>>> s = new_simple() +>>> unwrap_int(n) +42 +>>> unwrap_int_ref(n) +42 +>>> unwrap_int_const_ref(n) +42 +>>> unwrap_simple(s) +'hello, world' +>>> unwrap_simple_ref(s) +'hello, world' +>>> unwrap_simple_const_ref(s) +'hello, world' +>>> unwrap_int(5) +5 + +Can't get a non-const reference to a built-in integer object +>>> try: +... unwrap_int_ref(7) +... except: pass +... else: print('no exception') + +>>> unwrap_int_const_ref(9) +9 + +>>> wrap_int(n) +42 + +try: wrap_int_ref(n) +... except: pass +... else: print('no exception') + +>>> wrap_int_const_ref(n) +42 + +>>> unwrap_simple_ref(wrap_simple(s)) +'hello, world' + +>>> unwrap_simple_ref(wrap_simple_ref(s)) +'hello, world' + +>>> unwrap_simple_ref(wrap_simple_const_ref(s)) +'hello, world' + +>>> f(s) +12 + +>>> unwrap_simple(g(s)) +'hello, world' + +>>> f(g(s)) +12 + +>>> f_mutable_ref(g(s)) +12 + +>>> f_const_ptr(g(s)) +12 + +>>> f_mutable_ptr(g(s)) +12 + +>>> f2(g(s)) +12 + +Create an extension class which wraps "complicated" (init1 and get_n) +are a complicated constructor and member function, respectively. + +>>> c1 = complicated(s, 99) +>>> c1.get_n() +99 +>>> c2 = complicated(s) +>>> c2.get_n() +0 + + a quick regression test for a bug where None could be converted + to the target of any member function. To see it, we need to + access the __dict__ directly, to bypass the type check supplied + by the Method property which wraps the method when accessed as an + attribute. + +>>> try: A.__dict__['name'](None) +... except TypeError: pass +... else: print('expected an exception!') + + +>>> a = A() +>>> b = B() +>>> c = C() +>>> d = D() + + +>>> take_a(a).name() +'A' + +>>> try: +... take_b(a) +... except: pass +... else: print('no exception') + +>>> try: +... take_c(a) +... except: pass +... else: print('no exception') + +>>> try: +... take_d(a) +... except: pass +... else: print('no exception') + +------ +>>> take_a(b).name() +'A' + +>>> take_b(b).name() +'B' + +>>> try: +... take_c(b) +... except: pass +... else: print('no exception') + +>>> try: +... take_d(b) +... except: pass +... else: print('no exception') + +------- +>>> take_a(c).name() +'A' + +>>> try: +... take_b(c) +... except: pass +... else: print('no exception') + +>>> take_c(c).name() +'C' + +>>> try: +... take_d(c) +... except: pass +... else: print('no exception') + +------- +>>> take_a(d).name() +'A' +>>> take_b(d).name() +'B' +>>> take_c(d).name() +'C' +>>> take_d(d).name() +'D' + +>>> take_d_shared_ptr(d).name() +'D' + +>>> d_as_a = d_factory() +>>> dd = take_d(d_as_a) +>>> dd.name() +'D' +>>> print(g.__doc__.splitlines()[1]) +g( (Simple)arg1) -> Simple : + +""" + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/numpy/dtype.cpp b/src/boost/libs/python/test/numpy/dtype.cpp new file mode 100644 index 000000000..3a011a25e --- /dev/null +++ b/src/boost/libs/python/test/numpy/dtype.cpp @@ -0,0 +1,49 @@ +// Copyright Jim Bosch & Ankit Daftery 2010-2012. +// Copyright Stefan Seefeld 2016. +// 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 <boost/python/numpy.hpp> +#include <boost/cstdint.hpp> + +namespace p = boost::python; +namespace np = boost::python::numpy; + +template <typename T> +np::dtype accept(T) { + return np::dtype::get_builtin<T>(); +} + +BOOST_PYTHON_MODULE(dtype_ext) +{ + np::initialize(); + // wrap dtype equivalence test, since it isn't available in Python API. + p::def("equivalent", np::equivalent); + // integers, by number of bits + p::def("accept_int8", accept<boost::int8_t>); + p::def("accept_uint8", accept<boost::uint8_t>); + p::def("accept_int16", accept<boost::int16_t>); + p::def("accept_uint16", accept<boost::uint16_t>); + p::def("accept_int32", accept<boost::int32_t>); + p::def("accept_uint32", accept<boost::uint32_t>); + p::def("accept_int64", accept<boost::int64_t>); + p::def("accept_uint64", accept<boost::uint64_t>); + // integers, by C name according to NumPy + p::def("accept_bool_", accept<bool>); + p::def("accept_byte", accept<signed char>); + p::def("accept_ubyte", accept<unsigned char>); + p::def("accept_short", accept<short>); + p::def("accept_ushort", accept<unsigned short>); + p::def("accept_intc", accept<int>); + p::def("accept_uintc", accept<unsigned int>); + // floats and complex + p::def("accept_float32", accept<float>); + p::def("accept_complex64", accept< std::complex<float> >); + p::def("accept_float64", accept<double>); + p::def("accept_complex128", accept< std::complex<double> >); + if (sizeof(long double) > sizeof(double)) { + p::def("accept_longdouble", accept<long double>); + p::def("accept_clongdouble", accept< std::complex<long double> >); + } +} diff --git a/src/boost/libs/python/test/numpy/dtype.py b/src/boost/libs/python/test/numpy/dtype.py new file mode 100644 index 000000000..a27ee0f55 --- /dev/null +++ b/src/boost/libs/python/test/numpy/dtype.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +# Copyright Jim Bosch & Ankit Daftery 2010-2012. +# 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 dtype_ext +import unittest +import numpy +import sys +if (sys.version_info.major >= 3): + long = int + +class DtypeTestCase(unittest.TestCase): + + def assertEquivalent(self, a, b): + return self.assert_(dtype_ext.equivalent(a, b), "%r is not equivalent to %r") + + def testIntegers(self): + for bits in (8, 16, 32, 64): + s = getattr(numpy, "int%d" % bits) + u = getattr(numpy, "uint%d" % bits) + fs = getattr(dtype_ext, "accept_int%d" % bits) + fu = getattr(dtype_ext, "accept_uint%d" % bits) + self.assertEquivalent(fs(s(1)), numpy.dtype(s)) + self.assertEquivalent(fu(u(1)), numpy.dtype(u)) + # these should just use the regular Boost.Python converters + self.assertEquivalent(fs(True), numpy.dtype(s)) + self.assertEquivalent(fu(True), numpy.dtype(u)) + self.assertEquivalent(fs(int(1)), numpy.dtype(s)) + self.assertEquivalent(fu(int(1)), numpy.dtype(u)) + self.assertEquivalent(fs(long(1)), numpy.dtype(s)) + self.assertEquivalent(fu(long(1)), numpy.dtype(u)) + for name in ("bool_", "byte", "ubyte", "short", "ushort", "intc", "uintc"): + t = getattr(numpy, name) + ft = getattr(dtype_ext, "accept_%s" % name) + self.assertEquivalent(ft(t(1)), numpy.dtype(t)) + # these should just use the regular Boost.Python converters + self.assertEquivalent(ft(True), numpy.dtype(t)) + if name != "bool_": + self.assertEquivalent(ft(int(1)), numpy.dtype(t)) + self.assertEquivalent(ft(long(1)), numpy.dtype(t)) + + + def testFloats(self): + f = numpy.float32 + c = numpy.complex64 + self.assertEquivalent(dtype_ext.accept_float32(f(numpy.pi)), numpy.dtype(f)) + self.assertEquivalent(dtype_ext.accept_complex64(c(1+2j)), numpy.dtype(c)) + f = numpy.float64 + c = numpy.complex128 + self.assertEquivalent(dtype_ext.accept_float64(f(numpy.pi)), numpy.dtype(f)) + self.assertEquivalent(dtype_ext.accept_complex128(c(1+2j)), numpy.dtype(c)) + if hasattr(numpy, "longdouble") and hasattr(dtype_ext, "accept_longdouble"): + f = numpy.longdouble + c = numpy.clongdouble + self.assertEquivalent(dtype_ext.accept_longdouble(f(numpy.pi)), numpy.dtype(f)) + self.assertEquivalent(dtype_ext.accept_clongdouble(c(1+2j)), numpy.dtype(c)) + + +if __name__=="__main__": + unittest.main() diff --git a/src/boost/libs/python/test/numpy/indexing.cpp b/src/boost/libs/python/test/numpy/indexing.cpp new file mode 100644 index 000000000..f3cc45717 --- /dev/null +++ b/src/boost/libs/python/test/numpy/indexing.cpp @@ -0,0 +1,28 @@ +// Copyright Jim Bosch & Ankit Daftery 2010-2012. +// Copyright Stefan Seefeld 2016. +// 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 <boost/python/numpy.hpp> +#include <boost/python/slice.hpp> + +namespace p = boost::python; +namespace np = boost::python::numpy; + +p::object single(np::ndarray ndarr, int i) { return ndarr[i];} +p::object slice(np::ndarray ndarr, p::slice sl) { return ndarr[sl];} +p::object indexarray(np::ndarray ndarr, np::ndarray d1) { return ndarr[d1];} +p::object indexarray_2d(np::ndarray ndarr, np::ndarray d1,np::ndarray d2) { return ndarr[p::make_tuple(d1,d2)];} +p::object indexslice(np::ndarray ndarr, np::ndarray d1, p::slice sl) { return ndarr[p::make_tuple(d1, sl)];} + +BOOST_PYTHON_MODULE(indexing_ext) +{ + np::initialize(); + p::def("single", single); + p::def("slice", slice); + p::def("indexarray", indexarray); + p::def("indexarray", indexarray_2d); + p::def("indexslice", indexslice); + +} diff --git a/src/boost/libs/python/test/numpy/indexing.py b/src/boost/libs/python/test/numpy/indexing.py new file mode 100644 index 000000000..ebd9dcbab --- /dev/null +++ b/src/boost/libs/python/test/numpy/indexing.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +# Copyright Jim Bosch & Ankit Daftery 2010-2012. +# 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 unittest +import numpy +import indexing_ext + +class TestIndexing(unittest.TestCase): + + def testSingle(self): + x = numpy.arange(0,10) + for i in range(0,10): + numpy.testing.assert_equal(indexing_ext.single(x,i), i) + for i in range(-10,0): + numpy.testing.assert_equal(indexing_ext.single(x,i),10+i) + + def testSlice(self): + x = numpy.arange(0,10) + sl = slice(3,8) + b = [3,4,5,6,7] + numpy.testing.assert_equal(indexing_ext.slice(x,sl), b) + + def testStepSlice(self): + x = numpy.arange(0,10) + sl = slice(3,8,2) + b = [3,5,7] + numpy.testing.assert_equal(indexing_ext.slice(x,sl), b) + + def testIndex(self): + x = numpy.arange(0,10) + chk = numpy.array([3,4,5,6]) + numpy.testing.assert_equal(indexing_ext.indexarray(x,chk),chk) + chk = numpy.array([[0,1],[2,3]]) + numpy.testing.assert_equal(indexing_ext.indexarray(x,chk),chk) + x = numpy.arange(9).reshape(3,3) + y = numpy.array([0,1]) + z = numpy.array([0,2]) + chk = numpy.array([0,5]) + numpy.testing.assert_equal(indexing_ext.indexarray(x,y,z),chk) + x = numpy.arange(0,10) + b = x>4 + chk = numpy.array([5,6,7,8,9]) + numpy.testing.assert_equal(indexing_ext.indexarray(x,b),chk) + x = numpy.arange(9).reshape(3,3) + b = numpy.array([0,2]) + sl = slice(0,3) + chk = numpy.array([[0,1,2],[6,7,8]]) + numpy.testing.assert_equal(indexing_ext.indexslice(x,b,sl),chk) + +if __name__=="__main__": + unittest.main() diff --git a/src/boost/libs/python/test/numpy/ndarray.cpp b/src/boost/libs/python/test/numpy/ndarray.cpp new file mode 100644 index 000000000..75a101043 --- /dev/null +++ b/src/boost/libs/python/test/numpy/ndarray.cpp @@ -0,0 +1,51 @@ +// Copyright Jim Bosch & Ankit Daftery 2010-2012. +// Copyright Stefan Seefeld 2016. +// 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 <boost/python/numpy.hpp> + +namespace p = boost::python; +namespace np = boost::python::numpy; + +np::ndarray zeros(p::tuple shape, np::dtype dt) { return np::zeros(shape, dt);} +np::ndarray array2(p::object obj, np::dtype dt) { return np::array(obj,dt);} +np::ndarray array1(p::object obj) { return np::array(obj);} +np::ndarray empty1(p::tuple shape, np::dtype dt) { return np::empty(shape,dt);} + +np::ndarray c_empty(p::tuple shape, np::dtype dt) +{ + // convert 'shape' to a C array so we can test the corresponding + // version of the constructor + unsigned len = p::len(shape); + Py_intptr_t *c_shape = new Py_intptr_t[len]; + for (unsigned i = 0; i != len; ++i) + c_shape[i] = p::extract<Py_intptr_t>(shape[i]); + np::ndarray result = np::empty(len, c_shape, dt); + delete [] c_shape; + return result; +} + +np::ndarray transpose(np::ndarray arr) { return arr.transpose();} +np::ndarray squeeze(np::ndarray arr) { return arr.squeeze();} +np::ndarray reshape(np::ndarray arr,p::tuple tup) { return arr.reshape(tup);} + +Py_intptr_t shape_index(np::ndarray arr,int k) { return arr.shape(k); } +Py_intptr_t strides_index(np::ndarray arr,int k) { return arr.strides(k); } + +BOOST_PYTHON_MODULE(ndarray_ext) +{ + np::initialize(); + p::def("zeros", zeros); + p::def("zeros_matrix", zeros, np::as_matrix<>()); + p::def("array", array2); + p::def("array", array1); + p::def("empty", empty1); + p::def("c_empty", c_empty); + p::def("transpose", transpose); + p::def("squeeze", squeeze); + p::def("reshape", reshape); + p::def("shape_index", shape_index); + p::def("strides_index", strides_index); +} diff --git a/src/boost/libs/python/test/numpy/ndarray.py b/src/boost/libs/python/test/numpy/ndarray.py new file mode 100644 index 000000000..2acc384a5 --- /dev/null +++ b/src/boost/libs/python/test/numpy/ndarray.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python + +# Copyright Jim Bosch & Ankit Daftery 2010-2012. +# 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 ndarray_ext +import unittest +import numpy + +class TestNdarray(unittest.TestCase): + + def testNdzeros(self): + for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128): + v = numpy.zeros(60, dtype=dtp) + dt = numpy.dtype(dtp) + for shape in ((60,),(6,10),(4,3,5),(2,2,3,5)): + a1 = ndarray_ext.zeros(shape,dt) + a2 = v.reshape(a1.shape) + self.assertEqual(shape,a1.shape) + self.assert_((a1 == a2).all()) + + def testNdzeros_matrix(self): + for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128): + dt = numpy.dtype(dtp) + shape = (6, 10) + a1 = ndarray_ext.zeros_matrix(shape, dt) + a2 = numpy.matrix(numpy.zeros(shape, dtype=dtp)) + self.assertEqual(shape,a1.shape) + self.assert_((a1 == a2).all()) + self.assertEqual(type(a1), type(a2)) + + def testNdarray(self): + a = range(0,60) + for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128): + v = numpy.array(a, dtype=dtp) + dt = numpy.dtype(dtp) + a1 = ndarray_ext.array(a) + a2 = ndarray_ext.array(a,dt) + self.assert_((a1 == v).all()) + self.assert_((a2 == v).all()) + for shape in ((60,),(6,10),(4,3,5),(2,2,3,5)): + a1 = a1.reshape(shape) + self.assertEqual(shape,a1.shape) + a2 = a2.reshape(shape) + self.assertEqual(shape,a2.shape) + + def testNdempty(self): + for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128): + dt = numpy.dtype(dtp) + for shape in ((60,),(6,10),(4,3,5),(2,2,3,5)): + a1 = ndarray_ext.empty(shape,dt) + a2 = ndarray_ext.c_empty(shape,dt) + self.assertEqual(shape,a1.shape) + self.assertEqual(shape,a2.shape) + + def testTranspose(self): + for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128): + dt = numpy.dtype(dtp) + for shape in ((6,10),(4,3,5),(2,2,3,5)): + a1 = numpy.empty(shape,dt) + a2 = a1.transpose() + a1 = ndarray_ext.transpose(a1) + self.assertEqual(a1.shape,a2.shape) + + def testSqueeze(self): + a1 = numpy.array([[[3,4,5]]]) + a2 = a1.squeeze() + a1 = ndarray_ext.squeeze(a1) + self.assertEqual(a1.shape,a2.shape) + + def testReshape(self): + a1 = numpy.empty((2,2)) + a2 = ndarray_ext.reshape(a1,(1,4)) + self.assertEqual(a2.shape,(1,4)) + + def testShapeIndex(self): + a = numpy.arange(24) + a.shape = (1,2,3,4) + def shape_check(i): + print(i) + self.assertEqual(ndarray_ext.shape_index(a,i) ,a.shape[i] ) + for i in range(4): + shape_check(i) + for i in range(-1,-5,-1): + shape_check(i) + try: + ndarray_ext.shape_index(a,4) # out of bounds -- should raise IndexError + self.assertTrue(False) + except IndexError: + pass + + def testStridesIndex(self): + a = numpy.arange(24) + a.shape = (1,2,3,4) + def strides_check(i): + print(i) + self.assertEqual(ndarray_ext.strides_index(a,i) ,a.strides[i] ) + for i in range(4): + strides_check(i) + for i in range(-1,-5,-1): + strides_check(i) + try: + ndarray_ext.strides_index(a,4) # out of bounds -- should raise IndexError + self.assertTrue(False) + except IndexError: + pass + + +if __name__=="__main__": + unittest.main() diff --git a/src/boost/libs/python/test/numpy/shapes.cpp b/src/boost/libs/python/test/numpy/shapes.cpp new file mode 100644 index 000000000..a245df155 --- /dev/null +++ b/src/boost/libs/python/test/numpy/shapes.cpp @@ -0,0 +1,22 @@ +// Copyright Jim Bosch & Ankit Daftery 2010-2012. +// Copyright Stefan Seefeld 2016. +// 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 <boost/python/numpy.hpp> + +namespace p = boost::python; +namespace np = boost::python::numpy; + +np::ndarray reshape(np::ndarray old_array, p::tuple shape) +{ + np::ndarray local_shape = old_array.reshape(shape); + return local_shape; +} + +BOOST_PYTHON_MODULE(shapes_ext) +{ + np::initialize(); + p::def("reshape", reshape); +} diff --git a/src/boost/libs/python/test/numpy/shapes.py b/src/boost/libs/python/test/numpy/shapes.py new file mode 100644 index 000000000..d0a0099ca --- /dev/null +++ b/src/boost/libs/python/test/numpy/shapes.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python + +# Copyright Jim Bosch & Ankit Daftery 2010-2012. +# 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 shapes_ext +import unittest +import numpy + +class TestShapes(unittest.TestCase): + + def testShapes(self): + a1 = numpy.array([(0,1),(2,3)]) + a1_shape = (1,4) + a1 = shapes_ext.reshape(a1,a1_shape) + self.assertEqual(a1_shape,a1.shape) + +if __name__=="__main__": + unittest.main() diff --git a/src/boost/libs/python/test/numpy/templates.cpp b/src/boost/libs/python/test/numpy/templates.cpp new file mode 100644 index 000000000..83de6bd2f --- /dev/null +++ b/src/boost/libs/python/test/numpy/templates.cpp @@ -0,0 +1,63 @@ +// Copyright Jim Bosch & Ankit Daftery 2010-2012. +// Copyright Stefan Seefeld 2016. +// 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 <boost/python/numpy.hpp> +#include <boost/mpl/vector.hpp> +#include <boost/mpl/vector_c.hpp> + +namespace p = boost::python; +namespace np = boost::python::numpy; + +struct ArrayFiller +{ + + typedef boost::mpl::vector< short, int, float, std::complex<double> > TypeSequence; + typedef boost::mpl::vector_c< int, 1, 2 > DimSequence; + + explicit ArrayFiller(np::ndarray const & arg) : argument(arg) {} + + template <typename T, int N> + void apply() const + { + if (N == 1) + { + char * p = argument.get_data(); + int stride = argument.strides(0); + int size = argument.shape(0); + for (int n = 0; n != size; ++n, p += stride) + *reinterpret_cast<T*>(p) = static_cast<T>(n); + } + else + { + char * row_p = argument.get_data(); + int row_stride = argument.strides(0); + int col_stride = argument.strides(1); + int rows = argument.shape(0); + int cols = argument.shape(1); + int i = 0; + for (int n = 0; n != rows; ++n, row_p += row_stride) + { + char * col_p = row_p; + for (int m = 0; m != cols; ++i, ++m, col_p += col_stride) + *reinterpret_cast<T*>(col_p) = static_cast<T>(i); + } + } + } + + np::ndarray argument; +}; + +void fill(np::ndarray const & arg) +{ + ArrayFiller filler(arg); + np::invoke_matching_array<ArrayFiller::TypeSequence, ArrayFiller::DimSequence >(arg, filler); +} + +BOOST_PYTHON_MODULE(templates_ext) +{ + np::initialize(); + p::def("fill", fill); +} diff --git a/src/boost/libs/python/test/numpy/templates.py b/src/boost/libs/python/test/numpy/templates.py new file mode 100755 index 000000000..8290b13a0 --- /dev/null +++ b/src/boost/libs/python/test/numpy/templates.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +# Copyright Jim Bosch & Ankit Daftery 2010-2012. +# 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 templates_ext +import unittest +import numpy + +class TestTemplates(unittest.TestCase): + + def testTemplates(self): + for dtype in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128): + v = numpy.arange(12, dtype=dtype) + for shape in ((12,), (4, 3), (2, 6)): + a1 = numpy.zeros(shape, dtype=dtype) + a2 = v.reshape(a1.shape) + templates_ext.fill(a1) + self.assert_((a1 == a2).all()) + a1 = numpy.zeros((12,), dtype=numpy.float64) + self.assertRaises(TypeError, templates_ext.fill, a1) + a1 = numpy.zeros((12,2,3), dtype=numpy.float32) + self.assertRaises(TypeError, templates_ext.fill, a1) + +if __name__=="__main__": + unittest.main() diff --git a/src/boost/libs/python/test/numpy/ufunc.cpp b/src/boost/libs/python/test/numpy/ufunc.cpp new file mode 100644 index 000000000..3a9d43cbb --- /dev/null +++ b/src/boost/libs/python/test/numpy/ufunc.cpp @@ -0,0 +1,36 @@ +// Copyright Jim Bosch & Ankit Daftery 2010-2012. +// Copyright Stefan Seefeld 2016. +// 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 <boost/python/numpy.hpp> + +namespace p = boost::python; +namespace np = boost::python::numpy; + +struct UnaryCallable +{ + typedef double argument_type; + typedef double result_type; + + double operator()(double r) const { return r * 2;} +}; + +struct BinaryCallable +{ + typedef double first_argument_type; + typedef double second_argument_type; + typedef double result_type; + + double operator()(double a, double b) const { return a * 2 + b * 3;} +}; + +BOOST_PYTHON_MODULE(ufunc_ext) +{ + np::initialize(); + p::class_<UnaryCallable>("UnaryCallable") + .def("__call__", np::unary_ufunc<UnaryCallable>::make()); + p::class_< BinaryCallable>("BinaryCallable") + .def("__call__", np::binary_ufunc<BinaryCallable>::make()); +} diff --git a/src/boost/libs/python/test/numpy/ufunc.py b/src/boost/libs/python/test/numpy/ufunc.py new file mode 100755 index 000000000..e820121ee --- /dev/null +++ b/src/boost/libs/python/test/numpy/ufunc.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python + +# Copyright Jim Bosch & Ankit Daftery 2010-2012. +# 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 ufunc_ext +import unittest +import numpy +from numpy.testing.utils import assert_array_almost_equal + +class TestUnary(unittest.TestCase): + + def testScalar(self): + f = ufunc_ext.UnaryCallable() + assert_array_almost_equal(f(1.0), 2.0) + assert_array_almost_equal(f(3.0), 6.0) + + def testArray(self): + f = ufunc_ext.UnaryCallable() + a = numpy.arange(5, dtype=float) + b = f(a) + assert_array_almost_equal(b, a*2.0) + c = numpy.zeros(5, dtype=float) + d = f(a,output=c) + self.assert_(c is d) + assert_array_almost_equal(d, a*2.0) + + def testList(self): + f = ufunc_ext.UnaryCallable() + a = range(5) + b = f(a) + assert_array_almost_equal(b/2.0, a) + +class TestBinary(unittest.TestCase): + + def testScalar(self): + f = ufunc_ext.BinaryCallable() + assert_array_almost_equal(f(1.0, 3.0), 11.0) + assert_array_almost_equal(f(3.0, 2.0), 12.0) + + def testArray(self): + f = ufunc_ext.BinaryCallable() + a = numpy.random.randn(5) + b = numpy.random.randn(5) + assert_array_almost_equal(f(a,b), (a*2+b*3)) + c = numpy.zeros(5, dtype=float) + d = f(a,b,output=c) + self.assert_(c is d) + assert_array_almost_equal(d, a*2 + b*3) + assert_array_almost_equal(f(a, 2.0), a*2 + 6.0) + assert_array_almost_equal(f(1.0, b), 2.0 + b*3) + + +if __name__=="__main__": + unittest.main() diff --git a/src/boost/libs/python/test/object.cpp b/src/boost/libs/python/test/object.cpp new file mode 100644 index 000000000..b1f015187 --- /dev/null +++ b/src/boost/libs/python/test/object.cpp @@ -0,0 +1,392 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/object.hpp> +#include <boost/python/class.hpp> + +using namespace boost::python; + +class NotCopyable +{ +} not_copyable; + +object ref_to_noncopyable() +{ + return object(boost::ref(not_copyable)); +} + +object call_object_3(object f) +{ + return f(3); +} + +object message() +{ + return object("hello, world!"); +} + +object number() +{ + return object(42); +} + +object obj_getattr(object x, char const* name) +{ + return x.attr(name); +} + +object obj_objgetattr(object x, object const& name) +{ + return x.attr(name); +} + +object obj_const_getattr(object const& x, char const* name) +{ + return x.attr(name); +} + +object obj_const_objgetattr(object const& x, object const& name) +{ + return x.attr(name); +} + +void obj_setattr(object x, char const* name, object value) +{ + x.attr(name) = value; +} + +void obj_objsetattr(object x, object const& name, object value) +{ + x.attr(name) = value; +} + +void obj_setattr42(object x, char const* name) +{ + x.attr(name) = 42; +} + +void obj_objsetattr42(object x, object const& name) +{ + x.attr(name) = 42; +} + +void obj_moveattr(object& x, char const* src, char const* dst) +{ + x.attr(dst) = x.attr(src); +} + +void obj_objmoveattr(object& x, object const& src, object const& dst) +{ + x.attr(dst) = x.attr(src); +} + +void obj_delattr(object x, char const* name) +{ + x.attr(name).del(); +} + +void obj_objdelattr(object x, object const& name) +{ + x.attr(name).del(); +} + +object obj_getitem(object x, object key) +{ + return x[key]; +} + +object obj_getitem3(object x) +{ + return x[3]; +} + +object obj_const_getitem(object const& x, object key) +{ + return x[key]; +} + +void obj_setitem(object x, object key, object value) +{ + x[key] = value; +} + +void obj_setitem42(object x, object key) +{ + x[key] = 42; +} + +void obj_moveitem(object& x, object src, object dst) +{ + x[dst] = x[src]; +} + +void obj_moveitem2(object const& x_src, object k_src, object& x_dst, object k_dst) +{ + x_dst[k_dst] = x_src[k_src]; +} + +bool test(object y) +{ + return y; +} + +bool test_not(object y) +{ + return !y; +} + +bool test_attr(object y, char* name) +{ + return y.attr(name); +} + +bool test_objattr(object y, object& name) +{ + return y.attr(name); +} + +bool test_not_attr(object y, char* name) +{ + return !y.attr(name); +} + +bool test_not_objattr(object y, object& name) +{ + return !y.attr(name); +} + +bool test_item(object y, object key) +{ + return y[key]; +} + +bool test_not_item(object y, object key) +{ + return !y[key]; +} + +bool check_string_slice() +{ + object s("hello, world"); + + if (s.slice(_,-3) != "hello, wo") + return false; + + if (s.slice(-3,_) != "rld") + return false; + + if (s.slice(_,_) != s) + return false; + + if (", " != s.slice(5,7)) + return false; + + return s.slice(2,-1).slice(1,-1) == "lo, wor"; +} + +object test_call(object c, object args, object kwds) +{ + return c(*args, **kwds); +} + +bool check_binary_operators() +{ + int y; + + object x(3); + +#define TEST_BINARY(op) \ + for (y = 1; y < 6; ++y) \ + { \ + if ((x op y) != (3 op y)) \ + return false; \ + } \ + for (y = 1; y < 6; ++y) \ + { \ + if ((y op x) != (y op 3)) \ + return false; \ + } \ + for (y = 1; y < 6; ++y) \ + { \ + object oy(y); \ + if ((oy op x) != (oy op 3)) \ + return false; \ + } + TEST_BINARY(>) + TEST_BINARY(>=) + TEST_BINARY(<) + TEST_BINARY(<=) + TEST_BINARY(==) + TEST_BINARY(!=) + + TEST_BINARY(+) + TEST_BINARY(-) + TEST_BINARY(*) + TEST_BINARY(/) + TEST_BINARY(%) + TEST_BINARY(<<) + TEST_BINARY(>>) + TEST_BINARY(&) + TEST_BINARY(^) + TEST_BINARY(|) + return true; +} + +bool check_inplace(object l, object o) +{ + int y; +#define TEST_INPLACE(op) \ + for (y = 1; y < 6; ++y) \ + { \ + object x(666); \ + x op##= y; \ + if (x != (666 op y)) \ + return false; \ + } \ + for (y = 1; y < 6; ++y) \ + { \ + object x(666); \ + x op##= object(y); \ + if (!(x == (666 op y))) \ + return false; \ + } + TEST_INPLACE(+) + TEST_INPLACE(-) + TEST_INPLACE(*) + TEST_INPLACE(/) + TEST_INPLACE(%) + TEST_INPLACE(<<) + TEST_INPLACE(>>) + TEST_INPLACE(&) + TEST_INPLACE(^) + TEST_INPLACE(|) + + l += l; + for (y = 0; y < 6; ++y) + { + if (l[y] != y % 3) + return false; + } + +#define TEST_ITEM_INPLACE(index, op, n, r1, r2) \ + l[index] op##= n; \ + if (l[index] != r1) \ + return false; \ + l[index] op##= object(n); \ + if (!(l[index] == r2)) \ + return false; + + TEST_ITEM_INPLACE(0,+,7,7,14) + TEST_ITEM_INPLACE(1,-,2,-1,-3) + TEST_ITEM_INPLACE(2,*,3,6,18) + TEST_ITEM_INPLACE(2,/,2,9,4) + TEST_ITEM_INPLACE(0,%,4,2,2) + l[0] += 1; + TEST_ITEM_INPLACE(0,<<,2,12,48) + TEST_ITEM_INPLACE(0,>>,1,24,12) + l[4] = 15; + TEST_ITEM_INPLACE(4,&,(16+4+1),5,5) + TEST_ITEM_INPLACE(0,^,1,13,12) + TEST_ITEM_INPLACE(0,|,1,13,13) + + o.attr("x0") = 0; + o.attr("x1") = 1; + o.attr("x2") = 2; + o.attr("x3") = 0; + o.attr("x4") = 1; + +#define TEST_ATTR_INPLACE(index, op, n, r1, r2) \ + o.attr("x" #index) op##= n; \ + if (o.attr("x" #index) != r1) \ + return false; \ + o.attr("x" #index) op##= object(n); \ + if (o.attr("x" #index) != r2) \ + return false; + + TEST_ATTR_INPLACE(0,+,7,7,14) + TEST_ATTR_INPLACE(1,-,2,-1,-3) + TEST_ATTR_INPLACE(2,*,3,6,18) + TEST_ATTR_INPLACE(2,/,2,9,4) + TEST_ATTR_INPLACE(0,%,4,2,2) + o.attr("x0") += 1; + TEST_ATTR_INPLACE(0,<<,2,12,48) + TEST_ATTR_INPLACE(0,>>,1,24,12) + o.attr("x4") = 15; + TEST_ATTR_INPLACE(4,&,(16+4+1),5,5) + TEST_ATTR_INPLACE(0,^,1,13,12) + TEST_ATTR_INPLACE(0,|,1,13,13) + + if (l[0] != o.attr("x0")) + return false; + if (l[1] != o.attr("x1")) + return false; + if (l[2] != o.attr("x2")) + return false; + if (l[3] != o.attr("x3")) + return false; + if (l[4] != o.attr("x4")) + return false; + + // set item 5 to be a list, by calling l.__class__ + l[5] = l.attr("__class__")(); + // append an element + l[5].attr("append")(2); + // Check its value + if (l[5][0] != 2) + return false; + + return true; +} + +BOOST_PYTHON_MODULE(object_ext) +{ + class_<NotCopyable, boost::noncopyable>("NotCopyable", no_init); + + def("ref_to_noncopyable", ref_to_noncopyable); + def("call_object_3", call_object_3); + def("message", message); + def("number", number); + + def("obj_getattr", obj_getattr); + def("obj_objgetattr", obj_objgetattr); + def("obj_const_getattr", obj_const_getattr); + def("obj_const_objgetattr", obj_const_objgetattr); + def("obj_setattr", obj_setattr); + def("obj_objsetattr", obj_objsetattr); + def("obj_setattr42", obj_setattr42); + def("obj_objsetattr42", obj_objsetattr42); + def("obj_moveattr", obj_moveattr); + def("obj_objmoveattr", obj_objmoveattr); + def("obj_delattr", obj_delattr); + def("obj_objdelattr", obj_objdelattr); + + def("obj_getitem", obj_getitem); + def("obj_getitem3", obj_getitem); + def("obj_const_getitem", obj_const_getitem); + def("obj_setitem", obj_setitem); + def("obj_setitem42", obj_setitem42); + def("obj_moveitem", obj_moveitem); + def("obj_moveitem2", obj_moveitem2); + + def("test", test); + def("test_not", test_not); + + def("test_attr", test_attr); + def("test_objattr", test_objattr); + def("test_not_attr", test_not_attr); + def("test_not_objattr", test_not_objattr); + + def("test_item", test_item); + def("test_not_item", test_not_item); + + def("test_call", test_call); + def("check_binary_operators", check_binary_operators); + def("check_inplace", check_inplace); + def("check_string_slice", check_string_slice); + ; +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/object.py b/src/boost/libs/python/test/object.py new file mode 100644 index 000000000..67a46d936 --- /dev/null +++ b/src/boost/libs/python/test/object.py @@ -0,0 +1,180 @@ +# Copyright David Abrahams 2004. 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) +from __future__ import print_function +''' +>>> from object_ext import * + +>>> type(ref_to_noncopyable()) +<class 'object_ext.NotCopyable'> + +>>> def print1(x): +... print(x) +>>> call_object_3(print1) +3 +>>> message() +'hello, world!' +>>> number() +42 + +>>> test('hi') +1 +>>> test(None) +0 +>>> test_not('hi') +0 +>>> test_not(0) +1 + + Attributes + +>>> class X: pass +... +>>> x = X() + +>>> try: obj_getattr(x, 'foo') +... except AttributeError: pass +... else: print('expected an exception') +>>> try: obj_objgetattr(x, 'objfoo') +... except AttributeError: pass +... else: print('expected an exception') + +>>> obj_setattr(x, 'foo', 1) +>>> x.foo +1 +>>> obj_objsetattr(x, 'objfoo', 1) +>>> try:obj_objsetattr(x, 1) +... except TypeError: pass +... else: print('expected an exception') +>>> x.objfoo +1 +>>> obj_getattr(x, 'foo') +1 +>>> obj_objgetattr(x, 'objfoo') +1 +>>> try:obj_objgetattr(x, 1) +... except TypeError: pass +... else: print('expected an exception') +>>> obj_const_getattr(x, 'foo') +1 +>>> obj_const_objgetattr(x, 'objfoo') +1 +>>> obj_setattr42(x, 'foo') +>>> x.foo +42 +>>> obj_objsetattr42(x, 'objfoo') +>>> x.objfoo +42 +>>> obj_moveattr(x, 'foo', 'bar') +>>> x.bar +42 +>>> obj_objmoveattr(x, 'objfoo', 'objbar') +>>> x.objbar +42 +>>> test_attr(x, 'foo') +1 +>>> test_objattr(x, 'objfoo') +1 +>>> test_not_attr(x, 'foo') +0 +>>> test_not_objattr(x, 'objfoo') +0 +>>> x.foo = None +>>> test_attr(x, 'foo') +0 +>>> x.objfoo = None +>>> test_objattr(x, 'objfoo') +0 +>>> test_not_attr(x, 'foo') +1 +>>> test_not_objattr(x, 'objfoo') +1 +>>> obj_delattr(x, 'foo') +>>> obj_objdelattr(x, 'objfoo') +>>> try:obj_delattr(x, 'foo') +... except AttributeError: pass +... else: print('expected an exception') +>>> try:obj_objdelattr(x, 'objfoo') +... except AttributeError: pass +... else: print('expected an exception') + + Items + +>>> d = {} +>>> obj_setitem(d, 'foo', 1) +>>> d['foo'] +1 +>>> obj_getitem(d, 'foo') +1 +>>> obj_const_getitem(d, 'foo') +1 +>>> obj_setitem42(d, 'foo') +>>> obj_getitem(d, 'foo') +42 +>>> d['foo'] +42 +>>> obj_moveitem(d, 'foo', 'bar') +>>> d['bar'] +42 +>>> obj_moveitem2(d, 'bar', d, 'baz') +>>> d['baz'] +42 +>>> test_item(d, 'foo') +1 +>>> test_not_item(d, 'foo') +0 +>>> d['foo'] = None +>>> test_item(d, 'foo') +0 +>>> test_not_item(d, 'foo') +1 + + Slices + +>>> assert check_string_slice() + + Operators + +>>> def print_args(*args, **kwds): +... print(args, kwds) +>>> test_call(print_args, (0, 1, 2, 3), {'a':'A'}) +(0, 1, 2, 3) {'a': 'A'} + + +>>> assert check_binary_operators() + +>>> class X: pass +... +>>> assert check_inplace(list(range(3)), X()) + + + Now make sure that object is actually managing reference counts + +>>> import weakref +>>> class Z: pass +... +>>> z = Z() +>>> def death(r): print('death') +... +>>> r = weakref.ref(z, death) +>>> z.foo = 1 +>>> obj_getattr(z, 'foo') +1 +>>> del z +death +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/object_fail1.cpp b/src/boost/libs/python/test/object_fail1.cpp new file mode 100644 index 000000000..6bb2eda5c --- /dev/null +++ b/src/boost/libs/python/test/object_fail1.cpp @@ -0,0 +1,11 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/object.hpp> + +int f(boost::python::object const& x) +{ + x._("hello") = 1; + return 0; +} diff --git a/src/boost/libs/python/test/object_manager.cpp b/src/boost/libs/python/test/object_manager.cpp new file mode 100644 index 000000000..e3608c1f1 --- /dev/null +++ b/src/boost/libs/python/test/object_manager.cpp @@ -0,0 +1,33 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/converter/object_manager.hpp> +#include <boost/python/borrowed.hpp> +#include <boost/static_assert.hpp> +#include <boost/python/handle.hpp> + +using namespace boost::python; +using namespace boost::python::converter; + +struct X {}; + +int main() +{ + BOOST_STATIC_ASSERT(is_object_manager<handle<> >::value); + BOOST_STATIC_ASSERT(!is_object_manager<int>::value); + BOOST_STATIC_ASSERT(!is_object_manager<X>::value); + + BOOST_STATIC_ASSERT(is_reference_to_object_manager<handle<>&>::value); + BOOST_STATIC_ASSERT(is_reference_to_object_manager<handle<> const&>::value); + BOOST_STATIC_ASSERT(is_reference_to_object_manager<handle<> volatile&>::value); + BOOST_STATIC_ASSERT(is_reference_to_object_manager<handle<> const volatile&>::value); + + BOOST_STATIC_ASSERT(!is_reference_to_object_manager<handle<> >::value); + BOOST_STATIC_ASSERT(!is_reference_to_object_manager<X>::value); + BOOST_STATIC_ASSERT(!is_reference_to_object_manager<X&>::value); + BOOST_STATIC_ASSERT(!is_reference_to_object_manager<X const&>::value); + + return 0; +} + diff --git a/src/boost/libs/python/test/opaque.cpp b/src/boost/libs/python/test/opaque.cpp new file mode 100644 index 000000000..f15e9458f --- /dev/null +++ b/src/boost/libs/python/test/opaque.cpp @@ -0,0 +1,76 @@ +// Copyright David Abrahams and Gottfried Ganssauge 2003. +// 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 <boost/python/return_opaque_pointer.hpp> +# include <boost/python/def.hpp> +# include <boost/python/module.hpp> +# include <boost/python/return_value_policy.hpp> + +typedef struct opaque_ *opaque; +typedef struct opaque2_ *opaque2; + +opaque the_op = ((opaque) 0x47110815); +opaque2 the_op2 = ((opaque2) 0x08154711); + +opaque get() { return the_op; } + +void use(opaque op) +{ + if (op != the_op) + throw std::runtime_error (std::string ("failed")); +} + +int useany(opaque op) +{ + return op ? 1 : 0; +} + +opaque getnull() +{ + return 0; +} + +void failuse (opaque op) +{ + if (op == the_op) + throw std::runtime_error (std::string ("success")); +} + +opaque2 get2 () { return the_op2; } + +void use2 (opaque2 op) +{ + if (op != the_op2) + throw std::runtime_error (std::string ("failed")); +} + +void failuse2 (opaque2 op) +{ + if (op == the_op2) + throw std::runtime_error (std::string ("success")); +} + +BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(opaque_) +BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(opaque2_) + +namespace bpl = boost::python; + +BOOST_PYTHON_MODULE(opaque_ext) +{ + bpl::def ( + "get", &::get, bpl::return_value_policy<bpl::return_opaque_pointer>()); + bpl::def ("use", &::use); + bpl::def ("useany", &::useany); + bpl::def ("getnull", &::getnull, bpl::return_value_policy<bpl::return_opaque_pointer>()); + bpl::def ("failuse", &::failuse); + + bpl::def ( + "get2", + &::get2, + bpl::return_value_policy<bpl::return_opaque_pointer>()); + bpl::def ("use2", &::use2); + bpl::def ("failuse2", &::failuse2); +} + +# include "module_tail.cpp" diff --git a/src/boost/libs/python/test/opaque.py b/src/boost/libs/python/test/opaque.py new file mode 100644 index 000000000..9f5663723 --- /dev/null +++ b/src/boost/libs/python/test/opaque.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +# Copyright Gottfried Ganßauge 2003..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) + + +""" +>>> from opaque_ext import * + + + Check for correct conversion + +>>> use(get()) + + Check that None is converted to a NULL opaque pointer + +>>> useany(get()) +1 +>>> useany(None) +0 + + Check that we don't lose type information by converting NULL + opaque pointers to None + +>>> assert getnull() is None +>>> useany(getnull()) +0 + +>>> failuse(get()) +Traceback (most recent call last): + ... +RuntimeError: success + + Check that there is no conversion from integers ... + +>>> try: use(0) +... except TypeError: pass +... else: print('expected a TypeError') + + ... and from strings to opaque objects + +>>> try: use("") +... except TypeError: pass +... else: print('expected a TypeError') + + Now check the same for another opaque pointer type + +>>> use2(get2()) +>>> failuse2(get2()) +Traceback (most recent call last): + ... +RuntimeError: success +>>> try: use2(0) +... except TypeError: pass +... else: print('expected a TypeError') +>>> try: use2("") +... except TypeError: pass +... else: print('expected a TypeError') + + Check that opaque types are distinct + +>>> try: use(get2()) +... except TypeError: pass +... else: print('expected a TypeError') +>>> try: use2(get()) +... except TypeError: pass +... else: print('expected a TypeError') + + This used to result in a segmentation violation + +>>> type(get()) != type (get2()) +1 +""" +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/operators.cpp b/src/boost/libs/python/test/operators.cpp new file mode 100644 index 000000000..c58f2b005 --- /dev/null +++ b/src/boost/libs/python/test/operators.cpp @@ -0,0 +1,175 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/operators.hpp> +#include <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include "test_class.hpp" +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/operators.hpp> +#include <boost/operators.hpp> +//#include <boost/python/str.hpp> +// Just use math.h here; trying to use std::pow() causes too much +// trouble for non-conforming compilers and libraries. +#include <math.h> + +#if __GNUC__ != 2 +# include <ostream> +#else +# include <ostream.h> +#endif + +using namespace boost::python; + + +using namespace boost::python; + +struct X : test_class<> +{ + typedef test_class<> base_t; + + X(int x) : base_t(x) {} + X const operator+(X const& r) const { return X(value() + r.value()); } + +// typedef int (X::*safe_bool)() const; +// operator safe_bool() const { return value() != 0 ? &X::value : 0; } +}; + +X operator-(X const& l, X const& r) { return X(l.value() - r.value()); } +X operator-(int l, X const& r) { return X(l - r.value()); } +X operator-(X const& l, int r) { return X(l.value() - r); } + +X operator-(X const& x) { return X(-x.value()); } + +X& operator-=(X& l, X const& r) { l.set(l.value() - r.value()); return l; } + +bool operator<(X const& x, X const& y) { return x.value() < y.value(); } +bool operator<(X const& x, int y) { return x.value() < y; } +bool operator<(int x, X const& y) { return x < y.value(); } + +X abs(X x) { return X(x.value() < 0 ? -x.value() : x.value()); } + +X pow(X x, int y) +{ + return X(int(pow(double(x.value()), double(y)))); +} + +X pow(X x, X y) +{ + return X(int(pow(double(x.value()), double(y.value())))); +} + +int pow(int x, X y) +{ + return int(pow(double(x), double(y.value()))); +} + +std::ostream& operator<<(std::ostream& s, X const& x) +{ + return s << x.value(); +} + +struct number + : boost::integer_arithmetic<number> +{ + explicit number(long x_) : x(x_) {} + operator long() const { return x; } + + template <class T> + number& operator+=(T const& rhs) + { x += rhs; return *this; } + + template <class T> + number& operator-=(T const& rhs) + { x -= rhs; return *this; } + + template <class T> + number& operator*=(T const& rhs) + { x *= rhs; return *this; } + + template <class T> + number& operator/=(T const& rhs) + { x /= rhs; return *this; } + + template <class T> + number& operator%=(T const& rhs) + { x %= rhs; return *this; } + + long x; +}; + +BOOST_PYTHON_MODULE(operators_ext) +{ + class_<X>("X", init<int>()) + .def("value", &X::value) + .def(self + self) + .def(self - self) + .def(self - int()) + .def(other<int>() - self) + .def(-self) + .def(self < other<int>()) + .def(self < self) + .def(1 < self) + .def(self -= self) + + .def(abs(self)) + .def(str(self)) + + .def(pow(self,self)) + .def(pow(self,int())) + .def(pow(int(),self)) + .def( + !self + // "not self" is legal here but causes friction on a few + // nonconforming compilers; it's cute because it looks + // like python, but doing it here doesn't prove much and + // just causes tests to fail or complicated workarounds to + // be enacted. + ) + ; + + class_<number>("number", init<long>()) + // 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) + ; + + class_<test_class<1> >("Z", init<int>()) + .def(int_(self)) + .def(float_(self)) + .def(complex_(self)) + ; +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/operators.py b/src/boost/libs/python/test/operators.py new file mode 100644 index 000000000..5b369803c --- /dev/null +++ b/src/boost/libs/python/test/operators.py @@ -0,0 +1,102 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from operators_ext import * + + Check __nonzero__ support + +>>> assert X(2) +>>> assert not X(0) + + ---- + +>>> x = X(42) +>>> x.value() +42 +>>> y = x - X(5) +>>> y.value() +37 +>>> y = x - 4 +>>> y.value() +38 +>>> y = 3 - x +>>> y.value() +-39 +>>> (-y).value() +39 + +>>> (x + y).value() +3 + +>>> abs(y).value() +39 + +>>> x < 10 +0 +>>> x < 43 +1 + +>>> 10 < x +1 +>>> 43 < x +0 + +>>> x < y +0 +>>> y < x +1 + + ------ +>>> x > 10 +1 +>>> x > 43 +0 + +>>> 10 > x +0 +>>> 43 > x +1 + +>>> x > y +1 +>>> y > x +0 + +>>> y = x - 5 +>>> x -= y +>>> x.value() +5 +>>> str(x) +'5' + +>>> z = Z(10) +>>> int(z) +10 +>>> float(z) +10.0 +>>> complex(z) +(10+0j) + +>>> pow(2,x) +32 +>>> pow(x,2).value() +25 +>>> pow(X(2),x).value() +32 +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/operators_wrapper.cpp b/src/boost/libs/python/test/operators_wrapper.cpp new file mode 100644 index 000000000..12f30048d --- /dev/null +++ b/src/boost/libs/python/test/operators_wrapper.cpp @@ -0,0 +1,42 @@ +#include "boost/python.hpp" +#include <memory> + +struct vector +{ + virtual ~vector() {} + + vector operator+( const vector& ) const + { return vector(); } + + vector& operator+=( const vector& ) + { return *this; } + + vector operator-() const + { return *this; } +}; + +struct dvector : vector +{}; + +using namespace boost::python; + +struct vector_wrapper + : vector, wrapper< vector > +{ + vector_wrapper(vector const&) {} + vector_wrapper() {} +}; + +BOOST_PYTHON_MODULE( operators_wrapper_ext ) +{ + class_< vector_wrapper >( "vector" ) + .def( self + self ) + .def( self += self ) + .def( -self ) + ; + + scope().attr("v") = vector(); + std::auto_ptr<vector> dp(new dvector); + register_ptr_to_python< std::auto_ptr<vector> >(); + scope().attr("d") = dp; +} diff --git a/src/boost/libs/python/test/operators_wrapper.py b/src/boost/libs/python/test/operators_wrapper.py new file mode 100644 index 000000000..6c889b0a3 --- /dev/null +++ b/src/boost/libs/python/test/operators_wrapper.py @@ -0,0 +1,11 @@ +from operators_wrapper_ext import * + +class D2(vector): pass +d2 = D2() + +for lhs in (v,d,d2): + -lhs + for rhs in (v,d,d2): + lhs + rhs + lhs += rhs + diff --git a/src/boost/libs/python/test/pickle1.cpp b/src/boost/libs/python/test/pickle1.cpp new file mode 100644 index 000000000..cc4ad6795 --- /dev/null +++ b/src/boost/libs/python/test/pickle1.cpp @@ -0,0 +1,62 @@ +// Copyright Ralf W. Grosse-Kunstleve 2002-2004. 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) + +/* + This example shows how to make an Extension Class "pickleable". + + The world class below can be fully restored by passing the + appropriate argument to the constructor. Therefore it is sufficient + to define the pickle interface method __getinitargs__. + + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/tuple.hpp> + +#include <string> + +namespace boost_python_test { + + // A friendly class. + class world + { + private: + std::string country; + public: + world(const std::string& _country) { + this->country = _country; + } + std::string greet() const { return "Hello from " + country + "!"; } + std::string get_country() const { return country; } + }; + + struct world_pickle_suite : boost::python::pickle_suite + { + static + boost::python::tuple + getinitargs(const world& w) + { + return boost::python::make_tuple(w.get_country()); + } + }; + + // To support test of "pickling not enabled" error message. + struct noop {}; +} + +BOOST_PYTHON_MODULE(pickle1_ext) +{ + using namespace boost::python; + using namespace boost_python_test; + class_<world>("world", init<const std::string&>()) + .def("greet", &world::greet) + .def_pickle(world_pickle_suite()) + ; + + // To support test of "pickling not enabled" error message. + class_<noop>("noop"); +} diff --git a/src/boost/libs/python/test/pickle1.py b/src/boost/libs/python/test/pickle1.py new file mode 100644 index 000000000..b8f4efd9b --- /dev/null +++ b/src/boost/libs/python/test/pickle1.py @@ -0,0 +1,41 @@ +# Copyright David Abrahams 2004. 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) +r'''>>> import pickle1_ext + >>> import pickle + >>> pickle1_ext.world.__module__ + 'pickle1_ext' + >>> pickle1_ext.world.__safe_for_unpickling__ + 1 + >>> pickle1_ext.world.__name__ + 'world' + >>> pickle1_ext.world('Hello').__reduce__() + (<class 'pickle1_ext.world'>, ('Hello',)) + >>> wd = pickle1_ext.world('California') + >>> pstr = pickle.dumps(wd) + >>> wl = pickle.loads(pstr) + >>> print(wd.greet()) + Hello from California! + >>> print(wl.greet()) + Hello from California! + + >>> noop = pickle1_ext.noop() + >>> try: pickle.dumps(noop) + ... except RuntimeError as e: print(str(e)[:55]) + Pickling of "pickle1_ext.noop" instances is not enabled +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/pickle2.cpp b/src/boost/libs/python/test/pickle2.cpp new file mode 100644 index 000000000..c9610946e --- /dev/null +++ b/src/boost/libs/python/test/pickle2.cpp @@ -0,0 +1,97 @@ +// Copyright Ralf W. Grosse-Kunstleve 2002-2004. 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) + +/* + This example shows how to make an Extension Class "pickleable". + + The world class below contains member data (secret_number) that + cannot be restored by any of the constructors. Therefore it is + necessary to provide the __getstate__/__setstate__ pair of pickle + interface methods. + + 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 safety guards are provided to catch + the cases where this assumption is not true. + + pickle3.cpp shows how to include the object's __dict__ in the + result of __getstate__. + + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/extract.hpp> + +namespace boost_python_test { + + // A friendly class. + class world + { + public: + world(const std::string& _country) : secret_number(0) { + this->country = _country; + } + std::string greet() const { return "Hello from " + country + "!"; } + std::string get_country() const { return country; } + void set_secret_number(int number) { secret_number = number; } + int get_secret_number() const { return secret_number; } + private: + std::string country; + int secret_number; + }; + + struct world_pickle_suite : boost::python::pickle_suite + { + static + boost::python::tuple + getinitargs(const world& w) + { + return boost::python::make_tuple(w.get_country()); + } + + static + boost::python::tuple + getstate(const world& w) + { + return boost::python::make_tuple(w.get_secret_number()); + } + + static + void + setstate(world& w, boost::python::tuple state) + { + using namespace boost::python; + if (len(state) != 1) + { + PyErr_SetObject(PyExc_ValueError, + ("expected 1-item tuple in call to __setstate__; got %s" + % state).ptr() + ); + throw_error_already_set(); + } + + long number = extract<long>(state[0]); + if (number != 42) + w.set_secret_number(number); + } + }; + +} + +BOOST_PYTHON_MODULE(pickle2_ext) +{ + using namespace boost_python_test; + boost::python::class_<world>( + "world", boost::python::init<const std::string&>()) + .def("greet", &world::greet) + .def("get_secret_number", &world::get_secret_number) + .def("set_secret_number", &world::set_secret_number) + .def_pickle(world_pickle_suite()) + ; +} diff --git a/src/boost/libs/python/test/pickle2.py b/src/boost/libs/python/test/pickle2.py new file mode 100644 index 000000000..f4788d3b8 --- /dev/null +++ b/src/boost/libs/python/test/pickle2.py @@ -0,0 +1,51 @@ +# Copyright David Abrahams 2004. 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) +from __future__ import print_function +r'''>>> import pickle2_ext + >>> import pickle + >>> pickle2_ext.world.__module__ + 'pickle2_ext' + >>> pickle2_ext.world.__safe_for_unpickling__ + 1 + >>> pickle2_ext.world.__name__ + 'world' + >>> pickle2_ext.world('Hello').__reduce__() + (<class 'pickle2_ext.world'>, ('Hello',), (0,)) + >>> for number in (24, 42): + ... wd = pickle2_ext.world('California') + ... wd.set_secret_number(number) + ... pstr = pickle.dumps(wd) + ... wl = pickle.loads(pstr) + ... print(wd.greet(), wd.get_secret_number()) + ... print(wl.greet(), wl.get_secret_number()) + Hello from California! 24 + Hello from California! 24 + Hello from California! 42 + Hello from California! 0 + +# Now show that the __dict__ is not taken care of. + >>> wd = pickle2_ext.world('California') + >>> wd.x = 1 + >>> wd.__dict__ + {'x': 1} + >>> try: pstr = pickle.dumps(wd) + ... except RuntimeError as err: print(err) + ... + Incomplete pickle support (__getstate_manages_dict__ not set) +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/pickle3.cpp b/src/boost/libs/python/test/pickle3.cpp new file mode 100644 index 000000000..7afe2dbfa --- /dev/null +++ b/src/boost/libs/python/test/pickle3.cpp @@ -0,0 +1,107 @@ +// Copyright Ralf W. Grosse-Kunstleve 2002-2004. 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) + +/* + This example shows how to make an Extension Class "pickleable". + + The world class below contains member data (secret_number) that + cannot be restored by any of the constructors. Therefore it is + necessary to provide the __getstate__/__setstate__ pair of pickle + interface methods. + + The object's __dict__ is included in the result of __getstate__. + This requires more code (compare with pickle2.cpp), but is + unavoidable if the object's __dict__ is not always empty. + + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/dict.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/back_reference.hpp> + +namespace boost_python_test { + + // A friendly class. + class world + { + public: + world(const std::string& _country) : secret_number(0) { + this->country = _country; + } + std::string greet() const { return "Hello from " + country + "!"; } + std::string get_country() const { return country; } + void set_secret_number(int number) { secret_number = number; } + int get_secret_number() const { return secret_number; } + private: + std::string country; + int secret_number; + }; + + struct world_pickle_suite : boost::python::pickle_suite + { + static + boost::python::tuple + getinitargs(const world& w) + { + return boost::python::make_tuple(w.get_country()); + } + + static + boost::python::tuple + getstate(boost::python::object w_obj) + { + world const& w = boost::python::extract<world const&>(w_obj)(); + + return boost::python::make_tuple( + w_obj.attr("__dict__"), + w.get_secret_number()); + } + + static + void + setstate(boost::python::object w_obj, boost::python::tuple state) + { + using namespace boost::python; + world& w = extract<world&>(w_obj)(); + + if (len(state) != 2) + { + PyErr_SetObject(PyExc_ValueError, + ("expected 2-item tuple in call to __setstate__; got %s" + % state).ptr() + ); + throw_error_already_set(); + } + + // restore the object's __dict__ + dict d = extract<dict>(w_obj.attr("__dict__"))(); + d.update(state[0]); + + // restore the internal state of the C++ object + long number = extract<long>(state[1]); + if (number != 42) + w.set_secret_number(number); + } + + static bool getstate_manages_dict() { return true; } + }; + +} + +BOOST_PYTHON_MODULE(pickle3_ext) +{ + using namespace boost_python_test; + boost::python::class_<world>( + "world", boost::python::init<const std::string&>()) + .def("greet", &world::greet) + .def("get_secret_number", &world::get_secret_number) + .def("set_secret_number", &world::set_secret_number) + .def_pickle(world_pickle_suite()) + ; +} diff --git a/src/boost/libs/python/test/pickle3.py b/src/boost/libs/python/test/pickle3.py new file mode 100644 index 000000000..932e30f3c --- /dev/null +++ b/src/boost/libs/python/test/pickle3.py @@ -0,0 +1,46 @@ +# Copyright David Abrahams 2004. 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) +from __future__ import print_function +r'''>>> import pickle3_ext + >>> import pickle + >>> pickle3_ext.world.__module__ + 'pickle3_ext' + >>> pickle3_ext.world.__safe_for_unpickling__ + 1 + >>> pickle3_ext.world.__getstate_manages_dict__ + 1 + >>> pickle3_ext.world.__name__ + 'world' + >>> pickle3_ext.world('Hello').__reduce__() + (<class 'pickle3_ext.world'>, ('Hello',), ({}, 0)) + >>> for number in (24, 42): + ... wd = pickle3_ext.world('California') + ... wd.set_secret_number(number) + ... wd.x = 2 * number + ... wd.y = 'y' * number + ... wd.z = 3. * number + ... pstr = pickle.dumps(wd) + ... wl = pickle.loads(pstr) + ... print(wd.greet(), wd.get_secret_number(), wd.x, wd.y, wd.z) + ... print(wl.greet(), wl.get_secret_number(), wl.x, wl.y, wl.z) + Hello from California! 24 48 yyyyyyyyyyyyyyyyyyyyyyyy 72.0 + Hello from California! 24 48 yyyyyyyyyyyyyyyyyyyyyyyy 72.0 + Hello from California! 42 84 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy 126.0 + Hello from California! 0 84 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy 126.0 +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/pickle4.cpp b/src/boost/libs/python/test/pickle4.cpp new file mode 100644 index 000000000..1374cc7dc --- /dev/null +++ b/src/boost/libs/python/test/pickle4.cpp @@ -0,0 +1,44 @@ +// Copyright Ralf W. Grosse-Kunstleve 2004. 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) + +/* + This example shows how to enable pickling without using the + pickle_suite. The pickling interface (__getinitargs__) is + implemented in Python. + + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> + +#include <string> + +namespace boost_python_test { + + // A friendly class. + class world + { + private: + std::string country; + public: + world(const std::string& _country) { + this->country = _country; + } + std::string greet() const { return "Hello from " + country + "!"; } + std::string get_country() const { return country; } + }; + +} + +BOOST_PYTHON_MODULE(pickle4_ext) +{ + using namespace boost::python; + using namespace boost_python_test; + class_<world>("world", init<const std::string&>()) + .enable_pickling() + .def("greet", &world::greet) + .def("get_country", &world::get_country) + ; +} diff --git a/src/boost/libs/python/test/pickle4.py b/src/boost/libs/python/test/pickle4.py new file mode 100644 index 000000000..be813bbb1 --- /dev/null +++ b/src/boost/libs/python/test/pickle4.py @@ -0,0 +1,39 @@ +# Copyright David Abrahams 2004. 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) +r'''>>> import pickle4_ext + >>> import pickle + >>> def world_getinitargs(self): + ... return (self.get_country(),) + >>> pickle4_ext.world.__getinitargs__ = world_getinitargs + >>> pickle4_ext.world.__module__ + 'pickle4_ext' + >>> pickle4_ext.world.__safe_for_unpickling__ + 1 + >>> pickle4_ext.world.__name__ + 'world' + >>> pickle4_ext.world('Hello').__reduce__() + (<class 'pickle4_ext.world'>, ('Hello',)) + >>> wd = pickle4_ext.world('California') + >>> pstr = pickle.dumps(wd) + >>> wl = pickle.loads(pstr) + >>> print(wd.greet()) + Hello from California! + >>> print(wl.greet()) + Hello from California! +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/pointee.cpp b/src/boost/libs/python/test/pointee.cpp new file mode 100644 index 000000000..2aa5dc3d8 --- /dev/null +++ b/src/boost/libs/python/test/pointee.cpp @@ -0,0 +1,34 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/pointee.hpp> +#include <boost/python/detail/type_traits.hpp> +#include <memory> +#include <boost/shared_ptr.hpp> +#include <boost/static_assert.hpp> + +struct A; + +int main() +{ + BOOST_STATIC_ASSERT( + (boost::python::detail::is_same< + boost::python::pointee<std::auto_ptr<char**> >::type + , char** + >::value)); + + BOOST_STATIC_ASSERT( + (boost::python::detail::is_same< + boost::python::pointee<boost::shared_ptr<A> >::type + , A>::value)); + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + BOOST_STATIC_ASSERT( + (boost::python::detail::is_same< + boost::python::pointee<char*>::type + , char + >::value)); +#endif + return 0; +} diff --git a/src/boost/libs/python/test/pointer_type_id_test.cpp b/src/boost/libs/python/test/pointer_type_id_test.cpp new file mode 100644 index 000000000..02e168c7e --- /dev/null +++ b/src/boost/libs/python/test/pointer_type_id_test.cpp @@ -0,0 +1,43 @@ +// Copyright David Abrahams 2004. 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 <boost/python/type_id.hpp> + +#include <boost/detail/lightweight_test.hpp> +#include <boost/python/converter/pointer_type_id.hpp> + +int main() +{ + using namespace boost::python::converter; + + boost::python::type_info x + = boost::python::type_id<int>(); + + + BOOST_TEST(pointer_type_id<int*>() == x); + BOOST_TEST(pointer_type_id<int const*>() == x); + BOOST_TEST(pointer_type_id<int volatile*>() == x); + BOOST_TEST(pointer_type_id<int const volatile*>() == x); + + BOOST_TEST(pointer_type_id<int*&>() == x); + BOOST_TEST(pointer_type_id<int const*&>() == x); + BOOST_TEST(pointer_type_id<int volatile*&>() == x); + BOOST_TEST(pointer_type_id<int const volatile*&>() == x); + + BOOST_TEST(pointer_type_id<int*const&>() == x); + BOOST_TEST(pointer_type_id<int const*const&>() == x); + BOOST_TEST(pointer_type_id<int volatile*const&>() == x); + BOOST_TEST(pointer_type_id<int const volatile*const&>() == x); + + BOOST_TEST(pointer_type_id<int*volatile&>() == x); + BOOST_TEST(pointer_type_id<int const*volatile&>() == x); + BOOST_TEST(pointer_type_id<int volatile*volatile&>() == x); + BOOST_TEST(pointer_type_id<int const volatile*volatile&>() == x); + + BOOST_TEST(pointer_type_id<int*const volatile&>() == x); + BOOST_TEST(pointer_type_id<int const*const volatile&>() == x); + BOOST_TEST(pointer_type_id<int volatile*const volatile&>() == x); + BOOST_TEST(pointer_type_id<int const volatile*const volatile&>() == x); + + return boost::report_errors(); +} diff --git a/src/boost/libs/python/test/pointer_vector.cpp b/src/boost/libs/python/test/pointer_vector.cpp new file mode 100644 index 000000000..08cd48619 --- /dev/null +++ b/src/boost/libs/python/test/pointer_vector.cpp @@ -0,0 +1,52 @@ +// Copyright Joel de Guzman 2005-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) +#include <boost/python.hpp> +#include <boost/python/suite/indexing/vector_indexing_suite.hpp> +#include <vector> + +using namespace boost::python; + +class Abstract +{ +public: + virtual ~Abstract() {}; // silence compiler warningsa + virtual std::string f() =0; +}; + +class Concrete1 : public Abstract +{ +public: + virtual std::string f() { return "harru"; } +}; + +typedef std::vector<Abstract*> ListOfObjects; + +class DoesSomething +{ +public: + DoesSomething() {} + + ListOfObjects returnList() + { + ListOfObjects lst; + lst.push_back(new Concrete1()); return lst; + } +}; + +BOOST_PYTHON_MODULE(pointer_vector_ext) +{ +class_<Abstract, boost::noncopyable>("Abstract", no_init) + .def("f", &Abstract::f) + ; + +class_<ListOfObjects>("ListOfObjects") + .def( vector_indexing_suite<ListOfObjects>() ) + ; + +class_<DoesSomething>("DoesSomething") + .def("returnList", &DoesSomething::returnList) + ; +} + + diff --git a/src/boost/libs/python/test/pointer_vector.py b/src/boost/libs/python/test/pointer_vector.py new file mode 100644 index 000000000..234eff2c0 --- /dev/null +++ b/src/boost/libs/python/test/pointer_vector.py @@ -0,0 +1,31 @@ +# Copyright Joel de Guzman 2004. 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 pointer_vector_ext +>>> d = pointer_vector_ext.DoesSomething() +>>> lst = d.returnList() +>>> lst[0].f(); +'harru' + +''' + + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) + + + diff --git a/src/boost/libs/python/test/polymorphism.cpp b/src/boost/libs/python/test/polymorphism.cpp new file mode 100644 index 000000000..02713ae26 --- /dev/null +++ b/src/boost/libs/python/test/polymorphism.cpp @@ -0,0 +1,162 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/python/manage_new_object.hpp> +#include <boost/python/reference_existing_object.hpp> +#include <boost/python/call_method.hpp> +#include <boost/python/pure_virtual.hpp> +#include <boost/python/def.hpp> +#include <boost/utility.hpp> + +using namespace boost::python; + +struct Callback +{ + Callback(PyObject* o) : mSelf(o) {} + PyObject* mSelf; +}; + +struct P +{ + virtual ~P(){} + virtual std::string f() = 0; + std::string g() { return "P::g()"; } +}; + +struct PCallback : P, Callback +{ + PCallback (PyObject* self) : Callback(self) {} + + std::string f() + { + return call_method<std::string>(mSelf, "f"); + } +}; + +struct Q : virtual P +{ + std::string f() { return "Q::f()"; } +}; + +struct A +{ + virtual ~A(){} + virtual std::string f() { return "A::f()"; } +}; + +struct ACallback : A, Callback +{ + ACallback (PyObject* self) : Callback(self) {} + + + std::string f() + { + return call_method<std::string>(mSelf, "f"); + } + + std::string default_f() + { + return A::f(); + } +}; + +struct B : A +{ + virtual std::string f() { return "B::f()"; } +}; + +struct C : A +{ + virtual std::string f() { return "C::f()"; } +}; + +struct D : A +{ + virtual std::string f() { return "D::f()"; } + std::string g() { return "D::g()"; } +}; + +struct DCallback : D, Callback +{ + DCallback (PyObject* self) : Callback(self) {} + + std::string f() + { + return call_method<std::string>(mSelf, "f"); + } + + std::string default_f() + { + return A::f(); + } +}; + + +A& getBCppObj () +{ + static B b; + return b; +} + +std::string call_f(A& a) { return a.f(); } + +A* factory(unsigned choice) +{ + switch (choice % 3) + { + case 0: return new A; + break; + case 1: return new B; + break; + default: return new C; + break; + } +} + +C& getCCppObj () +{ + static C c; + return c; +} + +A* pass_a(A* x) { return x; } + +BOOST_PYTHON_MODULE_INIT(polymorphism_ext) +{ + class_<A,boost::noncopyable,ACallback>("A") + .def("f", &A::f, &ACallback::default_f) + ; + + def("getBCppObj", getBCppObj, return_value_policy<reference_existing_object>()); + + class_<C,bases<A>,boost::noncopyable>("C") + .def("f", &C::f) + ; + + class_<D,bases<A>,DCallback,boost::noncopyable>("D") + .def("f", &D::f, &DCallback::default_f) + .def("g", &D::g) + ; + + def("pass_a", &pass_a, return_internal_reference<>()); + + def("getCCppObj", getCCppObj, return_value_policy<reference_existing_object>()); + + def("factory", factory, return_value_policy<manage_new_object>()); + + def("call_f", call_f); + + class_<P,boost::noncopyable,PCallback>("P") + .def("f", pure_virtual(&P::f)) + ; + + class_<Q, bases<P> >("Q") + .def("g", &P::g) // make sure virtual inheritance doesn't interfere + ; +} + +//#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/polymorphism.py b/src/boost/libs/python/test/polymorphism.py new file mode 100644 index 000000000..e3c66ea27 --- /dev/null +++ b/src/boost/libs/python/test/polymorphism.py @@ -0,0 +1,74 @@ +# Copyright David Abrahams 2004. 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 unittest +from polymorphism_ext import * + +class PolymorphTest(unittest.TestCase): + + def testReturnCpp(self): + + # Python Created Object With Same Id As + # Cpp Created B Object + # b = B(872) + + # Get Reference To Cpp Created B Object + a = getBCppObj() + + # Python Created B Object and Cpp B Object + # Should have same result by calling f() + self.assertEqual ('B::f()', a.f()) + self.assertEqual ('B::f()', call_f(a)) + self.assertEqual ('A::f()', call_f(A())) + + def test_references(self): + # B is not exposed to Python + a = getBCppObj() + self.assertEqual(type(a), A) + + # C is exposed to Python + c = getCCppObj() + self.assertEqual(type(c), C) + + def test_factory(self): + self.assertEqual(type(factory(0)), A) + self.assertEqual(type(factory(1)), A) + self.assertEqual(type(factory(2)), C) + + def test_return_py(self): + + class X(A): + def f(self): + return 'X.f' + + x = X() + + self.assertEqual ('X.f', x.f()) + self.assertEqual ('X.f', call_f(x)) + + def test_wrapper_downcast(self): + a = pass_a(D()) + self.assertEqual('D::g()', a.g()) + + def test_pure_virtual(self): + p = P() + self.assertRaises(RuntimeError, p.f) + + q = Q() + self.assertEqual ('Q::f()', q.f()) + + class R(P): + def f(self): + return 'R.f' + + r = R() + self.assertEqual ('R.f', r.f()) + + +if __name__ == "__main__": + + # remove the option which upsets unittest + import sys + sys.argv = [ x for x in sys.argv if x != '--broken-auto-ptr' ] + + unittest.main() diff --git a/src/boost/libs/python/test/polymorphism2.cpp b/src/boost/libs/python/test/polymorphism2.cpp new file mode 100644 index 000000000..8aefbc3af --- /dev/null +++ b/src/boost/libs/python/test/polymorphism2.cpp @@ -0,0 +1,172 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/python/manage_new_object.hpp> +#include <boost/python/reference_existing_object.hpp> +#include <boost/python/pure_virtual.hpp> +#include <boost/python/wrapper.hpp> +#include <boost/python/def.hpp> +#include <boost/python/call.hpp> +#include <boost/utility.hpp> + +#include <memory> + +#ifdef HELD_BY_AUTO_PTR +# define HELD_PTR(X) , std::auto_ptr< X > +#else +# define HELD_PTR(X) +#endif + +using namespace boost::python; + +struct P +{ + virtual ~P(){} + virtual char const* f() = 0; + char const* g() { return "P::g()"; } +}; + +struct PCallback : P, wrapper<P> +{ + char const* f() + { +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + return call<char const*>(this->get_override("f").ptr()); +#else + return this->get_override("f")(); +#endif + } +}; + +struct Q : virtual P +{ + char const* f() { return "Q::f()"; } +}; + +struct A +{ + virtual ~A(){} + virtual char const* f() { return "A::f()"; } +}; + +struct ACallback : A, wrapper<A> +{ + char const* f() + { + if (override f = this->get_override("f")) +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + return call<char const*>(f.ptr()); +#else + return f(); +#endif + + return A::f(); + } + + char const* default_f() { return this->A::f(); } +}; + +struct B : A +{ + virtual char const* f() { return "B::f()"; } +}; + +struct C : A +{ + virtual char const* f() { return "C::f()"; } +}; + +struct D : A +{ + virtual char const* f() { return "D::f()"; } + char const* g() { return "D::g()"; } +}; + +struct DCallback : D, wrapper<D> +{ + char const* f() + { + if (override f = this->get_override("f")) +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + return call<char const*>(f.ptr()); +#else + return f(); +#endif + //else + return D::f(); + } +}; + + +A& getBCppObj () +{ + static B b; + return b; +} + +char const* call_f(A& a) { return a.f(); } + +A* factory(unsigned choice) +{ + switch (choice % 3) + { + case 0: return new A; + break; + case 1: return new B; + break; + default: return new C; + break; + } +} + +C& getCCppObj () +{ + static C c; + return c; +} + +A* pass_a(A* x) { return x; } + +#ifdef HELD_BY_AUTO_PTR +BOOST_PYTHON_MODULE_INIT(polymorphism2_auto_ptr_ext) +#else +BOOST_PYTHON_MODULE_INIT(polymorphism2_ext) +#endif +{ + class_<ACallback HELD_PTR(A),boost::noncopyable>("A") + .def("f", &A::f, &ACallback::default_f) + ; + + def("getBCppObj", getBCppObj, return_value_policy<reference_existing_object>()); + + class_<C HELD_PTR(C),bases<A>,boost::noncopyable>("C") + .def("f", &C::f) + ; + + class_<DCallback HELD_PTR(D),bases<A>,boost::noncopyable>("D") + .def("f", &D::f) + .def("g", &D::g) + ; + + def("pass_a", &pass_a, return_internal_reference<>()); + + def("getCCppObj", getCCppObj, return_value_policy<reference_existing_object>()); + + def("factory", factory, return_value_policy<manage_new_object>()); + + def("call_f", call_f); + + class_<PCallback,boost::noncopyable>("P") + .def("f", pure_virtual(&P::f)) + ; + + class_<Q HELD_PTR(Q), bases<P> >("Q") + .def("g", &P::g) // make sure virtual inheritance doesn't interfere + ; +} + +//#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/polymorphism2.py b/src/boost/libs/python/test/polymorphism2.py new file mode 100644 index 000000000..cf7384fab --- /dev/null +++ b/src/boost/libs/python/test/polymorphism2.py @@ -0,0 +1,94 @@ +# Copyright David Abrahams 2004. 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 unittest +import sys + +class PolymorphTest(unittest.TestCase): + + def testReturnCpp(self): + + # Python Created Object With Same Id As + # Cpp Created B Object + # b = B(872) + + # Get Reference To Cpp Created B Object + a = getBCppObj() + + # Python Created B Object and Cpp B Object + # Should have same result by calling f() + self.assertEqual ('B::f()', a.f()) + self.assertEqual ('B::f()', call_f(a)) + self.assertEqual ('A::f()', call_f(A())) + + def test_references(self): + # B is not exposed to Python + a = getBCppObj() + self.assertEqual(type(a), A) + + # C is exposed to Python + c = getCCppObj() + self.assertEqual(type(c), C) + + def test_factory(self): + self.assertEqual(type(factory(0)), A) + self.assertEqual(type(factory(1)), A) + self.assertEqual(type(factory(2)), C) + + def test_return_py(self): + + class X(A): + def f(self): + return 'X.f' + + x = X() + + self.assertEqual ('X.f', x.f()) + self.assertEqual ('X.f', call_f(x)) + + def test_self_default(self): + + class X(A): + def f(self): + return 'X.f() -> ' + A.f(self) + + x = X() + + self.assertEqual ('X.f() -> A::f()', x.f()) + + # This one properly raises the "dangling reference" exception + # self.failUnlessEqual ('X.f() -> A::f()', call_f(x)) + + def test_wrapper_downcast(self): + a = pass_a(D()) + self.assertEqual('D::g()', a.g()) + + def test_pure_virtual(self): + p = P() + self.assertRaises(RuntimeError, p.f) + + q = Q() + self.assertEqual ('Q::f()', q.f()) + + class R(P): + def f(self): + return 'R.f' + + r = R() + self.assertEqual ('R.f', r.f()) + + +def test(): + # remove the option that upsets unittest + import sys + sys.argv = [ x for x in sys.argv if x != '--broken-auto-ptr' ] + unittest.main() + +# This nasty hack basically says that if we're loaded by another module, we'll +# be testing polymorphism2_auto_ptr_ext instead of polymorphism2_ext. +if __name__ == "__main__": + from polymorphism2_ext import * + test() +else: + from polymorphism2_auto_ptr_ext import * + diff --git a/src/boost/libs/python/test/polymorphism2_auto_ptr.cpp b/src/boost/libs/python/test/polymorphism2_auto_ptr.cpp new file mode 100644 index 000000000..8cd5ef247 --- /dev/null +++ b/src/boost/libs/python/test/polymorphism2_auto_ptr.cpp @@ -0,0 +1,6 @@ +// Copyright David Abrahams 2005. 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) + +#define HELD_BY_AUTO_PTR +#include "polymorphism2.cpp" diff --git a/src/boost/libs/python/test/polymorphism2_auto_ptr.py b/src/boost/libs/python/test/polymorphism2_auto_ptr.py new file mode 100644 index 000000000..88cf664ab --- /dev/null +++ b/src/boost/libs/python/test/polymorphism2_auto_ptr.py @@ -0,0 +1,5 @@ +# Copyright David Abrahams 2005. 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 polymorphism2 +polymorphism2.test() diff --git a/src/boost/libs/python/test/properties.cpp b/src/boost/libs/python/test/properties.cpp new file mode 100644 index 000000000..d338beb91 --- /dev/null +++ b/src/boost/libs/python/test/properties.cpp @@ -0,0 +1,100 @@ +// Copyright David Abrahams 2004. 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 <boost/python.hpp> + +using namespace boost::python; + +namespace test { + +// Hmm. return_internal_reference<>() wants to wrap a real class. +class ret_type +{ + public: + ret_type() : i(42.5) {} + double i; +}; + +class crash_me +{ + private: + ret_type i; + public: + ret_type& get_i() { return i; } +}; + +} + +struct X +{ + X( int value ) : m_value( value ) + { ++s_count; } + + X( const X &other ) : m_value( other.m_value ) + { ++s_count; } + + ~X() + { --s_count; } + + int get_value() const + { return m_value; } + + void set_value(int new_value) + { m_value = new_value; } + + static int get_instance_count() + { return s_count; } + + int m_value; + + static int s_count; +}; + +int X::s_count = 0; + +int get_X_instance_count() +{ return X::get_instance_count(); } + + + +BOOST_PYTHON_MODULE(properties_ext) +{ + typedef return_value_policy<return_by_value> return_by_value_t; + typedef return_internal_reference<> return_by_internal_reference_t; + class_<X>("X", init<int>() ) + //defining read only property + .add_property( "value_r", &X::get_value ) + .add_property( "value_r_ds", &X::get_value, "value_r_ds is read-only") + //defining read \ write property + .add_property( "value_rw", &X::get_value, &X::set_value ) + .add_property( "value_rw_ds", &X::get_value, &X::set_value, + "value_rw_ds is read-write") + //defining read \ write property using make_getter and make_setter + .add_property( "value_direct", + make_getter( &X::m_value, return_by_value_t() ), + make_setter( &X::m_value, return_by_internal_reference_t() ) ) + //defining read only property for static member + .add_static_property( "instance_count", &X::get_instance_count ) + //defining read \ write property for static member using make_getter and make_setter + .add_static_property( "instance_count_direct", + make_getter( &X::s_count, return_by_value_t() ), + make_setter( &X::s_count, return_by_internal_reference_t() ) ) + //defining class property using a global function + .add_static_property( "instance_count_injected", &get_X_instance_count ); + + + class_< test::ret_type>( "ret_type") + .add_property( "i", &test::ret_type::i, &test::ret_type::i) + ; + + class_< test::crash_me> crash_me_wrapper( "crash_me"); + + crash_me_wrapper + .def( "get_i", &test::crash_me::get_i , return_internal_reference<>()) + ; + + crash_me_wrapper.add_property( "i", crash_me_wrapper.attr("get_i")); + +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/properties.py b/src/boost/libs/python/test/properties.py new file mode 100644 index 000000000..1bc7a624b --- /dev/null +++ b/src/boost/libs/python/test/properties.py @@ -0,0 +1,106 @@ +# Copyright David Abrahams 2004. 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) +""" +This is test module for properties. + +>>> r = properties.ret_type() +>>> r.i = 22.5 +>>> r.i +22.5 +>>> c = properties.crash_me() +>>> c.i.i +42.5 + +>>> X = properties.X + +>>> x1 = X(1) + +value read only +>>> x1.value_r +1 + +value read - write +>>> x1.value_rw +1 + +value direct access +>>> x1.value_direct +1 + +class instance count read - only +>>> X.instance_count +1 + +class instance count direct +>>> X.instance_count_direct +1 + +class instance count injected +>>> X.instance_count_injected +1 + +class instance count from object +>>> x1.instance_count +1 + +class instance count from object +>>> x1.instance_count_direct +1 + +class instance count from object: +>>> x1.instance_count_injected +1 + +as expected you can't assign new value to read only property +>>> x1.value_r = 2 +Traceback (most recent call last): + File "properties.py", line 49, in ? + x1.value_r = 2 +AttributeError: can't set attribute + +setting value_rw to 2. value_direct: +>>> x1.value_rw = 2 +>>> x1.value_rw +2 + +setting value_direct to 3. value_direct: +>>> x1.value_direct = 3 +>>> x1.value_direct +3 + +>>> assert x1.value_r == 3 + +>>> x2 = X(2) + +after creating second intstance of X instances count is 2 +>>> x2.instance_count +2 + +>>> del x2 +>>> assert x1.instance_count == 1 + +>>> assert properties.X.value_r_ds.__doc__ == "value_r_ds is read-only" + +>>> assert properties.X.value_rw_ds.__doc__ == "value_rw_ds is read-write" + +""" + +#import sys; sys.path.append(r'P:\Actimize4.0\smart_const\py_smart_const___Win32_Debug') +import properties_ext as properties + + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/pyrun.py b/src/boost/libs/python/test/pyrun.py new file mode 100644 index 000000000..d330773ea --- /dev/null +++ b/src/boost/libs/python/test/pyrun.py @@ -0,0 +1,7 @@ +import sys + +pythonpath = sys.argv[1] +scriptfile = sys.argv[2] +sys.argv = sys.argv[2:] +sys.path.append(pythonpath) +exec(compile(open(scriptfile).read(), scriptfile, 'exec')) diff --git a/src/boost/libs/python/test/pytype_function.cpp b/src/boost/libs/python/test/pytype_function.cpp new file mode 100644 index 000000000..46cce19e6 --- /dev/null +++ b/src/boost/libs/python/test/pytype_function.cpp @@ -0,0 +1,85 @@ +// Copyright Joel de Guzman 2004. 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/to_python_converter.hpp> +#include <boost/python/class.hpp> + +using namespace boost::python; + +struct A +{ +}; + +struct B +{ + A a; + B(const A& a_):a(a_){} +}; + +// Converter from A to python int +struct BToPython +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + : converter::to_python_target_type<A> //inherits get_pytype +#endif +{ + static PyObject* convert(const B& b) + { + return boost::python::incref(boost::python::object(b.a).ptr()); + } +}; + +// Conversion from python int to A +struct BFromPython +{ + BFromPython() + { + boost::python::converter::registry::push_back( + &convertible, + &construct, + boost::python::type_id< B >() +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + , &converter::expected_from_python_type<A>::get_pytype//convertible to A can be converted to B +#endif + ); + } + + static void* convertible(PyObject* obj_ptr) + { + extract<const A&> ex(obj_ptr); + if (!ex.check()) return 0; + return obj_ptr; + } + + static void construct( + PyObject* obj_ptr, + boost::python::converter::rvalue_from_python_stage1_data* data) + { + void* storage = ( + (boost::python::converter::rvalue_from_python_storage< B >*)data)-> storage.bytes; + + extract<const A&> 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,true >(); //has get_pytype + BFromPython(); + + class_<A>("A") ; + + def("func", &func); + +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/pytype_function.py b/src/boost/libs/python/test/pytype_function.py new file mode 100644 index 000000000..a7101fb99 --- /dev/null +++ b/src/boost/libs/python/test/pytype_function.py @@ -0,0 +1,32 @@ +# Copyright David Abrahams 2004. 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) +""" +>>> from pytype_function_ext import * + +>>> print(func.__doc__.splitlines()[1]) +func( (A)arg1) -> A : + +>>> print(func.__module__) +pytype_function_ext + +>>> print(func.__name__) +func +""" +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) + + + diff --git a/src/boost/libs/python/test/raw_ctor.cpp b/src/boost/libs/python/test/raw_ctor.cpp new file mode 100644 index 000000000..a825ae019 --- /dev/null +++ b/src/boost/libs/python/test/raw_ctor.cpp @@ -0,0 +1,43 @@ +// Copyright David Abrahams 2004. 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 <boost/python/class.hpp> +#include <boost/python/raw_function.hpp> +#include <boost/python/make_constructor.hpp> +#include <boost/python/dict.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/module.hpp> + +using namespace boost::python; + +class Foo +{ + public: + Foo(tuple args, dict kw) + : args(args), kw(kw) {} + + tuple args; + dict kw; +}; + +object init_foo(tuple args, dict kw) +{ + tuple rest(args.slice(1,_)); + return args[0].attr("__init__")(rest, kw); +} + +BOOST_PYTHON_MODULE(raw_ctor_ext) +{ + // using no_init postpones defining __init__ function until after + // raw_function for proper overload resolution order, since later + // defs get higher priority. + class_<Foo>("Foo", no_init) + .def("__init__", raw_function(&init_foo)) + .def(init<tuple, dict>()) + .def_readwrite("args", &Foo::args) + .def_readwrite("kw", &Foo::kw) + ; +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/raw_ctor.py b/src/boost/libs/python/test/raw_ctor.py new file mode 100644 index 000000000..1e9a9192a --- /dev/null +++ b/src/boost/libs/python/test/raw_ctor.py @@ -0,0 +1,76 @@ +# Copyright David Abrahams 2004. 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) +""" +>>> 'importing' +'importing' +>>> from raw_ctor_ext import * +>>> 'imported' +'imported' +>>> import sys +>>> sys.stdout.flush() +>>> f = Foo(1, 2, 'a', bar = 3, baz = 4) +>>> f.args +(1, 2, 'a') +>>> sorted(f.kw.items()) +[('bar', 3), ('baz', 4)] +""" +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/python/test/raw_pyobject_fail1.cpp b/src/boost/libs/python/test/raw_pyobject_fail1.cpp new file mode 100644 index 000000000..f9dd54bc3 --- /dev/null +++ b/src/boost/libs/python/test/raw_pyobject_fail1.cpp @@ -0,0 +1,11 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/converter/arg_to_python.hpp> + +int main() +{ + boost::python::converter::arg_to_python<PyTypeObject*> x(0); + return 0; +} diff --git a/src/boost/libs/python/test/raw_pyobject_fail2.cpp b/src/boost/libs/python/test/raw_pyobject_fail2.cpp new file mode 100644 index 000000000..62c57ae74 --- /dev/null +++ b/src/boost/libs/python/test/raw_pyobject_fail2.cpp @@ -0,0 +1,13 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/converter/arg_to_python.hpp> + +struct X : PyObject {}; + +int main() +{ + boost::python::converter::arg_to_python<X*> x(0); + return 0; +} diff --git a/src/boost/libs/python/test/register_ptr.cpp b/src/boost/libs/python/test/register_ptr.cpp new file mode 100644 index 000000000..6cd4d7856 --- /dev/null +++ b/src/boost/libs/python/test/register_ptr.cpp @@ -0,0 +1,55 @@ +// Copyright David Abrahams 2004. 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 <boost/python.hpp> +#include <boost/shared_ptr.hpp> + +using namespace boost; +using namespace python; + +struct A +{ + virtual int f() { return 0; } +}; + +shared_ptr<A> New() { return shared_ptr<A>( new A() ); } + +int Call( const shared_ptr<A> & a ) +{ + return a->f(); +} + +int Fail( shared_ptr<A> & a ) +{ + return a->f(); +} + +struct A_Wrapper: A +{ + A_Wrapper(PyObject* self_): self(self_) {} + A_Wrapper(PyObject* self_, const A& a): self(self_), A(a) {} + + int f() + { + return call_method<int>(self, "f"); + } + + int default_f() + { + return A::f(); + } + + PyObject* self; +}; + +BOOST_PYTHON_MODULE(register_ptr) +{ + class_<A, A_Wrapper>("A") + .def("f", &A::f, &A_Wrapper::default_f) + ; + register_ptr_to_python< shared_ptr<A> >(); + def("New", &New); + def("Call", &Call); + def("Fail", &Fail); +} diff --git a/src/boost/libs/python/test/register_ptr_test.py b/src/boost/libs/python/test/register_ptr_test.py new file mode 100644 index 000000000..674e5572f --- /dev/null +++ b/src/boost/libs/python/test/register_ptr_test.py @@ -0,0 +1,25 @@ +# Copyright David Abrahams 2004. 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 unittest +from register_ptr import * + +class RegisterPtrTest(unittest.TestCase): + + def testIt(self): + + class B(A): + def f(self): + return 10 + + a = New() # this must work + b = B() + self.assertEqual(Call(a), 0) + self.assertEqual(Call(b), 10) + def fails(): + Fail(A()) + self.assertRaises(TypeError, fails) + self.assertEqual(Fail(a), 0) # ok, since a is held by shared_ptr + +if __name__ == '__main__': + unittest.main() diff --git a/src/boost/libs/python/test/result.cpp b/src/boost/libs/python/test/result.cpp new file mode 100644 index 000000000..d5f43cc3d --- /dev/null +++ b/src/boost/libs/python/test/result.cpp @@ -0,0 +1,111 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/detail/result.hpp> +#include <boost/type.hpp> +#include <functional> + +using boost::python::detail::result; +using boost::type; + +void expect_int(type<int>*) {} +void expect_string(type<char*>*) {} + +struct X {}; + +int main() +{ + // Test the usage which works for functions, member functions, and data members + expect_int( + result((int(*)())0) + ); + + expect_int( + result((int(*)(char))0) + ); + + expect_int( + result((int(X::*)())0) + ); + + expect_int( + result((int(X::*)(char))0) + ); + + expect_int( + result((int(X::*))0) + ); + + expect_string( + result((char*(*)())0) + ); + + expect_string( + result((char*(*)(char))0) + ); + + expect_string( + result((char*(X::*)())0) + ); + + expect_string( + result((char*(X::*)(char))0) + ); + + expect_string( + result((char*(X::*))0) + ); + + // Show that we can use the general version that works for + // AdaptableFunctions + expect_int( + result((int(*)())0,0) + ); + + expect_int( + result((int(*)(char))0,0) + ); + + expect_int( + result((int(X::*)())0,0) + ); + + expect_int( + result((int(X::*)(char))0,0) + ); + + expect_int( + result((int(X::*))0,0) + ); + + expect_int( + result(std::plus<int>(),0) + ); + + expect_string( + result((char*(*)())0,0) + ); + + expect_string( + result((char*(*)(char))0,0) + ); + + expect_string( + result((char*(X::*)())0,0) + ); + + expect_string( + result((char*(X::*)(char))0,0) + ); + + expect_string( + result((char*(X::*))0,0) + ); + + expect_string( + result(std::plus<char*>(),0) + ); + + return 0; +} diff --git a/src/boost/libs/python/test/return_arg.cpp b/src/boost/libs/python/test/return_arg.cpp new file mode 100644 index 000000000..d8d3c1ddb --- /dev/null +++ b/src/boost/libs/python/test/return_arg.cpp @@ -0,0 +1,67 @@ +// Copyright David Abrahams and Nikolay Mladenov 2003. +// 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 <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/def.hpp> +#include <boost/python/return_arg.hpp> + +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_; +}; + +void return_arg_f(boost::python::object) {} + +using namespace boost::python; +BOOST_PYTHON_MODULE(return_arg_ext) +{ + class_<Widget>("Widget") + .def("sensitive", &Widget::get_sensitive) + .def("sensitive", &Widget::set_sensitive, return_self<>()) + ; + + class_<Label, bases<Widget> >("Label") + .def("label", &Label::get_label)//,return_arg<0>()) //error(s) + .def("label", &Label::set_label, return_self<>()) + ; + + def("return_arg", return_arg_f, return_arg<1>()); +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/return_arg.py b/src/boost/libs/python/test/return_arg.py new file mode 100644 index 000000000..e66a0b8d9 --- /dev/null +++ b/src/boost/libs/python/test/return_arg.py @@ -0,0 +1,27 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from return_arg_ext import * +>>> l1=Label() +>>> assert l1 is l1.label("bar") +>>> assert l1 is l1.label("bar").sensitive(0) +>>> assert l1.label("foo").sensitive(0) is l1.sensitive(1).label("bar") +>>> assert return_arg is return_arg(return_arg) + +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/select_arg_to_python_test.cpp b/src/boost/libs/python/test/select_arg_to_python_test.cpp new file mode 100644 index 000000000..c5faace36 --- /dev/null +++ b/src/boost/libs/python/test/select_arg_to_python_test.cpp @@ -0,0 +1,70 @@ +// Copyright David Abrahams 2004. 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 <boost/python/converter/arg_to_python.hpp> +#include <boost/python/type_id.hpp> +#include <boost/python/handle.hpp> +#include <boost/python/object.hpp> +#include <iostream> + +// gcc 2.95.x and MIPSpro 7.3.1.3 linker seem to demand this definition +#if ((defined(__GNUC__) && __GNUC__ < 3)) \ + || (defined(__sgi) && defined(__EDG_VERSION__) && (__EDG_VERSION__ == 238)) +namespace boost { namespace python { +BOOST_PYTHON_DECL bool handle_exception_impl(function0<void>) +{ + return true; +} +}} +#endif + +int result; + +#define ASSERT_SAME(T1,T2) assert_same< T1,T2 >() + +template <class T, class U> +void assert_same(U* = 0, T* = 0) +{ + BOOST_STATIC_ASSERT((boost::is_same<T,U>::value)); + +} + + +int main() +{ + using namespace boost::python::converter::detail; + using namespace boost::python::converter; + using namespace boost::python; + using namespace boost; + + + ASSERT_SAME( + select_arg_to_python<int>::type, value_arg_to_python<int> + ); + + ASSERT_SAME( + select_arg_to_python<reference_wrapper<int> >::type, reference_arg_to_python<int> + ); + + ASSERT_SAME( + select_arg_to_python<pointer_wrapper<int> >::type, pointer_shallow_arg_to_python<int> + ); + + ASSERT_SAME( + select_arg_to_python<int*>::type, pointer_deep_arg_to_python<int*> + ); + + ASSERT_SAME( + select_arg_to_python<handle<> >::type, object_manager_arg_to_python<handle<> > + ); + + ASSERT_SAME( + select_arg_to_python<object>::type, object_manager_arg_to_python<object> + ); + + ASSERT_SAME( + select_arg_to_python<char[20]>::type, arg_to_python<char const*> + ); + + return result; +} diff --git a/src/boost/libs/python/test/select_from_python_test.cpp b/src/boost/libs/python/test/select_from_python_test.cpp new file mode 100644 index 000000000..bb60962a3 --- /dev/null +++ b/src/boost/libs/python/test/select_from_python_test.cpp @@ -0,0 +1,161 @@ +// Copyright David Abrahams 2004. 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 <boost/python/converter/arg_from_python.hpp> +#include <boost/python/type_id.hpp> +#include <iostream> + +// gcc 2.95.x, MIPSpro 7.3.1.3 and IBM XL for Linux linker seem to demand this definition +#if (defined(__GNUC__) && (__GNUC__ < 3)) \ + || (defined(__sgi) && defined(__EDG_VERSION__) && (__EDG_VERSION__ == 238)) \ + || (defined(__IBMCPP__) && defined(__linux__)) +namespace boost { namespace python { +BOOST_PYTHON_DECL bool handle_exception_impl(function0<void>) +{ + return true; +} +}} +#endif + +int result; + +#define ASSERT_SAME(T1,T2) \ + if (!is_same< T1, T2 >::value) { \ + std::cout << "*********************\n"; \ + std::cout << python::type_id< T1 >() << " != " << python::type_id< T2 >() << "\n"; \ + std::cout << "*********************\n"; \ + result = 1; \ + } + +int main() +{ + using namespace boost::python::converter; + using namespace boost; + + + ASSERT_SAME( + select_arg_from_python<int>::type, arg_rvalue_from_python<int> + ); + + ASSERT_SAME( + select_arg_from_python<int const>::type, arg_rvalue_from_python<int const> + ); + + ASSERT_SAME( + select_arg_from_python<int volatile>::type, arg_rvalue_from_python<int volatile> + ); + + ASSERT_SAME( + select_arg_from_python<int const volatile>::type, arg_rvalue_from_python<int const volatile> + ); + + + + ASSERT_SAME( + select_arg_from_python<int*>::type, pointer_arg_from_python<int*> + ); + + ASSERT_SAME( + select_arg_from_python<int const*>::type, pointer_arg_from_python<int const*> + ); + + ASSERT_SAME( + select_arg_from_python<int volatile*>::type, pointer_arg_from_python<int volatile*> + ); + + ASSERT_SAME( + select_arg_from_python<int const volatile*>::type, pointer_arg_from_python<int const volatile*> + ); + + + + + ASSERT_SAME( + select_arg_from_python<int&>::type, reference_arg_from_python<int&> + ); + + ASSERT_SAME( + select_arg_from_python<int const&>::type, arg_rvalue_from_python<int const&> + ); + + ASSERT_SAME( + select_arg_from_python<int volatile&>::type, reference_arg_from_python<int volatile&> + ); + + ASSERT_SAME( + select_arg_from_python<int const volatile&>::type, reference_arg_from_python<int const volatile&> + ); + + + + ASSERT_SAME( + select_arg_from_python<int*&>::type, reference_arg_from_python<int*&> + ); + + ASSERT_SAME( + select_arg_from_python<int const*&>::type, reference_arg_from_python<int const*&> + ); + + ASSERT_SAME( + select_arg_from_python<int volatile*&>::type, reference_arg_from_python<int volatile*&> + ); + + ASSERT_SAME( + select_arg_from_python<int const volatile*&>::type, reference_arg_from_python<int const volatile*&> + ); + + + + ASSERT_SAME( + select_arg_from_python<int* const&>::type, pointer_cref_arg_from_python<int*const&> + ); + + ASSERT_SAME( + select_arg_from_python<int const* const&>::type, pointer_cref_arg_from_python<int const*const&> + ); + + ASSERT_SAME( + select_arg_from_python<int volatile* const&>::type, pointer_cref_arg_from_python<int volatile*const&> + ); + + ASSERT_SAME( + select_arg_from_python<int const volatile* const&>::type, pointer_cref_arg_from_python<int const volatile*const&> + ); + + + + ASSERT_SAME( + select_arg_from_python<int*volatile&>::type, reference_arg_from_python<int*volatile&> + ); + + ASSERT_SAME( + select_arg_from_python<int const*volatile&>::type, reference_arg_from_python<int const*volatile&> + ); + + ASSERT_SAME( + select_arg_from_python<int volatile*volatile&>::type, reference_arg_from_python<int volatile*volatile&> + ); + + ASSERT_SAME( + select_arg_from_python<int const volatile*volatile&>::type, reference_arg_from_python<int const volatile*volatile&> + ); + + + + ASSERT_SAME( + select_arg_from_python<int*const volatile&>::type, reference_arg_from_python<int*const volatile&> + ); + + ASSERT_SAME( + select_arg_from_python<int const*const volatile&>::type, reference_arg_from_python<int const*const volatile&> + ); + + ASSERT_SAME( + select_arg_from_python<int volatile*const volatile&>::type, reference_arg_from_python<int volatile*const volatile&> + ); + + ASSERT_SAME( + select_arg_from_python<int const volatile*const volatile&>::type, reference_arg_from_python<int const volatile*const volatile&> + ); + return result; +} diff --git a/src/boost/libs/python/test/select_holder.cpp b/src/boost/libs/python/test/select_holder.cpp new file mode 100644 index 000000000..8650bd06a --- /dev/null +++ b/src/boost/libs/python/test/select_holder.cpp @@ -0,0 +1,76 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/object/class_metadata.hpp> +#include <boost/python/has_back_reference.hpp> +#include <boost/python/detail/not_specified.hpp> +#include <boost/static_assert.hpp> +#include <boost/python/detail/type_traits.hpp> +#include <boost/function/function0.hpp> +#include <boost/mpl/bool.hpp> +#include <memory> + +struct BR {}; + +struct Base {}; +struct Derived : Base {}; + +namespace boost { namespace python +{ + // specialization + template <> + struct has_back_reference<BR> + : mpl::true_ + { + }; +}} // namespace boost::python + +template <class T, class U> +void assert_same(U* = 0, T* = 0) +{ + BOOST_STATIC_ASSERT((boost::python::detail::is_same<T,U>::value)); + +} + +template <class T, class Held, class Holder> +void assert_holder(T* = 0, Held* = 0, Holder* = 0) +{ + using namespace boost::python::detail; + using namespace boost::python::objects; + + typedef typename class_metadata< + T,Held,not_specified,not_specified + >::holder h; + + assert_same<Holder>( + (h*)0 + ); +} + +int test_main(int, char * []) +{ + using namespace boost::python::detail; + using namespace boost::python::objects; + + assert_holder<Base,not_specified,value_holder<Base> >(); + + assert_holder<BR,not_specified,value_holder_back_reference<BR,BR> >(); + assert_holder<Base,Base,value_holder_back_reference<Base,Base> >(); + assert_holder<BR,BR,value_holder_back_reference<BR,BR> >(); + + assert_holder<Base,Derived + ,value_holder_back_reference<Base,Derived> >(); + + assert_holder<Base,std::auto_ptr<Base> + ,pointer_holder<std::auto_ptr<Base>,Base> >(); + + assert_holder<Base,std::auto_ptr<Derived> + ,pointer_holder_back_reference<std::auto_ptr<Derived>,Base> >(); + + assert_holder<BR,std::auto_ptr<BR> + ,pointer_holder_back_reference<std::auto_ptr<BR>,BR> > (); + + return 0; +} + diff --git a/src/boost/libs/python/test/shared_ptr.cpp b/src/boost/libs/python/test/shared_ptr.cpp new file mode 100644 index 000000000..f72e6f029 --- /dev/null +++ b/src/boost/libs/python/test/shared_ptr.cpp @@ -0,0 +1,19 @@ +// Copyright David Abrahams 2002. +// Copyright Stefan Seefeld 2016. +// 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 <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/call_method.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/def.hpp> +#include <memory> + +using std::shared_ptr; +#define MODULE shared_ptr_ext + +#include "shared_ptr.hpp" +#include "module_tail.cpp" + diff --git a/src/boost/libs/python/test/shared_ptr.hpp b/src/boost/libs/python/test/shared_ptr.hpp new file mode 100644 index 000000000..9f9a4b69e --- /dev/null +++ b/src/boost/libs/python/test/shared_ptr.hpp @@ -0,0 +1,206 @@ +// Copyright David Abrahams 2002. +// Copyright Stefan Seefeld 2016. +// 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 "test_class.hpp" + +using namespace boost::python; + +typedef test_class<> X; +typedef test_class<1> Y; + +template <class T> +struct functions +{ + static int look(shared_ptr<T> const& x) + { + return (x.get()) ? x->value() : -1; + } + + static void store(shared_ptr<T> x) + { + storage = x; + } + + static void release_store() + { + store(shared_ptr<T>()); + } + + static void modify(shared_ptr<T>& x) + { + x.reset(); + } + + static shared_ptr<T> get() { return storage; } + static shared_ptr<T> &get1() { return storage; } + + static int look_store() + { + return look(get()); + } + + template <class C> + static void expose(C const& c) + { + def("look", &look); + def("store", &store); + def("modify", &modify); + def("identity", &identity); + def("null", &null); + + const_cast<C&>(c) + .def("look", &look) + .staticmethod("look") + .def("store", &store) + .staticmethod("store") + .def("modify", &modify) + .staticmethod("modify") + .def("look_store", &look_store) + .staticmethod("look_store") + .def("identity", &identity) + .staticmethod("identity") + .def("null", &null) + .staticmethod("null") + .def("get1", &get1, return_internal_reference<>()) + .staticmethod("get1") + .def("get", &get) + .staticmethod("get") + .def("count", &T::count) + .staticmethod("count") + .def("release", &release_store) + .staticmethod("release") + ; + } + + static shared_ptr<T> identity(shared_ptr<T> x) { return x; } + static shared_ptr<T> null(T const&) { return shared_ptr<T>(); } + + + static shared_ptr<T> storage; +}; + +template <class T> shared_ptr<T> functions<T>::storage; + +struct Z : test_class<2> +{ + Z(int x) : test_class<2>(x) {} + virtual int v() { return this->value(); } +}; + +struct ZWrap : Z +{ + ZWrap(PyObject* self, int x) + : Z(x), m_self(self) {} + + + virtual int v() { return call_method<int>(m_self, "v"); } + int default_v() { return Z::v(); } + + + PyObject* m_self; +}; + +struct YY : Y +{ + YY(int n) : Y(n) {} +}; + +struct YYY : Y +{ + YYY(int n) : Y(n) {} +}; + +shared_ptr<Y> factory(int n) +{ + return shared_ptr<Y>(n < 42 ? new Y(n) : new YY(n)); +} + +// regressions from Nicodemus + struct A + { + virtual ~A() {}; // silence compiler warnings + virtual int f() = 0; + static int call_f(shared_ptr<A>& a) { return a->f(); } + }; + + struct B: A + { + int f() { return 1; } + }; + + shared_ptr<A> New(bool make) + { + return shared_ptr<A>( make ? new B() : 0 ); + } + + struct A_Wrapper: A + { + A_Wrapper(PyObject* self_): + A(), self(self_) {} + + int f() { + return call_method< int >(self, "f"); + } + + PyObject* self; + }; + +// ------ + +// from Neal Becker + +struct Test { + shared_ptr<X> x; +}; +// ------ + + +BOOST_PYTHON_MODULE(MODULE) +{ + class_<A, shared_ptr<A_Wrapper>, boost::noncopyable>("A") + .def("call_f", &A::call_f) + .staticmethod("call_f") + ; + + // This is the ugliness required to register a to-python converter + // for shared_ptr<A>. + objects::class_value_wrapper< + shared_ptr<A> + , objects::make_ptr_instance<A, objects::pointer_holder<shared_ptr<A>,A> > + >(); + + def("New", &New); + + def("factory", factory); + + functions<X>::expose( + class_<X, boost::noncopyable>("X", init<int>()) + .def("value", &X::value) + ); + + functions<Y>::expose( + class_<Y, shared_ptr<Y> >("Y", init<int>()) + .def("value", &Y::value) + ); + + class_<YY, bases<Y>, boost::noncopyable>("YY", init<int>()) + ; + + class_<YYY, shared_ptr<YYY>, bases<Y> >("YYY", init<int>()) + ; + + functions<Z>::expose( + class_<Z, ZWrap>("Z", init<int>()) + .def("value", &Z::value) + .def("v", &Z::v, &ZWrap::default_v) + ); + +// from Neal Becker + class_<Test> ("Test") + .def_readonly ("x", &Test::x, "x") + ; +// ------ +} diff --git a/src/boost/libs/python/test/shared_ptr.py b/src/boost/libs/python/test/shared_ptr.py new file mode 100644 index 000000000..d250ae7ec --- /dev/null +++ b/src/boost/libs/python/test/shared_ptr.py @@ -0,0 +1,130 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from shared_ptr_ext import * + + Test that shared_ptr<Derived> can be converted to shared_ptr<Base> + +>>> Y.store(YYY(42)) + +>>> x = X(17) +>>> null_x = null(x) +>>> null_x # should be None +>>> identity(null_x) # should also be None + +>>> a = New(1) +>>> A.call_f(a) +1 +>>> New(0) + +>>> type(factory(3)) +<class 'shared_ptr_ext.Y'> +>>> type(factory(42)) +<class 'shared_ptr_ext.YY'> + +>>> class P(Z): +... def v(self): +... return -Z.v(self); +... def __del__(self): +... print('bye') +... +>>> p = P(12) +>>> p.value() +12 +>>> p.v() +-12 +>>> look(p) +12 +>>> try: modify(p) +... except TypeError: pass +... else: 'print(expected a TypeError)' +>>> look(None) +-1 +>>> store(p) +>>> del p +>>> Z.get().v() +-12 +>>> Z.count() +1 +>>> Z.look_store() +12 +>>> Z.release() +bye +>>> Z.count() +0 + +>>> z = Z(13) +>>> z.value() +13 +>>> z.v() +13 +>>> try: modify(z) +... except TypeError: pass +... else: 'print(expected a TypeError)' + +>>> Z.get() # should be None +>>> store(z) +>>> assert Z.get() is z # show that deleter introspection works +>>> del z +>>> Z.get().value() +13 +>>> Z.count() +1 +>>> Z.look_store() +13 +>>> Z.release() +>>> Z.count() +0 + +>>> x = X(17) +>>> x.value() +17 +>>> look(x) +17 +>>> try: modify(x) +... except TypeError: pass +... else: 'print(expected a TypeError)' +>>> look(None) +-1 +>>> store(x) +>>> del x +>>> X.count() +1 +>>> X.look_store() +17 +>>> X.release() +>>> X.count() +0 + + +>>> y = Y(19) +>>> y.value() +19 +>>> modify(y) +>>> look(y) +-1 +>>> store(Y(23)) +>>> Y.count() +1 +>>> Y.look_store() +23 +>>> Y.release() +>>> Y.count() +0 +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/simple_type.hpp b/src/boost/libs/python/test/simple_type.hpp new file mode 100644 index 000000000..d1314ff97 --- /dev/null +++ b/src/boost/libs/python/test/simple_type.hpp @@ -0,0 +1,13 @@ +// Copyright David Abrahams 2001. +// 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) +#ifndef SIMPLE_TYPE_DWA2001128_HPP +# define SIMPLE_TYPE_DWA2001128_HPP + +struct simple +{ + char* s; +}; + +#endif // SIMPLE_TYPE_DWA2001128_HPP diff --git a/src/boost/libs/python/test/slice.cpp b/src/boost/libs/python/test/slice.cpp new file mode 100644 index 000000000..b1b965fa1 --- /dev/null +++ b/src/boost/libs/python/test/slice.cpp @@ -0,0 +1,98 @@ +#include <boost/python.hpp> +#include <boost/python/slice.hpp> +#include <boost/python/str.hpp> +#include <vector> + +// Copyright (c) 2004 Jonathan Brandmeyer +// Use, modification and distribution are subject to 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) + +using namespace boost::python; + +#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) +# define make_tuple boost::python::make_tuple +#endif + +// These checks are only valid under Python 2.3 +// (rich slicing wasn't supported for builtins under Python 2.2) +bool check_string_rich_slice() +{ + object s("hello, world"); + + // default slice + if (s[slice()] != "hello, world") + return false; + + // simple reverse + if (s[slice(_,_,-1)] != "dlrow ,olleh") + return false; + + // reverse with mixed-sign offsets + if (s[slice(-6,1,-1)] != " ,oll") + return false; + + // all of the object.cpp check_string_slice() checks should work + // with the form that omits the step argument. + if (s[slice(_,-3)] != "hello, wo") + return false; + if (s[slice(-3,_)] != "rld") + return false; + if (", " != s[slice(5,7)]) + return false; + + return s[slice(2,-1)][slice(1,-1)] == "lo, wor"; +} + +// Tried to get more info into the error message (actual array +// contents) but Numeric complains that treating an array as a boolean +// value doesn't make any sense. +#define ASSERT_EQUAL( e1, e2 ) \ + if (!all((e1) == (e2))) \ + return "assertion failed: " #e1 " == " #e2 "\nLHS:\n%s\nRHS:\n%s" % make_tuple(e1,e2); \ +else + +// Verify functions accepting a slice argument can be called +bool accept_slice( slice) { return true; } + +#if BOOST_WORKAROUND( BOOST_MSVC, BOOST_TESTED_AT(1400)) \ + || BOOST_WORKAROUND( BOOST_INTEL_WIN, == 710) +int check_slice_get_indices(slice index); +#endif +int check_slice_get_indices( +#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) + const +#endif + slice index) +{ + // A vector of integers from [-5, 5]. + std::vector<int> coll(11); + typedef std::vector<int>::iterator coll_iterator; + + for (coll_iterator i = coll.begin(); i != coll.end(); ++i) { + *i = i - coll.begin() - 5; + } + + slice::range<std::vector<int>::iterator> bounds; + try { + bounds = index.get_indices(coll.begin(), coll.end()); + } + catch (std::invalid_argument) { + return 0; + } + int sum = 0; + while (bounds.start != bounds.stop) { + sum += *bounds.start; + std::advance( bounds.start, bounds.step); + } + sum += *bounds.start; + return sum; +} + + +BOOST_PYTHON_MODULE(slice_ext) +{ + def( "accept_slice", accept_slice); + def( "check_string_rich_slice", check_string_rich_slice); + def( "check_slice_get_indices", check_slice_get_indices); +} diff --git a/src/boost/libs/python/test/slice.py b/src/boost/libs/python/test/slice.py new file mode 100644 index 000000000..c58bbc029 --- /dev/null +++ b/src/boost/libs/python/test/slice.py @@ -0,0 +1,54 @@ +# Copyright David Abrahams 2004. 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) +""" +>>> from slice_ext import * +>>> accept_slice(slice(1, None, (1,2))) +1 +>>> try: +... accept_slice(list((1,2))) +... print("test failed") +... except: +... print("test passed") +... +test passed +>>> import sys +>>> if sys.version_info[0] == 2 and sys.version_info[1] >= 3: +... check_string_rich_slice() +... elif sys.version_info[0] > 2: +... check_string_rich_slice() +... else: +... print(1) +... +1 +>>> check_slice_get_indices( slice(None)) +0 +>>> check_slice_get_indices( slice(2,-2)) +0 +>>> check_slice_get_indices( slice(2, None, 2)) +5 +>>> check_slice_get_indices( slice(2, None, -1)) +-12 +>>> check_slice_get_indices( slice( 20, None)) +0 +>>> check_slice_get_indices( slice( -2, -5, -2)) +6 +""" + +# Performs an affirmative and negative argument resolution check. +# checks the operation of extended slicing in new strings (Python 2.3 only). + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/staticmethod.cpp b/src/boost/libs/python/test/staticmethod.cpp new file mode 100644 index 000000000..dcd75ca82 --- /dev/null +++ b/src/boost/libs/python/test/staticmethod.cpp @@ -0,0 +1,48 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/call_method.hpp> +#include <boost/ref.hpp> +#include <boost/utility.hpp> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> + +using namespace boost::python; + +struct X +{ + explicit X(int x) : x(x), magic(7654321) { ++counter; } + X(X const& rhs) : x(rhs.x), magic(7654321) { ++counter; } + virtual ~X() { BOOST_ASSERT(magic == 7654321); magic = 6666666; x = 9999; --counter; } + + void set(int _x) { BOOST_ASSERT(magic == 7654321); this->x = _x; } + int value() const { BOOST_ASSERT(magic == 7654321); return x; } + static int count() { return counter; } + private: + void operator=(X const&); + private: + int x; + long magic; + static int counter; +}; +int X::counter; +int getXmagic(){return 7654321;} + +BOOST_PYTHON_MODULE(staticmethod_ext) +{ + class_<X>("X", init<int>()) + .def("value", &X::value) + .def("set", &X::set) + .def("count", &X::count) + .staticmethod("count") + .def("magic", &getXmagic) + .staticmethod("magic") + ; +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/staticmethod.py b/src/boost/libs/python/test/staticmethod.py new file mode 100644 index 000000000..3dd355b13 --- /dev/null +++ b/src/boost/libs/python/test/staticmethod.py @@ -0,0 +1,57 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from staticmethod_ext import * + +>>> class X1(X): +... pass + + +>>> x = X(16) +>>> x1 = X1(17) + + + +>>> x1.count() +2 + +>>> x.count() +2 + +>>> X1.count() +2 + +>>> X.count() +2 + + +>>> x1.magic() +7654321 + +>>> x.magic() +7654321 + +>>> X1.magic() +7654321 + +>>> X.magic() +7654321 + + +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/stl_iterator.cpp b/src/boost/libs/python/test/stl_iterator.cpp new file mode 100644 index 000000000..409e0da84 --- /dev/null +++ b/src/boost/libs/python/test/stl_iterator.cpp @@ -0,0 +1,33 @@ +// Copyright Eric Niebler 2005. +// 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/iterator.hpp> +#include <boost/python/stl_iterator.hpp> +#include <list> + +using namespace boost::python; + +typedef std::list<int> list_int; + +void assign(list_int& x, object const& y) +{ + stl_input_iterator<int> begin(y), end; + x.clear(); + for( ; begin != end; ++begin) + x.push_back(*begin); +} + +BOOST_PYTHON_MODULE(stl_iterator_ext) +{ + using boost::python::iterator; // gcc 2.96 bug workaround + + class_<list_int>("list_int") + .def("assign", assign) + .def("__iter__", iterator<list_int>()) + ; +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/stl_iterator.py b/src/boost/libs/python/test/stl_iterator.py new file mode 100644 index 000000000..4743ed632 --- /dev/null +++ b/src/boost/libs/python/test/stl_iterator.py @@ -0,0 +1,39 @@ +# Copyright Eric Niebler 2005. 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) +''' +>>> from stl_iterator_ext import * +>>> x = list_int() +>>> x.assign(iter([1,2,3,4,5])) +>>> for y in x: +... print(y) +1 +2 +3 +4 +5 +>>> def generator(): +... yield 1 +... yield 2 +... raise RuntimeError("oops") +>>> try: +... x.assign(iter(generator())) +... print("NOT OK") +... except RuntimeError: +... print("OK") +OK +''' +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/str.cpp b/src/boost/libs/python/test/str.cpp new file mode 100644 index 000000000..0505b250a --- /dev/null +++ b/src/boost/libs/python/test/str.cpp @@ -0,0 +1,84 @@ +// Copyright David Abrahams 2004. 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 <boost/python/module.hpp> +#include <boost/assert.hpp> + +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/str.hpp> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> + +using namespace boost::python; + +object convert_to_string(object data) +{ + return str(data); +} + +void work_with_string(object print) +{ + str data("this is a demo string"); + print(data.split(" ")); + print(data.split(" ",3)); + print(str("<->").join(data.split(" "))); + print(data.capitalize()); + print('[' + data.center(30) + ']'); + print(data.count("t")); +#if PY_VERSION_HEX < 0x03000000 + print(data.encode("utf-8")); + print(data.decode("utf-8")); +#else + print(data.encode("utf-8").attr("decode")("utf-8")); + print(data.encode("utf-8").attr("decode")("utf-8")); +#endif + + BOOST_ASSERT(!data.endswith("xx")); + BOOST_ASSERT(!data.startswith("test")); + + print(data.splitlines()); + print(data.strip()); + print(data.swapcase()); + print(data.title()); + + print("find"); + print(data.find("demo")); + print(data.find("demo"),3,5); + print(data.find(std::string("demo"))); + print(data.find(std::string("demo"),9)); + + print("expandtabs"); + str tabstr("\t\ttab\tdemo\t!"); + print(tabstr.expandtabs()); + print(tabstr.expandtabs(4)); + print(tabstr.expandtabs(7L)); + + print("operators"); + print( str("part1") + str("part2") ); +// print( str("a test string").slice(3,_) ); +// print( str("another test")[5] ); + + print(data.replace("demo",std::string("blabla"))); + print(data.rfind("i",5)); + print(data.rindex("i",5)); + + BOOST_ASSERT(!data.startswith("asdf")); + BOOST_ASSERT(!data.endswith("asdf")); + + print(data.translate(str('a')*256)); + + + bool tmp = data.isalnum() || data.isalpha() || data.isdigit() || data.islower() || + data.isspace() || data.istitle() || data.isupper(); + (void)tmp; // ignored. +} + + +BOOST_PYTHON_MODULE(str_ext) +{ + def("convert_to_string",convert_to_string); + def("work_with_string",work_with_string); +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/str.py b/src/boost/libs/python/test/str.py new file mode 100644 index 000000000..4eba0e876 --- /dev/null +++ b/src/boost/libs/python/test/str.py @@ -0,0 +1,54 @@ +# Copyright David Abrahams 2004. 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) +from __future__ import print_function +""" +>>> from str_ext import * +>>> def printer(*args): +... for x in args: print(x, end='') +... print('') +... +>>> work_with_string(printer) #doctest: +NORMALIZE_WHITESPACE +['this', 'is', 'a', 'demo', 'string'] +['this', 'is', 'a', 'demo string'] +this<->is<->a<->demo<->string +This is a demo string +[ this is a demo string ] +2 +this is a demo string +this is a demo string +['this is a demo string'] +this is a demo string +THIS IS A DEMO STRING +This Is A Demo String +find +10 +10 3 5 +10 +10 +expandtabs + tab demo ! + tab demo ! + tab demo ! +operators +part1part2 +this is a blabla string +18 +18 +aaaaaaaaaaaaaaaaaaaaa +""" + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/string_literal.cpp b/src/boost/libs/python/test/string_literal.cpp new file mode 100644 index 000000000..7a349d6c2 --- /dev/null +++ b/src/boost/libs/python/test/string_literal.cpp @@ -0,0 +1,42 @@ +// Copyright David Abrahams 2004. 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 <boost/python/detail/string_literal.hpp> +//#include <stdio.h> + +#include <boost/detail/lightweight_test.hpp> +#include <boost/static_assert.hpp> + +using namespace boost::python::detail; + + +template <class T> +void expect_string_literal(T const&) +{ + BOOST_STATIC_ASSERT(is_string_literal<T const>::value); +} + +int main() +{ + expect_string_literal("hello"); + BOOST_STATIC_ASSERT(!is_string_literal<int*&>::value); + BOOST_STATIC_ASSERT(!is_string_literal<int* const&>::value); + BOOST_STATIC_ASSERT(!is_string_literal<int*volatile&>::value); + BOOST_STATIC_ASSERT(!is_string_literal<int*const volatile&>::value); + + BOOST_STATIC_ASSERT(!is_string_literal<char const*>::value); + BOOST_STATIC_ASSERT(!is_string_literal<char*>::value); + BOOST_STATIC_ASSERT(!is_string_literal<char*&>::value); + BOOST_STATIC_ASSERT(!is_string_literal<char* const&>::value); + BOOST_STATIC_ASSERT(!is_string_literal<char*volatile&>::value); + BOOST_STATIC_ASSERT(!is_string_literal<char*const volatile&>::value); + + BOOST_STATIC_ASSERT(!is_string_literal<char[20]>::value); + BOOST_STATIC_ASSERT(is_string_literal<char const[20]>::value); + BOOST_STATIC_ASSERT(is_string_literal<char const[3]>::value); + + BOOST_STATIC_ASSERT(!is_string_literal<int[20]>::value); + BOOST_STATIC_ASSERT(!is_string_literal<int const[20]>::value); + BOOST_STATIC_ASSERT(!is_string_literal<int const[3]>::value); + return boost::report_errors(); +} diff --git a/src/boost/libs/python/test/test_builtin_converters.py b/src/boost/libs/python/test/test_builtin_converters.py new file mode 100644 index 000000000..e612ed23d --- /dev/null +++ b/src/boost/libs/python/test/test_builtin_converters.py @@ -0,0 +1,312 @@ +# Copyright David Abrahams 2004. 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 sys +if (sys.version_info.major >= 3): + long = int +r""" +>>> from builtin_converters_ext import * + +# Provide values for integer converter tests +>>> def _signed_values(s): +... base = 2 ** (8 * s - 1) +... return [[-base, -1, 1, base - 1], [-base - 1, base]] +>>> def _unsigned_values(s): +... base = 2 ** (8 * s) +... return [[1, base - 1], [long(-1), -1, base]] + +# Wrappers to simplify tests +>>> def should_pass(method, values): +... result = map(method, values[0]) +... if result != values[0]: +... print("Got %s but expected %s" % (result, values[0])) +>>> def test_overflow(method, values): +... for v in values[1]: +... try: method(v) +... except OverflowError: pass +... else: print("OverflowError expected") + +# Synthesize idendity functions in case long long not supported +>>> if not 'rewrap_value_long_long' in dir(): +... def rewrap_value_long_long(x): return long(x) +... def rewrap_value_unsigned_long_long(x): return long(x) +... def rewrap_const_reference_long_long(x): return long(x) +... def rewrap_const_reference_unsigned_long_long(x): return long(x) +>>> if not 'long_long_size' in dir(): +... def long_long_size(): return long_size() + +>>> try: bool_exists = bool +... except: pass +... else: +... rewrap_value_bool(True) +... rewrap_value_bool(False) +True +False + +>>> rewrap_value_bool(None) +0 +>>> rewrap_value_bool(0) +0 +>>> rewrap_value_bool(33) +1 +>>> rewrap_value_char('x') +'x' + + Note that there's currently silent truncation of strings passed to + char arguments. + +>>> rewrap_value_char('xy') +'x' +>>> rewrap_value_signed_char(42) +42 +>>> rewrap_value_unsigned_char(42) +42 +>>> rewrap_value_int(42) +42 +>>> rewrap_value_unsigned_int(42) +42 +>>> rewrap_value_short(42) +42 +>>> rewrap_value_unsigned_short(42) +42 +>>> rewrap_value_long(42) +42 +>>> rewrap_value_unsigned_long(42) +42 + + test unsigned long values which don't fit in a signed long. + strip any 'L' characters in case the platform has > 32 bit longs + +>>> hex(rewrap_value_unsigned_long(long(0x80000001))).replace('L','') +'0x80000001' + +>>> rewrap_value_long_long(42) == 42 +True +>>> rewrap_value_unsigned_long_long(42) == 42 +True + + show that we have range checking. + +>>> should_pass(rewrap_value_signed_char, _signed_values(char_size())) +>>> should_pass(rewrap_value_short, _signed_values(short_size())) +>>> should_pass(rewrap_value_int, _signed_values(int_size())) +>>> should_pass(rewrap_value_long, _signed_values(long_size())) +>>> should_pass(rewrap_value_long_long, _signed_values(long_long_size())) + +>>> should_pass(rewrap_value_unsigned_char, _unsigned_values(char_size())) +>>> should_pass(rewrap_value_unsigned_short, _unsigned_values(short_size())) +>>> should_pass(rewrap_value_unsigned_int, _unsigned_values(int_size())) +>>> should_pass(rewrap_value_unsigned_long, _unsigned_values(long_size())) +>>> should_pass(rewrap_value_unsigned_long_long, +... _unsigned_values(long_long_size())) + +>>> test_overflow(rewrap_value_signed_char, _signed_values(char_size())) +>>> test_overflow(rewrap_value_short, _signed_values(short_size())) +>>> test_overflow(rewrap_value_int, _signed_values(int_size())) +>>> test_overflow(rewrap_value_long, _signed_values(long_size())) +>>> test_overflow(rewrap_value_long_long, _signed_values(long_long_size())) + +>>> test_overflow(rewrap_value_unsigned_char, _unsigned_values(char_size())) +>>> test_overflow(rewrap_value_unsigned_short, _unsigned_values(short_size())) +>>> test_overflow(rewrap_value_unsigned_int, _unsigned_values(int_size())) +>>> test_overflow(rewrap_value_unsigned_long, _unsigned_values(long_size())) + +# Exceptionally for PyLong_AsUnsignedLongLong(), a negative value raises +# TypeError on Python versions prior to 2.7 +>>> for v in _unsigned_values(long_long_size())[1]: +... try: rewrap_value_unsigned_long_long(v) +... except (OverflowError, TypeError): pass +... else: print("OverflowError or TypeError expected") + +>>> assert abs(rewrap_value_float(4.2) - 4.2) < .000001 +>>> rewrap_value_double(4.2) - 4.2 +0.0 +>>> rewrap_value_long_double(4.2) - 4.2 +0.0 + +>>> assert abs(rewrap_value_complex_float(4+.2j) - (4+.2j)) < .000001 +>>> assert abs(rewrap_value_complex_double(4+.2j) - (4+.2j)) < .000001 +>>> assert abs(rewrap_value_complex_long_double(4+.2j) - (4+.2j)) < .000001 + +>>> rewrap_value_cstring('hello, world') +'hello, world' +>>> rewrap_value_string('yo, wassup?') +'yo, wassup?' + +>>> print(rewrap_value_wstring(u'yo, wassup?')) +yo, wassup? + +>>> print(rewrap_value_wstring(u'\U0001f4a9')) +\U0001f4a9 + + test that overloading on unicode works: + +>>> print(rewrap_value_string(u'yo, wassup?')) +yo, wassup? + + wrap strings with embedded nulls: + +>>> rewrap_value_string('yo,\0wassup?') +'yo,\x00wassup?' + +>>> rewrap_value_handle(1) +1 +>>> x = 'hi' +>>> assert rewrap_value_handle(x) is x +>>> assert rewrap_value_object(x) is x + + Note that we can currently get a mutable pointer into an immutable + Python string: + +>>> rewrap_value_mutable_cstring('hello, world') +'hello, world' + +>>> rewrap_const_reference_bool(None) +0 +>>> rewrap_const_reference_bool(0) +0 + +>>> try: rewrap_const_reference_bool('yes') +... except TypeError: pass +... else: print('expected a TypeError exception') + +>>> rewrap_const_reference_char('x') +'x' + + Note that there's currently silent truncation of strings passed to + char arguments. + +>>> rewrap_const_reference_char('xy') +'x' +>>> rewrap_const_reference_signed_char(42) +42 +>>> rewrap_const_reference_unsigned_char(42) +42 +>>> rewrap_const_reference_int(42) +42 +>>> rewrap_const_reference_unsigned_int(42) +42 +>>> rewrap_const_reference_short(42) +42 +>>> rewrap_const_reference_unsigned_short(42) +42 +>>> rewrap_const_reference_long(42) +42 +>>> rewrap_const_reference_unsigned_long(42) +42 +>>> rewrap_const_reference_long_long(42) == 42 +True +>>> rewrap_const_reference_unsigned_long_long(42) == 42 +True + + +>>> assert abs(rewrap_const_reference_float(4.2) - 4.2) < .000001 +>>> rewrap_const_reference_double(4.2) - 4.2 +0.0 +>>> rewrap_const_reference_long_double(4.2) - 4.2 +0.0 + +>>> assert abs(rewrap_const_reference_complex_float(4+.2j) - (4+.2j)) < .000001 +>>> assert abs(rewrap_const_reference_complex_double(4+.2j) - (4+.2j)) < .000001 +>>> assert abs(rewrap_const_reference_complex_long_double(4+.2j) - (4+.2j)) < .000001 + +>>> rewrap_const_reference_cstring('hello, world') +'hello, world' +>>> rewrap_const_reference_string('yo, wassup?') +'yo, wassup?' + +>>> rewrap_const_reference_handle(1) +1 +>>> x = 'hi' +>>> assert rewrap_const_reference_handle(x) is x +>>> assert rewrap_const_reference_object(x) is x +>>> assert rewrap_reference_object(x) is x + + +Check that None <==> NULL + +>>> rewrap_const_reference_cstring(None) + +But None cannot be converted to a string object: + +>>> try: rewrap_const_reference_string(None) +... except TypeError: pass +... else: print('expected a TypeError exception') + +Now check implicit conversions between floating/integer types + +>>> rewrap_const_reference_float(42) +42.0 + +>>> rewrap_const_reference_float(long(42)) +42.0 + +>>> try: rewrap_const_reference_int(42.0) +... except TypeError: pass +... else: print('expected a TypeError exception') + +>>> rewrap_value_float(42) +42.0 + +>>> try: rewrap_value_int(42.0) +... except TypeError: pass +... else: print('expected a TypeError exception') + +Check that classic classes also work + +>>> class FortyTwo: +... def __int__(self): +... return 42 +... def __float__(self): +... return 42.0 +... def __complex__(self): +... return complex(4+.2j) +... def __str__(self): +... return '42' + +>>> try: rewrap_const_reference_float(FortyTwo()) +... except TypeError: pass +... else: print('expected a TypeError exception') + +>>> try: rewrap_value_int(FortyTwo()) +... except TypeError: pass +... else: print('expected a TypeError exception') + +>>> try: rewrap_const_reference_string(FortyTwo()) +... except TypeError: pass +... else: print('expected a TypeError exception') + +>>> try: rewrap_value_complex_double(FortyTwo()) +... except TypeError: pass +... else: print('expected a TypeError exception') + +# show that arbitrary handle<T> instantiations can be returned +>>> assert get_type(1) is type(1) + +>>> assert return_null_handle() is None +""" + +import sys +if (sys.version_info.major >= 3): + long = int + +def run(args = None): + import sys + import doctest + import builtin_converters_ext + + if 'rewrap_value_long_long' in dir(builtin_converters_ext): + print('LONG_LONG supported, testing...') + else: + print('LONG_LONG not supported, skipping those tests...') + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print("running...") + import sys + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/test_class.hpp b/src/boost/libs/python/test/test_class.hpp new file mode 100644 index 000000000..5404fdba2 --- /dev/null +++ b/src/boost/libs/python/test/test_class.hpp @@ -0,0 +1,32 @@ +// Copyright David Abrahams 2002. +// 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) +#ifndef TEST_CLASS_DWA2002326_HPP +# define TEST_CLASS_DWA2002326_HPP +# include <boost/detail/lightweight_test.hpp> + +template <int n = 0> +struct test_class +{ + explicit test_class(int x) : x(x), magic(7654321 + n) { ++counter; } + test_class(test_class const& rhs) : x(rhs.x), magic(7654321 + n) { ++counter; } + virtual ~test_class() { BOOST_TEST(magic == 7654321 + n); magic = 6666666; x = 9999; --counter; } + + void set(int _x) { BOOST_TEST(magic == 7654321 + n); this->x = _x; } + int value() const { BOOST_TEST(magic == 7654321 + n); return x; } + operator int() const { return x; } + static int count() { return counter; } + + int x; + long magic; + static int counter; + + private: + void operator=(test_class const&); +}; + +template <int n> +int test_class<n>::counter; + +#endif // TEST_CLASS_DWA2002326_HPP diff --git a/src/boost/libs/python/test/test_cltree.py b/src/boost/libs/python/test/test_cltree.py new file mode 100644 index 000000000..2127b7cdb --- /dev/null +++ b/src/boost/libs/python/test/test_cltree.py @@ -0,0 +1,43 @@ +# Copyright David Abrahams 2004. 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) +#!/usr/bin/env python + +from cltree import basic,symbol,constant,variable + +b = basic() +c = constant() +s = symbol() +v = variable() + +assert isinstance(b,basic) +assert not isinstance(b,symbol) +assert not isinstance(b,constant) +assert not isinstance(b,variable) + +assert isinstance(c,basic) +assert isinstance(c,constant) +assert not isinstance(c,symbol) +assert not isinstance(c,variable) + +assert not isinstance(s,basic) +assert isinstance(s,symbol) +assert not isinstance(s,constant) +assert not isinstance(s,variable) + +assert isinstance(v,basic) +assert not isinstance(v,symbol) +assert not isinstance(v,constant) +assert isinstance(v,variable) + +print('b=',b) +assert repr(b)=='cltree.basic()' +print('s=',s) +assert repr(s)!='cltree.wrapped_symbol()' # because not isinstance(s,basic) +print('c=',c) +assert repr(c)=='cltree.constant()' +print('v=',v) +assert repr(v)=='cltree.wrapped_variable()' + + +print('ok') diff --git a/src/boost/libs/python/test/test_enum.py b/src/boost/libs/python/test/test_enum.py new file mode 100644 index 000000000..e4ad70bd5 --- /dev/null +++ b/src/boost/libs/python/test/test_enum.py @@ -0,0 +1,85 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from enum_ext import * + +>>> identity(color.red) # in case of duplicated enums it always take the last enum +enum_ext.color.blood + +>>> identity(color.green) +enum_ext.color.green + +>>> identity(color.blue) +enum_ext.color.blue + +>>> identity(color(1)) # in case of duplicated enums it always take the last enum +enum_ext.color.blood + +>>> identity(color(2)) +enum_ext.color.green + +>>> identity(color(3)) +enum_ext.color(3) + +>>> identity(color(4)) +enum_ext.color.blue + + --- check export to scope --- + +>>> identity(red) +enum_ext.color.blood + +>>> identity(green) +enum_ext.color.green + +>>> identity(blue) +enum_ext.color.blue + +>>> try: identity(1) +... except TypeError: pass +... else: print('expected a TypeError') + +>>> c = colorized() +>>> c.x +enum_ext.color.blood +>>> c.x = green +>>> c.x +enum_ext.color.green +>>> red == blood +True +>>> red == green +False +>>> hash(red) == hash(blood) +True +>>> hash(red) == hash(green) +False +''' + +# pickling of enums only works with Python 2.3 or higher +exercise_pickling = ''' +>>> import pickle +>>> p = pickle.dumps(color.green, pickle.HIGHEST_PROTOCOL) +>>> l = pickle.loads(p) +>>> identity(l) +enum_ext.color.green +''' + +def run(args = None): + import sys + import doctest + import pickle + + if args is not None: + sys.argv = args + self = sys.modules.get(__name__) + if (hasattr(pickle, "HIGHEST_PROTOCOL")): + self.__doc__ += exercise_pickling + return doctest.testmod(self) + +if __name__ == '__main__': + print("running...") + import sys + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/test_overload_resolution.cpp b/src/boost/libs/python/test/test_overload_resolution.cpp new file mode 100644 index 000000000..e15bcc6a7 --- /dev/null +++ b/src/boost/libs/python/test/test_overload_resolution.cpp @@ -0,0 +1,53 @@ +// Copyright Troy D. Straszheim 2009 +// 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) +// +// +// example that shows problems with overloading and automatic conversion. +// if you call one of the below functions from python with bool/int/double, +// you'll see that the overload called is first match, not best match. +// See overload matching in luabind for an example of how to do this better. +// +// see this mail: +// http://mail.python.org/pipermail/cplusplus-sig/2009-March/014362.html +// +// This test isn't called by the cmake/jamfiles. For future use. +// +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <complex> +#include <boost/python/handle.hpp> +#include <boost/python/cast.hpp> +#include <boost/python/object.hpp> +#include <boost/python/detail/wrap_python.hpp> + +using boost::python::def; +using boost::python::handle; +using boost::python::object; +using boost::python::borrowed; + +std::string takes_bool(bool b) { return "bool"; } +std::string takes_int(int b) { return "int"; } +std::string takes_double(double b) { return "double"; } + + +BOOST_PYTHON_MODULE(overload_resolution) +{ + def("bid", takes_bool); + def("bid", takes_int); + def("bid", takes_double); + + def("dib", takes_double); + def("dib", takes_int); + def("dib", takes_bool); + + def("idb", takes_int); + def("idb", takes_double); + def("idb", takes_bool); + + def("bdi", takes_bool); + def("bdi", takes_double); + def("bdi", takes_int); +} + diff --git a/src/boost/libs/python/test/test_pointer_adoption.cpp b/src/boost/libs/python/test/test_pointer_adoption.cpp new file mode 100644 index 000000000..a4e14af5d --- /dev/null +++ b/src/boost/libs/python/test/test_pointer_adoption.cpp @@ -0,0 +1,125 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/python/manage_new_object.hpp> +#include <boost/python/return_internal_reference.hpp> +#include <boost/python/class.hpp> + +using namespace boost::python; + +int a_instances = 0; + +int num_a_instances() { return a_instances; } + +struct inner +{ + inner(std::string const& s) + : s(s) + {} + + void change(std::string const& new_s) + { + this->s = new_s; + } + + std::string s; +}; + +struct Base +{ + virtual ~Base() {} +}; + +struct A : Base +{ + A(std::string const& s) + : x(s) + { + ++a_instances; + } + + ~A() + { + --a_instances; + } + + std::string content() const + { + return x.s; + } + + inner& get_inner() + { + return x; + } + + inner x; +}; + +struct B +{ + B() : x(0) {} + B(A* x_) : x(x_) {} + + inner const* adopt(A* _x) { this->x = _x; return &_x->get_inner(); } + + std::string a_content() + { + return x ? x->content() : std::string("empty"); + } + + A* x; +}; + + +A* create(std::string const& s) +{ + return new A(s); +} + +A* as_A(Base* b) +{ + return dynamic_cast<A*>(b); +} + +BOOST_PYTHON_MODULE(test_pointer_adoption_ext) +{ + def("num_a_instances", num_a_instances); + + // Specify the manage_new_object return policy to take + // ownership of create's result + def("create", create, return_value_policy<manage_new_object>()); + + def("as_A", as_A, return_internal_reference<>()); + + class_<Base>("Base") + ; + + class_<A, bases<Base> >("A", no_init) + .def("content", &A::content) + .def("get_inner", &A::get_inner, return_internal_reference<>()) + ; + + class_<inner>("inner", no_init) + .def("change", &inner::change) + ; + + class_<B>("B") + .def(init<A*>()[with_custodian_and_ward_postcall<1,2>()]) + + .def("adopt", &B::adopt + // Adopt returns a pointer referring to a subobject of its 2nd argument (1st being "self") + , return_internal_reference<2 + // Meanwhile, self holds a reference to the 2nd argument. + , with_custodian_and_ward<1,2> >() + ) + + .def("a_content", &B::a_content) + ; +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/test_pointer_adoption.py b/src/boost/libs/python/test/test_pointer_adoption.py new file mode 100644 index 000000000..0fdf3b98e --- /dev/null +++ b/src/boost/libs/python/test/test_pointer_adoption.py @@ -0,0 +1,93 @@ +# Copyright David Abrahams 2004. 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) +""" +>>> from test_pointer_adoption_ext import * + +>>> num_a_instances() +0 + +>>> a = create('dynamically allocated') +>>> num_a_instances() +1 + +>>> a.content() +'dynamically allocated' + +>>> innards = a.get_inner() +>>> innards.change('with an exposed reference') +>>> a.content() +'with an exposed reference' + +# The a instance should be kept alive... +>>> a = None +>>> num_a_instances() +1 + +# ...until we're done with its innards +>>> innards = None +>>> num_a_instances() +0 + +>>> b = B() +>>> a = create('another') +>>> b.a_content() +'empty' +>>> innards = b.adopt(a); +>>> b.a_content() +'another' +>>> num_a_instances() +1 +>>> del a # innards and b are both holding a reference +>>> num_a_instances() +1 +>>> innards.change('yet another') +>>> b.a_content() +'yet another' + +>>> del innards +>>> num_a_instances() # b still owns a reference to a +1 +>>> del b +>>> num_a_instances() +0 + +Test call policies for constructors here + +>>> a = create('second a') +>>> num_a_instances() +1 +>>> b = B(a) +>>> num_a_instances() +1 +>>> a.content() +'second a' + +>>> del a +>>> num_a_instances() +1 +>>> b.a_content() +'second a' + +>>> del b +>>> num_a_instances() +0 + +>>> assert as_A(create('dynalloc')) is not None +>>> base = Base() +>>> assert as_A(base) is None +""" +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/tuple.cpp b/src/boost/libs/python/test/tuple.cpp new file mode 100644 index 000000000..d48e91d88 --- /dev/null +++ b/src/boost/libs/python/test/tuple.cpp @@ -0,0 +1,33 @@ +// Copyright David Abrahams 2005. 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 <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/tuple.hpp> + +using namespace boost::python; + +object convert_to_tuple(object data) +{ + return tuple(data); +} + +void test_operators(tuple t1, tuple t2, object print) +{ + print(t1 + t2); +} + +tuple mktuple0() { return make_tuple(); } +tuple mktuple1(int x) { return make_tuple(x); } +tuple mktuple2(char const* a1, int x) { return make_tuple(a1, x); } + +BOOST_PYTHON_MODULE(tuple_ext) +{ + def("convert_to_tuple",convert_to_tuple); + def("test_operators",test_operators); + def("make_tuple", mktuple0); + def("make_tuple", mktuple1); + def("make_tuple", mktuple2); +} diff --git a/src/boost/libs/python/test/tuple.py b/src/boost/libs/python/test/tuple.py new file mode 100644 index 000000000..1aec5fded --- /dev/null +++ b/src/boost/libs/python/test/tuple.py @@ -0,0 +1,38 @@ +# Copyright David Abrahams 2004. 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) +from __future__ import print_function +""" +>>> from tuple_ext import * +>>> def printer(*args): +... for x in args: print(x,) +... print('') +... +>>> print(convert_to_tuple("this is a test string")) +('t', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 's', 't', ' ', 's', 't', 'r', 'i', 'n', 'g') +>>> t1 = convert_to_tuple("this is") +>>> t2 = (1,2,3,4) +>>> test_operators(t1,t2,printer) #doctest: +NORMALIZE_WHITESPACE +('t', 'h', 'i', 's', ' ', 'i', 's', 1, 2, 3, 4) +>>> make_tuple() +() +>>> make_tuple(42) +(42,) +>>> make_tuple('hello', 42) +('hello', 42) +""" + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/upcast.cpp b/src/boost/libs/python/test/upcast.cpp new file mode 100644 index 000000000..255429f16 --- /dev/null +++ b/src/boost/libs/python/test/upcast.cpp @@ -0,0 +1,19 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/cast.hpp> +#include <boost/detail/lightweight_test.hpp> + +struct X { long x; }; +struct Y : X, PyObject {}; + +int main() +{ + PyTypeObject o; + Y y; + BOOST_TEST(&Py_REFCNT(boost::python::upcast<PyObject>(&o)) == &Py_REFCNT(&o)); + BOOST_TEST(&Py_REFCNT(boost::python::upcast<PyObject>(&y)) == &Py_REFCNT(&y)); + return boost::report_errors(); +} diff --git a/src/boost/libs/python/test/vector_indexing_suite.cpp b/src/boost/libs/python/test/vector_indexing_suite.cpp new file mode 100644 index 000000000..0f9cd74ca --- /dev/null +++ b/src/boost/libs/python/test/vector_indexing_suite.cpp @@ -0,0 +1,62 @@ +// Copyright Joel de Guzman 2004. 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 <boost/python/suite/indexing/vector_indexing_suite.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/implicit.hpp> + +using namespace boost::python; + +struct X // a container element +{ + std::string s; + X():s("default") {} + X(std::string s):s(s) {} + std::string repr() const { return s; } + void reset() { s = "reset"; } + void foo() { s = "foo"; } + bool operator==(X const& x) const { return s == x.s; } + bool operator!=(X const& x) const { return s != x.s; } +}; + +std::string x_value(X const& x) +{ + return "gotya " + x.s; +} + +BOOST_PYTHON_MODULE(vector_indexing_suite_ext) +{ + class_<X>("X") + .def(init<>()) + .def(init<X>()) + .def(init<std::string>()) + .def("__repr__", &X::repr) + .def("reset", &X::reset) + .def("foo", &X::foo) + ; + + def("x_value", x_value); + implicitly_convertible<std::string, X>(); + + class_<std::vector<X> >("XVec") + .def(vector_indexing_suite<std::vector<X> >()) + ; + + // Compile check only... + class_<std::vector<float> >("FloatVec") + .def(vector_indexing_suite<std::vector<float> >()) + ; + + // Compile check only... + class_<std::vector<bool> >("BoolVec") + .def(vector_indexing_suite<std::vector<bool> >()) + ; + + // vector of strings + class_<std::vector<std::string> >("StringVec") + .def(vector_indexing_suite<std::vector<std::string> >()) + ; +} + diff --git a/src/boost/libs/python/test/vector_indexing_suite.py b/src/boost/libs/python/test/vector_indexing_suite.py new file mode 100644 index 000000000..478cd0151 --- /dev/null +++ b/src/boost/libs/python/test/vector_indexing_suite.py @@ -0,0 +1,370 @@ +# Copyright Joel de Guzman 2004. 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) +''' + +##################################################################### +# Check an object that we will use as container element +##################################################################### + +>>> from vector_indexing_suite_ext import * +>>> x = X('hi') +>>> x +hi +>>> x.reset() # a member function that modifies X +>>> x +reset +>>> x.foo() # another member function that modifies X +>>> x +foo + +# test that a string is implicitly convertible +# to an X +>>> x_value('bochi bochi') +'gotya bochi bochi' + +##################################################################### +# Iteration +##################################################################### +>>> def print_xvec(xvec): +... s = '[ ' +... for x in xvec: +... s += repr(x) +... s += ' ' +... s += ']' +... print(s) + +##################################################################### +# Replace all the contents using slice syntax +##################################################################### + +>>> v = XVec() +>>> v[:] = [X('a'),X('b'),X('c'),X('d'),X('e')] +>>> print_xvec(v) +[ a b c d e ] + +##################################################################### +# Indexing +##################################################################### +>>> len(v) +5 +>>> v[0] +a +>>> v[1] +b +>>> v[2] +c +>>> v[3] +d +>>> v[4] +e +>>> v[-1] +e +>>> v[-2] +d +>>> v[-3] +c +>>> v[-4] +b +>>> v[-5] +a + +##################################################################### +# Deleting an element +##################################################################### + +>>> del v[0] +>>> v[0] = 'yaba' # must do implicit conversion +>>> print_xvec(v) +[ yaba c d e ] + +##################################################################### +# Calling a mutating function of a container element +##################################################################### +>>> v[3].reset() +>>> v[3] +reset + +##################################################################### +# Copying a container element +##################################################################### +>>> x = X(v[3]) +>>> x +reset +>>> x.foo() +>>> x +foo +>>> v[3] # should not be changed to 'foo' +reset + +##################################################################### +# Referencing a container element +##################################################################### +>>> x = v[3] +>>> x +reset +>>> x.foo() +>>> x +foo +>>> v[3] # should be changed to 'foo' +foo + +##################################################################### +# Slice +##################################################################### + +>>> sl = v[0:2] +>>> print_xvec(sl) +[ yaba c ] +>>> sl[0].reset() +>>> sl[0] +reset + +##################################################################### +# Reset the container again +##################################################################### +>>> v[:] = ['a','b','c','d','e'] # perform implicit conversion to X +>>> print_xvec(v) +[ a b c d e ] + +##################################################################### +# Slice: replace [1:3] with an element +##################################################################### +>>> v[1:3] = X('z') +>>> print_xvec(v) +[ a z d e ] + +##################################################################### +# Slice: replace [0:2] with a list +##################################################################### +>>> v[0:2] = ['1','2','3','4'] # perform implicit conversion to X +>>> print_xvec(v) +[ 1 2 3 4 d e ] + +##################################################################### +# Slice: delete [3:4] +##################################################################### +>>> del v[3:4] +>>> print_xvec(v) +[ 1 2 3 d e ] + +##################################################################### +# Slice: set [3:] to a list +##################################################################### +>>> v[3:] = [X('trailing'), X('stuff')] # a list +>>> print_xvec(v) +[ 1 2 3 trailing stuff ] + +##################################################################### +# Slice: delete [:3] +##################################################################### +>>> del v[:3] +>>> print_xvec(v) +[ trailing stuff ] + +##################################################################### +# Slice: insert a tuple to [0:0] +##################################################################### +>>> v[0:0] = ('leading','stuff') # can also be a tuple +>>> print_xvec(v) +[ leading stuff trailing stuff ] + +##################################################################### +# Reset the container again +##################################################################### +>>> v[:] = ['a','b','c','d','e'] + +##################################################################### +# Some references to the container elements +##################################################################### +>>> z0 = v[0] +>>> z1 = v[1] +>>> z2 = v[2] +>>> z3 = v[3] +>>> z4 = v[4] + +>>> z0 # proxy +a +>>> z1 # proxy +b +>>> z2 # proxy +c +>>> z3 # proxy +d +>>> z4 # proxy +e + +##################################################################### +# Delete a container element +##################################################################### + +>>> del v[2] +>>> print_xvec(v) +[ a b d e ] + +##################################################################### +# Show that the references are still valid +##################################################################### +>>> z0 # proxy +a +>>> z1 # proxy +b +>>> z2 # proxy detached +c +>>> z3 # proxy index adjusted +d +>>> z4 # proxy index adjusted +e + +##################################################################### +# Delete all container elements +##################################################################### +>>> del v[:] +>>> print_xvec(v) +[ ] + +##################################################################### +# Show that the references are still valid +##################################################################### +>>> z0 # proxy detached +a +>>> z1 # proxy detached +b +>>> z2 # proxy detached +c +>>> z3 # proxy detached +d +>>> z4 # proxy detached +e + +##################################################################### +# Reset the container again +##################################################################### +>>> v[:] = ['a','b','c','d','e'] + +##################################################################### +# renew the references to the container elements +##################################################################### +>>> z0 = v[0] +>>> z1 = v[1] +>>> z2 = v[2] +>>> z3 = v[3] +>>> z4 = v[4] + +>>> z0 # proxy +a +>>> z1 # proxy +b +>>> z2 # proxy +c +>>> z3 # proxy +d +>>> z4 # proxy +e + +##################################################################### +# Set [2:4] to a list such that there will be more elements +##################################################################### +>>> v[2:4] = ['x','y','v'] +>>> print_xvec(v) +[ a b x y v e ] + +##################################################################### +# Show that the references are still valid +##################################################################### +>>> z0 # proxy +a +>>> z1 # proxy +b +>>> z2 # proxy detached +c +>>> z3 # proxy detached +d +>>> z4 # proxy index adjusted +e + +##################################################################### +# Contains +##################################################################### +>>> v[:] = ['a','b','c','d','e'] # reset again + +>>> assert 'a' in v +>>> assert 'b' in v +>>> assert 'c' in v +>>> assert 'd' in v +>>> assert 'e' in v +>>> assert not 'X' in v +>>> assert not 12345 in v + +##################################################################### +# Show that iteration allows mutable access to the elements +##################################################################### +>>> v[:] = ['a','b','c','d','e'] # reset again +>>> for x in v: +... x.reset() +>>> print_xvec(v) +[ reset reset reset reset reset ] + +##################################################################### +# append +##################################################################### +>>> v[:] = ['a','b','c','d','e'] # reset again +>>> v.append('f') +>>> print_xvec(v) +[ a b c d e f ] + +##################################################################### +# extend +##################################################################### +>>> v[:] = ['a','b','c','d','e'] # reset again +>>> v.extend(['f','g','h','i','j']) +>>> print_xvec(v) +[ a b c d e f g h i j ] + +##################################################################### +# extend using a generator expression +##################################################################### +>>> v[:] = ['a','b','c','d','e'] # reset again +>>> def generator(): +... addlist = ['f','g','h','i','j'] +... for i in addlist: +... if i != 'g': +... yield i +>>> v.extend(generator()) +>>> print_xvec(v) +[ a b c d e f h i j ] + +##################################################################### +# vector of strings +##################################################################### +>>> sv = StringVec() +>>> sv.append('a') +>>> print(sv[0]) +a + +##################################################################### +# END.... +##################################################################### + +''' + + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) + + + + + diff --git a/src/boost/libs/python/test/virtual_functions.cpp b/src/boost/libs/python/test/virtual_functions.cpp new file mode 100644 index 000000000..774b11b12 --- /dev/null +++ b/src/boost/libs/python/test/virtual_functions.cpp @@ -0,0 +1,125 @@ +// Copyright David Abrahams 2002. +// 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 <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/return_internal_reference.hpp> +#include <boost/python/call_method.hpp> +#include <boost/ref.hpp> +#include <boost/utility.hpp> + +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> + +using namespace boost::python; + +struct X +{ + explicit X(int x) : x(x), magic(7654321) { ++counter; } + X(X const& rhs) : x(rhs.x), magic(7654321) { ++counter; } + virtual ~X() { BOOST_ASSERT(magic == 7654321); magic = 6666666; x = 9999; --counter; } + + void set(int _x) { BOOST_ASSERT(magic == 7654321); this->x = _x; } + int value() const { BOOST_ASSERT(magic == 7654321); return x; } + static int count() { return counter; } + private: + void operator=(X const&); + private: + int x; + long magic; + static int counter; +}; + +struct Y : X +{ + Y(int x) : X(x) {}; +}; + +struct abstract : X +{ + abstract(int x) : X(x) {}; + int call_f(Y const& y) { return f(y); } + virtual int f(Y const& y) = 0; + abstract& call_g(Y const& y) { return g(y); } + virtual abstract& g(Y const& y) = 0; +}; + +struct concrete : X +{ + concrete(int x) : X(x) {}; + int call_f(Y const& y) { return f(y); } + virtual int f(Y const& y) { set(y.value()); return y.value(); } +}; + +struct abstract_callback : abstract +{ + abstract_callback(PyObject* p, int x) + : abstract(x), self(p) + {} + + int f(Y const& y) + { + return call_method<int>(self, "f", boost::ref(y)); + } + + abstract& g(Y const& y) + { + return call_method<abstract&>(self, "g", boost::ref(y)); + } + + PyObject* self; +}; + +struct concrete_callback : concrete +{ + concrete_callback(PyObject* p, int x) + : concrete(x), self(p) + {} + + concrete_callback(PyObject* p, concrete const& x) + : concrete(x), self(p) + {} + + int f(Y const& y) + { + return call_method<int>(self, "f", boost::ref(y)); + } + + int f_impl(Y const& y) + { + return this->concrete::f(y); + } + + PyObject* self; +}; + +int X::counter; + +BOOST_PYTHON_MODULE(virtual_functions_ext) +{ + class_<concrete, concrete_callback>("concrete", init<int>()) + .def("value", &concrete::value) + .def("set", &concrete::set) + .def("call_f", &concrete::call_f) + .def("f", &concrete_callback::f_impl) + ; + + class_<abstract, boost::noncopyable, abstract_callback + >("abstract", init<int>()) + + .def("value", &abstract::value) + .def("call_f", &abstract::call_f) + .def("call_g", &abstract::call_g, return_internal_reference<>()) + .def("set", &abstract::set) + ; + + class_<Y>("Y", init<int>()) + .def("value", &Y::value) + .def("set", &Y::set) + ; +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/virtual_functions.py b/src/boost/libs/python/test/virtual_functions.py new file mode 100644 index 000000000..cba21edd6 --- /dev/null +++ b/src/boost/libs/python/test/virtual_functions.py @@ -0,0 +1,110 @@ +# Copyright David Abrahams 2004. 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) +''' +>>> from virtual_functions_ext import * + +>>> class C1(concrete): +... def f(self, y): +... return concrete.f(self, Y(-y.value())) + +>>> class C2(concrete): +... pass + +>>> class A1(abstract): +... def f(self, y): +... return y.value() * 2 +... def g(self, y): +... return self + +>>> class A2(abstract): +... pass + + +>>> y1 = Y(16) +>>> y2 = Y(17) + + + +# +# Test abstract with f,g overridden +# +>>> a1 = A1(42) +>>> a1.value() +42 + +# Call f,g indirectly from C++ +>>> a1.call_f(y1) +32 +>>> assert type(a1.call_g(y1)) is abstract + +# Call f directly from Python +>>> a1.f(y2) +34 + +# +# Test abstract with f not overridden +# +>>> a2 = A2(42) +>>> a2.value() +42 + +# Call f indirectly from C++ +>>> try: a2.call_f(y1) +... except AttributeError: pass +... else: print('no exception') + +# Call f directly from Python +>>> try: a2.call_f(y2) +... except AttributeError: pass +... else: print('no exception') + +############# Concrete Tests ############ + +# +# Test concrete with f overridden +# +>>> c1 = C1(42) +>>> c1.value() +42 + +# Call f indirectly from C++ +>>> c1.call_f(y1) +-16 + +# Call f directly from Python +>>> c1.f(y2) +-17 + +# +# Test concrete with f not overridden +# +>>> c2 = C2(42) +>>> c2.value() +42 + +# Call f indirectly from C++ +>>> c2.call_f(y1) +16 + +# Call f directly from Python +>>> c2.f(y2) +17 + + +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/voidptr.cpp b/src/boost/libs/python/test/voidptr.cpp new file mode 100644 index 000000000..82e412bea --- /dev/null +++ b/src/boost/libs/python/test/voidptr.cpp @@ -0,0 +1,43 @@ +// Copyright Niall Douglas 2005. +// 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 <boost/python/return_opaque_pointer.hpp> +# include <boost/python/def.hpp> +# include <boost/python/module.hpp> +# include <boost/python/return_value_policy.hpp> + +static void *test=(void *) 78; + +void *get() +{ + return test; +} + +void *getnull() +{ + return 0; +} + +void use(void *a) +{ + if(a!=test) + throw std::runtime_error(std::string("failed")); +} + +int useany(void *a) +{ + return a ? 1 : 0; +} + + +namespace bpl = boost::python; + +BOOST_PYTHON_MODULE(voidptr_ext) +{ + bpl::def("get", &::get, bpl::return_value_policy<bpl::return_opaque_pointer>()); + bpl::def("getnull", &::getnull, bpl::return_value_policy<bpl::return_opaque_pointer>()); + bpl::def("use", &::use); + bpl::def("useany", &::useany); +} diff --git a/src/boost/libs/python/test/voidptr.py b/src/boost/libs/python/test/voidptr.py new file mode 100644 index 000000000..0e189c965 --- /dev/null +++ b/src/boost/libs/python/test/voidptr.py @@ -0,0 +1,54 @@ +# Copyright Niall Douglas 2005. +# 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) + + +""" +>>> from voidptr_ext import * + + + Check for correct conversion + +>>> use(get()) + + Check that None is converted to a NULL void pointer + +>>> useany(get()) +1 +>>> useany(None) +0 + + Check that we don't lose type information by converting NULL + opaque pointers to None + +>>> assert getnull() is None +>>> useany(getnull()) +0 + + Check that there is no conversion from integers ... + +>>> try: use(0) +... except TypeError: pass +... else: print('expected a TypeError') + + ... and from strings to opaque objects + +>>> try: use("") +... except TypeError: pass +... else: print('expected a TypeError') +""" +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/src/boost/libs/python/test/wrapper_held_type.cpp b/src/boost/libs/python/test/wrapper_held_type.cpp new file mode 100644 index 000000000..e99422796 --- /dev/null +++ b/src/boost/libs/python/test/wrapper_held_type.cpp @@ -0,0 +1,69 @@ +// Copyright David Abrahams 2005. 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 <boost/python/register_ptr_to_python.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/wrapper.hpp> +#include <boost/python/module.hpp> +#include <boost/python/implicit.hpp> + +#include <memory> + +struct data +{ + virtual ~data() {}; // silence compiler warnings + virtual int id() const + { + return 42; + } +}; + +std::auto_ptr<data> create_data() +{ + return std::auto_ptr<data>( new data ); +} + +void do_nothing( std::auto_ptr<data>& ){} + + +namespace bp = boost::python; + +struct data_wrapper : data, bp::wrapper< data > +{ + data_wrapper(data const & arg ) + : data( arg ) + , bp::wrapper< data >() + {} + + data_wrapper() + : data() + , bp::wrapper< data >() + {} + + virtual int id() const + { + if( bp::override id = this->get_override( "id" ) ) + return bp::call<int>(id.ptr()); // id(); + else + return data::id( ); + } + + virtual int default_id( ) const + { + return this->data::id( ); + } + +}; + +BOOST_PYTHON_MODULE(wrapper_held_type_ext) +{ + bp::class_< data_wrapper, std::auto_ptr< data > >( "data" ) + .def( "id", &data::id, &::data_wrapper::default_id ); + + bp::def( "do_nothing", &do_nothing ); + bp::def( "create_data", &create_data ); +} + +#include "module_tail.cpp" diff --git a/src/boost/libs/python/test/wrapper_held_type.py b/src/boost/libs/python/test/wrapper_held_type.py new file mode 100644 index 000000000..ff1bd1d24 --- /dev/null +++ b/src/boost/libs/python/test/wrapper_held_type.py @@ -0,0 +1,34 @@ +# Copyright David Abrahams 2005. 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) +''' +>>> from wrapper_held_type_ext import * +>>> d = data() +>>> print(d.id()) +42 +>>> do_nothing( d ) +>>> print(d.id()) +42 +>>> d = create_data() +>>> print(d.id()) +42 +>>> do_nothing( d ) +>>> print(d.id()) +42 +''' + +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 + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) + diff --git a/src/boost/libs/python/todo.txt b/src/boost/libs/python/todo.txt new file mode 100644 index 000000000..fb4f1c3c3 --- /dev/null +++ b/src/boost/libs/python/todo.txt @@ -0,0 +1,206 @@ +.. -*- mode: rst -*- + +==================================== + Boost.Python_ TODO list |(logo)|__ +==================================== + +.. |(logo)| image:: ../../boost.png + :alt: Boost + :class: boost-logo + +__ ../../index.htm + +.. _`Boost.Python`: index.html + +:copyright: Copyright David Abrahams 2003. Use, modification, and + distribution are subject to 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) + +.. contents:: Outline + +.. _`LICENSE_1_0.txt`: ../../LICENSE_1_0.txt + +Class Support +============= + +Base Class for Virtual Function Callback Wrappers +------------------------------------------------- + +* http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1456023 + (bottom of message) + +* http://mail.python.org/pipermail/c++-sig/2003-August/005297.html + (search for ``VirtualDispatcher``) describes how callback classes + can swap ownership relationship with their Python wrappers. + +* http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1860301 + describes how this can also be used to considerably simplify + callback classes, solve some "dangling reference" problems, and + optimize the calling of non-overridden virtual functions. + +Miscellaneous +============= + +Support for Enums with Duplicate Values +--------------------------------------- + + Scott Snyder provided a patch; Dave was dissatisfied for some + reason, but maybe it should just be applied if no further action + occurs http://aspn.activestate.com/ASPN/Mail/Message/1824616. + + +Functions +========= + +Wrapping Function Objects +-------------------------- + + It should be possible to wrap classes which support ``operator()`` + as Python methods. + + http://mail.python.org/pipermail/c++-sig/2003-August/005184.html + + +"Best Match" Overload Resolution +-------------------------------- + + Overload resolution currently depends on the order in which ``def`` + calls are made (preferring later overloads). This should be + changed so that the best-matching overload is always selected. + This may await Langbinding_ integration, since the technology is + already in Luabind_. + + .. _Luabind: http://luabind.sf.net + +Type Converters +=============== + +Lvalue conversions from non-const ``PyTypeObject*``\ s +------------------------------------------------------ + + http://aspn.activestate.com/ASPN/Mail/Message/C++-sig/1662717 + +Converter Scoping +----------------- + + http://article.gmane.org/gmane.comp.python.c++/2044 + + If this gets done at all, it is going to happen in conjunction + with `Luabind integration`__. + + __ Langbinding_ + + +``boost::tuple`` +---------------- + + Conversions to and from Python would be nice. See + http://news.gmane.org/find-root.php?message_id=%3cuvewak97m.fsf%40boost%2dconsulting.com%3e + +``FILE*`` conversions +--------------------- + + http://aspn.activestate.com/ASPN/Mail/Message/1411366 + +``void*`` conversions +--------------------- + + Pointers to *cv* ``void`` should be able to be passed and + returned as opaque values. + +Post-Call Actions +----------------- + + From-Python converters should be passed an extra reference to a + chain of post-call actions in the Policies object, where they can + register an additional action. See the end of + http://aspn.activestate.com/ASPN/Mail/Message/C++-sig/1755435 + +``PyUnicode`` Support +--------------------- + + Review and possibly incorporate changes from `Lijun Qin`_ at + http://aspn.activestate.com/ASPN/Mail/Message/C++-sig/1771145 + + .. _`Lijun Qin`: mailto:qinlj-at-solidshare.com + +Ownership Metadata +------------------ + + In the thread at + http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1860301, + Niall Douglas describes an idea for solving some "false" + dangling pointer/reference return errors by attaching data about + objects which lets the framework determine that the reference + count on an object doesn't tell us anything about the lifetime + of its data. + +Documentation +============= + +Builtin Converters +------------------ + + Builtin correspondences between builtiin Python types and C++ + types need to be documented + +Internals +--------- + + The structure of the framework needs to get documented; `Brett + Calcott`_ has promised to turn `this document`__ into something fit + for users + + __ doc/internals.html + + .. _`Brett Calcott`: mailto:brett.calcott-at-paradise.net.nz + + +Large Scale +=========== + +Full Threading Support +---------------------- + + Various people have proposed patches to improve threading support + in Boost.Python: see the thread at + http://aspn.activestate.com/ASPN/Mail/Message/1826544 and + http://aspn.activestate.com/ASPN/Mail/Message/1865842 for some + examples. The only problem is that these are incomplete + solutions and verifying that we *do* have a complete solution is + going to take some time and attention. + +Langbinding +----------- + + This project to generalizes Boost.Python to work for other + languages, initially Lua. See discussions at + http://lists.sourceforge.net/lists/listinfo/boost-langbinding + +Refactoring and Reorganization +------------------------------ + + http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1673338 + +NumArray Support Enhancements +----------------------------- + + Consider integrating the enhancements described in + http://aspn.activestate.com/ASPN/Mail/Message/C++-sig/1757092 + +``PyFinalize`` Safety +--------------------- + + Currently Boost.Python has several global (or function-static) + objects whose existence keeps reference counts from dropping to + zero until the Boost.Python shared object is unloaded. This can + cause a crash because when the reference counts *do* go to zero, + there's no interpreter. In order to make it safe to call + ``PyFinalize()`` we must register an ``atexit`` routine which + destroys these objects and releases all Python reference counts + so that Python can clean them up while there's still an + interpreter. `Dirk Gerrits`_ has promised to do this job. + + .. _`Dirk Gerrits`: mailto:dirk-at-gerrits.homeip.net + |