Skip to content

Commit 1c1fc8a

Browse files
authored
Code format updates (#166)
* Code format updates * usa alias for all
1 parent 384b980 commit 1c1fc8a

File tree

13 files changed

+182
-110
lines changed

13 files changed

+182
-110
lines changed

.github/workflows/lint.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,8 @@ jobs:
2525
- name: "Install requirements"
2626
run: python3 -m pip install -r requirements.txt
2727

28-
- name: "Run"
28+
- name: "Lint"
2929
run: python3 -m ruff check .
30+
31+
- name: "Format"
32+
run: python3 -m ruff format . --check

.ruff.toml

+7-30
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,16 @@ target-version = "py312"
44

55
[lint]
66
select = [
7-
"B007", # Loop control variable {name} not used within loop body
8-
"B014", # Exception handler with duplicate exception
9-
"C", # complexity
10-
"D", # docstrings
11-
"E", # pycodestyle
12-
"F", # pyflakes/autoflake
13-
"ICN001", # import concentions; {name} should be imported as {asname}
14-
"PGH004", # Use specific rule codes when using noqa
15-
"PLC0414", # Useless import alias. Import alias does not rename original package.
16-
"SIM105", # Use contextlib.suppress({exception}) instead of try-except-pass
17-
"SIM117", # Merge with-statements that use the same scope
18-
"SIM118", # Use {key} in {dict} instead of {key} in {dict}.keys()
19-
"SIM201", # Use {left} != {right} instead of not {left} == {right}
20-
"SIM212", # Use {a} if {a} else {b} instead of {b} if not {a} else {a}
21-
"SIM300", # Yoda conditions. Use 'age == 42' instead of '42 == age'.
22-
"SIM401", # Use get from dict with default instead of an if block
23-
"T20", # flake8-print
24-
"TRY004", # Prefer TypeError exception for invalid type
25-
"RUF006", # Store a reference to the return value of asyncio.create_task
26-
"UP", # pyupgrade
27-
"W", # pycodestyle
7+
"ALL",
288
]
299

3010
ignore = [
31-
"D202", # No blank lines allowed after function docstring
32-
"D203", # 1 blank line required before class docstring
33-
"D213", # Multi-line docstring summary should start at the second line
34-
"D404", # First word of the docstring should not be This
35-
"D406", # Section name should end with a newline
36-
"D407", # Section name underlining
37-
"D411", # Missing blank line before section
38-
"E501", # line too long
39-
"E731", # do not assign a lambda expression, use a def
11+
"ANN101", # Missing type annotation for `self` in method
12+
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed
13+
"D203", # no-blank-line-before-class (incompatible with formatter)
14+
"D212", # multi-line-summary-first-line (incompatible with formatter)
15+
"COM812", # incompatible with formatter
16+
"ISC001", # incompatible with formatter
4017
]
4118

4219
[lint.flake8-pytest-style]
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
1-
"""Custom integration to integrate integration_blueprint with Home Assistant.
1+
"""
2+
Custom integration to integrate integration_blueprint with Home Assistant.
23
34
For more details about this integration, please refer to
45
https://github.com/ludeeus/integration_blueprint
56
"""
7+
68
from __future__ import annotations
79

8-
from homeassistant.config_entries import ConfigEntry
10+
from typing import TYPE_CHECKING
11+
912
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, Platform
10-
from homeassistant.core import HomeAssistant
1113
from homeassistant.helpers.aiohttp_client import async_get_clientsession
14+
from homeassistant.loader import async_get_loaded_integration
1215

1316
from .api import IntegrationBlueprintApiClient
14-
from .const import DOMAIN
1517
from .coordinator import BlueprintDataUpdateCoordinator
18+
from .data import IntegrationBlueprintData
19+
20+
if TYPE_CHECKING:
21+
from homeassistant.core import HomeAssistant
22+
23+
from .data import IntegrationBlueprintConfigEntry
1624

1725
PLATFORMS: list[Platform] = [
1826
Platform.SENSOR,
@@ -22,17 +30,24 @@
2230

2331

2432
# https://developers.home-assistant.io/docs/config_entries_index/#setting-up-an-entry
25-
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
33+
async def async_setup_entry(
34+
hass: HomeAssistant,
35+
entry: IntegrationBlueprintConfigEntry,
36+
) -> bool:
2637
"""Set up this integration using UI."""
27-
hass.data.setdefault(DOMAIN, {})
28-
hass.data[DOMAIN][entry.entry_id] = coordinator = BlueprintDataUpdateCoordinator(
38+
coordinator = BlueprintDataUpdateCoordinator(
2939
hass=hass,
40+
)
41+
entry.runtime_data = IntegrationBlueprintData(
3042
client=IntegrationBlueprintApiClient(
3143
username=entry.data[CONF_USERNAME],
3244
password=entry.data[CONF_PASSWORD],
3345
session=async_get_clientsession(hass),
3446
),
47+
integration=async_get_loaded_integration(hass, entry.domain),
48+
coordinator=coordinator,
3549
)
50+
3651
# https://developers.home-assistant.io/docs/integration_fetching_data#coordinated-single-api-poll-for-data-for-all-entities
3752
await coordinator.async_config_entry_first_refresh()
3853

@@ -42,14 +57,18 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
4257
return True
4358

4459

45-
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
60+
async def async_unload_entry(
61+
hass: HomeAssistant,
62+
entry: IntegrationBlueprintConfigEntry,
63+
) -> bool:
4664
"""Handle removal of an entry."""
47-
if unloaded := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
48-
hass.data[DOMAIN].pop(entry.entry_id)
49-
return unloaded
65+
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
5066

5167

52-
async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
68+
async def async_reload_entry(
69+
hass: HomeAssistant,
70+
entry: IntegrationBlueprintConfigEntry,
71+
) -> None:
5372
"""Reload config entry."""
5473
await async_unload_entry(hass, entry)
5574
await async_setup_entry(hass, entry)

custom_components/integration_blueprint/api.py

+26-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
"""Sample API Client."""
2+
23
from __future__ import annotations
34

45
import socket
6+
from typing import Any
57

68
import aiohttp
79
import async_timeout
@@ -12,17 +14,27 @@ class IntegrationBlueprintApiClientError(Exception):
1214

1315

1416
class IntegrationBlueprintApiClientCommunicationError(
15-
IntegrationBlueprintApiClientError
17+
IntegrationBlueprintApiClientError,
1618
):
1719
"""Exception to indicate a communication error."""
1820

1921

2022
class IntegrationBlueprintApiClientAuthenticationError(
21-
IntegrationBlueprintApiClientError
23+
IntegrationBlueprintApiClientError,
2224
):
2325
"""Exception to indicate an authentication error."""
2426

2527

28+
def _verify_response_or_raise(response: aiohttp.ClientResponse) -> None:
29+
"""Verify that the response is valid."""
30+
if response.status in (401, 403):
31+
msg = "Invalid credentials"
32+
raise IntegrationBlueprintApiClientAuthenticationError(
33+
msg,
34+
)
35+
response.raise_for_status()
36+
37+
2638
class IntegrationBlueprintApiClient:
2739
"""Sample API Client."""
2840

@@ -37,13 +49,14 @@ def __init__(
3749
self._password = password
3850
self._session = session
3951

40-
async def async_get_data(self) -> any:
52+
async def async_get_data(self) -> Any:
4153
"""Get data from the API."""
4254
return await self._api_wrapper(
43-
method="get", url="https://jsonplaceholder.typicode.com/posts/1"
55+
method="get",
56+
url="https://jsonplaceholder.typicode.com/posts/1",
4457
)
4558

46-
async def async_set_title(self, value: str) -> any:
59+
async def async_set_title(self, value: str) -> Any:
4760
"""Get data from the API."""
4861
return await self._api_wrapper(
4962
method="patch",
@@ -58,7 +71,7 @@ async def _api_wrapper(
5871
url: str,
5972
data: dict | None = None,
6073
headers: dict | None = None,
61-
) -> any:
74+
) -> Any:
6275
"""Get information from the API."""
6376
try:
6477
async with async_timeout.timeout(10):
@@ -68,22 +81,21 @@ async def _api_wrapper(
6881
headers=headers,
6982
json=data,
7083
)
71-
if response.status in (401, 403):
72-
raise IntegrationBlueprintApiClientAuthenticationError(
73-
"Invalid credentials",
74-
)
75-
response.raise_for_status()
84+
_verify_response_or_raise(response)
7685
return await response.json()
7786

7887
except TimeoutError as exception:
88+
msg = f"Timeout error fetching information - {exception}"
7989
raise IntegrationBlueprintApiClientCommunicationError(
80-
"Timeout error fetching information",
90+
msg,
8191
) from exception
8292
except (aiohttp.ClientError, socket.gaierror) as exception:
93+
msg = f"Error fetching information - {exception}"
8394
raise IntegrationBlueprintApiClientCommunicationError(
84-
"Error fetching information",
95+
msg,
8596
) from exception
8697
except Exception as exception: # pylint: disable=broad-except
98+
msg = f"Something really wrong happened! - {exception}"
8799
raise IntegrationBlueprintApiClientError(
88-
"Something really wrong happened!"
100+
msg,
89101
) from exception

custom_components/integration_blueprint/binary_sensor.py

+17-6
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
"""Binary sensor platform for integration_blueprint."""
2+
23
from __future__ import annotations
34

5+
from typing import TYPE_CHECKING
6+
47
from homeassistant.components.binary_sensor import (
58
BinarySensorDeviceClass,
69
BinarySensorEntity,
710
BinarySensorEntityDescription,
811
)
912

10-
from .const import DOMAIN
11-
from .coordinator import BlueprintDataUpdateCoordinator
1213
from .entity import IntegrationBlueprintEntity
1314

15+
if TYPE_CHECKING:
16+
from homeassistant.core import HomeAssistant
17+
from homeassistant.helpers.entity_platform import AddEntitiesCallback
18+
19+
from .coordinator import BlueprintDataUpdateCoordinator
20+
from .data import IntegrationBlueprintConfigEntry
21+
1422
ENTITY_DESCRIPTIONS = (
1523
BinarySensorEntityDescription(
1624
key="integration_blueprint",
@@ -20,12 +28,15 @@
2028
)
2129

2230

23-
async def async_setup_entry(hass, entry, async_add_devices):
31+
async def async_setup_entry(
32+
hass: HomeAssistant, # noqa: ARG001 Unused function argument: `hass`
33+
entry: IntegrationBlueprintConfigEntry,
34+
async_add_entities: AddEntitiesCallback,
35+
) -> None:
2436
"""Set up the binary_sensor platform."""
25-
coordinator = hass.data[DOMAIN][entry.entry_id]
26-
async_add_devices(
37+
async_add_entities(
2738
IntegrationBlueprintBinarySensor(
28-
coordinator=coordinator,
39+
coordinator=entry.runtime_data.coordinator,
2940
entity_description=entity_description,
3041
)
3142
for entity_description in ENTITY_DESCRIPTIONS

custom_components/integration_blueprint/config_flow.py

+6-7
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
from __future__ import annotations
44

55
import voluptuous as vol
6-
from homeassistant import config_entries
6+
from homeassistant import config_entries, data_entry_flow
77
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
88
from homeassistant.helpers import selector
99
from homeassistant.helpers.aiohttp_client import async_create_clientsession
1010

11-
1211
from .api import (
1312
IntegrationBlueprintApiClient,
1413
IntegrationBlueprintApiClientAuthenticationError,
@@ -26,7 +25,7 @@ class BlueprintFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
2625
async def async_step_user(
2726
self,
2827
user_input: dict | None = None,
29-
) -> config_entries.FlowResult:
28+
) -> data_entry_flow.FlowResult:
3029
"""Handle a flow initialized by the user."""
3130
_errors = {}
3231
if user_input is not None:
@@ -56,18 +55,18 @@ async def async_step_user(
5655
{
5756
vol.Required(
5857
CONF_USERNAME,
59-
default=(user_input or {}).get(CONF_USERNAME),
58+
default=(user_input or {}).get(CONF_USERNAME, vol.UNDEFINED),
6059
): selector.TextSelector(
6160
selector.TextSelectorConfig(
62-
type=selector.TextSelectorType.TEXT
61+
type=selector.TextSelectorType.TEXT,
6362
),
6463
),
6564
vol.Required(CONF_PASSWORD): selector.TextSelector(
6665
selector.TextSelectorConfig(
67-
type=selector.TextSelectorType.PASSWORD
66+
type=selector.TextSelectorType.PASSWORD,
6867
),
6968
),
70-
}
69+
},
7170
),
7271
errors=_errors,
7372
)

custom_components/integration_blueprint/const.py

-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,5 @@
44

55
LOGGER: Logger = getLogger(__package__)
66

7-
NAME = "Integration blueprint"
87
DOMAIN = "integration_blueprint"
9-
VERSION = "0.0.0"
108
ATTRIBUTION = "Data provided by http://jsonplaceholder.typicode.com/"

custom_components/integration_blueprint/coordinator.py

+12-13
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,47 @@
11
"""DataUpdateCoordinator for integration_blueprint."""
2+
23
from __future__ import annotations
34

45
from datetime import timedelta
6+
from typing import TYPE_CHECKING, Any
57

6-
from homeassistant.config_entries import ConfigEntry
7-
from homeassistant.core import HomeAssistant
8-
from homeassistant.helpers.update_coordinator import (
9-
DataUpdateCoordinator,
10-
UpdateFailed,
11-
)
128
from homeassistant.exceptions import ConfigEntryAuthFailed
9+
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
1310

1411
from .api import (
15-
IntegrationBlueprintApiClient,
1612
IntegrationBlueprintApiClientAuthenticationError,
1713
IntegrationBlueprintApiClientError,
1814
)
1915
from .const import DOMAIN, LOGGER
2016

17+
if TYPE_CHECKING:
18+
from homeassistant.core import HomeAssistant
19+
20+
from .data import IntegrationBlueprintConfigEntry
21+
2122

2223
# https://developers.home-assistant.io/docs/integration_fetching_data#coordinated-single-api-poll-for-data-for-all-entities
2324
class BlueprintDataUpdateCoordinator(DataUpdateCoordinator):
2425
"""Class to manage fetching data from the API."""
2526

26-
config_entry: ConfigEntry
27+
config_entry: IntegrationBlueprintConfigEntry
2728

2829
def __init__(
2930
self,
3031
hass: HomeAssistant,
31-
client: IntegrationBlueprintApiClient,
3232
) -> None:
3333
"""Initialize."""
34-
self.client = client
3534
super().__init__(
3635
hass=hass,
3736
logger=LOGGER,
3837
name=DOMAIN,
39-
update_interval=timedelta(minutes=5),
38+
update_interval=timedelta(hours=1),
4039
)
4140

42-
async def _async_update_data(self):
41+
async def _async_update_data(self) -> Any:
4342
"""Update data via library."""
4443
try:
45-
return await self.client.async_get_data()
44+
return await self.config_entry.runtime_data.client.async_get_data()
4645
except IntegrationBlueprintApiClientAuthenticationError as exception:
4746
raise ConfigEntryAuthFailed(exception) from exception
4847
except IntegrationBlueprintApiClientError as exception:

0 commit comments

Comments
 (0)