add *.pyi stub generation support for bindings in rosetta.so (#588)
Adds the `--stubs` flag to build.py for building pyrosetta, which uses
[pybind11-stubgen](https://github.com/sizmailov/pybind11-stubgen/) to
inspect the C++ bindings generated by binder/pybind11 and generates
`*.pyi` type annotation stub files in the rosetta directory. This allows
static type checkers to see the members, arguments, and (most of the
time*) parameter types included in pyrosetta. Adding `**/*.pyi` files to
the `setup.py` package_data list means these stubs will be included
automatically with any distribution, meaning it should be plug-and-play
with a new release.
This PR adds a dependence on an external pypa package for stub
generation (it's imported in the generate_stubs method so won't affect
the process if unspecified) and I'm not familiar enough with the
setuptools / ez_setup build pipeline to know how that should be
integrated as a requirement. Thoughts? Should it be included as a
submodule like other dependencies? Currently I just throw an error in
generate_stubs in `build.py` if `--stubs` is specified but the package
isn't included.
I think this will make the experience a lot easier for new users. I've
tested it (installing from the `.whl` file in a fresh environment) in
VSCode, and it should be compatible with static type analyzers and
google colab as well!
*pybind11-stubgen uses the docstrings automatically generated by
pybind11 to infer by-reference parameter types. If a module member is
bound by pybind11 which references a type which has itself not yet been
bound, the docstring can't use the python type name (since where the
type should sit in the python module tree hasn't been specified) so it
defaults to the C++ type instead (see the [pybind11
documentation](https://pybind11.readthedocs.io/en/latest/advanced/misc.html#avoiding-cpp-types-in-docstrings)).
Pybind11-stubgen will still include these C++ docstrings in the `*.pyi`
files, which removes ambiguity for users most of the time [the user
sometimes needs to connect the dots that `std::shared_ptr<class
core::pose::PDBInfo>` corresponds to
`pyrosetta.rosetta.core.pose.PDBInfo`] even if it can't properly
annotate parameter types accordingly. This could *theoretically* be
fixed by updating binder to run in two passes, binding all classes first
and then all functions, but that would require a massive refactor for
only marginal gain.
---------
Co-authored-by: Sergey Lyskov <3302736+lyskov@users.noreply.github.com>