Skip to main content

A Python client for Habitify: manage habits, logs, completions, skips, and progress from code.

Project description

habitipie

Coverage

A typed Python client for Habitify API v2.

habitipie gives you a clean, typed way to bring Habitify into Python scripts, automation, dashboards, and internal tools.

Instead of stitching together raw HTTP calls, you get a resource-oriented client, predictable models, and an API surface that feels natural in Python from the first call.

If this project saves you time, consider starring the repository. It makes the project easier to discover and helps prioritize future work.

Highlights

  • Resource-style API: HabitipyClient(...).habits.list() and HabitipyClient(...).areas.list()
  • Typed request and response models powered by Pydantic
  • Native httpx transport with optional client injection
  • Explicit pagination objects for list endpoints
  • Mapped API errors for common HTTP failure cases

Why habitipie?

  • Build scripts and services around your Habitify data without hand-rolling API clients
  • Keep request and response handling strongly typed instead of passing unstructured payloads
  • Start simple with the built-in client or plug into an existing httpx.Client
  • Stay close to the Habitify API while keeping the calling code pleasant to read

Installation

habitipie supports Python 3.10 through 3.13.

pip install habitipie

Rename Notice

The PyPI distribution was renamed from habitipy to habitipie because the old distribution name was already taken.

This is an intentional breaking change:

  • install with pip install habitipie
  • import with from habitipie import HabitipyClient

Set your Habitify API key:

export HABITIFY_API_KEY="your-api-key"

Quick Start

import os

from habitipie import HabitipyClient

with HabitipyClient(api_key=os.environ["HABITIFY_API_KEY"]) as client:
    habits = client.habits.list(limit=10)
    for habit in habits.data:
        print(habit.name)

    areas = client.areas.list()
    for area in areas:
        print(area.name)

Resource API

Create a client and work through the habits and areas resources:

from habitipie import HabitipyClient

with HabitipyClient(api_key="YOUR_API_KEY") as client:
    page = client.habits.list(limit=25)
    for habit in page.data:
        print(habit.name)

    areas = client.areas.list()
    print(len(areas))

    journal_entries = client.habits.journal()
    print(journal_entries[0].status)

    stats = client.habits.statistics("habit-id")
    print(stats.total_logs)

If you already manage your own httpx.Client, you can inject it. HabitipyClient adds the X-API-Key header and default Habitify base URL when they are missing:

import httpx

from habitipie import HabitipyClient

with httpx.Client() as http_client:
    client = HabitipyClient(api_key="YOUR_API_KEY", client=http_client)
    page = client.habits.list(limit=25)

When you inject your own httpx.Client, HabitipyClient.close() does not close it for you.

Typed Results

List endpoints keep pagination metadata. For example, client.habits.list() returns a HabitListPage with .data and .pagination.

Single-resource and non-paginated endpoints are unwrapped for convenience:

  • client.habits.get(...) -> Habit
  • client.habits.journal(...) -> list[HabitJournalEntry]
  • client.habits.list_notes(...) -> list[HabitNote]
  • client.habits.statistics(...) -> HabitStatistics
  • client.areas.list() -> list[Area]

Write calls accept dedicated request models:

from habitipie import HabitLogRequest, HabitNoteCreateRequest, UnitSymbol

with HabitipyClient(api_key="YOUR_API_KEY") as client:
    client.habits.create_log(
        "habit-id",
        HabitLogRequest(unit_symbol=UnitSymbol.KM, value=5),
    )

    note = client.habits.create_note(
        "habit-id",
        HabitNoteCreateRequest(content="Solid run today"),
    )
    print(note.id)

Error Handling

HTTP status errors are mapped onto typed exceptions:

  • AuthenticationError for 401
  • NotFoundError for 404
  • RateLimitError for 429
  • ServerError for 5xx
  • ApiError for other non-success responses

Malformed JSON or unexpected top-level payloads raise ResponseDecodeError and UnexpectedResponseShapeError.

Development

Use Poetry for local development:

poetry install --extras dev
poetry run pre-commit install

Run the full local quality pass before finishing Python changes:

poetry run isort habitipie tests
poetry run black habitipie tests
poetry run ruff check habitipie tests
poetry run mypy habitipie

Or use the dedicated tox environment:

poetry run tox run -e quality

Pre-commit is configured for the same quality stack:

poetry run pre-commit run --all-files

Run a focused test slice:

poetry run pytest tests/test_habits.py

Generate coverage locally:

poetry run pytest --cov=habitipie --cov-report=term-missing

Run the declared Python support matrix with tox:

poetry run tox run -e py310,py311,py312,py313

CI

GitHub Actions runs the same quality and test commands on pull requests and on pushes to main:

  • poetry run tox run -e quality
  • poetry run tox run -e py310,py311,py312,py313
  • poetry run pytest --cov=habitipie --cov-report=xml

Coverage reports are uploaded to Codecov from the Coverage job. The workflow uses OIDC and also passes CODECOV_TOKEN, so repositories that require the token can use the same workflow without further changes.

Release

Pushing a version tag triggers the Release GitHub Actions workflow, which runs quality checks, the test matrix, builds the distributions, and publishes them to PyPI.

Before tagging a release:

  • update version in pyproject.toml
  • make sure the pypi GitHub environment and PyPI trusted publishing are configured

Create and push a release tag whose name matches v<version>:

git tag v0.1.0
git push origin v0.1.0

The workflow verifies that the tag matches pyproject.toml before publishing.

Project details


Download files

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

Source Distribution

habitipie-0.1.0.tar.gz (16.2 kB view details)

Uploaded Source

Built Distribution

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

habitipie-0.1.0-py3-none-any.whl (17.9 kB view details)

Uploaded Python 3

File details

Details for the file habitipie-0.1.0.tar.gz.

File metadata

  • Download URL: habitipie-0.1.0.tar.gz
  • Upload date:
  • Size: 16.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for habitipie-0.1.0.tar.gz
Algorithm Hash digest
SHA256 0d3119def9475d3de2a4bbec0ecc144db7de329a198ebfc019f2c11ed9f16de1
MD5 9e9169004c860b6122f86495fb180148
BLAKE2b-256 6e032668be5038d6a29a8c2484db0bf196808a0f229f03d5363ed0ca638dc89a

See more details on using hashes here.

Provenance

The following attestation bundles were made for habitipie-0.1.0.tar.gz:

Publisher: release.yml on ReiRev/habitipie

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

File details

Details for the file habitipie-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: habitipie-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 17.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for habitipie-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 104b3e8b29a00c506ffe1ab19cf5a0a6a7f895f8e90f640e0679292f97e7addd
MD5 316c43d37fe9c635976b54f2fa66fb1b
BLAKE2b-256 60fc3603483323b6fffe77c5e9ae2162cdfc275ac7fb0cdc35f37de4ba7665cd

See more details on using hashes here.

Provenance

The following attestation bundles were made for habitipie-0.1.0-py3-none-any.whl:

Publisher: release.yml on ReiRev/habitipie

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

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page