# Python Programming/Extending with C++

There are different ways to extend Python with C and C++ code:

-   In plain C, using Python.h
-   Using Swig
-   Using Boost.Python, optionally with Py++ preprocessing
-   Using pybind11
-   Using ../Cython/.

This page describes Boost.Python. Before the emergence of Cython, it was
the most comfortable way of writing C++ extension
modules.

Boost.Python comes bundled with the Boost C++ Libraries. To install it
on an Ubuntu system, you might need to run the following commands

`$ sudo apt-get install libboost-python-dev `\
`$ sudo apt-get install python-dev`

## A Hello World Example

### The C++ source code (hellomodule.cpp)

``` cpp
#include <iostream>

using namespace std;

void say_hello(const char* name) {
    cout << "Hello " <<  name << "!\n";
}

#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
using namespace boost::python;

BOOST_PYTHON_MODULE(hello)
{
    def("say_hello", say_hello);
}
```

### setup.py

``` python
#!/usr/bin/env python

from distutils.core import setup
from distutils.extension import Extension

setup(name="PackageName",
    ext_modules=[
        Extension("hello", ["hellomodule.cpp"],
        libraries = ["boost_python"])
    ])
```

Now we can build our module with

`python setup.py build`

The module \`hello.so\` will end up in e.g \`build/lib.linux-i686-2.4\`.

### Using the extension module

Change to the subdirectory where the file \`hello.so\` resides. In an
interactive python session you can use the module as follows.

`>>> import hello`\
`>>> hello.say_hello("World")`\
`Hello World!`

## An example with CGAL

Some, but not all, functions of the CGAL library already have Python
bindings. Here an example is provided for a case without such a binding
and how it might be implemented. The example is taken from the CGAL
Documentation.

``` Cpp
// test.cpp
using namespace std;

/* PYTHON */
#include <boost/python.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
namespace python = boost::python;

/* CGAL */
#include <CGAL/Cartesian.h>
#include <CGAL/Range_segment_tree_traits.h>
#include <CGAL/Range_tree_k.h>

typedef CGAL::Cartesian<double> K;
typedef CGAL::Range_tree_map_traits_2<K, char> Traits;
typedef CGAL::Range_tree_2<Traits> Range_tree_2_type;

typedef Traits::Key Key;
typedef Traits::Interval Interval;

Range_tree_2_type *Range_tree_2 = new Range_tree_2_type;

void create_tree()   {

  typedef Traits::Key Key;                
  typedef Traits::Interval Interval;    

  std::vector<Key> InputList, OutputList;
  InputList.push_back(Key(K::Point_2(8,5.1), 'a'));
  InputList.push_back(Key(K::Point_2(1.0,1.1), 'b'));
  InputList.push_back(Key(K::Point_2(3,2.1), 'c'));

  Range_tree_2->make_tree(InputList.begin(),InputList.end());
  Interval win(Interval(K::Point_2(1,2.1),K::Point_2(8.1,8.2)));
  std::cout << "\n Window Query:\n";
  Range_tree_2->window_query(win, std::back_inserter(OutputList));
  std::vector<Key>::iterator current=OutputList.begin();
  while(current!=OutputList.end()){
      std::cout << "  " << (*current).first.x() << "," << (*current).first.y()
           << ":" << (*current).second << std::endl;
      current++;
    }
  std::cout << "\n Done\n";
}

void initcreate_tree() {;}

using namespace boost::python;
BOOST_PYTHON_MODULE(test)
{
    def("create_tree", create_tree, "");
}
```

``` Cpp
// setup.py
#!/usr/bin/env python
 
from distutils.core import setup
from distutils.extension import Extension
 
setup(name="PackageName",
    ext_modules=[
        Extension("test", ["test.cpp"],
        libraries = ["boost_python"])
    ])
```

We then compile and run the module as follows:

`$ python setup.py build`\
`$ cd build/lib*`\
`$ python`\
`>>> import test`\
`>>> test.create_tree()`\
`Window Query:`\
` 3,2.1:c`\
` 8,5.1:a`\
`Done`\
`>>>`

## Handling Python objects and errors

One can also handle more complex data, e.g. Python objects like lists.
The attributes are accessed with the extract function executed on the
objects \"attr\" function output. We can also throw errors by telling
the library that an error has occurred and returning. In the following
case, we have written a C++ function called \"afunction\" which we want
to call. The function takes an integer N and a vector of length N as
input, we have to convert the python list to a vector of strings before
calling the function.

``` Cpp
#include <vector>
using namespace std;

void _afunction_wrapper(int N, boost::python::list mapping) {

    int mapping_length = boost::python::extract<int>(mapping.attr("__len__")());
    //Do Error checking, the mapping needs to be at least as long as N 
    if (mapping_length < N) {
        PyErr_SetString(PyExc_ValueError,
            "The string mapping must be at least of length N");
        boost::python::throw_error_already_set();
        return;
    }

    vector<string> mystrings(mapping_length);
    for (int i=0; i<mapping_length; i++) {
        mystrings[i] = boost::python::extract<char const *>(mapping[i]);
    }

   //now call our C++ function
   _afunction(N, mystrings);

}

using namespace boost::python;
BOOST_PYTHON_MODULE(c_afunction)
{
    def("afunction", _afunction_wrapper);
}
```

## External links

-   Boost.Python, boost.org
-   pybind11, pypi.org

