Skip to main content

pyfitparsernative

Fast FIT file parser using Rust, exposed to Python via PyO3.

Reads and writes Garmin FIT files using the rustyfit Rust crate. Roughly 5-10x faster than garmin-fit-sdk (Python) for reading, and ~20-25x faster for writing.

Both benchmarks below (tests/test_performance.py) use the same bundled real ride file (81km / 11,555 records, ~22.6k total messages across all message types) — read it once, then write the parsed result straight back out:

Operation garmin-fit-sdk (Python) pyfitparsernative (Rust) Speedup
Read (parse_fit_file) ~1.1-2.2s ~0.1-0.2s ~5-10x
Write (write_fit_bytes) ~2.0-2.7s ~0.1s ~20-25x

Numbers vary by machine/container; both benchmarks measure through the full Python API (dict marshalling included), not raw Rust-only timings.

Installation

pip install pyfitparsernative

No Rust toolchain required — pre-built wheels are provided for Linux (glibc and musl), macOS (Intel and Apple Silicon), and Windows (x64). The macOS Intel (x86_64) wheel is cross-compiled and not tested in CI since GitHub no longer offers Intel macOS runners.

Usage

from pyfitparsernative import parse_fit_file, parse_fit_bytes, write_fit_file, write_fit_bytes

# Parse from a file path
messages = parse_fit_file("activity.fit")

# Parse from bytes
with open("activity.fit", "rb") as f:
    messages = parse_fit_bytes(f.read())

Return type: list[dict[str, Any]]

Returns a flat list of message dicts in original FIT file order. Each dict includes a "message_type" key (e.g. "record", "session", "lap") alongside the field data. Timestamps are returned as naive ISO 8601 strings (YYYY-MM-DDTHH:MM:SS).

# Example: get average power from session message
session = [m for m in messages if m["message_type"] == "session"][0]
print(session["avg_power"])    # 160
print(session["max_power"])    # 489

# Example: iterate record (data) messages
for msg in messages:
    if msg["message_type"] == "record":
        print(msg["timestamp"], msg.get("power"), msg.get("heart_rate"))

Writing

write_fit_file/write_fit_bytes accept the same list[dict[str, Any]] shape that parse_fit_file/parse_fit_bytes return, so parsed messages can be modified and written back directly. Each dict must have a "message_type" key; field values use the same units/representation as the parser (naive ISO 8601 strings for timestamps, unscaled physical values for numeric fields). Input is validated up front: unrecognized field names, values outside a field's FIT type range (e.g. heart_rate: 300), and messages with no fields all raise ValueError, and a failed write_fit_file never leaves a partial file behind.

from pyfitparsernative import write_fit_file, write_fit_bytes

messages = [
    {"message_type": "file_id", "type": 5, "manufacturer": 1, "product": 0},
    {"message_type": "workout", "sport": 1, "num_valid_steps": 1, "wkt_name": "Easy Run"},
    {
        "message_type": "workout_step",
        "message_index": 0,
        "duration_type": 0,       # time
        "duration_value": 1800000,  # ms
        "target_type": 0,         # open
        "intensity": 0,           # active
    },
]

write_fit_file("workout.fit", messages)
data = write_fit_bytes(messages)  # -> bytes

Differences from garmin-fit-sdk

pyfitparsernative returns the same field names and numeric values as garmin-fit-sdk, with the following differences:

  • Timestamps — returned as naive ISO 8601 strings instead of timezone-aware datetime objects.
  • Enum fields — returned as raw integers instead of string labels.
  • Message types — no _mesgs suffix (e.g. "session" not "session_mesgs").
  • Developer fields — garmin-fit-sdk uses integer dict keys for developer fields (e.g. {61: 2554}); pyfitparsernative uses string keys ({"developer_field_61": 2554}). Native fields missing from the FIT profile use a separate "unknown_field_<N>" prefix, so the two numbering spaces never collide. When writing, developer_field_<N> keys are re-encoded as real developer fields; the message list must contain the defining field_description message (with developer_data_index, field_definition_number, and fit_base_type_id) before the first message that uses the field — parsed files satisfy this automatically.
  • Component field expansion — garmin-fit-sdk derives speed and altitude from the more precise enhanced_speed/enhanced_altitude fields when the base fields are absent from the message definition. pyfitparsernative applies the same expansion, so "speed" and "altitude" are always present in record messages alongside their enhanced_ counterparts.
  • Unknown message types — message numbers not in rustyfit's generated FIT profile fall back to their raw numeric string (e.g. "147") instead of a name.

Building from source

The docker/ directory contains scripts to build and test inside containers, avoiding the need for a local Rust toolchain. These are for local development only; CI/CD uses its own pipeline.

Build — compiles the wheel inside rust:1.93.1-trixie and writes it to dist/:

bash docker/docker-build.sh

Test — runs the test suite inside python:3.14.3-trixie against the wheel in dist/:

bash docker/docker-test.sh

On Windows, run these from Git Bash or WSL. Docker Desktop must be running with Linux containers enabled.

Releasing

Push a tag to trigger the CI/CD pipeline, which builds wheels for all platforms and publishes to PyPI:

git tag v0.1.0 && git push --tags

See .github/workflows/CI.yml for the full build matrix.

Download files

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

Source Distribution

pyfitparsernative-0.2.0.tar.gz (391.1 kB view details)

Uploaded Source

Built Distributions

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

pyfitparsernative-0.2.0-cp39-abi3-win_amd64.whl (254.4 kB view details)

Uploaded CPython 3.9+Windows x86-64

pyfitparsernative-0.2.0-cp39-abi3-musllinux_1_2_x86_64.whl (564.4 kB view details)

Uploaded CPython 3.9+musllinux: musl 1.2+ x86-64

pyfitparsernative-0.2.0-cp39-abi3-musllinux_1_2_aarch64.whl (515.5 kB view details)

Uploaded CPython 3.9+musllinux: musl 1.2+ ARM64

pyfitparsernative-0.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (371.0 kB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

pyfitparsernative-0.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (339.0 kB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

pyfitparsernative-0.2.0-cp39-abi3-macosx_11_0_arm64.whl (320.0 kB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

pyfitparsernative-0.2.0-cp39-abi3-macosx_10_12_x86_64.whl (328.8 kB view details)

Uploaded CPython 3.9+macOS 10.12+ x86-64

File details

Details for the file pyfitparsernative-0.2.0.tar.gz.

File metadata

  • Download URL: pyfitparsernative-0.2.0.tar.gz
  • Upload date:
  • Size: 391.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pyfitparsernative-0.2.0.tar.gz
Algorithm Hash digest
SHA256 68cf46a2b9af337f957c53bf86327397122df0d5c1d189592e89bab5c12789ab
MD5 c5507ea4eb0bb552d1932d8774047871
BLAKE2b-256 3e869c42d10199555c74a41468b541c1d7f872c89050397aee575990cbcfa45a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyfitparsernative-0.2.0.tar.gz:

Publisher: CI.yml on GedRap/pyfitparsernative

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

File details

Details for the file pyfitparsernative-0.2.0-cp39-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for pyfitparsernative-0.2.0-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 5927f2e269483f645a81b4fb3a6cd2629978bf8417d8632c413b2c7ef5de61dd
MD5 8f3b0f481860e5921036ef6edbd87039
BLAKE2b-256 44f9c596aa1ef6e46ebf899a0a7e1a566a2c6259e526cda619233252467d50ac

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyfitparsernative-0.2.0-cp39-abi3-win_amd64.whl:

Publisher: CI.yml on GedRap/pyfitparsernative

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

File details

Details for the file pyfitparsernative-0.2.0-cp39-abi3-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pyfitparsernative-0.2.0-cp39-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 c3fe21729a1f0b7aebe7d733a79d5c08dd7ef862d911486cb75080267c31d4ac
MD5 e41d8a6276ced42b39746f3f4f6f863c
BLAKE2b-256 2e90232c19542373ae27ad4e0da41671b6c3372d765226a43ec2a94c111a8e3b

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyfitparsernative-0.2.0-cp39-abi3-musllinux_1_2_x86_64.whl:

Publisher: CI.yml on GedRap/pyfitparsernative

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

File details

Details for the file pyfitparsernative-0.2.0-cp39-abi3-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for pyfitparsernative-0.2.0-cp39-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 2553e14dc4fd1e3f57aa6e41e97f3331cb936c3733d04bb074ee40a13d2e5793
MD5 6dc46d8b82a66fbf3f027a50c67c7d83
BLAKE2b-256 bd500fad191df947fb880bc382cec653cc5c07379c7b38e4a019ce8931a843ad

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyfitparsernative-0.2.0-cp39-abi3-musllinux_1_2_aarch64.whl:

Publisher: CI.yml on GedRap/pyfitparsernative

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

File details

Details for the file pyfitparsernative-0.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyfitparsernative-0.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 fdd3a0f50dd583d006a802b468600cce398af55bdb0ca3196b4c1b522403468e
MD5 9b2b663ee4b0e38dfaa150f958e87419
BLAKE2b-256 247d3e46839877966f8550fc1832c3cd97c5e0a9ea536449a798cb1eb59b37d6

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyfitparsernative-0.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: CI.yml on GedRap/pyfitparsernative

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

File details

Details for the file pyfitparsernative-0.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for pyfitparsernative-0.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 cebfef94aceca3e03823ed2f014dacc5033d4fc1f0f7d2be77e973750206cf88
MD5 b8cfabc90fe78a5d74c7b7514f18d9ed
BLAKE2b-256 6b8e41d2b311d8aa924921c4cf89d1dfdf5758879c7592292c29dba2c9f5099d

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyfitparsernative-0.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: CI.yml on GedRap/pyfitparsernative

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

File details

Details for the file pyfitparsernative-0.2.0-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pyfitparsernative-0.2.0-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 24a74359d9b01e0db2c149336c92b7ba9e7203eca41e63676c4e4b7f25bdc204
MD5 ad2e586d14e990022c0e44449018fd28
BLAKE2b-256 51cd7748a32b8bab4049633756b1997ca76181dc7653e7fd74f9936a616fb593

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyfitparsernative-0.2.0-cp39-abi3-macosx_11_0_arm64.whl:

Publisher: CI.yml on GedRap/pyfitparsernative

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

File details

Details for the file pyfitparsernative-0.2.0-cp39-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for pyfitparsernative-0.2.0-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 02762ffbd9662b81147c545fc3047d01b12c4f64dc885eeb0e9300d37d165d09
MD5 f2274dac83911b9e897b7f2a7e5d3492
BLAKE2b-256 696870063bab248eb5afdfde70b545782eecbd867df69d3014c4b13f7f1a0733

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyfitparsernative-0.2.0-cp39-abi3-macosx_10_12_x86_64.whl:

Publisher: CI.yml on GedRap/pyfitparsernative

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

Release history Release notifications | RSS feed

0.2.3

8 files

0.2.2

8 files

0.2.1

8 files

This release

0.2.0 This release

8 files

0.1.0

10 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