Development
portly is a hybrid Python + Rust package: a thin PyO3 extension over a pure-Rust core. See CONTRIBUTING.md for the full contributor guide; the essentials are below.
Setup
Requirements: Python 3.10+, a Rust toolchain (rustc 1.85+), and uv (or pip).
# Install dev dependencies.
uv sync --group dev
# Build and install the extension into the current environment.
maturin develop
# Run the tests.
pytest tests/
When you change Rust code you need to re-run maturin develop for the
Python tests to pick it up.
Quality gates
All of the following must pass before merging. The CI runs the same checks.
# Rust
cargo fmt -- --check
cargo clippy --all-targets -- -D warnings
cargo test
# Python
ruff check python/ tests/ examples/
ruff format --check python/ tests/ examples/
mypy python/portly tests
# Stubs must match the compiled extension.
python -m mypy.stubtest portly._lib --allowlist tests/stubtest-allowlist.txt
Project layout
src/lib.rs— the Rust extension. Platform-specific process lookup lives inmod platform(Linux:procfs, macOS:libproc, Windows:windows-sys). There are no subprocess calls — do not addlsof,netstat,wmic, or friends.python/portly/— the Python package: a thin re-export shim (__init__.py), the type stubs (_lib.pyi), andpy.typed.tests/— pytest suite (run against the installed module) plus the stubtest allowlist.examples/— the FastAPI playground demo.docs/— this documentation site (mkdocs + mkdocstrings).
Building the docs locally
uv sync --group docs
maturin develop # mkdocstrings imports the package, so the extension is needed
mkdocs serve # or: mkdocs build
Versioning and releases
portly follows SemVer. The version is single-sourced in
Cargo.toml; pyproject.toml uses dynamic = ["version"]. Releases are
driven by release-please, which
parses conventional commits and maintains release PRs. See
CONTRIBUTING.md for details.