Python-native bindings for roto-api longest-prefix lookups
Project description
roto-api-native
roto-api-native packages the roto-api Rust lookup engine as an installable Python module.
This package is an unofficial Python package/binding based on NLnetLabs/roto-api.
It is not affiliated with or endorsed by NLnet Labs.
Original project: https://github.com/NLnetLabs/roto-api
License: BSD-3-Clause
Install name:
roto-api-native
Python import name:
roto_api
It is meant for high-volume offline lookups where HTTP-per-IP is too expensive. The native path keeps the routing data in Rust memory and lets Python call directly into that code.
What It Does
- Loads
delegated_all.csv,pfx_asn_dfz_v4.csv,pfx_asn_dfz_v6.csv, and the timestamp files into the RustStore. - Exposes a Python class
roto_api.RotoLookup.
What It Does Not Do
- It is not the HTTP server.
- It does not include the Rust worker-pool API runtime.
- It does not run a background monitor that watches dump URLs and hot-reloads automatically.
- It does not download routing dumps on install, import, or lookup.
For long-running or production use, prepare the data snapshot separately and then load it without any network access.
Data Flow
- An external script prepares a local dataset snapshot.
load_lookup(...)orRotoLookup.from_data_dir(...)asks Rust to load that prepared snapshot into memory.lookup_ip(...)andlookup_ips(...)execute inside Rust and return compact Python dictionaries.
The package does not download or transform dump data. It only loads already-prepared files from disk.
Recommended Dump Workflow
The recommended pattern is:
- your Python app or updater job downloads and prepares the local snapshot
- your application code loads that snapshot with
load_lookup(...)
This separates:
- dump download and transformation
- snapshot validation and promotion
- lookup serving
That way your application process only reads a prepared snapshot and never depends on remote dump availability during startup.
If you omit the optional timestamp metadata files from that snapshot, source_status() simply returns an empty list.
FFI
FFI means Foreign Function Interface. In this project it is the boundary where Python calls compiled Rust code.
Examples of FFI calls here:
roto_api.RotoLookup.from_data_dir(...)roto_api.RotoLookup.lookup_ip(...)roto_api.RotoLookup.lookup_ips(...)
Those calls enter the compiled extension module roto_api._native built from src/python.rs.
Package Layout
src/python.rs: Rust bindings exposed to Python through PyO3.python/roto_api/__init__.py: package exports.scripts/bootstrap_data.py: optional script-side dump preparation helper.scripts/query_ips_native.py: repo-local test wrapper that uses the package API directly.
Additional docs:
API.md: public API referencePUBLISHING.md: release and PyPI publishing checklist
Install
From PyPI
Once published, install it like any other package:
pip install roto-api-native
On Linux x86_64 this should prefer a prebuilt wheel. On unsupported platforms, pip can fall back to the source distribution and build locally if Rust is installed.
Build a wheel locally
maturin build --release
Install the built wheel
$wheel = Get-ChildItem .\target\wheels\*.whl | Select-Object -First 1
pip install --force-reinstall $wheel.FullName
Linux source build
python -m pip install --upgrade pip maturin
maturin build --release
python -m pip install --force-reinstall target/wheels/roto_api_native-0.2.1-cp39-abi3-*.whl
Use From Python
Recommended explicit flow:
from bootstrap_data import prepare_data
from roto_api import load_lookup
prepare_data("./data")
lookup = load_lookup("./data")
print(lookup.lookup_ip("8.8.8.8"))
print(lookup.lookup_ips(["8.8.8.8", "1.1.1.1"]))
print(lookup.source_status())
Use From The Repo Test Script
python .\scripts\query_ips_native.py --data-dir .\data 8.8.8.8 1.1.1.1
Force fresh downloads:
python .\scripts\query_ips_native.py --data-dir .\data --refresh 8.8.8.8 1.1.1.1
Override source URLs from Python:
from bootstrap_data import prepare_data
prepare_data(
"./data",
refresh=True,
del_ext_sources={
"afrinic": "https://example.invalid/delegated-afrinic-extended-latest",
},
riswhois_sources={
"riswhois4": "https://example.invalid/riswhoisdump.IPv4.gz",
},
)
Override source URLs from environment variables:
export ROTO_API_DEL_EXT_AFRINIC_URL="https://example.invalid/delegated-afrinic-extended-latest"
export ROTO_API_RISWHOIS_RISWHOIS4_URL="https://example.invalid/riswhoisdump.IPv4.gz"
Upstream Data Sources
Delegated RIR files:
https://ftp.afrinic.net/pub/stats/afrinic/delegated-afrinic-extended-latesthttps://ftp.apnic.net/stats/apnic/delegated-apnic-extended-latesthttps://ftp.arin.net/pub/stats/arin/delegated-arin-extended-latesthttps://ftp.lacnic.net/pub/stats/lacnic/delegated-lacnic-extended-latesthttps://ftp.ripe.net/pub/stats/ripencc/delegated-ripencc-extended-latest
RIS Whois dumps:
https://www.ris.ripe.net/dumps/riswhoisdump.IPv4.gzhttps://www.ris.ripe.net/dumps/riswhoisdump.IPv6.gz
Size
Typical artifacts are small because the wheel only contains the Python package code and the compiled native extension. The routing dumps are not bundled into the wheel.
Check wheel size:
Get-ChildItem .\target\wheels\*.whl | Select-Object Name,Length
Check installed package files:
python -c "import roto_api, pathlib; p=pathlib.Path(roto_api.__file__).parent; print(p); [print(f'{f.name}`t{f.stat().st_size}') for f in p.rglob('*') if f.is_file()]"
Cross-Platform Support
There is no single native wheel that works on every operating system and CPU architecture. Native extensions must be built per target platform.
This package is structured so you can build wheels for the common targets:
- Windows x86_64
- Linux x86_64
- Linux aarch64
- macOS x86_64
- macOS arm64
The abi3 configuration means one wheel can cover multiple Python versions on the same platform, but not every platform.
For architectures without a published wheel, the source distribution is the portability fallback. If the target machine has a supported Rust toolchain and Python headers/runtime, pip install roto-api-native can build the extension locally.
Build Wheels For Multiple Platforms
The GitHub Actions workflows do two things:
.github/workflows/pkg.ymlruns CI, builds wheels for the main targets, and produces an sdist..github/workflows/publish.ymlpublishes those artifacts to PyPI when you push av*tag.
Before enabling publishing, configure a PyPI trusted publisher for this GitHub repository and the pypi environment used by the workflow.
Release flow:
- Bump the version in
pyproject.tomlandCargo.toml. - Commit and tag it, for example
v0.2.2. - Push the branch and tag.
- The publish workflow builds wheels and the sdist, then uploads them to PyPI.
Why It Is Fast
The native package is much faster than HTTP-per-IP because it removes:
- socket I/O for every lookup
- HTTP parsing for every lookup
- JSON serialization and parsing for every lookup
- request queueing between Python and a separate server process
The expensive work stays inside one Rust process and Python only crosses the boundary a small number of times.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file roto_api_native-0.2.1.tar.gz.
File metadata
- Download URL: roto_api_native-0.2.1.tar.gz
- Upload date:
- Size: 31.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
14239c101423f174e6156995feb151baec01d41b4345c901a69ddb972f0ca995
|
|
| MD5 |
83c0ede7fb578f381635b5caf9b773d2
|
|
| BLAKE2b-256 |
7ca0d97199094f0046497e95e52e91cb1ff2cb5244a71a75f14a39ae9f13b378
|
File details
Details for the file roto_api_native-0.2.1-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: roto_api_native-0.2.1-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 268.7 kB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
211f8bcb00b348b2fd7b65c16756b78554279784cf5b9ab59188f2b48d8b64e8
|
|
| MD5 |
9fb43243f19467493b4df117387d8d4e
|
|
| BLAKE2b-256 |
14c7a4fd3ebcfe7f0f8c21ef0933eb4f48d9aa7c14d0e5c35def2720b9336db5
|