Skip to content

Add FitnessActivity for training plan from coach#173

Merged
matin merged 2 commits intomainfrom
add-fitness-activity
Jan 12, 2026
Merged

Add FitnessActivity for training plan from coach#173
matin merged 2 commits intomainfrom
add-fitness-activity

Conversation

@matin
Copy link
Copy Markdown
Owner

@matin matin commented Jan 12, 2026

Summary

  • Adds FitnessActivity class to retrieve activities with adaptive coaching metadata
  • Uses /fitnessstats-service/activity/all endpoint
  • Includes workout type, coaching status, and training effects

Closes #162

Test plan

  • Added test for list() method
  • All 120 tests pass

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added FitnessActivity type to access fitness activity data with adaptive coaching metadata and coaching status information.
  • Documentation

    • Added comprehensive guide for retrieving and filtering fitness activities with adaptive coaching details, including coaching status values and practical usage examples.

✏️ Tip: You can customize this high-level summary in your review settings.

Adds FitnessActivity class to retrieve activities with adaptive coaching
metadata from the fitness stats service. This includes:
- workout_type (e.g., ADAPTIVE_COACHING)
- adaptive_coaching_workout_status (e.g., COMPLETED_VIA_ACTIVITY)
- aerobic_training_effect
- workout_group_enumerator

Closes #162

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 12, 2026

Walkthrough

This change introduces a new FitnessActivity data model to represent fitness activities with adaptive coaching information. It adds a list() classmethod to fetch activities from the fitness stats service, exposes the model through the public API layers, documents the functionality with examples, and includes test coverage validating the implementation.

Changes

Cohort / File(s) Summary
Documentation
docs/api/data.md
Adds "Fitness Activity (Adaptive Coaching)" section with API endpoint description, list() example output showing sample activities and fields, filtering code snippet, and coaching status enum values. Content appears duplicated in the file.
Public API Exports
src/garth/__init__.py, src/garth/data/__init__.py
Exposes FitnessActivity as a public symbol by importing from fitness_stats module and adding to __all__ lists at both package levels.
Core Implementation
src/garth/data/fitness_stats.py
Introduces FitnessActivity dataclass with fields for activity metadata (activity_id, start_local, activity_type, workout_type, adaptive_coaching_workout_status, etc.). Implements list() classmethod that queries /fitnessstats-service/activity/all endpoint, normalizes camelCase response keys to snake_case, instantiates objects, and returns sorted results.
Test Coverage
tests/data/test_fitness_stats.py
Adds test validating FitnessActivity.list() returns non-empty sorted list with valid activity properties and non-None coaching status when applicable. Uses VCR cassette for HTTP mocking.

Sequence Diagram

sequenceDiagram
    actor App as Application Code
    participant FA as FitnessActivity.list()
    participant Client as HTTP Client
    participant API as Fitness Stats Service
    participant Parser as Data Normalizer

    App->>FA: list(end, days, client)
    FA->>FA: Construct date range
    FA->>Client: GET /fitnessstats-service/activity/all
    Client->>API: HTTP Request with metrics
    API-->>Client: JSON Response (camelCase)
    Client-->>FA: Response data
    FA->>Parser: camel_to_snake_dict()
    Parser-->>FA: Normalized dict (snake_case)
    FA->>FA: Instantiate FitnessActivity objects
    FA->>FA: Sort by start_local
    FA-->>App: list[FitnessActivity]
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR introduces a documentation duplication issue where the 'Fitness Activity (Adaptive Coaching)' section is repeated twice in docs/api/data.md, which exceeds the scope of the stated objective to add FitnessActivity for training plans. Remove the duplicate 'Fitness Activity (Adaptive Coaching)' section from docs/api/data.md to eliminate redundant documentation content.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add FitnessActivity for training plan from coach' directly and clearly summarizes the main change: adding a FitnessActivity class to support training plan access from the adaptive coaching system.
Linked Issues check ✅ Passed The PR successfully implements the objective from issue #162 by adding FitnessActivity class with methods to retrieve activities and adaptive coaching metadata (workout_type, coaching_status, training_effects) from the fitness stats service.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch add-fitness-activity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (4a95ce1) to head (4ee4cc1).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main      #173   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           64        66    +2     
  Lines         2970      3020   +50     
=========================================
+ Hits          2970      3020   +50     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/garth/data/fitness_stats.py (1)

74-76: Consider replacing assert with explicit exception for runtime validation.

Using assert for validating API responses is fragile because assertions can be disabled globally with python -O. If the API unexpectedly returns a non-list (e.g., error dict), this check would be silently skipped in optimized mode.

♻️ Suggested fix
         data = client.connectapi(path, params=params)
-        assert isinstance(data, list), (
-            f"Expected list from {path}, got {type(data).__name__}"
-        )
+        if not isinstance(data, list):
+            raise TypeError(
+                f"Expected list from {path}, got {type(data).__name__}"
+            )
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a95ce1 and 4ee4cc1.

⛔ Files ignored due to path filters (1)
  • tests/data/cassettes/test_fitness_activity_list.yaml is excluded by !tests/**/cassettes/**
📒 Files selected for processing (5)
  • docs/api/data.md
  • src/garth/__init__.py
  • src/garth/data/__init__.py
  • src/garth/data/fitness_stats.py
  • tests/data/test_fitness_stats.py
🧰 Additional context used
📓 Path-based instructions (2)
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use pytest with VCR cassettes for HTTP recording/playback in tests
Mirror test directory structure to match source code structure

Files:

  • tests/data/test_fitness_stats.py
tests/**

⚙️ CodeRabbit configuration file

tests/**: - test functions shouldn't have a return type hint

  • it's ok to use assert instead of pytest.assume()

Files:

  • tests/data/test_fitness_stats.py
🧠 Learnings (1)
📚 Learning: 2026-01-09T22:41:07.978Z
Learnt from: CR
Repo: matin/garth PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T22:41:07.978Z
Learning: Use `data/` module for raw data retrieval from Garmin Connect API and `stats/` module for processed statistics and aggregated data

Applied to files:

  • src/garth/data/__init__.py
  • src/garth/__init__.py
🧬 Code graph analysis (4)
src/garth/data/__init__.py (1)
src/garth/data/fitness_stats.py (1)
  • FitnessActivity (14-83)
tests/data/test_fitness_stats.py (1)
src/garth/data/fitness_stats.py (1)
  • FitnessActivity (14-83)
src/garth/__init__.py (1)
src/garth/data/fitness_stats.py (1)
  • FitnessActivity (14-83)
src/garth/data/fitness_stats.py (3)
src/garth/utils.py (2)
  • camel_to_snake_dict (17-33)
  • format_end_date (66-71)
tests/conftest.py (1)
  • client (21-22)
src/garth/http.py (2)
  • Client (19-245)
  • connectapi (186-192)
🔇 Additional comments (8)
src/garth/data/fitness_stats.py (3)

1-11: LGTM - Clean imports and utility usage.

The imports are well-organized and the use of existing utilities (camel_to_snake_dict, format_end_date) promotes code reuse. Based on learnings, placing this in data/ module is correct for raw data retrieval from Garmin Connect API.


13-35: LGTM - Well-structured dataclass with clear documentation.

The dataclass fields align with the API response and the docstring provides a helpful usage example. Optional fields appropriately default to None.


78-81: No fix required—the API response contains only fields declared in the class.

The actual API response from the fitness stats service includes only the fields declared in FitnessActivity. After camel_to_snake_dict conversion, all response fields map exactly to class attributes (activityId → activity_id, startLocal → start_local, etc.), with no extra fields present. The test cassette confirms this pattern with real API data, so cls(**item) instantiation works as expected without raising TypeError.

src/garth/__init__.py (1)

8-8: LGTM - Proper public API exposure.

FitnessActivity is correctly imported and exported, maintaining alphabetical ordering consistent with the existing pattern.

Also applies to: 50-50

tests/data/test_fitness_stats.py (2)

1-7: LGTM - Imports and test setup follow project conventions.

The test file correctly uses pytest with VCR cassettes for HTTP recording/playback, as specified in the coding guidelines.


9-29: Good test coverage for the new functionality.

The test validates key behaviors: non-empty results, sorted ordering, required field presence, and coaching-specific fields. The @pytest.mark.vcr decorator and authed_client fixture usage follows project conventions.

One minor observation: line 29 only validates the first coaching activity's status. Consider validating all coaching activities if the VCR cassette contains multiple:

for activity in coaching:
    assert activity.adaptive_coaching_workout_status is not None
src/garth/data/__init__.py (1)

10-10: LGTM - Proper subpackage export.

FitnessActivity is correctly added to __all__ and imported from .fitness_stats, maintaining alphabetical order consistent with other exports.

Also applies to: 30-30

docs/api/data.md (1)

422-484: Well-documented new feature.

The documentation follows the existing pattern in the file, providing:

  • Clear description of the feature's purpose
  • Usage example with list() method
  • Sample output showing field values
  • Filtering example for coaching activities
  • Reference for coaching status enum values

@matin matin merged commit d1bd012 into main Jan 12, 2026
26 checks passed
@matin matin deleted the add-fitness-activity branch January 12, 2026 21:13
@matin matin mentioned this pull request Jan 12, 2026
19 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Training plan from coach

1 participant