Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/activity_parser/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"""Parser for loading FIT, TCX and GPX files into Pandas DataFrames."""

from .activity import Activity
from .exceptions import FitError, ParseError, XmlError
from .output import Activity
from .parse_activity import ActivityParser
from .parse_fit_file import parse_fit, parse_fit_raw
from .parse_fit import parse_fit, parse_fit_raw
from .parse_tcx_gpx import parse_gpx, parse_tcx
from .parser import ActivityParser

__all__ = [
"Activity",
Expand Down
36 changes: 34 additions & 2 deletions src/activity_parser/derive.py → src/activity_parser/activity.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,43 @@
"""Fills an ``Activity``'s missing fields by aggregating its own records/laps."""
"""Defines ``Activity``, a file-level summary across FIT, TCX, and GPX files.

Also defines the logic for filling missing ``Activity`` fields by calculating from the
file's records and laps.
"""

import dataclasses
from dataclasses import dataclass
from typing import Literal

import pandas as pd

from .output import Activity

@dataclass(frozen=True)
class Activity:
"""File-level summary, present across FIT/TCX/GPX.

Fields are populated from the source file's summary fields where reported, or
calculated from records and laps where practical. Fields are ``None`` when neither
is available.
"""

sport: str | None = None
start_time: pd.Timestamp | None = None
total_elapsed_time: float | None = None # seconds
total_timer_time: float | None = None # seconds, excludes paused time
total_distance: float | None = None # km
total_ascent: float | None = None # m
total_descent: float | None = None # m
total_calories: float | None = None # kcal
avg_heart_rate: float | None = None # bpm
max_heart_rate: float | None = None # bpm
avg_power: float | None = None # W
max_power: float | None = None # W
avg_cadence: float | None = None # rpm
max_cadence: float | None = None # rpm
avg_speed: float | None = None # kph
max_speed: float | None = None # kph
creator: str | None = None # device/app that recorded or wrote the file
notes: str | None = None


def _aggregate(
Expand Down
87 changes: 0 additions & 87 deletions src/activity_parser/output.py

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@
import pandas as pd
from garmin_fit_sdk import Decoder, Profile, Stream

from .derive import fill_activity
from .activity import Activity, fill_activity
from .exceptions import FitError
from .fit_fields import LAP_UNITS, RECORD_UNITS, SESSION_UNITS, convert_units, convert_units_mapping
from .output import Activity
from .postprocess import coerce_numeric_columns, index_by_time

if TYPE_CHECKING:
Expand Down
3 changes: 1 addition & 2 deletions src/activity_parser/parse_tcx_gpx.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@
import pandas as pd
from lxml import etree

from .derive import fill_activity
from .activity import Activity, fill_activity
from .exceptions import XmlError
from .output import Activity
from .postprocess import index_by_time
from .sports import normalize_sport
from .xml_fields import (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,63 @@

import pandas as pd

from .output import DEFAULT_LAP_COLUMNS, DEFAULT_RECORD_COLUMNS, Activity
from .parse_fit_file import parse_fit
from .activity import Activity
from .parse_fit import parse_fit
from .parse_tcx_gpx import parse_gpx, parse_tcx

DEFAULT_RECORD_COLUMNS: tuple[str, ...] = (
"latitude",
"longitude",
"altitude",
"distance",
"speed",
"cadence",
"heart_rate",
"power",
"left_balance",
"right_balance",
"accumulated_power",
"temperature",
"water_temperature",
"depth",
"course",
"bearing",
)

DEFAULT_LAP_COLUMNS: tuple[str, ...] = (
"start_time",
"total_elapsed_time",
"total_timer_time",
"start_position_lat",
"start_position_long",
"end_position_lat",
"end_position_long",
"total_distance",
"total_ascent",
"total_descent",
"avg_vam",
"avg_speed",
"max_speed",
"avg_cadence",
"max_cadence",
"total_strokes",
"steps",
"avg_heart_rate",
"max_heart_rate",
"time_in_hr_zone",
"avg_power",
"max_power",
"normalized_power",
"left_balance",
"right_balance",
"time_in_power_zone",
"total_work",
"avg_temperature",
"max_temperature",
"total_calories",
"total_fat_calories",
)


def select_and_reorder_cols(
df: pd.DataFrame,
Expand Down
3 changes: 1 addition & 2 deletions tests/test_derive.py → tests/test_activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

import pandas as pd

from activity_parser.derive import fill_activity
from activity_parser.output import Activity
from activity_parser.activity import Activity, fill_activity
from activity_parser.parse_tcx_gpx import parse_tcx

FILES = Path(__file__).parent / "files"
Expand Down
2 changes: 1 addition & 1 deletion tests/test_parse_fit.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import synthetic_fit

from activity_parser import ActivityParser, FitError
from activity_parser.parse_fit_file import (
from activity_parser.parse_fit import (
LEFT_RIGHT_BALANCE_PERCENT_MASK,
LEFT_RIGHT_BALANCE_PERCENT_MASK_100,
LEFT_RIGHT_BALANCE_RIGHT_FLAG,
Expand Down
2 changes: 1 addition & 1 deletion tests/test_parse_activity.py → tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import pytest

from activity_parser import ActivityParser
from activity_parser.parse_activity import (
from activity_parser.parser import (
infer_extension,
normalize_extension,
select_and_reorder_cols,
Expand Down
3 changes: 2 additions & 1 deletion tests/test_readme.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from dataclasses import fields
from pathlib import Path

from activity_parser.output import DEFAULT_LAP_COLUMNS, DEFAULT_RECORD_COLUMNS, Activity
from activity_parser.activity import Activity
from activity_parser.parser import DEFAULT_LAP_COLUMNS, DEFAULT_RECORD_COLUMNS

README = Path(__file__).parent.parent / "README.md"
COLUMN_NAME = re.compile(r"`(\w+)`")
Expand Down