DEVELOPMENT
requirements
- uv: python package/project management
- rust: the language this is written in
- just: just a task runner
goals
- Provide a really nice ergonomic API to work with (this is the highest priority)
- Get naming right (this is a hard one!)
- Be fast
development-setup
- clone repo
- install
just(cargo install just) - create a virtual env (using ye olde
venvoruvor dare I sayconda) – I am still working out the kinks of usinguvwith maturin - install the dev-requirements (
pip install -r requirements.dev.txt) - run
just devto build and test the library - run
just fmtto format the python and rust code
style guide
- Naming conventions:
- For python classes/structs/types prefer
AsyncXYZoverXYZAsync - use
snake_casefor functions and variables - use
CamelCasefor types and traits - use
SCREAMING_SNAKE_CASEfor constants and static-class-attributes
- For python classes/structs/types prefer
- NO UNWRAPPING – use
expectoverunwrap - NO PANICS – don’t panic!
- NO
blazingly-fast–ryis fast and does not need an adverb - USE CLIPPY
just clippyorjust ci - USE RUSTFMT AND RUFF
just fmt - library style guide:
- python objects/structs/classes defined in the library should be named either
Py<CLASSNAME>orRy<CLASSNAME>and the prefix should be consistent throughout the library (egryo3-jiffusesRyas the internal prefix to not conflict with thePy<CLASSNAME>structs provided bypyo3) - For wrapper libraries, attempt to mirror the structure of the original library as much as possible
- wrapper library names should be of the form
ryo3-<LIB_NAME>where<LIB_NAME>is the name of the wrapped library - library directories should be
kebab-caseand should beryo3-<LIB_NAME>
- python objects/structs/classes defined in the library should be named either
- pyo3-signature-formatting; put spaces around
=:- ok:
#[pyo3(signature = (data = None, *, mode = Foo::BAR, _check = false))] - bad:
#[pyo3(signature=(data=None, *, mode=Foo::BAR, _check=false))]
- ok:
deprecations
- Keep deprecation warnings consistent across Rust warnings, python stubs, and generated docs.
- Use this warning message format:
`Thing` is deprecated; use `OtherThing` instead [removal: vX.Y.Z]
- Prefer naming the exact symbol being deprecated and the exact replacement symbol.
- Keep deprecated APIs around for AT LEAST 2-3 published releases unless the API is private.
- When adding a deprecation:
- update the Rust
#[pyo3(warn(...))]message - update the matching
@deprecated(...)message in the.pyistub - update generated docs if they include the deprecated symbol
- update the Rust
Example for copy-pasta
rust code
#![allow(unused)]
fn main() {
#[pymethods]
impl Dingo {
#[pyo3(
warn(
message = "`Dingo.old_name` is deprecated; use `Dingo.new_name` instead [removal: v0.0.100]",
category = pyo3::exceptions::PyDeprecationWarning
)
)]
fn awoo(&self) -> String {
self.bruff()
}
fn bruff(&self) -> String {
"bruff".to_string()
}
}
#[pyfunction]
#[pyo3(
warn(
message = "`awoo_func` is deprecated; use `bruff_func` instead [removal: v0.0.100]",
category = pyo3::exceptions::PyDeprecationWarning
)
)]
fn awoo_func() -> String {
bruff_func()
}
fn bruff_func() -> String {
"bruff".to_string()
}
}
python stub code
if sys.version_info >= (3, 13):
from warnings import deprecated
else:
from typing_extensions import deprecated
class Dingo:
@deprecated(
"`Dingo.awoo` is deprecated; use `Dingo.bruff` instead [removal: v0.0.100]"
)
def awoo(self) -> str: ...
def bruff(self) -> str: ...
@deprecated("`awoo_func` is deprecated; use `bruff_func` instead [removal: v0.0.100]")
def awoo_func() -> str: ...
def bruff_func() -> str: ...
Creating a new library/wrapper-thing
- copy the template library
ryo3-quick-mathslibrary to your new library name - refer to the above style guide for naming conventions
tools
python
maturinis used for builds- python versions 3.11+ are supported
pytestfor testing as well as the following plugins:anyio(which I am increasingly thinking is actually a bit of a turd)hypothesispytest-benchmarkpytest-cov
just
cargo install just
- we use
justfor task running - to see all tasks run
justorjust --list(our default task echos the list of tasks)
just-recipes just -l (ca. 2026-04-10):
Available recipes:
bench # benchmark ry python package
build # build
build-release # build release
cargo-doc # generate cargo docs for all crates (in workspace)
cargo-fmt # cargo format
cargo-fmtc # cargo format check
cargo-test # cargo test
check-features # run cargo check with feature-powerset via cargo-hack
ci # ci rust checks
clean # clean out local caches/artifacts/stuff
clippy # run clippy
clippy-features # run clippy with feature-powerset via cargo-hack
depgraph-svg # generate depgraph for docs
dev # dev run build + tests
develop # maturin develop
devrel # maturin develop release
doctest # run pytest
fmt # format
fmtc # format check
fmtcpy # python format check
fmtpy # python format
gen # generate code tasks
justfilefmt # justfile format
justfilefmtc # justfile format check
lint # lint python and rust
mat *ARGS # maturin develop (shorthand)
mdfmt # format markdown
mypy # run mypy type checker
pip-compile # pip compile requirements
pyprojectfmt # pyproject-fmt
pyright # run pyright
pytest +ARGS='python tests' # run pytest
pytestv # run pytest (printing captured output)
repl # run ry.dev python repl
ruff # run ruff linter
ruff-fmt # ruff format
ruff-fmtc # ruff format check
ruffix # run ruff + fix
sort-all # ruff sort '__all__'
sort-all-check # ruff check sorting of '__all__'
sync # uv sync
test # run all test
test-release # test ry package