Have you used Cython at all?
It is my favorite way to use C and C++ libraries from Python (compared to binding generators, or writing extensions by hand, or cffi). It provides a very natural way to transfer data to and from C or C++ library code using typed numpy arrays. It can take some patience to get what you want from the documentation, but if you are already used to Python and have some familiarity with C and C++ it makes it very easy to migrate code between C / C++ and Python. So, for example, you can prototype in Python and gradually shift functionality over to C or C++.
What I have found easiest is to put the heavy-lifting code in a static C++ library, building from the (awesome) deal.II tutorials and documentation, and then wrap that C++ library into a loadable Python extension module using Cython. Then you can pass arguments from Python to your solver using the extension module.
In my experience, the trickiest part of this is not Cython per se, but getting testing and continuous integration working with the mix of languages: C++, Cython, Python, and your build system (CMake?) mini-language.
If you choose this route, another option for controlling your solver from Python (possibly with less pain / dependencies than Boost.Python?) might be pybind11 (disclaimer: haven't tried it myself).
Best
Alex