summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/python/example
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/python/example')
-rw-r--r--src/boost/libs/python/example/Jamroot35
-rw-r--r--src/boost/libs/python/example/README.md11
-rw-r--r--src/boost/libs/python/example/numpy/Jamfile29
-rw-r--r--src/boost/libs/python/example/numpy/demo_gaussian.py37
-rw-r--r--src/boost/libs/python/example/numpy/dtype.cpp49
-rw-r--r--src/boost/libs/python/example/numpy/fromdata.cpp48
-rw-r--r--src/boost/libs/python/example/numpy/gaussian.cpp315
-rw-r--r--src/boost/libs/python/example/numpy/ndarray.cpp71
-rw-r--r--src/boost/libs/python/example/numpy/simple.cpp32
-rw-r--r--src/boost/libs/python/example/numpy/ufunc.cpp86
-rw-r--r--src/boost/libs/python/example/numpy/wrap.cpp135
-rw-r--r--src/boost/libs/python/example/quickstart/Jamfile35
-rw-r--r--src/boost/libs/python/example/quickstart/embedding.cpp154
-rw-r--r--src/boost/libs/python/example/quickstart/extending.cpp41
-rw-r--r--src/boost/libs/python/example/quickstart/script.py7
-rw-r--r--src/boost/libs/python/example/quickstart/test_extending.py37
-rw-r--r--src/boost/libs/python/example/tutorial/Jamfile19
-rw-r--r--src/boost/libs/python/example/tutorial/hello.cpp20
-rwxr-xr-xsrc/boost/libs/python/example/tutorial/hello.py8
19 files changed, 1169 insertions, 0 deletions
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())