From 8c5c8ed1536f427c3f5ec6928bc205cb0a9a633b Mon Sep 17 00:00:00 2001 From: Michael <35783820+mib1185@users.noreply.github.com> Date: Fri, 21 May 2021 14:33:54 +0200 Subject: [PATCH] Add strict type annotations to fitbit (#50740) * add strict type annotations * cast json_load() * apply suggestions * move SCAN_INTERVAL back to platform file * apply suggestion * apply suggestion * apply suggestions * rename to PARENT_PLATFORM_SCHEMA --- .coveragerc | 2 +- .strict-typing | 1 + homeassistant/components/fitbit/const.py | 148 ++++++++++++ homeassistant/components/fitbit/sensor.py | 267 +++++++++------------- mypy.ini | 14 +- script/hassfest/mypy_config.py | 1 - 6 files changed, 264 insertions(+), 169 deletions(-) create mode 100644 homeassistant/components/fitbit/const.py diff --git a/.coveragerc b/.coveragerc index d4116e3ab46..227d932643c 100644 --- a/.coveragerc +++ b/.coveragerc @@ -309,7 +309,7 @@ omit = homeassistant/components/firmata/pin.py homeassistant/components/firmata/sensor.py homeassistant/components/firmata/switch.py - homeassistant/components/fitbit/sensor.py + homeassistant/components/fitbit/* homeassistant/components/fixer/sensor.py homeassistant/components/fleetgo/device_tracker.py homeassistant/components/flexit/climate.py diff --git a/.strict-typing b/.strict-typing index 1fbaaa39c30..4087f970e47 100644 --- a/.strict-typing +++ b/.strict-typing @@ -21,6 +21,7 @@ homeassistant.components.camera.* homeassistant.components.cover.* homeassistant.components.device_automation.* homeassistant.components.elgato.* +homeassistant.components.fitbit.* homeassistant.components.fritzbox.* homeassistant.components.frontend.* homeassistant.components.geo_location.* diff --git a/homeassistant/components/fitbit/const.py b/homeassistant/components/fitbit/const.py new file mode 100644 index 00000000000..e5891758f60 --- /dev/null +++ b/homeassistant/components/fitbit/const.py @@ -0,0 +1,148 @@ +"""Constants for the Fitbit platform.""" +from __future__ import annotations + +from typing import Final + +from homeassistant.const import ( + CONF_CLIENT_ID, + CONF_CLIENT_SECRET, + LENGTH_FEET, + MASS_KILOGRAMS, + MASS_MILLIGRAMS, + PERCENTAGE, + TIME_MILLISECONDS, + TIME_MINUTES, +) + +ATTR_ACCESS_TOKEN: Final = "access_token" +ATTR_REFRESH_TOKEN: Final = "refresh_token" +ATTR_LAST_SAVED_AT: Final = "last_saved_at" + +ATTR_DURATION: Final = "duration" +ATTR_DISTANCE: Final = "distance" +ATTR_ELEVATION: Final = "elevation" +ATTR_HEIGHT: Final = "height" +ATTR_WEIGHT: Final = "weight" +ATTR_BODY: Final = "body" +ATTR_LIQUIDS: Final = "liquids" +ATTR_BLOOD_GLUCOSE: Final = "blood glucose" +ATTR_BATTERY: Final = "battery" + +CONF_MONITORED_RESOURCES: Final = "monitored_resources" +CONF_CLOCK_FORMAT: Final = "clock_format" +ATTRIBUTION: Final = "Data provided by Fitbit.com" + +FITBIT_AUTH_CALLBACK_PATH: Final = "/api/fitbit/callback" +FITBIT_AUTH_START: Final = "/api/fitbit" +FITBIT_CONFIG_FILE: Final = "fitbit.conf" +FITBIT_DEFAULT_RESOURCES: Final[list[str]] = ["activities/steps"] + +DEFAULT_CONFIG: Final[dict[str, str]] = { + CONF_CLIENT_ID: "CLIENT_ID_HERE", + CONF_CLIENT_SECRET: "CLIENT_SECRET_HERE", +} +DEFAULT_CLOCK_FORMAT: Final = "24H" + +FITBIT_RESOURCES_LIST: Final[dict[str, tuple[str, str | None, str]]] = { + "activities/activityCalories": ("Activity Calories", "cal", "fire"), + "activities/calories": ("Calories", "cal", "fire"), + "activities/caloriesBMR": ("Calories BMR", "cal", "fire"), + "activities/distance": ("Distance", "", "map-marker"), + "activities/elevation": ("Elevation", "", "walk"), + "activities/floors": ("Floors", "floors", "walk"), + "activities/heart": ("Resting Heart Rate", "bpm", "heart-pulse"), + "activities/minutesFairlyActive": ("Minutes Fairly Active", TIME_MINUTES, "walk"), + "activities/minutesLightlyActive": ("Minutes Lightly Active", TIME_MINUTES, "walk"), + "activities/minutesSedentary": ( + "Minutes Sedentary", + TIME_MINUTES, + "seat-recline-normal", + ), + "activities/minutesVeryActive": ("Minutes Very Active", TIME_MINUTES, "run"), + "activities/steps": ("Steps", "steps", "walk"), + "activities/tracker/activityCalories": ("Tracker Activity Calories", "cal", "fire"), + "activities/tracker/calories": ("Tracker Calories", "cal", "fire"), + "activities/tracker/distance": ("Tracker Distance", "", "map-marker"), + "activities/tracker/elevation": ("Tracker Elevation", "", "walk"), + "activities/tracker/floors": ("Tracker Floors", "floors", "walk"), + "activities/tracker/minutesFairlyActive": ( + "Tracker Minutes Fairly Active", + TIME_MINUTES, + "walk", + ), + "activities/tracker/minutesLightlyActive": ( + "Tracker Minutes Lightly Active", + TIME_MINUTES, + "walk", + ), + "activities/tracker/minutesSedentary": ( + "Tracker Minutes Sedentary", + TIME_MINUTES, + "seat-recline-normal", + ), + "activities/tracker/minutesVeryActive": ( + "Tracker Minutes Very Active", + TIME_MINUTES, + "run", + ), + "activities/tracker/steps": ("Tracker Steps", "steps", "walk"), + "body/bmi": ("BMI", "BMI", "human"), + "body/fat": ("Body Fat", PERCENTAGE, "human"), + "body/weight": ("Weight", "", "human"), + "devices/battery": ("Battery", None, "battery"), + "sleep/awakeningsCount": ("Awakenings Count", "times awaken", "sleep"), + "sleep/efficiency": ("Sleep Efficiency", PERCENTAGE, "sleep"), + "sleep/minutesAfterWakeup": ("Minutes After Wakeup", TIME_MINUTES, "sleep"), + "sleep/minutesAsleep": ("Sleep Minutes Asleep", TIME_MINUTES, "sleep"), + "sleep/minutesAwake": ("Sleep Minutes Awake", TIME_MINUTES, "sleep"), + "sleep/minutesToFallAsleep": ( + "Sleep Minutes to Fall Asleep", + TIME_MINUTES, + "sleep", + ), + "sleep/startTime": ("Sleep Start Time", None, "clock"), + "sleep/timeInBed": ("Sleep Time in Bed", TIME_MINUTES, "hotel"), +} + +FITBIT_MEASUREMENTS: Final[dict[str, dict[str, str]]] = { + "en_US": { + ATTR_DURATION: TIME_MILLISECONDS, + ATTR_DISTANCE: "mi", + ATTR_ELEVATION: LENGTH_FEET, + ATTR_HEIGHT: "in", + ATTR_WEIGHT: "lbs", + ATTR_BODY: "in", + ATTR_LIQUIDS: "fl. oz.", + ATTR_BLOOD_GLUCOSE: f"{MASS_MILLIGRAMS}/dL", + ATTR_BATTERY: "", + }, + "en_GB": { + ATTR_DURATION: TIME_MILLISECONDS, + ATTR_DISTANCE: "kilometers", + ATTR_ELEVATION: "meters", + ATTR_HEIGHT: "centimeters", + ATTR_WEIGHT: "stone", + ATTR_BODY: "centimeters", + ATTR_LIQUIDS: "milliliters", + ATTR_BLOOD_GLUCOSE: "mmol/L", + ATTR_BATTERY: "", + }, + "metric": { + ATTR_DURATION: TIME_MILLISECONDS, + ATTR_DISTANCE: "kilometers", + ATTR_ELEVATION: "meters", + ATTR_HEIGHT: "centimeters", + ATTR_WEIGHT: MASS_KILOGRAMS, + ATTR_BODY: "centimeters", + ATTR_LIQUIDS: "milliliters", + ATTR_BLOOD_GLUCOSE: "mmol/L", + ATTR_BATTERY: "", + }, +} + +BATTERY_LEVELS: Final[dict[str, int]] = { + "High": 100, + "Medium": 50, + "Low": 20, + "Empty": 0, +} diff --git a/homeassistant/components/fitbit/sensor.py b/homeassistant/components/fitbit/sensor.py index 263ae24ff34..9f99b3d0bb0 100644 --- a/homeassistant/components/fitbit/sensor.py +++ b/homeassistant/components/fitbit/sensor.py @@ -1,162 +1,70 @@ """Support for the Fitbit API.""" + +from __future__ import annotations + import datetime import logging import os import time +from typing import Any, Final, cast +from aiohttp.web import Request from fitbit import Fitbit from fitbit.api import FitbitOauth2Client from oauthlib.oauth2.rfc6749.errors import MismatchingStateError, MissingTokenError import voluptuous as vol from homeassistant.components.http import HomeAssistantView -from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity +from homeassistant.components.sensor import ( + PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA, + SensorEntity, +) from homeassistant.const import ( ATTR_ATTRIBUTION, CONF_CLIENT_ID, CONF_CLIENT_SECRET, CONF_UNIT_SYSTEM, - LENGTH_FEET, - MASS_KILOGRAMS, - MASS_MILLIGRAMS, - PERCENTAGE, - TIME_MILLISECONDS, - TIME_MINUTES, ) -from homeassistant.core import callback +from homeassistant.core import HomeAssistant, callback import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.icon import icon_for_battery_level from homeassistant.helpers.network import get_url +from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.util.json import load_json, save_json -_CONFIGURING = {} -_LOGGER = logging.getLogger(__name__) +from .const import ( + ATTR_ACCESS_TOKEN, + ATTR_LAST_SAVED_AT, + ATTR_REFRESH_TOKEN, + ATTRIBUTION, + BATTERY_LEVELS, + CONF_CLOCK_FORMAT, + CONF_MONITORED_RESOURCES, + DEFAULT_CLOCK_FORMAT, + DEFAULT_CONFIG, + FITBIT_AUTH_CALLBACK_PATH, + FITBIT_AUTH_START, + FITBIT_CONFIG_FILE, + FITBIT_DEFAULT_RESOURCES, + FITBIT_MEASUREMENTS, + FITBIT_RESOURCES_LIST, +) -ATTR_ACCESS_TOKEN = "access_token" -ATTR_REFRESH_TOKEN = "refresh_token" -ATTR_LAST_SAVED_AT = "last_saved_at" +_LOGGER: Final = logging.getLogger(__name__) -CONF_MONITORED_RESOURCES = "monitored_resources" -CONF_CLOCK_FORMAT = "clock_format" -ATTRIBUTION = "Data provided by Fitbit.com" +_CONFIGURING: dict[str, str] = {} -FITBIT_AUTH_CALLBACK_PATH = "/api/fitbit/callback" -FITBIT_AUTH_START = "/api/fitbit" -FITBIT_CONFIG_FILE = "fitbit.conf" -FITBIT_DEFAULT_RESOURCES = ["activities/steps"] +SCAN_INTERVAL: Final = datetime.timedelta(minutes=30) -SCAN_INTERVAL = datetime.timedelta(minutes=30) - -DEFAULT_CONFIG = { - CONF_CLIENT_ID: "CLIENT_ID_HERE", - CONF_CLIENT_SECRET: "CLIENT_SECRET_HERE", -} - -FITBIT_RESOURCES_LIST = { - "activities/activityCalories": ["Activity Calories", "cal", "fire"], - "activities/calories": ["Calories", "cal", "fire"], - "activities/caloriesBMR": ["Calories BMR", "cal", "fire"], - "activities/distance": ["Distance", "", "map-marker"], - "activities/elevation": ["Elevation", "", "walk"], - "activities/floors": ["Floors", "floors", "walk"], - "activities/heart": ["Resting Heart Rate", "bpm", "heart-pulse"], - "activities/minutesFairlyActive": ["Minutes Fairly Active", TIME_MINUTES, "walk"], - "activities/minutesLightlyActive": ["Minutes Lightly Active", TIME_MINUTES, "walk"], - "activities/minutesSedentary": [ - "Minutes Sedentary", - TIME_MINUTES, - "seat-recline-normal", - ], - "activities/minutesVeryActive": ["Minutes Very Active", TIME_MINUTES, "run"], - "activities/steps": ["Steps", "steps", "walk"], - "activities/tracker/activityCalories": ["Tracker Activity Calories", "cal", "fire"], - "activities/tracker/calories": ["Tracker Calories", "cal", "fire"], - "activities/tracker/distance": ["Tracker Distance", "", "map-marker"], - "activities/tracker/elevation": ["Tracker Elevation", "", "walk"], - "activities/tracker/floors": ["Tracker Floors", "floors", "walk"], - "activities/tracker/minutesFairlyActive": [ - "Tracker Minutes Fairly Active", - TIME_MINUTES, - "walk", - ], - "activities/tracker/minutesLightlyActive": [ - "Tracker Minutes Lightly Active", - TIME_MINUTES, - "walk", - ], - "activities/tracker/minutesSedentary": [ - "Tracker Minutes Sedentary", - TIME_MINUTES, - "seat-recline-normal", - ], - "activities/tracker/minutesVeryActive": [ - "Tracker Minutes Very Active", - TIME_MINUTES, - "run", - ], - "activities/tracker/steps": ["Tracker Steps", "steps", "walk"], - "body/bmi": ["BMI", "BMI", "human"], - "body/fat": ["Body Fat", PERCENTAGE, "human"], - "body/weight": ["Weight", "", "human"], - "devices/battery": ["Battery", None, None], - "sleep/awakeningsCount": ["Awakenings Count", "times awaken", "sleep"], - "sleep/efficiency": ["Sleep Efficiency", PERCENTAGE, "sleep"], - "sleep/minutesAfterWakeup": ["Minutes After Wakeup", TIME_MINUTES, "sleep"], - "sleep/minutesAsleep": ["Sleep Minutes Asleep", TIME_MINUTES, "sleep"], - "sleep/minutesAwake": ["Sleep Minutes Awake", TIME_MINUTES, "sleep"], - "sleep/minutesToFallAsleep": [ - "Sleep Minutes to Fall Asleep", - TIME_MINUTES, - "sleep", - ], - "sleep/startTime": ["Sleep Start Time", None, "clock"], - "sleep/timeInBed": ["Sleep Time in Bed", TIME_MINUTES, "hotel"], -} - -FITBIT_MEASUREMENTS = { - "en_US": { - "duration": TIME_MILLISECONDS, - "distance": "mi", - "elevation": LENGTH_FEET, - "height": "in", - "weight": "lbs", - "body": "in", - "liquids": "fl. oz.", - "blood glucose": f"{MASS_MILLIGRAMS}/dL", - "battery": "", - }, - "en_GB": { - "duration": TIME_MILLISECONDS, - "distance": "kilometers", - "elevation": "meters", - "height": "centimeters", - "weight": "stone", - "body": "centimeters", - "liquids": "milliliters", - "blood glucose": "mmol/L", - "battery": "", - }, - "metric": { - "duration": TIME_MILLISECONDS, - "distance": "kilometers", - "elevation": "meters", - "height": "centimeters", - "weight": MASS_KILOGRAMS, - "body": "centimeters", - "liquids": "milliliters", - "blood glucose": "mmol/L", - "battery": "", - }, -} - -BATTERY_LEVELS = {"High": 100, "Medium": 50, "Low": 20, "Empty": 0} - -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( +PLATFORM_SCHEMA: Final = PARENT_PLATFORM_SCHEMA.extend( { vol.Optional( CONF_MONITORED_RESOURCES, default=FITBIT_DEFAULT_RESOURCES ): vol.All(cv.ensure_list, [vol.In(FITBIT_RESOURCES_LIST)]), - vol.Optional(CONF_CLOCK_FORMAT, default="24H"): vol.In(["12H", "24H"]), + vol.Optional(CONF_CLOCK_FORMAT, default=DEFAULT_CLOCK_FORMAT): vol.In( + ["12H", "24H"] + ), vol.Optional(CONF_UNIT_SYSTEM, default="default"): vol.In( ["en_GB", "en_US", "metric", "default"] ), @@ -164,11 +72,17 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( ) -def request_app_setup(hass, config, add_entities, config_path, discovery_info=None): +def request_app_setup( + hass: HomeAssistant, + config: ConfigType, + add_entities: AddEntitiesCallback, + config_path: str, + discovery_info: DiscoveryInfoType | None = None, +) -> None: """Assist user with configuring the Fitbit dev application.""" configurator = hass.components.configurator - def fitbit_configuration_callback(callback_data): + def fitbit_configuration_callback(fields: list[dict[str, str]]) -> None: """Handle configuration updates.""" config_path = hass.config.path(FITBIT_CONFIG_FILE) if os.path.isfile(config_path): @@ -206,7 +120,7 @@ def request_app_setup(hass, config, add_entities, config_path, discovery_info=No ) -def request_oauth_completion(hass): +def request_oauth_completion(hass: HomeAssistant) -> None: """Request user complete Fitbit OAuth2 flow.""" configurator = hass.components.configurator if "fitbit" in _CONFIGURING: @@ -216,7 +130,7 @@ def request_oauth_completion(hass): return - def fitbit_configuration_callback(callback_data): + def fitbit_configuration_callback(fields: list[dict[str, str]]) -> None: """Handle configuration updates.""" start_url = f"{get_url(hass)}{FITBIT_AUTH_START}" @@ -231,28 +145,37 @@ def request_oauth_completion(hass): ) -def setup_platform(hass, config, add_entities, discovery_info=None): +def setup_platform( + hass: HomeAssistant, + config: ConfigType, + add_entities: AddEntitiesCallback, + discovery_info: DiscoveryInfoType | None = None, +) -> None: """Set up the Fitbit sensor.""" config_path = hass.config.path(FITBIT_CONFIG_FILE) if os.path.isfile(config_path): - config_file = load_json(config_path) + config_file: ConfigType = cast(ConfigType, load_json(config_path)) if config_file == DEFAULT_CONFIG: request_app_setup( hass, config, add_entities, config_path, discovery_info=None ) - return False + return else: save_json(config_path, DEFAULT_CONFIG) request_app_setup(hass, config, add_entities, config_path, discovery_info=None) - return False + return if "fitbit" in _CONFIGURING: hass.components.configurator.request_done(_CONFIGURING.pop("fitbit")) - access_token = config_file.get(ATTR_ACCESS_TOKEN) - refresh_token = config_file.get(ATTR_REFRESH_TOKEN) - expires_at = config_file.get(ATTR_LAST_SAVED_AT) - if None not in (access_token, refresh_token): + access_token: str | None = config_file.get(ATTR_ACCESS_TOKEN) + refresh_token: str | None = config_file.get(ATTR_REFRESH_TOKEN) + expires_at: int | None = config_file.get(ATTR_LAST_SAVED_AT) + if ( + access_token is not None + and refresh_token is not None + and expires_at is not None + ): authd_client = Fitbit( config_file.get(CONF_CLIENT_ID), config_file.get(CONF_CLIENT_SECRET), @@ -278,8 +201,8 @@ def setup_platform(hass, config, add_entities, discovery_info=None): dev = [] registered_devs = authd_client.get_devices() - clock_format = config.get(CONF_CLOCK_FORMAT) - for resource in config.get(CONF_MONITORED_RESOURCES): + clock_format = config.get(CONF_CLOCK_FORMAT, DEFAULT_CLOCK_FORMAT) + for resource in config.get(CONF_MONITORED_RESOURCES, FITBIT_DEFAULT_RESOURCES): # monitor battery for all linked FitBit devices if resource == "devices/battery": @@ -339,16 +262,21 @@ class FitbitAuthCallbackView(HomeAssistantView): url = FITBIT_AUTH_CALLBACK_PATH name = "api:fitbit:callback" - def __init__(self, config, add_entities, oauth): + def __init__( + self, + config: ConfigType, + add_entities: AddEntitiesCallback, + oauth: FitbitOauth2Client, + ) -> None: """Initialize the OAuth callback view.""" self.config = config self.add_entities = add_entities self.oauth = oauth @callback - async def get(self, request): + async def get(self, request: Request) -> str: """Finish OAuth callback request.""" - hass = request.app["hass"] + hass: HomeAssistant = request.app["hass"] data = request.query response_message = """Fitbit has been successfully authorized! @@ -408,8 +336,14 @@ class FitbitSensor(SensorEntity): """Implementation of a Fitbit sensor.""" def __init__( - self, client, config_path, resource_type, is_metric, clock_format, extra=None - ): + self, + client: Fitbit, + config_path: str, + resource_type: str, + is_metric: bool, + clock_format: str, + extra: dict[str, str] | None = None, + ) -> None: """Initialize the Fitbit sensor.""" self.client = client self.config_path = config_path @@ -418,7 +352,7 @@ class FitbitSensor(SensorEntity): self.clock_format = clock_format self.extra = extra self._name = FITBIT_RESOURCES_LIST[self.resource_type][0] - if self.extra: + if self.extra is not None: self._name = f"{self.extra.get('deviceVersion')} Battery" unit_type = FITBIT_RESOURCES_LIST[self.resource_type][1] if unit_type == "": @@ -432,48 +366,53 @@ class FitbitSensor(SensorEntity): measurement_system = FITBIT_MEASUREMENTS["en_US"] unit_type = measurement_system[split_resource[-1]] self._unit_of_measurement = unit_type - self._state = 0 + self._state: str | None = None @property - def name(self): + def name(self) -> str: """Return the name of the sensor.""" return self._name @property - def state(self): + def state(self) -> str | None: """Return the state of the sensor.""" return self._state @property - def unit_of_measurement(self): + def unit_of_measurement(self) -> str | None: """Return the unit of measurement of this entity, if any.""" return self._unit_of_measurement @property - def icon(self): + def icon(self) -> str: """Icon to use in the frontend, if any.""" - if self.resource_type == "devices/battery" and self.extra: - battery_level = BATTERY_LEVELS[self.extra.get("battery")] - return icon_for_battery_level(battery_level=battery_level, charging=None) - return f"mdi:{FITBIT_RESOURCES_LIST[self.resource_type][2]}" + if self.resource_type == "devices/battery" and self.extra is not None: + extra_battery = self.extra.get("battery") + if extra_battery is not None: + battery_level = BATTERY_LEVELS.get(extra_battery) + if battery_level is not None: + return icon_for_battery_level(battery_level=battery_level) + fitbit_ressource = FITBIT_RESOURCES_LIST[self.resource_type] + return f"mdi:{fitbit_ressource[2]}" @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> dict[str, str | None]: """Return the state attributes.""" - attrs = {} + attrs: dict[str, str | None] = {} attrs[ATTR_ATTRIBUTION] = ATTRIBUTION - if self.extra: + if self.extra is not None: attrs["model"] = self.extra.get("deviceVersion") - attrs["type"] = self.extra.get("type").lower() + extra_type = self.extra.get("type") + attrs["type"] = extra_type.lower() if extra_type is not None else None return attrs - def update(self): + def update(self) -> None: """Get the latest data from the Fitbit API and update the states.""" - if self.resource_type == "devices/battery" and self.extra: - registered_devs = self.client.get_devices() + if self.resource_type == "devices/battery" and self.extra is not None: + registered_devs: list[dict[str, Any]] = self.client.get_devices() device_id = self.extra.get("id") self.extra = list( filter(lambda device: device.get("id") == device_id, registered_devs) diff --git a/mypy.ini b/mypy.ini index 0ca5b618fc6..c2af1b1f643 100644 --- a/mypy.ini +++ b/mypy.ini @@ -242,6 +242,17 @@ no_implicit_optional = true warn_return_any = true warn_unreachable = true +[mypy-homeassistant.components.fitbit.*] +check_untyped_defs = true +disallow_incomplete_defs = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_decorators = true +disallow_untyped_defs = true +no_implicit_optional = true +warn_return_any = true +warn_unreachable = true + [mypy-homeassistant.components.fritzbox.*] check_untyped_defs = true disallow_incomplete_defs = true @@ -884,9 +895,6 @@ ignore_errors = true [mypy-homeassistant.components.firmata.*] ignore_errors = true -[mypy-homeassistant.components.fitbit.*] -ignore_errors = true - [mypy-homeassistant.components.flo.*] ignore_errors = true diff --git a/script/hassfest/mypy_config.py b/script/hassfest/mypy_config.py index 94f5bc81a0d..3372750b507 100644 --- a/script/hassfest/mypy_config.py +++ b/script/hassfest/mypy_config.py @@ -63,7 +63,6 @@ IGNORED_MODULES: Final[list[str]] = [ "homeassistant.components.fints.*", "homeassistant.components.fireservicerota.*", "homeassistant.components.firmata.*", - "homeassistant.components.fitbit.*", "homeassistant.components.flo.*", "homeassistant.components.fortios.*", "homeassistant.components.foscam.*",