With the Swedish summer upon us, things are more calm at Bitcraze. The summer is usually a time for us to look a bit more at fixing infrastructure and other things that we do not have time to work on the rest of the year. One of the things I have been looking at improving lately is the state of our Python projects.
We currently use Python as the default language for everything we do on PC. This includes the Crazyflie lib, Client and other tools for our ecosystem. Over the years the state of the Python projects have greatly evolved. It started in ~2011 with almost no project management at all; just Python files. Then we switched to setup.py
/pip
support. Recently the Crazyflie client got the pyproject.toml
treatment. Now that most Linux distributions prevent pip install
-ing packages we need to juggle with venv
s in order to use or develop in Python.
In essence, Python started with an easy to use language but has now become quite complex and hard to handle. Things become even more complicated when we take into account CI in Github actions that have to test that our projects actually work with all supported version of Python on Linux/Mac/Windows.

A bit or Rust (tooling) in our Python
As you might have gathered from our previous blog posts over the years, we like Rust quite a bit at Bitcraze and hope to use it more in our products moving forward. One of the great parts of Rust is the quality of the tooling and of the compiler feedback. Cargo as a project management tool helps a lot working with projects in a comfortable and repeatable way.
This is why we are now quite interested in using uv
going forward as an official tool to work with the Bitcraze Python projects. uv
can replace both venv
and pip
and makes working with a Python project as easy as working on a Rust one with cargo
. It is also very fast and efficient since it is written in … Rust
of course :-).
We are also looking at switching from Flake8
to Ruff
and Ty
for linting and type checking respectively. These two tools, from the same developer as uv
are very fast and give very high quality error messages and warnings – this should make it much easier to maintain good code quality.
These changes would mostly be on our documentation and development side. The resulting projects are still compatible with pip
and can still be used as they where used before. However we would make sure the projects can be efficiently used with uv
.
Example
The Crazyflie client is currently already fully able to run with uv
since it already uses the ‘new’ pyproject.toml
project config file. So working with the project, from within the project folder, would look like that:
crazyflie-clients-python $ uv run cfclient # Run the Crazyflie client GUI
(...)
crazyflie-clients-python $ uv run ruff check # Check the code, runs in ~100ms!
All checks passed!
crazyflie-clients-python $ uv run pre-commit
Built cfclient @ file:///home/arnaud/dev/bitcraze/crazyflie-clients-python
Uninstalled 1 package in 0.97ms
░░░░░░░░░░░░░░░░░░░░ [0/1] Installing wheels... warning: Failed to hardlink files; falling back to full copy. This may lead to degraded performance.
Installed 1 package in 4ms
[WARNING] Unstaged files detected.
[INFO] Stashing unstaged files to /home/arnaud/.cache/pre-commit/patch1750684440-121836.
flake8...............................................(no files to check)Skipped
[INFO] Restored changes from /home/arnaud/.cache/pre-commit/patch1750684440-121836.
Code language: Bash (bash)
This last command is a great example of the usefulness of uv
: currently one need to install pre-commit on a virtual environment, enter it, and run pre-commit in the project. With uv
is just works out of the box. In the back of course, pre-commit
is installed in a virtual environment in the project folder. But this is all done automatically.
Finally we will also easily be able to test multiple versions of Python:
crazyflie-clients-python $ uv run --python 3.10 pre-commit
Using CPython 3.10.18 interpreter at: /home/linuxbrew/.linuxbrew/opt/python@3.10/bin/python3.10
Removed virtual environment at: .venv
Creating virtual environment at: .venv
Built cfclient @ file:///(...)/crazyflie-clients-python
Updated https://github.com/bitcraze/crazyflie-lib-python.git (3a35d22026c2ed8251b821e4f5b10e67091f811f)
Built cflib @ git+https://github.com/bitcraze/crazyflie-lib-python.git@3a35d22026c2ed8251b821e4f5b10e67091f811f
░░░░░░░░░░░░░░░░░░░░ [0/32] Installing wheels... warning: Failed to hardlink files; falling back to full copy. This may lead to degraded performance.
Installed 32 packages in 699ms
[WARNING] Unstaged files detected.
[INFO] Stashing unstaged files to /home/arnaud/.cache/pre-commit/patch1750684632-123219.
[INFO] Installing environment for https://github.com/PyCQA/flake8.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
flake8...............................................(no files to check)Skipped
[INFO] Restored changes from /home/arnaud/.cache/pre-commit/patch1750684632-123219.
Code language: JavaScript (javascript)
And, for the end user, uvx
also simplify running the client:
$ uvx cfclient # Pulls and run cfclient from Pypi
(...)
$ uvx --from cfclient cfloader
Built cfclient
Installed 22 packages in 164ms
==============================
CrazyLoader Flash Utility
==============================
Usage: /(...)/.cache/uv/archive-v0/_OZwn5_zGeTE-qFoK_kEG/bin/cfloader [CRTP options] <action> [parameters]
The CRTP options are described above
Crazyload option:
info : Print the info of the bootloader and quit.
Will let the target in bootloader mode
reset : Reset the device in firmware mode
flash <file> [targets] : flash the <img> binary file from the first
possible page in flash and reset to firmware
mode.
Code language: HTML, XML (xml)
This last command would likely be added to all our firmware Makefile
s to be used when calling make cload
to flash the Crazyflie.
Feedback?
This currently does seem like a good idea to us. If you have any feedback or ideas on how to handle Python projects in a better way we are very interested to hear them. Like I mentioned, the summer is kind of a ‘clean up’ time for us so this is when we have time to look at this kind of things.