Skip to main content

High-level bindings to the Valhalla C++ library

Project description

Valhalla Python bindings

pyvalhalla version

This folder (src/bindings/python) contains the Python bindings for the Valhalla routing engine.

[!NOTE] pyvalhalla packages are currently only published for:

  • linux-x86_x64
  • linux-aarch64
  • win-amd64
  • macos-arm64

On top of the (very) high-level Python bindings, we package some data-building Valhalla executables to ease the process of graph creation or run Valhalla as a service, see below.

Installation

We publish CPython packages as binary wheels for Win (amd64), MacOS (arm64) and Linux (x86_64/aarch64) distributions with glibc>=2.28. To decrease disk footprint of the PyPI releases, we only publish a single abi3 wheel per platform, which requires Python >= 3.12. To install on Python < 3.12, make sure to install the system dependencies as described in the docs before trying a pip install pyvalhalla.

Or manually in the current Python environment with e.g.

git clone https://github.com/valhalla/valhalla
cd valhalla
pip install .

In case you need to do a source installation (from sdist), follow the build instructions for your platform to install the needed dependencies. Then a simple pip install pyvalhalla should work fine for Linux/OSX. On Windows one needs to install C++ developer tools, see also below in the developer notes for external vcpkg usage to resolve dependencies.

[!TIP] For developers: pip install -e (editable build) will by default build into a temp directory, so everytime it's invoked it'll rebuild all of libvalhalla. Use the following command to enable real incremental builds:

pip install -e . --no-build-isolation \
  -Cbuild-dir=build_python (or other build dir) \
  -Ccmake.build-type=Release \
  -Ccmake.define.VALHALLA_VERSION_MODIFIER="$(git rev-parse --short HEAD)"
  # optionally for vcpkg package management
  -Ccmake.define.CMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"
  -Ccmake.define.VCPKG_TARGET_TRIPLET=x64-windows
  -Ccmake.define.VCPKG_OVERLAY_PORTS=overlay-ports-vcpkg

Similarly for building a wheel:

pip wheel . -w dist --no-build-isolation \
  -Cbuild-dir=build_python (or other build dir) \
  -Ccmake.build-type=Release \
  -Ccmake.define.VALHALLA_VERSION_MODIFIER="$(git rev-parse --short HEAD)"
  # optionally for vcpkg package management
  -Ccmake.define.CMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"
  -Ccmake.define.VCPKG_TARGET_TRIPLET=x64-windows
  -Ccmake.define.VCPKG_OVERLAY_PORTS=overlay-ports-vcpkg

Both commands have to repeated for each build.

Typing support

We (try to) include full typing support for pyvalhalla. If you're using mypy with strict typing policies, you'll need to install pyvalhalla appropriately with pip install pyvalhalla[typing].

Usage

Bindings

Find a more extended notebook in ./examples, e.g. how to use the actor.

Before using the Python bindings you need to have access to a routable Valhalla graph. Once you installed the pyvalhalla package you can create one with

wget https://download.geofabrik.de/europe/andorra-latest.osm.pbf
python -m valhalla valhalla_build_tiles -c <valhalla.json> andorra-latest.osm.pbf

Once you have created a graph locally, you can use it like this:

from valhalla import Actor, get_config, get_help

# generate configuration
config = get_config(tile_extract='./custom_files/valhalla_tiles.tar', verbose=True)

# print the help for specific config items (has the same structure as the output of get_config()
print(get_help()["service_limits"]["auto"]["max_distance"])

# instantiate Actor to load graph and call actions
actor = Actor(config)
route = actor.route({"locations": [...]})

Error Handling

When a routing operation fails, a ValhallaError is raised (a subclass of RuntimeError) with structured fields from Valhalla's internal error codes:

from valhalla import Actor, ValhallaError, get_config

actor = Actor(get_config(tile_extract='./valhalla_tiles.tar'))

try:
    actor.route({"locations": [{"lat": 0.0, "lon": 0.0}, {"lat": 0.1, "lon": 0.1}], "costing": "auto"})
except ValhallaError as e:
    print(e.code)          # 171
    print(e.message)       # "No suitable edges near location"
    print(e.http_code)     # 400
    print(e.http_message)  # "Bad Request"

Graph Utilities

Access to low-level graph data structures for advanced use cases:

from valhalla.baldr import GraphId
from valhalla.baldr.utils import GraphUtils

# Create a GraphId from its string representation or numeric value
edge_id = GraphId("2/421920/20")  # format: "level/tileid/id"
# or
edge_id = GraphId(674464020)

# Initialize GraphUtils with config (reuse for multiple queries)
# Accepts: file path (str/Path), JSON string, or dict
config = "/path/to/valhalla.json"
# or dict config
config = {"mjolnir": {"tile_extract": "/path/to/tiles.tar"}}
graph = GraphUtils(config)

# Get the polyline geometry for an edge
shape = graph.get_edge_shape(edge_id)

# shape is a list of (lon, lat) tuples
print(f"Edge has {len(shape)} coordinate points")
for lon, lat in shape:
    print(f"  ({lon:.6f}, {lat:.6f})")

# Convert to GeoJSON LineString
geojson = {
    "type": "Feature",
    "geometry": {
        "type": "LineString",
        "coordinates": [[lon, lat] for lon, lat in shape]
    }
}

Speed Compression Utilities

Valhalla uses DCT-2 (Discrete Cosine Transform) to compress historical speed profiles. These utilities allow you to work with compressed speed data:

import numpy as np
from valhalla.baldr.utils import (
    compress_speed_buckets,
    decompress_speed_bucket,
    encode_compressed_speeds,
    decode_compressed_speeds,
    BUCKETS_PER_WEEK,
    COEFFICIENT_COUNT,
)

# Compress 2016 speed buckets (7 days × 288 five-minute intervals)
speeds = np.full(BUCKETS_PER_WEEK, 50.0, dtype=np.float32)  # 50 KPH constant
coefficients = compress_speed_buckets(speeds)

# Decompress a specific bucket (e.g., Monday 10:00 AM)
bucket_idx = 120  # (24 hours × 12 buckets/hour) × 0 days + 10 × 12
speed = decompress_speed_bucket(coefficients, bucket_idx)

# Encode coefficients for storage/transmission
encoded = encode_compressed_speeds(coefficients)
print(f"Compressed to {len(encoded)} characters")

# Decode from string
coefficients_restored = decode_compressed_speeds(encoded)

Valhalla executables

C++ executables

To access the C++ (native) executables, there are 2 options:

  • (recommended) execute the module, e.g. python -m valhalla valhalla_build_tiles -h
  • execute the Python wrapper scripts directly, e.g. valhalla_build_tiles -h

[!NOTE] For the latter option to work, the Python environment's bin/ folder has to be in the $PATH. Inside virtual environments, that's always the case.

Executing the scripts directly might also not work properly if there's a system-wide Valhalla installation, unless the Python environment's bin/ folder has higher priority than system folders in $PATH. The module execution uses an explicit Python executable which should be preferred.

There are also some additional commands we added:

  • --help: print the help for python -m valhalla explicitly
  • --quiet: redirect stdout of the C++ executables to /dev/null; can be added once anywhere in the command, will not be forwarded to a C++ executable
  • print_bin_path: simply prints the absolute path to the package-internal bin/ directory where the C++ executables are; useful if the executables should be accessed directly in some script

To find out which Valhalla executables are currently included, run python -m valhalla --help. We limit the number of executables to control the wheel size. However, we're open to include any other executable if there's a good reason.

Pure Python scripts

The following tools are implemented in pure Python and installed as console scripts:

  • valhalla_build_config: Generate or merge Valhalla configuration JSON files
  • valhalla_build_elevation: Download elevation (DEM) tiles for a given region
  • valhalla_build_extract: Create tar extracts from routing tiles

These are invoked directly, e.g. valhalla_build_config -h or valhalla_build_extract -h. They do not go through the python -m valhalla module mechanism.

Building from source

Note, building the bindings from source is usually best done by building Valhalla with cmake -B build -DENABLE_PYTHON_BINDING=ON .... However, if you want to package your own pyvalhalla bindings for some reason (e.g. fork in a bigger team), you can follow the below instructions, which are also executed by our CI.

The Python build respects a few CMake configuration variables:

  • VALHALLA_VERSION_MODIFIER (optional): Will append a string to the actual Valhalla version string, e.g. $(git rev-parse --short HEAD) will append the current branch's commit hash.

Type stubs (.pyi)

The .pyi files alongside each compiled module are auto-generated by nanobind_add_stub from the C++ bindings — do not edit by hand. They refresh on every build with -DENABLE_PYTHON_BINDINGS=On; a CI guard fails if the committed stubs drift from the live bindings. To regenerate manually: ./scripts/regenerate_python_stubs.sh <build-dir>.

Docstring placement: prose for a class/method that has a Python wrapper (e.g. Actor, Actor.route) lives as a string literal in the Python wrapper file — intellisense tools don't work well with that level of abstraction. Prose for things without a Python wrapper (e.g. ValhallaError, free functions in _graph_utils and predicted_speeds) stays in the C++ .def(...) / nb::class_(...) arg, where stubgen picks it up for the .pyi.

cibuildwheel

On our CI, this orchestrates the packaging of all pyvalhalla wheels for every supported, minor Python version and every platform. It can also be run locally (obviously only being able to build wheels for your platform), e.g.

python -m pip install cibuildwheel
cibuildwheel --print-build-identifiers
cibuildwheel --only cp313-manylinux_x86_64

# for windows you'll have to set an env var to the vcpkg win root
VCPKG_ARCH_ROOT="build/vcpkg_installed/custom-x64-windows" cibuildwheel --only cp313-win_amd64

The build looks at a few environment variables:

  • VCPKG_ARCH_ROOT (required for Win): The relative/absolute directory of the vcpkg root.

In the end, you'll find the wheel in ./wheelhouse.

Linux

To package arch-dependent Linux bindings we use a manylinux fork, where we install all dependencies into the manylinux_2_28 image, based on AlmaLinux 8. This is necessary to have a broad glibc compatibility with many semi-recent Linux distros.

Either pull the manylinux image, or build it locally for testing:

docker pull ghcr.io/valhalla/manylinux:2_28_valhalla_python

# or pull the image from ghcr.io
git clone https://github.com/valhalla/manylinux
cd manylinux
POLICY=manylinux_2_28 PLATFORM=x86_64 COMMIT_SHA=$(git rev-parse --verify HEAD) BUILDX_BUILDER=builder-docker-container ./build.sh
docker tag quay.io/pypa/manylinux_2_28_x86_64:$(git rev-parse --verify HEAD) ghcr.io/valhalla/manylinux:2_28_valhalla_python

Once built, start a container to actually build Valhalla using AlmaLinux 8:

cd valhalla
docker run -dt -v $PWD:/valhalla-py --name valhalla-py --workdir /valhalla-py ghcr.io/valhalla/manylinux:2_28_valhalla_python
docker exec -t valhalla-py /valhalla-py/src/bindings/python/scripts/build_manylinux.sh build_manylinux 3.13

This will also build & install libvalhalla before building the bindings. At this point there should be a wheelhouse folder with the fixed python wheel, ready to be installed or distributed to arbitrary python 3.13 installations.

Testing

Test wheel (linux only)

We have a small test script which makes sure that all the executables are working properly. If run locally for some reason, install a pyvalhalla wheel first. We run this in CI in a fresh Docker container with no dependencies installed, mostly to verify dynamic linking of the vendored dependencies.

Running the unit tests locally

The binding tests live in test/bindings/python/. The tile-dependent ones read test/bindings/python/valhalla.json, whose tile_dir points at test/data/utrecht_tiles, so one needs to execute the tests in the build directory:

# build the tile fixture once (needs ENABLE_DATA_TOOLS=ON)
cmake --build build/Release --target utrecht_tiles -j$(nproc)

# run from the build dir so test/data/utrecht_tiles/* resolves there
( cd <build_dir> && python -m unittest discover -s ../../test/bindings/python -v )

The CMake target run-python_valhalla is the canonical entry point.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyvalhalla-3.8.1.tar.gz (36.0 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

pyvalhalla-3.8.1-cp312-abi3-win_amd64.whl (21.6 MB view details)

Uploaded CPython 3.12+Windows x86-64

pyvalhalla-3.8.1-cp312-abi3-manylinux_2_28_x86_64.whl (36.4 MB view details)

Uploaded CPython 3.12+manylinux: glibc 2.28+ x86-64

pyvalhalla-3.8.1-cp312-abi3-manylinux_2_28_aarch64.whl (33.7 MB view details)

Uploaded CPython 3.12+manylinux: glibc 2.28+ ARM64

pyvalhalla-3.8.1-cp312-abi3-macosx_14_0_arm64.whl (25.3 MB view details)

Uploaded CPython 3.12+macOS 14.0+ ARM64

File details

Details for the file pyvalhalla-3.8.1.tar.gz.

File metadata

  • Download URL: pyvalhalla-3.8.1.tar.gz
  • Upload date:
  • Size: 36.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyvalhalla-3.8.1.tar.gz
Algorithm Hash digest
SHA256 fc5ac5a44e0d4439fa65e5711441ddb74e467db94f000a10f64d23158826f501
MD5 335c04e059211d6f6ca372df583efb4b
BLAKE2b-256 7c0cc9c92692d3f8e62f1fc34f5a737262ad1542aab3686c824f00da2745897a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyvalhalla-3.8.1.tar.gz:

Publisher: osx_win_python_builds.yml on valhalla/valhalla

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyvalhalla-3.8.1-cp312-abi3-win_amd64.whl.

File metadata

  • Download URL: pyvalhalla-3.8.1-cp312-abi3-win_amd64.whl
  • Upload date:
  • Size: 21.6 MB
  • Tags: CPython 3.12+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyvalhalla-3.8.1-cp312-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 1d892952fb269b6ff66cbbd9bd9e1d409cb198f4942efa27be68300fb025a46a
MD5 ec3fdb3c7761f3847ac395db0d952a7f
BLAKE2b-256 dfd9c9152ebd120c3ff8106c9dfc46c335c41c02a5c23138d8efe04c2ab75b9b

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyvalhalla-3.8.1-cp312-abi3-win_amd64.whl:

Publisher: osx_win_python_builds.yml on valhalla/valhalla

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyvalhalla-3.8.1-cp312-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pyvalhalla-3.8.1-cp312-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 2188daae2158e4c84fef52c373e67eddae2a0c8454a6b75f9a1872f2872dd61a
MD5 b22016f4557222f89520a052a2968f8d
BLAKE2b-256 3fbf7f7e0c2db24f1d734ab4dff40917ec2eb33dc046622278130133e8392575

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyvalhalla-3.8.1-cp312-abi3-manylinux_2_28_x86_64.whl:

Publisher: osx_win_python_builds.yml on valhalla/valhalla

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyvalhalla-3.8.1-cp312-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for pyvalhalla-3.8.1-cp312-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 f15139ca2894dafa9b5d4208611962bbdf8e5ba56ef2014434e283400291c4c5
MD5 6f7b62a358f3b901543f7d734e741de4
BLAKE2b-256 c8f5074067057dc0f67f224eb6ed766dc6ab1eb236d28622706c333aab30445b

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyvalhalla-3.8.1-cp312-abi3-manylinux_2_28_aarch64.whl:

Publisher: osx_win_python_builds.yml on valhalla/valhalla

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyvalhalla-3.8.1-cp312-abi3-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for pyvalhalla-3.8.1-cp312-abi3-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 edfdf959d14655a3e6e1de51f54feaa0eb76685f4a2ffece1aeaa8fcc3cfde94
MD5 b8518f640552642ea36b5d5a1d347fed
BLAKE2b-256 a87f456289bf343c1ce3d7d5ec8ca827f02ade14e3ca5791b7f065b919ab8394

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyvalhalla-3.8.1-cp312-abi3-macosx_14_0_arm64.whl:

Publisher: osx_win_python_builds.yml on valhalla/valhalla

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page