Skip to content

Commit

Permalink
mypy fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
zxdavb committed Nov 2, 2024
1 parent 6b6648b commit 3a24bd1
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 65 deletions.
57 changes: 34 additions & 23 deletions src/evohomeasync2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@


class TokenManager(AbstractTokenManager): # used only by EvohomeClientOld
"""A wrapper to expose the new EvohomeClient without a TokenManager."""
"""A TokenManager wrapper to help expose the new EvohomeClient."""

def __init__(
self,
Expand Down Expand Up @@ -76,8 +76,8 @@ async def save_access_token(self) -> None:
class EvohomeClientNew: # requires a Token Manager
"""Provide a client to access the Honeywell TCC API."""

_installation_config: _EvoListT | None = None # all locations
_user_information: _EvoDictT | None = None
_install_config: _EvoListT | None = None # all locations
_user_info: _EvoDictT | None = None

def __init__(
self,
Expand Down Expand Up @@ -119,25 +119,31 @@ async def update(
"""

if reset_config:
self._user_information = None
self._installation_config = None
self._user_info = None
self._install_config = None

if not self._user_information:
if self._user_info is None:
url = "userAccount"
self._user_information = await self.auth.get(url, schema=SCH_USER_ACCOUNT)
self._user_info = await self.auth.get(url, schema=SCH_USER_ACCOUNT) # type: ignore[assignment]

if not self._installation_config:
url = (
f"location/installationInfo?userId={self._user_information[SZ_USER_ID]}"
)
assert self._user_info is not None # mypy hint

if self._install_config is None:
url = f"location/installationInfo?userId={self._user_info[SZ_USER_ID]}"
url += "&includeTemperatureControlSystems=True"

self._installation_config = await self.auth.get(url, schema=SCH_FULL_CONFIG)
self._install_config = await self.auth.get(url, schema=SCH_FULL_CONFIG) # type: ignore[assignment]

self._locations = None
self._location_by_id = None

assert self._install_config is not None # mypy hint

if self._locations is None:
self._locations = []
self._location_by_id = {}

for loc_config in self._installation_config:
for loc_config in self._install_config:
loc = Location(self, loc_config)
self._locations.append(loc)
self._location_by_id[loc.id] = loc
Expand All @@ -148,42 +154,47 @@ async def update(
"limits by individually updating only the necessary locations."
)

assert self._locations is not None # mypy hint

if not dont_update_status:
for loc in self._locations:
await loc.update()

return self._installation_config
return self._install_config

@property
def user_information(self) -> _EvoDictT:
"""Return the information of the user account."""

if not self._user_information:
if not self._user_info:
raise exc.NoSystemConfigError(
f"{self}: The account information is not (yet) available"
)

return convert_keys_to_snake_case(self._user_information)
return convert_keys_to_snake_case(self._user_info)

@property
def installation_config(self) -> _EvoListT:
"""Return the installation info (config) of all the user's locations."""

if not self._installation_config:
if not self._install_config:
raise exc.NoSystemConfigError(
f"{self}: The installation information is not (yet) available"
)

return convert_keys_to_snake_case(self._installation_config)
return convert_keys_to_snake_case(self._install_config)

@property
def locations(self) -> list[Location]:
"""Return the list of locations."""

if self._installation_config is None:
if self._install_config is None:
raise exc.NoSystemConfigError(
f"{self}: The installation information is not (yet) available"
)

assert self._locations # mypy hint

return self._locations

# Most users only have exactly one TCS, thus these convenience methods...
Expand Down Expand Up @@ -295,22 +306,22 @@ def __init__(
super().__init__(self._token_manager, debug=debug)

@property
def access_token(self) -> str: # type: ignore[override]
def access_token(self) -> str:
"""Return the access_token attr."""
return self._token_manager.access_token

@property
def access_token_expires(self) -> dt: # type: ignore[override]
def access_token_expires(self) -> dt:
"""Return the access_token_expires attr."""
return self._token_manager.access_token_expires

@property
def refresh_token(self) -> str: # type: ignore[override]
def refresh_token(self) -> str:
"""Return the refresh_token attr."""
return self._token_manager.refresh_token

@property
def username(self) -> str: # type: ignore[override]
def username(self) -> str:
"""Return the username attr."""
return self._token_manager.username

Expand Down
4 changes: 2 additions & 2 deletions src/evohomeasync2/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,10 +211,10 @@ async def cleanup(
if cache_tokens: # restore cached tokens, if any
await token_manager.load_access_token()

evo = EvohomeClientNew(websession, token_manager, debug=bool(debug))
evo = EvohomeClientNew(token_manager, debug=bool(debug))

try:
await evo.login()
await evo.update()
except exc.AuthenticationFailedError:
await websession.close()
raise
Expand Down
4 changes: 2 additions & 2 deletions src/evohomeasync2/location.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
if TYPE_CHECKING:
import voluptuous as vol

from . import EvohomeClient
from . import EvohomeClientNew
from .schema import _EvoDictT


Expand All @@ -35,7 +35,7 @@ class Location(EntityBase):
STATUS_SCHEMA: Final[vol.Schema] = SCH_LOCN_STATUS
TYPE: Final = EntityType.LOC # type: ignore[misc]

def __init__(self, client: EvohomeClient, config: _EvoDictT) -> None:
def __init__(self, client: EvohomeClientNew, config: _EvoDictT) -> None:
super().__init__(
config[SZ_LOCATION_INFO][SZ_LOCATION_ID],
client.auth,
Expand Down
4 changes: 2 additions & 2 deletions tests/tests_rf/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def patches_for_tests(monkeypatch: pytest.MonkeyPatch) -> None:
if _DBG_USE_REAL_AIOHTTP:
import aiohttp
else:
from .faked_server import aiohttp
from .faked_server import aiohttp # type: ignore[no-redef]

monkeypatch.setattr("evohomeasync.auth.aiohttp", aiohttp)
monkeypatch.setattr("evohomeasync2.auth.aiohttp", aiohttp)
Expand All @@ -52,7 +52,7 @@ async def client_session() -> AsyncGenerator[aiohttp.ClientSession, None]:
if _DBG_USE_REAL_AIOHTTP:
import aiohttp
else:
from .faked_server import aiohttp
from .faked_server import aiohttp # type: ignore[no-redef]

if _DBG_USE_REAL_AIOHTTP:
client_session = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=30))
Expand Down
9 changes: 5 additions & 4 deletions tests/tests_rf/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,13 @@ async def wait_for_comm_task_v2(evo: evo2.EvohomeClientNew, task_id: str) -> boo
response = await should_work(evo, HTTPMethod.GET, url)
assert isinstance(response, dict | list), response

if response["state"] == "Succeeded": # type: ignore[call-overload]
task = response[0] if isinstance(response, list) else response

if task["state"] == "Succeeded":
return True

if response["state"] in ("Created", "Running"): # type: ignore[call-overload]
if task["state"] in ("Created", "Running"):
await asyncio.sleep(0.3)
continue

else:
raise RuntimeError(f"Unexpected state: {response['state']}")
raise RuntimeError(f"Unexpected state: {task['state']}")
12 changes: 6 additions & 6 deletions tests/tests_rf/test_token_mgr.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,20 +157,20 @@ async def _test_evo_update_00(

evo = evohome_v2

assert evo._user_information is None
assert evo._installation_config is None
assert evo._user_info is None
assert evo._install_config is None

await evo.update(reset_config=False, dont_update_status=False)

assert evo._user_information
assert evo._installation_config
assert evo._user_info is not None
assert evo._install_config is not None # type: ignore[unreachable]

assert evo.locations[0]._status == {}

await evo.update(reset_config=True)

assert evo._user_information
assert evo._installation_config
assert evo._user_info is not None
assert evo._install_config is not None

assert evo.locations[0]._status != {}

Expand Down
20 changes: 10 additions & 10 deletions tests/tests_rf/test_v2_apis.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@
#######################################################################################


async def _test_basics_apis(evo: evo2.EvohomeClient) -> None:
async def _test_basics_apis(evo: evo2.EvohomeClientNew) -> None:
"""Test authentication, `user_account()` and `installation()`."""

# STEP 1: retrieve base data
await evo.update(dont_update_status=False)

assert SCH_USER_ACCOUNT(evo._installation_config)
assert SCH_FULL_CONFIG(evo._user_information)
assert SCH_USER_ACCOUNT(evo._install_config)
assert SCH_FULL_CONFIG(evo._user_info)

# STEP 4: Status, GET /location/{loc.id}/status
for loc in evo.locations:
Expand All @@ -42,7 +42,7 @@ async def _test_basics_apis(evo: evo2.EvohomeClient) -> None:
pass


async def _test_sched__apis(evo: evo2.EvohomeClient) -> None:
async def _test_sched__apis(evo: evo2.EvohomeClientNew) -> None:
"""Test `get_schedule()` and `get_schedule()`."""

# STEP 1: retrieve base data
Expand Down Expand Up @@ -70,7 +70,7 @@ async def _test_sched__apis(evo: evo2.EvohomeClient) -> None:
assert False


async def _test_update_apis(evo: evo2.EvohomeClient) -> None:
async def _test_update_apis(evo: evo2.EvohomeClientNew) -> None:
"""Test `_update()` for DHW/zone."""

# STEP 1: retrieve config
Expand All @@ -88,7 +88,7 @@ async def _test_update_apis(evo: evo2.EvohomeClient) -> None:
pass


async def _test_system_apis(evo: evo2.EvohomeClient) -> None:
async def _test_system_apis(evo: evo2.EvohomeClientNew) -> None:
"""Test `set_mode()` for TCS."""

# STEP 1: retrieve base data
Expand All @@ -114,22 +114,22 @@ async def _test_system_apis(evo: evo2.EvohomeClient) -> None:
#######################################################################################


async def test_basics(evohome_v2: evo2.EvohomeClient) -> None:
async def test_basics(evohome_v2: evo2.EvohomeClientNew) -> None:
"""Test authentication, `user_account()` and `installation()`."""
await _test_basics_apis(evohome_v2)


async def _test_sched_(evohome_v2: evo2.EvohomeClient) -> None:
async def _test_sched_(evohome_v2: evo2.EvohomeClientNew) -> None:
"""Test `get_schedule()` and `get_schedule()`."""
await _test_sched__apis(evohome_v2)


async def test_status(evohome_v2: evo2.EvohomeClient) -> None:
async def test_status(evohome_v2: evo2.EvohomeClientNew) -> None:
"""Test `_update()` for DHW/zone."""
await _test_update_apis(evohome_v2)


async def test_system(evohome_v2: evo2.EvohomeClient) -> None:
async def test_system(evohome_v2: evo2.EvohomeClientNew) -> None:
"""Test `set_mode()` for TCS"""

try:
Expand Down
4 changes: 2 additions & 2 deletions tests/tests_rf/test_v2_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#######################################################################################


async def _test_task_id(evo: evo2.EvohomeClient) -> None:
async def _test_task_id(evo: evo2.EvohomeClientNew) -> None:
"""Test the task_id returned when using the vendor's RESTful APIs.
This test can be used to prove that JSON keys are can be camelCase or PascalCase.
Expand Down Expand Up @@ -186,7 +186,7 @@ async def _test_task_id(evo: evo2.EvohomeClient) -> None:
#######################################################################################


async def test_task_id(evohome_v2: evo2.EvohomeClient) -> None:
async def test_task_id(evohome_v2: evo2.EvohomeClientNew) -> None:
"""Test /location/{loc.id}/status"""

if not _DBG_USE_REAL_AIOHTTP:
Expand Down
Loading

0 comments on commit 3a24bd1

Please sign in to comment.