project-gemmi / gemmi

macromolecular crystallography library and utilities
https://project-gemmi.github.io/
Mozilla Public License 2.0
205 stars 42 forks source link

python bindings: convert from pybind11 to nanobind, add type stubs #293

Open wojdyr opened 6 months ago

wojdyr commented 6 months ago

Plan to switch to nanobind.

About 20 years ago, when I needed Python bindings to C++, the main tools were SWIG, with its own syntax of interface files, which is used to generate the code of the bindings, and Boost.Python with mind-boggling meta-programming tricks to keep everything as C++ code. I used SWIG at the time.

7 years ago, when I was starting Gemmi, there was also pybind11, created by Wenzel Jakob, a better Boost.Python (simpler, smaller, easier to use and faster to compile, thanks to C++11). At that time, Boost.Python was abandoned by its original developers. SWIG was still being maintained. And at Google, there was ongoing work on a new C++ wrapper generator CLIF, which has its own syntax of interface files. I chose pybind11 and I've had a better experience with it than with SWIG, apart from the long build times. (To be fair, SWIG can generate bindings for many languages, and the other tools above only for Python.)

But things have changed again. Nowadays there is also nanobind, created by Wenzel Jakob, a better pybind11 (simpler, smaller, faster to compile and run, thanks to C++17, and because it supports Python 3.8+ only). In the meantime, Boost.Python has found a new maintainer. SWIG is still maintained. And at Google there is ongoing work on a new C++ wrapper generator pywrapcc, which is a fork of pybind11 with CLIF integration (interestingly, this work is done largely by RWGK, one of the old Boost.Python maintainers and an expert in crystallography.) I've been planning to switch to nanobind since about a year ago, for the reasons given on the nanobind website, but couldn't drop support for Python 3.7 yet. Now I can and I think I'll give it a try after the next release, in a month or two.

The migration may involve small changes to the API. To make it easier to adjust Python programs, I'd like to add type annotations, to allow automatic checking of calls to gemmi with type checkers. I don't know how much this will help, though.

Type stubs (annotations in *.pyi files) can be automatically generated with pybind11-stubgen (the author of this project contributed to gemmi in the past). From what I see, there are four Python type checkers:

Pylint 3.0 can also use pyi files. The plan is to evaluate at least some of the tools above and include type stubs in the next release (while still using pybind11).