Skip to main content

fitfast

Fast Garmin FIT file parsing for Python — a thin PyO3 binding around the excellent rustyfit Rust crate.

~36× faster than the official pure-Python Garmin SDK for the common "FIT file → NumPy/DataFrame" workflow (17× for dict decode, 60× for file validation), with output semantics that match the official SDK.

import fitfast

# Columnar decode: every numeric record field as a float64 NumPy array
cols = fitfast.records("activity.fit")
cols["heart_rate"]      # array([ 96., 101., 103., ...])
cols["timestamp"]       # Unix epoch seconds
cols["position_lat"]    # degrees (semicircles converted for you)

# Works for any message kind
laps = fitfast.records("activity.fit", message="lap")

# Classic dict output (garmin-fit-sdk-style), enums as names
data = fitfast.parse("activity.fit")
data["session"][0]["sport"]           # "running"
data["session"][0]["total_distance"]  # 77265.02  (scale/offset applied)

# Cheap full-file validation and exploration
n_messages, n_fields = fitfast.count("activity.fit")
fitfast.message_counts("activity.fit")   # {"file_id": 1, "record": 35079, ...}

All functions accept a path, bytes, bytearray, memoryview, or a binary file-like object.

Install

pip install fitfast

Prebuilt wheels are available for Linux, macOS, and Windows (CPython ≥ 3.10, one abi3 wheel per platform). Building from source requires a Rust toolchain.

Why this package

Every existing Python FIT parser decodes the binary format in pure Python. The FIT format is dense — a single long activity is easily 100k+ messages and >1M fields — and pure-Python decoding costs seconds per file, which hurts anyone batch-processing an activity archive. Meanwhile the fastest FIT decoder we measured in any language is a Rust crate (see roznet/fit-benchmarks). fitfast bridges that gap: it is (to our knowledge) the first Python FIT package backed by a native core.

Two design choices keep the speedup from evaporating at the FFI boundary:

  1. Columnar first. records() returns NumPy arrays built in Rust — no per-message Python objects at all. This is the fast path for analytics (pandas/polars/matplotlib) and the reason the end-to-end speedup stays ~36×.
  2. Dicts when you want them. parse() produces the familiar dict-of-messages shape with profile names, scale/offset, enum names, and invalid-value handling matching the official SDK — still 17× faster than pure-Python parsers, because only the final objects are built in Python.

Benchmarks

Decoding a 3.6 MB, 147,482-message activity file (a 77 km ultra with 35k GPS records), Apple M-series, median of repeated in-process runs:

Task: FIT → NumPy columns for all record messages (31 columns) Time Relative
fitfast.records() 0.075 s 1×
garmin-fit-sdk (official) + NumPy conversion 2.68 s 36× slower
Task: FIT → per-message dicts Time Relative
fitfast.parse() 0.15 s 1×
garmin-fit-sdk (official, pure Python) 2.57 s 17× slower
fitdecode 3.88 s 26× slower
fitparse 6.72 s 45× slower
Task: validate the whole file (structure + CRCs) Time Relative
fitfast.count() 0.043 s 1×
garmin-fit-sdk (official) 2.57 s 60× slower

Reproduce with benchmarks/bench.py and any FIT file:

python benchmarks/bench.py path/to/activity.fit

API

fitfast.records(source, message="record", *, degrees=True)

Columnar decode of one message kind → dict[str, np.ndarray] (float64).

  • Every numeric scalar field that occurs in any message of that kind becomes a column; rows where the field is absent or invalid are NaN.
  • Profile scale/offset applied; date_time fields become Unix seconds; semicircle coordinates become degrees (disable with degrees=False).
  • Developer fields are included under their field_description names.
  • String- and array-valued fields are skipped (use parse() for those).
  • Unknown message kinds return {}.

fitfast.parse(source, *, enum_names=True, datetimes=False)

Full decode → dict[str, list[dict]], keyed by message name ("record", "session", ...; manufacturer-specific messages as "unknown_<num>").

  • Semantics follow the official Garmin FIT SDK: scale/offset applied, fields holding the FIT "invalid" sentinel omitted, developer fields resolved.
  • enum_names=True renders profile enums as names ("running"), unknown values stay numeric. datetimes=True yields timezone-aware UTC datetime objects instead of Unix epoch ints.
  • Fields not in the profile are keyed by integer field number (matching garmin-fit-sdk); the same fields appear as unknown_<num> columns in records(), where keys must be strings.
  • Array fields keep invalid elements as None; BYTE-typed fields are returned as Python bytes (opaque payloads, e.g. application_id).

fitfast.count(source) / fitfast.message_counts(source)

Fast full-file validation → (n_messages, n_fields), and per-kind message counts. Structure and CRCs are verified while decoding; invalid input raises fitfast.FitDecodeError (a ValueError subclass).

Notes and current limitations

  • Chained FIT files (multiple FIT sequences in one file) are decoded fully.
  • local_date_time fields are converted with the same FIT-epoch offset as date_time (no timezone shift is applied — FIT does not store the offset).
  • Compressed-timestamp headers, component expansion (enhanced_speed, ...) and accumulated fields are handled by the rustyfit decoder.
  • Dynamic sub-fields are not yet resolved (the main field's name is used) — planned for a future release.
  • records() intentionally returns only numeric scalars.
  • Files are decoded fully into memory; decoded messages can take an order of magnitude more RAM than the file size.

Credits

All of the actual FIT decoding is done by rustyfit by Hikmatulloh Hari Mukti (BSD-3-Clause), the fastest FIT implementation we measured in any language — see also their Go implementation muktihari/fit. If you need FIT parsing in Rust or Go, use those crates directly. fitfast adds only the Python-facing layer: columnar extraction, official-SDK-compatible value semantics, and the PyO3 bindings.

Cross-language performance context: roznet/fit-benchmarks.

License

fitfast is licensed under the BSD 3-Clause License.

Bundled third-party code: the compiled extension statically links rustyfit (BSD-3-Clause) and rust-numpy (BSD-2-Clause), see THIRD-PARTY-NOTICES.md.

The FIT Protocol itself is proprietary to Garmin; use of FIT-decoding software may require compliance with the FIT Protocol License. This project is not affiliated with or endorsed by Garmin.

Development

uv venv && uv pip install -e '.[dev]'   # or: pip install -e '.[dev]'
maturin develop --release               # rebuild the extension
pytest                                  # run the test suite

The test suite builds synthetic FIT files byte-by-byte (little/big endian, compressed timestamps, developer fields, chained files, corrupt CRCs) and cross-checks output against the official garmin-fit-sdk.

Metadata

Release files for fitfast 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fitfast 0.1.0
File Size Uploaded
fitfast-0.1.0.tar.gz 30.3 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for fitfast 0.1.0
File
fitfast-0.1.0-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details
fitfast-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-64 Details
fitfast-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.10 abi3 Linux glibc 2.17+ ARM64 Details
fitfast-0.1.0-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details
fitfast-0.1.0-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details

Total release size: 1.8 MB

Release files / fitfast-0.1.0.tar.gz

Download URL fitfast-0.1.0.tar.gz
Size 30.3 kB
Tags Source
SHA-256 checksum
How to use checksums
11fc0e470ee5a780ff676ad69838f68b2d27e1328a1eaba03c74a340bf1d40a7
BLAKE2b-256 checksum
How to use checksums
929a37e4e7410572ad909c172ca16ffe221974e844e6b2e2e33ff5ce8a579196
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 29, 2026.

Transparency log

Release files / fitfast-0.1.0-cp310-abi3-win_amd64.whl

Download URL fitfast-0.1.0-cp310-abi3-win_amd64.whl
Size 289.3 kB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
21b217cccb4e0dea7f5efce1a99249981ae35e903f149ba2b1909bfdd31e130b
BLAKE2b-256 checksum
How to use checksums
fe1dd444b639c1c059f8b5ee3769036c1c9a7968b43e946016e6f15d2be0746b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 29, 2026.

Transparency log

Release files / fitfast-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL fitfast-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 376.7 kB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
3297da4af1cd1716e5ad0f8b7c0dc832ae292aac65c81db0ca51e6e87f69de54
BLAKE2b-256 checksum
How to use checksums
e38bbd913c2b8d0016425d3be802ae252f426c694951757217097cf8c221353f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 29, 2026.

Transparency log

Release files / fitfast-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL fitfast-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 356.3 kB
Tags CPython 3.10 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
fe7fd3f95712ea8ff4be04776e5e74d4b7c804cdc85619bca838d69b485156c9
BLAKE2b-256 checksum
How to use checksums
6b3b3032caabf9c0f23eccb8dee5f02f5fadc5268ec2076ffc55aa2dcf37db0c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 29, 2026.

Transparency log

Release files / fitfast-0.1.0-cp310-abi3-macosx_11_0_arm64.whl

Download URL fitfast-0.1.0-cp310-abi3-macosx_11_0_arm64.whl
Size 340.9 kB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
bde5b4f78b74c89084a14dfede40fc0b244d891684f933d749347ff70c9c86d1
BLAKE2b-256 checksum
How to use checksums
13dce50a5a7e46814a820ae98e0deed45e686b63024b38f25d9d0144ab623823
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 29, 2026.

Transparency log

Release files / fitfast-0.1.0-cp310-abi3-macosx_10_12_x86_64.whl

Download URL fitfast-0.1.0-cp310-abi3-macosx_10_12_x86_64.whl
Size 364.2 kB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
79d4fc6f9aab7c01abf374981407a90b28b9e6b2232899a12818304223c4404c
BLAKE2b-256 checksum
How to use checksums
9bf896e4f0f22af42427da1301e7db5aef402614e7b5e3293a65c63c3c92eed1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 29, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

6 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page