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
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Development:
- Pull requests should only be merged when CI passes.
- Commits should be small and complete.
- Don't reference Claude or Anthropic in commit messages.
- Tests and lint should pass before committing.
- Tests and lint (ruff, ty) should pass before committing.
- Never use `git push --force`. Use `--force-with-lease` instead.
- Strive for total behavioral coverage, but 100% structural coverage isn't
worthwhile.
Expand Down
7 changes: 5 additions & 2 deletions custom_components/consumable_tracker/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
from __future__ import annotations

from datetime import date
from typing import TYPE_CHECKING

from homeassistant.components.button import ButtonEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback

if TYPE_CHECKING:
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .const import (
CONF_CONSUMABLE_NAME,
Expand Down
46 changes: 38 additions & 8 deletions custom_components/consumable_tracker/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@

from __future__ import annotations

from typing import TYPE_CHECKING

import voluptuous as vol
from homeassistant import config_entries
from homeassistant.core import callback

if TYPE_CHECKING:
from typing import Any

from homeassistant.config_entries import ConfigFlowResult

from .const import (
CONF_CONSUMABLE_NAME,
CONF_CONSUMABLES,
Expand Down Expand Up @@ -54,7 +61,10 @@ def __init__(self) -> None:
self.device_name: str | None = None
self.consumables: list[dict[str, object]] = []

async def async_step_user(self, user_input=None):
async def async_step_user(
self,
user_input: dict[str, Any] | None = None,
) -> ConfigFlowResult:
"""Handle the initial step - device name."""
errors = {}

Expand All @@ -77,7 +87,10 @@ async def async_step_user(self, user_input=None):
},
)

async def async_step_add_consumable(self, user_input=None):
async def async_step_add_consumable(
self,
user_input: dict[str, Any] | None = None,
) -> ConfigFlowResult:
"""Handle adding a consumable."""
errors: dict[str, str] = {}

Expand Down Expand Up @@ -134,7 +147,9 @@ async def async_step_add_consumable(self, user_input=None):

@staticmethod
@callback
def async_get_options_flow(config_entry):
def async_get_options_flow(
config_entry: config_entries.ConfigEntry,
) -> ConsumableTrackerOptionsFlow:
"""Get the options flow for this handler."""
return ConsumableTrackerOptionsFlow(config_entry)

Expand All @@ -150,7 +165,10 @@ def __init__(self, config_entry: config_entries.ConfigEntry) -> None:
)
self.editing_index: int | None = None

async def async_step_init(self, user_input=None):
async def async_step_init(
self,
user_input: dict[str, Any] | None = None,
) -> ConfigFlowResult:
"""Manage the options - choose what to do."""
if user_input is not None:
action = user_input.get("action")
Expand Down Expand Up @@ -199,7 +217,10 @@ async def async_step_init(self, user_input=None):
},
)

async def async_step_add_consumable(self, user_input=None):
async def async_step_add_consumable(
self,
user_input: dict[str, Any] | None = None,
) -> ConfigFlowResult:
"""Add a new consumable."""
errors: dict[str, str] = {}

Expand Down Expand Up @@ -229,7 +250,10 @@ async def async_step_add_consumable(self, user_input=None):
step_id="add_consumable", data_schema=data_schema, errors=errors
)

async def async_step_select_consumable(self, user_input=None):
async def async_step_select_consumable(
self,
user_input: dict[str, Any] | None = None,
) -> ConfigFlowResult:
"""Select which consumable to edit."""
if user_input is not None:
self.editing_index = int(user_input["consumable"])
Expand All @@ -244,7 +268,10 @@ async def async_step_select_consumable(self, user_input=None):
data_schema=vol.Schema({vol.Required("consumable"): vol.In(choices)}),
)

async def async_step_edit_consumable(self, user_input=None):
async def async_step_edit_consumable(
self,
user_input: dict[str, Any] | None = None,
) -> ConfigFlowResult:
"""Edit the selected consumable."""
errors: dict[str, str] = {}
assert self.editing_index is not None
Expand Down Expand Up @@ -289,7 +316,10 @@ async def async_step_edit_consumable(self, user_input=None):
step_id="edit_consumable", data_schema=data_schema, errors=errors
)

async def async_step_delete_consumable(self, user_input=None):
async def async_step_delete_consumable(
self,
user_input: dict[str, Any] | None = None,
) -> ConfigFlowResult:
"""Delete a consumable."""
if user_input is not None:
index = int(user_input["consumable"])
Expand Down
7 changes: 5 additions & 2 deletions custom_components/consumable_tracker/date.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
from __future__ import annotations

from datetime import date
from typing import TYPE_CHECKING

from homeassistant.components.date import DateEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.restore_state import RestoreEntity

if TYPE_CHECKING:
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .const import (
CONF_CONSUMABLE_NAME,
CONF_CONSUMABLES,
Expand Down
14 changes: 8 additions & 6 deletions custom_components/consumable_tracker/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@
from __future__ import annotations

from datetime import date, datetime, timedelta
from typing import TYPE_CHECKING

from homeassistant.components.sensor import SensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import Event, HomeAssistant, callback
from homeassistant.core import callback
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import (
EventStateChangedData,
async_track_state_change_event,
)
from homeassistant.helpers.event import async_track_state_change_event

if TYPE_CHECKING:
from homeassistant.core import Event, HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import EventStateChangedData

from .const import (
CONF_CONSUMABLE_NAME,
Expand Down
6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ requires-python = ">=3.13.2"
[dependency-groups]
dev = [
"ruff>=0.9.4",
"ty>=0.0.8",
"ty>=0.0.10",
"pytest-homeassistant-custom-component>=0.13.0",
]

Expand All @@ -29,11 +29,15 @@ select = [
"C4", # flake8-comprehensions
"UP", # pyupgrade
"SIM", # flake8-simplify
"ANN", # flake8-annotations
]
ignore = [
"E501", # line too long (handled by formatter)
]

[tool.ruff.lint.per-file-ignores]
"tests/*" = ["ANN"] # Don't require annotations in tests

[tool.ruff.lint.isort]
known-first-party = ["custom_components.consumable_tracker"]

Expand Down
43 changes: 21 additions & 22 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.