Skip to content

[Proposal]: Split __init__.py (2957 lines) into domain modules #355

@sorlen008

Description

@sorlen008

Context

garminconnect/__init__.py has grown to 2,957 lines containing the entire Garmin class with 132 public methods. Navigating it is rough — finding a specific method means scrolling or grepping, and code review on PRs that touch multiple domains is harder than it needs to be.

I'd like to propose splitting the file along domain boundaries, while keeping the single Garmin class as the public API so this is 100% backward compatible.

Proposal

Move method groups into separate module files, then have Garmin compose them via inheritance (mixin pattern):

garminconnect/
├── __init__.py          # Garmin class (inherits mixins), exports (~300 lines)
├── client.py            # (unchanged — auth/transport)
├── exceptions.py        # (unchanged)
├── workout.py           # (unchanged)
├── fit.py               # (unchanged)
├── _validation.py       # (new) _validate_date_format, constants, helpers
└── _mixins/             # (new)
    ├── __init__.py
    ├── health.py        # HrV, stress, readiness, sleep, respiration, spo2, intensity
    ├── activity.py      # activities, steps, heart rates, training status/load
    ├── body.py          # body composition, weigh-ins, hydration, blood pressure
    ├── nutrition.py     # food, meals, nutrition settings
    ├── workouts.py      # workout CRUD, scheduling
    ├── devices.py       # devices, device settings, gear
    ├── badges.py        # earned/available/in_progress badges, challenges
    ├── social.py        # connections, personal records
    └── admin.py         # login, logout, connectapi wrappers, download

__init__.py would become:

from ._mixins.health import HealthMixin
from ._mixins.activity import ActivityMixin
# ... etc

class Garmin(
    AdminMixin,
    HealthMixin,
    ActivityMixin,
    BodyMixin,
    NutritionMixin,
    WorkoutMixin,
    DeviceMixin,
    BadgeMixin,
    SocialMixin,
):
    \"\"\"Main client, composed of domain mixins.\"\"\"

Each mixin file is ~200-400 lines and covers one area. Much easier to navigate, grep, and review.

What it doesn't change

  • Public API is identical. from garminconnect import Garmin still works, every method name and signature is preserved.
  • No behavior changes. This is pure mechanical refactoring — git log --follow still works because we're moving code, not rewriting it.
  • Tests don't change — they import garminconnect.Garmin and call methods. Same behavior.

Risks

  1. Diff size is large (~3000 lines moved across ~10 files). Hard to review for correctness.
  2. Git blame noise — tracing history of a specific method requires --follow.
  3. Potential ordering bugs if mixins accidentally override each other. Method names are all unique today, so this should be safe, but I'd add a test that enumerates all methods and asserts uniqueness.
  4. Imports get more complex_mixins/__init__.py needs to export everything cleanly.

Alternative: leave it alone

Honestly, 2957 lines is large but not unmanageable. If you prefer the monolithic style for grep-ability / context-retention, that's a totally valid choice and I'll drop it. I mostly wanted to raise it as an option since I've been touching the file a lot recently for other PRs (#351, #352, #353) and kept getting lost.

What I'm asking

Not asking for an immediate yes/no — just whether you're open to the idea in principle. If yes, I'd draft a single large refactor PR that you can review as one atomic change. If no, I'll leave it alone and focus on other contributions.

Thanks again for all the work on this library.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions