Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace flake8 with ruff #925

Merged
merged 1 commit into from
Nov 6, 2024
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
12 changes: 6 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ repos:
language: system
types: [python]
require_serial: true
- id: mypy
name: mypy
entry: poetry run mypy
- id: ruff-check
name: ruff check
entry: poetry run ruff check --fix
language: system
types: [python]
require_serial: true
- id: flake8
name: flake8
entry: poetry run flake8
- id: mypy
name: mypy
entry: poetry run mypy
language: system
types: [python]
require_serial: true
Expand Down
9 changes: 5 additions & 4 deletions custom_components/google_home/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
"""
Custom integration to integrate Google Home with Home Assistant.
"""Custom integration to integrate Google Home with Home Assistant.

For more details about this integration, please refer to
https://github.com/leikoilja/ha-google-home
"""

from datetime import timedelta
import logging
from typing import cast
from typing import TYPE_CHECKING, cast

from homeassistant.components import zeroconf
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
Expand All @@ -28,9 +27,11 @@
STARTUP_MESSAGE,
UPDATE_INTERVAL,
)
from .models import GoogleHomeDevice
from .types import GoogleHomeConfigEntry

if TYPE_CHECKING:
from .models import GoogleHomeDevice

_LOGGER: logging.Logger = logging.getLogger(__package__)


Expand Down
62 changes: 33 additions & 29 deletions custom_components/google_home/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,12 @@
from http import HTTPStatus
import ipaddress
import logging
from typing import Literal, cast
from typing import TYPE_CHECKING, Literal, cast

from aiohttp import ClientError, ClientSession, ClientTimeout
from aiohttp.client_exceptions import ClientConnectorError, ContentTypeError
from glocaltokens.client import Device, GLocalAuthenticationTokens
from glocaltokens.utils.token import is_aas_et
from zeroconf import Zeroconf

from homeassistant.core import HomeAssistant

from .const import (
API_ENDPOINT_ALARM_DELETE,
Expand All @@ -35,11 +32,16 @@
from .models import GoogleHomeDevice
from .types import AlarmJsonDict, JsonDict, TimerJsonDict

if TYPE_CHECKING:
from zeroconf import Zeroconf

from homeassistant.core import HomeAssistant

_LOGGER: logging.Logger = logging.getLogger(__package__)


class GlocaltokensApiClient:
"""API client"""
"""API client."""

def __init__(
self,
Expand Down Expand Up @@ -69,7 +71,7 @@ def __init__(
self.zeroconf_instance = zeroconf_instance

async def async_get_master_token(self) -> str:
"""Get master API token"""
"""Get master API token."""

def _get_master_token() -> str | None:
return self._client.get_master_token()
Expand All @@ -80,7 +82,7 @@ def _get_master_token() -> str | None:
return master_token

async def async_get_access_token(self) -> str:
"""Get access token using master token"""
"""Get access token using master token."""

def _get_access_token() -> str | None:
return self._client.get_access_token()
Expand All @@ -92,7 +94,9 @@ def _get_access_token() -> str | None:

async def get_google_devices(self) -> list[GoogleHomeDevice]:
"""Get google device authentication tokens.
Note this method will fetch necessary access tokens if missing"""

Note this method will fetch necessary access tokens if missing.
"""

if not self.google_devices:

Expand All @@ -116,7 +120,7 @@ def _get_google_devices() -> list[Device]:
return self.google_devices

async def get_android_id(self) -> str:
"""Generate random android_id"""
"""Generate random android_id."""

def _get_android_id() -> str:
return self._client.get_android_id()
Expand All @@ -125,15 +129,16 @@ def _get_android_id() -> str:

@staticmethod
def create_url(ip_address: str, port: int, api_endpoint: str) -> str:
"""Creates url to endpoint.
Note: port argument is unused because all request must be done to 8443"""
"""Create url to endpoint.

Note: port argument is unused because all request must be done to 8443.
"""
if isinstance(ipaddress.ip_address(ip_address), ipaddress.IPv6Address):
ip_address = f"[{ip_address}]"
return f"https://{ip_address}:{port}/{api_endpoint}"

async def update_google_devices_information(self) -> list[GoogleHomeDevice]:
"""Retrieves devices from glocaltokens and
fetches alarm/timer data from each of the device"""
"""Retrieve devices from glocaltokens and fetches alarm/timer data from each of the device."""

devices = await self.get_google_devices()

Expand All @@ -151,28 +156,26 @@ async def update_google_devices_information(self) -> list[GoogleHomeDevice]:
device.name,
)

coordinator_data = await asyncio.gather(
return await asyncio.gather(
*[
self.collect_data_from_endpoints(device)
for device in devices
if device.ip_address and device.auth_token
]
)
return coordinator_data

async def collect_data_from_endpoints(
self, device: GoogleHomeDevice
) -> GoogleHomeDevice:
"""Collect data from different endpoints."""
device = await self.update_alarms_and_timers(device)
device = await self.update_alarm_volume(device)
device = await self.update_do_not_disturb(device)
return device
return await self.update_do_not_disturb(device)

async def update_alarms_and_timers(
self, device: GoogleHomeDevice
) -> GoogleHomeDevice:
"""Fetches timers and alarms from google device"""
"""Fetch timers and alarms from google device."""
response = await self.request(
method="GET", endpoint=API_ENDPOINT_ALARMS, device=device, polling=True
)
Expand Down Expand Up @@ -201,8 +204,10 @@ async def update_alarms_and_timers(
async def delete_alarm_or_timer(
self, device: GoogleHomeDevice, item_to_delete: str
) -> None:
"""Deletes a timer or alarm.
Can also delete multiple if a list is provided (Not implemented yet)."""
"""Delete a timer or alarm.

Can also delete multiple if a list is provided (Not implemented yet).
"""

data = {"ids": [item_to_delete]}

Expand Down Expand Up @@ -247,7 +252,7 @@ async def delete_alarm_or_timer(
)

async def reboot_google_device(self, device: GoogleHomeDevice) -> None:
"""Reboots a Google Home device if it supports this."""
"""Reboot a Google Home device if it supports this."""

# "now" means reboot and "fdr" means factory reset (Not implemented).
data = {"params": "now"}
Expand All @@ -271,7 +276,7 @@ async def reboot_google_device(self, device: GoogleHomeDevice) -> None:
async def update_do_not_disturb(
self, device: GoogleHomeDevice, enable: bool | None = None
) -> GoogleHomeDevice:
"""Gets or sets the do not disturb setting on a Google Home device."""
"""Get or set the do not disturb setting on a Google Home device."""

data = None
polling = False
Expand Down Expand Up @@ -324,7 +329,7 @@ async def update_do_not_disturb(
async def update_alarm_volume(
self, device: GoogleHomeDevice, volume: int | None = None
) -> GoogleHomeDevice:
"""Gets or sets the alarm volume setting on a Google Home device."""
"""Get or set the alarm volume setting on a Google Home device."""

data: JsonDict | None = None
polling = False
Expand Down Expand Up @@ -394,7 +399,7 @@ async def request(
data: JsonDict | None = None,
polling: bool = False,
) -> JsonDict | None:
"""Shared request method"""
"""Shared request method."""

if device.ip_address is None:
_LOGGER.warning("Device %s doesn't have an IP address!", device.name)
Expand Down Expand Up @@ -479,15 +484,14 @@ async def request(
device.name,
)
device.available = False
except ClientError as ex:
except ClientError:
# Make sure that we log the exception from the client if one occurred.
_LOGGER.error(
"Request from %s device error: %s",
_LOGGER.exception(
"Request from %s device error",
device.name,
ex,
)
device.available = False
except asyncio.TimeoutError:
except TimeoutError:
_LOGGER.debug(
"%s device timed out while performing a request to it - Raw data: %s",
device.name,
Expand Down
46 changes: 24 additions & 22 deletions custom_components/google_home/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"""Adds config flow for Google Home"""
"""Adds config flow for Google Home."""

from __future__ import annotations

from datetime import timedelta
import logging
from typing import Self
from typing import TYPE_CHECKING, Self

from requests.exceptions import RequestException
import voluptuous as vol
Expand All @@ -27,7 +27,9 @@
UPDATE_INTERVAL,
)
from .exceptions import InvalidMasterToken
from .types import ConfigFlowDict, GoogleHomeConfigEntry, OptionsFlowDict

if TYPE_CHECKING:
from .types import ConfigFlowDict, GoogleHomeConfigEntry, OptionsFlowDict

_LOGGER: logging.Logger = logging.getLogger(__package__)

Expand Down Expand Up @@ -81,20 +83,19 @@ async def async_step_user(
title = f"{MANUFACTURER} (master_token)"
else:
self._errors["base"] = "master-token-invalid"
# master_token not provided, so use username/password authentication
elif len(password) < MAX_PASSWORD_LENGTH:
client = GlocaltokensApiClient(
hass=self.hass,
session=session,
username=username,
password=password,
)
master_token = await self._get_master_token(client)
if not master_token:
self._errors["base"] = "auth"
else:
# master_token not provided, so use username/password authentication
if len(password) < MAX_PASSWORD_LENGTH:
client = GlocaltokensApiClient(
hass=self.hass,
session=session,
username=username,
password=password,
)
master_token = await self._get_master_token(client)
if not master_token:
self._errors["base"] = "auth"
else:
self._errors["base"] = "pass-len"
self._errors["base"] = "pass-len"

if client and not self._errors:
config_data: dict[str, str] = {}
Expand All @@ -112,6 +113,7 @@ async def async_step_user(
def async_get_options_flow(
config_entry: GoogleHomeConfigEntry,
) -> GoogleHomeOptionsFlowHandler:
"""Handle options flow."""
return GoogleHomeOptionsFlowHandler(config_entry)

async def _show_config_form(self) -> ConfigFlowResult:
Expand All @@ -130,22 +132,22 @@ async def _show_config_form(self) -> ConfigFlowResult:

@staticmethod
async def _get_master_token(client: GlocaltokensApiClient) -> str:
"""Returns master token if credentials are valid."""
"""Return master token if credentials are valid."""
master_token = ""
try:
master_token = await client.async_get_master_token()
except (InvalidMasterToken, RequestException) as exception:
_LOGGER.error(exception)
except (InvalidMasterToken, RequestException):
_LOGGER.exception("Failed to get master token")
return master_token

@staticmethod
async def _get_access_token(client: GlocaltokensApiClient) -> str:
"""Returns access token if master token is valid."""
"""Return access token if master token is valid."""
access_token = ""
try:
access_token = await client.async_get_access_token()
except (InvalidMasterToken, RequestException) as exception:
_LOGGER.error(exception)
except (InvalidMasterToken, RequestException):
_LOGGER.exception("Failed to get access token")
return access_token


Expand Down
17 changes: 11 additions & 6 deletions custom_components/google_home/entity.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
"""Defines base entities for Google Home"""
"""Defines base entities for Google Home."""

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import TYPE_CHECKING

from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
)

from .api import GlocaltokensApiClient
from .const import DEFAULT_NAME, DOMAIN, MANUFACTURER
from .models import GoogleHomeDevice

if TYPE_CHECKING:
from homeassistant.helpers.device_registry import DeviceInfo

from .api import GlocaltokensApiClient


class GoogleHomeBaseEntity(
CoordinatorEntity[DataUpdateCoordinator[list[GoogleHomeDevice]]], ABC
):
"""Base entity base for Google Home sensors"""
"""Base entity base for Google Home sensors."""

def __init__(
self,
Expand All @@ -28,6 +32,7 @@ def __init__(
device_name: str,
device_model: str,
):
"""Create Google Home base entity."""
super().__init__(coordinator)
self.client = client
self.device_id = device_id
Expand All @@ -51,6 +56,7 @@ def unique_id(self) -> str: # type: ignore[override]

@property
def device_info(self) -> DeviceInfo | None: # type: ignore[override]
"""Return device info."""
return {
"identifiers": {(DOMAIN, self.device_id)},
"name": f"{DEFAULT_NAME} {self.device_name}",
Expand All @@ -59,8 +65,7 @@ def device_info(self) -> DeviceInfo | None: # type: ignore[override]
}

def get_device(self) -> GoogleHomeDevice | None:
"""Return the device matched by device name
from the list of google devices in coordinator_data"""
"""Return the device matched by device name from the list of google devices in coordinator_data."""
matched_devices: list[GoogleHomeDevice] = [
device
for device in self.coordinator.data
Expand Down
Loading