pthom / litgen_template

A quickstart template for litgen

Home Page:https://pthom.github.io/litgen

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Quickstart with litgen

litgen_template is a template repository to build python bindings using litgen, and scikit-build.

This template is based on scikit_build_example.

Usage for final users

Below are the instructions you would give to final users of your bindings. They are extremely short:

First, install the package from source

git clone https://github.com/pthom/litgen_template.git && cd litgen_template
pip install -v .

Then, use it from python

import daft_lib
daft_lib.add(1, 2)

(this template builds bindings for a C++ library called DaftLib, and publishes it as a python module called daft_lib)

Of course, you could also publish your bindings to PyPI, and tell your users to install them with pip install daft-lib. This template provides tooling to make the publishing process easier, via cibuildwheel


Autogenerate the binding code

Install requirements

Create a virtual environment

python3 -m venv venv
source venv/bin/activate

Install the requirements

pip install -r requirements-dev.txt

This will install litgen (the bindings generator), pybind11 (a library to create C++ to Python bindings), pytest (for the tests), black (a code formatter), and mypy (static type checker for python).

See requirements-dev.txt.

Generate bindings

Optionally, change the C++ code

Run the code generation via litgen

python tools/autogenerate_bindings.py

This will:

Tip: compare the python stubs with the C++ header file to see how close they are!

Note: the options inside autogenerate_bindings.py showcase a subset of litgen customization capabilities. See the litgen documentation for more details. They are heavily documented, and correspond to the documentation you can find in DaftLib.h


Adapt for your own library

Names, names, names

In this template repository:

  • the C++ library is called DaftLib
  • the native python module generated by pybind11 is called _daft_lib
  • the python module which is imported by users is called daft_lib (it imports and optionally adapts _daft_lib)
  • the pip package that can optionally be published to PyPI is called daft-lib (as Pypi does not allow dashes in package names)

You can change these names by running change_lib_name.py in the tools/change_lib_name folder.


Structure of this template

Bound C++ library

The C++ library DaftLib is stored inside src/cpp_libraries/DaftLib/

src/cpp_libraries/
└── DaftLib/
    ├── CMakeLists.txt
    ├── DaftLib.h
    └── cpp/
        └── DaftLib.cpp

Python bindings

The python bindings are stored inside src/python_bindings/

src/python_bindings/
      ├─── module.cpp              # Main entry point of the python module
      │── pybind_DaftLib.cpp       # File with bindings *generated by litgen*
      │
      └─ daft_lib/
          ├── __init__.pyi         # Stubs *generated by litgen*
          ├── __init__.py          # The python module (daft_lib) main entry point
          │                        # (it imports and optionally adapts _daft_lib)
          ├── py.typed             # An empty file that indicates that the python module is typed
          │
          └── _daft_lib.xxx.so*    # (optional: the native _daftlib module generated by pybind11,
                                   #  only present in editable mode)

Tooling for the bindings generation

tools/
├── autogenerate_bindings.py
└── change_lib_name/
    └── change_lib_name.py

tools/autogenerate_bindings.py is the script that will generate the bindings using litgen.

tools/change_lib_name/change_lib_name.py is an optional utility that you can use once after cloning this template, in order to rename the libraries (e.g. from DaftLib to MyLib, daft_lib to my_lib, etc.)

Compilation

├── CMakeLists.txt                 # CMakeLists (used also by pip, via skbuild)
├── litgen_cmake/                  # litgen_setup_module() is a cmake function that simplifies
│   └── litgen_setup_module.cmake  # the deployment of a python module with litgen
│
├── requirements-dev.txt           # Requirements for development (litgen, pybind11, pytest, black, mypy)

Deployment

pyproject.toml is used by pip and skbuild to build and deploy the package. It defines the name of the package, the version, the dependencies, etc.

Continuous integration

Several github workflows are defined in .github/workflows:

.github/
├── dependabot.yml   # Configuration for dependabot (automatically update CI dependencies)
├── workflows/
    ├── conda.yml    # Build the package with conda
    ├── pip.yml      # Build the package with pip
    └── wheels.yml   # Build the wheels with cibuildwheel, and publish them to PyPI
                     # (when a new release is created on github)

Note:

Tests

├── tests/daft_lib_test.py    # This is a list of python tests that will check
└── pytest.ini

Those tests are run by cibuildwheel and by the pip CI workflow.


Editable development mode

If you want to quickly iterate on the C++ code, and see the changes reflected in python without having to reinstall the package, you should use the python editable development mode.

Setup editable mode

Step1: Install the package in editable mode

pip install -v -e .  # -e stands for --editable, and -v stands for --verbose

Step 2: Create a standard C++ build directory

mkdir build && cd build
cmake ..
make # rebuild when you change the C++ code, and the changes will be reflected in python!

Debug C++ bindings in editable mode

The pybind_native_debug executable provided in this template is a simple C++ program that can be used to debug the bindings in editable mode.

src/pybind_native_debug/
        ├── CMakeLists.txt
        ├── pybind_native_debug.cpp
        └── pybind_native_debug.py

Simply edit the python file pybind_native_debug.py by adding calls to the C++ functions you want to debug. Then, place breakpoints in the C++ code, and debug the C++ program.


Development tooling

This template is ready to be used with additional tools:

  • pre-commit
  • ruff
  • mypy
  • pyright
  • black
  • pytest
  • cibuildwheel

pre-commit

pre-commit is a tool that allows you to run checks on your code before committing it. This template provides a default pre-commit configuration for it, but it is not active by default;

You can install pre-commit with:

pip install pre-commit

Then, you can activate the pre-commit hooks for your repository with:

pre-commit install

The pre-commit configuration file .pre-commit-config.yaml, is configured with the following hooks:

  • basic sanity checks: trailing-whitespace, end-of-file-fixer,check-yaml, check-added-large-files
  • black: uncompromising Python code formatter
  • ruff: fast Python linter and code formatter (only used for linting)
  • mypy: static type checker for python

You can find more interesting hooks on the pre-commit hooks repository, and for example add ruff, mypy, black, etc.

You may want to disable some checks in the .pre-commit-config.yaml file if you think this is too strict for your project.

ruff: python linter and code formatter

ruff is a very fast python linter and code formatter. You can install it and run it with:

pip install ruff # install ruff (once)
ruff . # each time you want to check your python code

mypy and pyright: static type checkers for python

mypy and pyright are static type checkers for python.

You can use either one of them, or both.

mypy

pip install mypy  # install mypy (once)
mypy # each time you want to check your python code

mypy is configured via the mypy.ini file.

pyright

pip install pyright # install pyright (once)
pyright # each time you want to check your python code

pyright is configured via the pyrightconfig.json file.

black: python code formatter

black is a python code formatter.

pip install black # install black (once)
black . # each time you want to format your python code

pytest: python tests

pytest is an easy-to-use python test framework.

pip install pytest # install pytest (once)
pytest # each time you want to run your python tests

It is configured via the pytest.ini file, and tests are stored in the tests folder.

cibuildwheel: build wheels for all platforms

ci-buildwheel is a tool that allows you to build wheels for all platforms.

It is configured via the pyproject.toml file (see the [tool.cibuildwheel] section), and the github workflow file.

run_all_checks

tools/run_all_checks.sh is a script you can run before committing or pushing. It will run a collection of checks (mypy, black, ruff, pytest).

About

A quickstart template for litgen

https://pthom.github.io/litgen

License:Other


Languages

Language:Python 43.6%Language:C++ 35.7%Language:CMake 19.9%Language:Shell 0.8%