Skip to content

Conversation

vactomas
Copy link

@vactomas vactomas commented Jun 20, 2025

Hi, matin,
I have added an option to pull daily summary for a user as I believe it is nice to have simple overview available directly.

I wasn't sure if it belongs in data or stats, but given the format of the request, I have chosen the data directory as the best possible place.

Please, let me know if there is anything else that needs to be done.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features
    • Introduced a new daily health summary feature, allowing users to access a comprehensive overview of daily metrics such as calories, steps, heart rate, stress, activity, and more.
  • Tests
    • Added tests to verify fetching and listing of daily health summaries for specific dates and date ranges.
  • Documentation
    • Added detailed usage instructions and examples for retrieving daily summary data in the README.

Copy link
Contributor

coderabbitai bot commented Jun 20, 2025

"""

Walkthrough

A new DailySummary data class has been introduced to encapsulate daily health metrics. This class is now imported and exported in the relevant __init__.py files, making it part of the public API. The DailySummary class includes a method for fetching daily summary data from an external API.

Changes

File(s) Change Summary
src/garth/data/daily_summary.py Added new DailySummary data class with health metrics and a class method to fetch data from API.
src/garth/data/init.py Imported DailySummary and added it to __all__ for public export.
src/garth/init.py Imported DailySummary and included it in the package's __all__ list.
tests/data/test_daily_summary.py Added tests for DailySummary.get and listing daily summaries with HTTP interaction recording.
README.md Added "Daily Summary" section with usage examples and sample output for the new DailySummary API.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant DailySummary
    participant http.Client
    participant API

    User->>DailySummary: DailySummary.get(day, client)
    DailySummary->>http.Client: get("/wellness/dailySummary", params=day)
    http.Client->>API: HTTP GET /wellness/dailySummary?date=day
    API-->>http.Client: Response (daily summary data)
    http.Client-->>DailySummary: Response data
    DailySummary->>DailySummary: Convert keys, validate, instantiate object
    DailySummary-->>User: DailySummary instance or None
Loading

Suggested reviewers

  • matin
    """
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Post Copyable Unit Tests in Comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
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: 1

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c1bdee8 and 6833870.

📒 Files selected for processing (3)
  • src/garth/__init__.py (2 hunks)
  • src/garth/data/__init__.py (2 hunks)
  • src/garth/data/daily_summary.py (1 hunks)
🧰 Additional context used
🪛 Pylint (3.3.7)
src/garth/data/daily_summary.py

[refactor] 12-12: Too many instance attributes (27/7)

(R0902)

🔇 Additional comments (4)
src/garth/data/__init__.py (1)

6-6: LGTM! Proper API exposure.

The changes correctly add DailySummary to the module's public API following established patterns for other data classes.

Also applies to: 19-19

src/garth/__init__.py (1)

1-7: LGTM! Clean package-level integration.

The changes properly integrate DailySummary into the main package API with improved import formatting and correct alphabetical ordering in __all__.

Also applies to: 34-34

src/garth/data/daily_summary.py (2)

1-8: LGTM! Well-organized imports.

Import statements follow Python conventions with proper separation of standard library, third-party, and local imports.


11-40: Data class design is appropriate despite many fields.

While static analysis flags 27 instance attributes as excessive, this is justified for a comprehensive daily health summary data class. All fields represent distinct health metrics that logically belong together, and the optional nature accommodates varying data availability from fitness devices.

Comment on lines +41 to +56
@classmethod
def get(
cls, day: date | str, *, client: http.Client | None = None
) -> Self | None:
client = client or http.client
path = f"/usersummary-service/usersummary/daily/?calendarDate={day}"
daily_summary = client.connectapi(path)
if not daily_summary:
return None
daily_summary = camel_to_snake_dict(daily_summary)
assert isinstance(daily_summary, dict)
return cls(**daily_summary)
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling and input validation.

The method has several areas for improvement:

  1. Input validation: No validation for string date format
  2. Error handling: API failures aren't handled beyond checking data existence
  3. Assertion improvement: The assertion lacks context for debugging

Consider this improved implementation:

 @classmethod
 def get(
     cls, day: date | str, *, client: http.Client | None = None
 ) -> Self | None:
+    # Validate string date format if needed
+    if isinstance(day, str):
+        try:
+            # Attempt to parse to validate format
+            from datetime import datetime
+            datetime.strptime(str(day), '%Y-%m-%d')
+        except ValueError as e:
+            raise ValueError(f"Invalid date format '{day}'. Expected YYYY-MM-DD") from e
+    
     client = client or http.client
     path = f"/usersummary-service/usersummary/daily/?calendarDate={day}"
-    daily_summary = client.connectapi(path)
+    try:
+        daily_summary = client.connectapi(path)
+    except Exception as e:
+        # Log the error or handle appropriately based on your error handling strategy
+        raise RuntimeError(f"Failed to fetch daily summary for {day}") from e
+        
     if not daily_summary:
         return None
     daily_summary = camel_to_snake_dict(daily_summary)
-    assert isinstance(daily_summary, dict)
+    if not isinstance(daily_summary, dict):
+        raise ValueError(f"Expected dict from API, got {type(daily_summary)}")
     return cls(**daily_summary)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@classmethod
def get(
cls, day: date | str, *, client: http.Client | None = None
) -> Self | None:
client = client or http.client
path = f"/usersummary-service/usersummary/daily/?calendarDate={day}"
daily_summary = client.connectapi(path)
if not daily_summary:
return None
daily_summary = camel_to_snake_dict(daily_summary)
assert isinstance(daily_summary, dict)
return cls(**daily_summary)
@classmethod
def get(
cls, day: date | str, *, client: http.Client | None = None
) -> Self | None:
# Validate string date format if needed
if isinstance(day, str):
try:
# Attempt to parse to validate format
from datetime import datetime
datetime.strptime(str(day), '%Y-%m-%d')
except ValueError as e:
raise ValueError(f"Invalid date format '{day}'. Expected YYYY-MM-DD") from e
client = client or http.client
path = f"/usersummary-service/usersummary/daily/?calendarDate={day}"
try:
daily_summary = client.connectapi(path)
except Exception as e:
# Log the error or handle appropriately based on your error handling strategy
raise RuntimeError(f"Failed to fetch daily summary for {day}") from e
if not daily_summary:
return None
daily_summary = camel_to_snake_dict(daily_summary)
if not isinstance(daily_summary, dict):
raise ValueError(f"Expected dict from API, got {type(daily_summary)}")
return cls(**daily_summary)
🤖 Prompt for AI Agents
In src/garth/data/daily_summary.py lines 41 to 52, improve the get method by
adding validation to ensure the day parameter, if a string, matches the expected
date format before using it. Enhance error handling by catching exceptions from
the client.connectapi call and handling them gracefully instead of only checking
for falsy data. Replace the bare assertion with a conditional check that raises
a descriptive error if daily_summary is not a dictionary, providing context for
debugging. These changes will make the method more robust and easier to
troubleshoot.

Copy link
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)
tests/data/test_daily_summary.py (1)

9-27: Consider adding edge case tests and error handling validation.

While the current tests cover the happy path well, consider adding tests for:

  • Invalid date formats
  • Network error scenarios
  • Empty result sets
  • Boundary conditions (e.g., days=0 in list method)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6833870 and bb93746.

📒 Files selected for processing (1)
  • tests/data/test_daily_summary.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`tests/**`: - test functions shouldn't have a return type hint - it's ok to use `assert` instead of `pytest.assume()`

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

  • it's ok to use assert instead of pytest.assume()
  • tests/data/test_daily_summary.py
🔇 Additional comments (3)
tests/data/test_daily_summary.py (3)

1-6: Imports look good and follow conventions.

The imports are well-organized and appropriate for the test functionality.


19-27: Test implementation looks solid with good coverage.

The test effectively validates the list functionality with appropriate assertions for both count and date verification. The max_workers=1 parameter is a good practice for deterministic testing.


10-16: I’ll inspect the tests for DailySummary.list usage and then check the base Data class where list is likely defined:

#!/usr/bin/env bash
set -e

# Show tests for DailySummary
echo "--- tests/data/test_daily_summary.py ---"
sed -n '1,200p' tests/data/test_daily_summary.py

# Locate the file defining the base Data class
data_file=$(rg -l "class Data" -n src/garth/data)
echo "Data class implemented in: $data_file"

# Show the Data class definition context
echo -e "\n--- Data class definition ---"
rg -n -A5 "class Data" "$data_file"

# Show list() and get() signatures in Data
echo -e "\n--- Data.list() signature ---"
rg -n -C2 "def list" "$data_file"

echo -e "\n--- Data.get() signature ---"
rg -n -C2 "def get" "$data_file"

@vactomas vactomas force-pushed the feature/daily-summary branch from bb93746 to d0aab1f Compare June 20, 2025 16:29
@matin
Copy link
Owner

matin commented Jun 22, 2025

@vactomas this is a good feature to add. ci is failing. could you check the tests?

@vactomas
Copy link
Author

vactomas commented Jun 22, 2025

I see the problem, I have not generated VCR cassettes. I have a question, do I just run the tests against my account or is there some other way?

I have locally temporarily set vcr record_mode to once, but it fails with 401 not authorized error on the tests I ran. I presume this is due to the sanitized tokens in conftest.py.

@vactomas vactomas force-pushed the feature/daily-summary branch from d0aab1f to 3d14c9c Compare June 22, 2025 09:54
Copy link
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

♻️ Duplicate comments (1)
src/garth/data/daily_summary.py (1)

45-56: Address the unresolved issues from previous review.

The issues identified in the previous review regarding error handling and input validation remain unaddressed. As mentioned in the past review comments, this method needs:

  1. Input validation for string date format
  2. Proper error handling for API failures
  3. Descriptive error messages instead of bare assertions
🧹 Nitpick comments (1)
README.md (1)

910-910: Fix missing article for better readability.

-Retrieve user's daily summary for given date.
+Retrieve user's daily summary for a given date.
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d0aab1f and 3d14c9c.

📒 Files selected for processing (5)
  • README.md (1 hunks)
  • src/garth/__init__.py (2 hunks)
  • src/garth/data/__init__.py (2 hunks)
  • src/garth/data/daily_summary.py (1 hunks)
  • tests/data/test_daily_summary.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/garth/init.py
  • src/garth/data/init.py
  • tests/data/test_daily_summary.py
🧰 Additional context used
🪛 LanguageTool
README.md

[uncategorized] ~910-~910: Possible missing article found.
Context: ...mary Retrieve user's daily summary for given date. ```python garth.DailySummary.get...

(AI_HYDRA_LEO_MISSING_A)

🪛 Pylint (3.3.7)
src/garth/data/daily_summary.py

[refactor] 12-12: Too many instance attributes (31/7)

(R0902)

🔇 Additional comments (2)
src/garth/data/daily_summary.py (1)

11-43: Well-structured data class for comprehensive health metrics.

The DailySummary dataclass effectively models the extensive daily health data from Garmin Connect. The use of optional fields with None defaults is appropriate since not all metrics may be available for every day.

README.md (1)

908-1027: Excellent documentation following established patterns.

The new "Daily Summary" section provides clear usage examples and comprehensive sample output that will help users understand the available metrics. The documentation structure is consistent with other sections in the README.

@matin
Copy link
Owner

matin commented Jun 22, 2025

you have to log in, save your tokens and set the GARTH_HOME env bar.

to generate the cassettes, this'll let you generate the tests against your account. all sensitive info should be masked, but i recommend double checking to cassettes before committing them

@vactomas
Copy link
Author

I see, thanks. I have some trouble getting it to work, but I'll again later. Hopefully, I can get it to cooperate and get the cassettes ready

@vactomas vactomas force-pushed the feature/daily-summary branch from 3d14c9c to 65d9bd4 Compare June 26, 2025 19:16
@vactomas vactomas force-pushed the feature/daily-summary branch from 65d9bd4 to 4cb66bf Compare June 26, 2025 19:18
@vactomas
Copy link
Author

I have managed to get these cassettes to work locally. Hopefully, it will work even in CI

Copy link
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

♻️ Duplicate comments (1)
src/garth/data/daily_summary.py (1)

45-56: Duplicate: Error handling and input validation improvements needed.

The error handling and input validation concerns raised in the previous review are still applicable to this implementation. The method would benefit from:

  1. Input validation for string date format
  2. Proper error handling around the API call
  3. Replacing the bare assertion with a descriptive error
🧹 Nitpick comments (1)
README.md (1)

910-910: Fix grammatical issue: missing article.

The phrase "for given date" should include an article.

-Retrieve user's daily summary for given date.
+Retrieve user's daily summary for a given date.
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d14c9c and 4cb66bf.

⛔ Files ignored due to path filters (2)
  • tests/data/cassettes/test_daily_summary_get.yaml is excluded by !tests/**/cassettes/**
  • tests/data/cassettes/test_daily_summary_list.yaml is excluded by !tests/**/cassettes/**
📒 Files selected for processing (5)
  • README.md (1 hunks)
  • src/garth/__init__.py (2 hunks)
  • src/garth/data/__init__.py (2 hunks)
  • src/garth/data/daily_summary.py (1 hunks)
  • tests/data/test_daily_summary.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/garth/init.py
  • tests/data/test_daily_summary.py
  • src/garth/data/init.py
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/garth/data/daily_summary.py (3)
src/garth/utils.py (1)
  • camel_to_snake_dict (17-33)
src/garth/data/_base.py (1)
  • Data (15-47)
src/garth/http.py (2)
  • Client (19-244)
  • connectapi (186-192)
🪛 LanguageTool
README.md

[uncategorized] ~910-~910: Possible missing article found.
Context: ...mary Retrieve user's daily summary for given date. ```python garth.DailySummary.get...

(AI_HYDRA_LEO_MISSING_A)

🪛 Pylint (3.3.7)
src/garth/data/daily_summary.py

[refactor] 12-12: Too many instance attributes (31/7)

(R0902)

🔇 Additional comments (3)
README.md (1)

908-1027: Excellent documentation for the new Daily Summary feature.

The documentation follows the established pattern and provides comprehensive examples with clear sample output. The code examples demonstrate both single date retrieval and date range functionality effectively.

src/garth/data/daily_summary.py (2)

11-43: Well-structured data class for comprehensive health metrics.

The DailySummary class appropriately captures a wide range of daily health metrics with proper type annotations. While Pylint flags the high number of attributes (31), this is reasonable and expected for a comprehensive daily health summary that consolidates various health metrics into a single data structure.


1-8: Clean and appropriate imports.

The imports are well-organized and include all necessary dependencies for the implementation.

Copy link

codecov bot commented Jun 26, 2025

Codecov Report

❌ Patch coverage is 98.50746% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 99.94%. Comparing base (4b027e1) to head (4cb66bf).

Files with missing lines Patch % Lines
src/garth/data/daily_summary.py 97.95% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##              main     #132      +/-   ##
===========================================
- Coverage   100.00%   99.94%   -0.06%     
===========================================
  Files           45       47       +2     
  Lines         1898     1965      +67     
===========================================
+ Hits          1898     1964      +66     
- Misses           0        1       +1     
Flag Coverage Δ
unittests 99.94% <98.50%> (-0.06%) ⬇️

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.

@vactomas
Copy link
Author

vactomas commented Jul 5, 2025

I looked at the test coverage issue. There is a problem with the part:

if not daily_summary:
  return None

That said, if we try to pull a summary from time when the account wasn't used or has no data, it will still return non-empty return, but every single key is marked as None essentially.

I believe the best way to solve this is to drop the if condition completely. What are your thoughts @matin? Also, is there anything else that needs to be solved?

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.

2 participants