From 898c9776ac27e3c6728ed04a90ab2df3b7ab8219 Mon Sep 17 00:00:00 2001 From: John de Rooij Date: Sat, 25 Nov 2023 20:57:50 +0100 Subject: [PATCH] Used python 3.9 compatible Optional[x] instead of 'x | None' --- mytoyota/api.py | 29 ++++++++++++----------- mytoyota/client.py | 3 ++- mytoyota/controller.py | 38 +++++++++++++++---------------- mytoyota/models/dashboard.py | 18 ++++++++------- mytoyota/models/endpoints/trip.py | 10 ++++---- mytoyota/models/hvac.py | 28 +++++++++++------------ mytoyota/models/location.py | 3 ++- mytoyota/models/sensors.py | 30 ++++++++++++------------ mytoyota/models/trip.py | 7 +++--- mytoyota/models/vehicle.py | 20 ++++++++-------- 10 files changed, 98 insertions(+), 88 deletions(-) diff --git a/mytoyota/api.py b/mytoyota/api.py index 741ee091..deeb9a67 100644 --- a/mytoyota/api.py +++ b/mytoyota/api.py @@ -1,8 +1,7 @@ """Toyota Connected Services API""" -from datetime import datetime -from typing import Any +from datetime import date, datetime +from typing import Any, Optional from uuid import uuid4 -from datetime import date from .const import BASE_URL from .controller import Controller @@ -18,7 +17,7 @@ def __init__(self, controller: Controller) -> None: self.controller = controller @property - def uuid(self) -> str | None: + def uuid(self) -> Optional[str]: """Returns uuid from controller""" return self.controller.uuid @@ -44,7 +43,7 @@ async def get_wake_endpoint(self) -> None: method="POST", base_url=BASE_URL, endpoint="/v2/global/remote/wake" ) - async def get_vehicles_endpoint(self) -> list[dict[str, Any] | None] | None: + async def get_vehicles_endpoint(self) -> Optional[list[Optional[dict[str, Any]]]]: """Retrieves list of cars you have registered with MyT""" return await self.controller.request( method="GET", @@ -54,7 +53,7 @@ async def get_vehicles_endpoint(self) -> list[dict[str, Any] | None] | None: async def get_location_endpoint( self, vin: str - ) -> dict[str, Any] | None: # pragma: no cover + ) -> Optional[dict[str, Any]]: # pragma: no cover """Get where you have parked your car.""" ret = await self.controller.request( method="GET", @@ -71,7 +70,7 @@ async def get_location_endpoint( async def get_vehicle_health_status_endpoint( self, vin: str - ) -> dict[str, Any] | None: + ) -> Optional[dict[str, Any]]: """Get information about the vehicle.""" return await self.controller.request( method="GET", @@ -80,7 +79,7 @@ async def get_vehicle_health_status_endpoint( headers={"VIN": vin}, ) - async def get_vehicle_status_endpoint(self, vin: str) -> dict[str, Any] | None: + async def get_vehicle_status_endpoint(self, vin: str) -> Optional[dict[str, Any]]: """Get information about the vehicle.""" return await self.controller.request( method="GET", @@ -91,7 +90,7 @@ async def get_vehicle_status_endpoint(self, vin: str) -> dict[str, Any] | None: async def get_vehicle_electric_status_endpoint( self, vin: str - ) -> dict[str, Any] | None: + ) -> Optional[dict[str, Any]]: """Get information about the vehicle.""" try: return await self.controller.request( @@ -104,7 +103,7 @@ async def get_vehicle_electric_status_endpoint( # TODO This is wrong, but lets change the Vehicle class return None - async def get_telemetry_endpoint(self, vin: str) -> dict[str, Any] | None: + async def get_telemetry_endpoint(self, vin: str) -> Optional[dict[str, Any]]: """Get information about the vehicle.""" return await self.controller.request( method="GET", @@ -113,7 +112,7 @@ async def get_telemetry_endpoint(self, vin: str) -> dict[str, Any] | None: headers={"vin": vin}, ) - async def get_notification_endpoint(self, vin: str) -> dict[str, Any] | None: + async def get_notification_endpoint(self, vin: str) -> Optional[dict[str, Any]]: """Get information about the vehicle.""" resp = await self.controller.request( method="GET", @@ -125,8 +124,8 @@ async def get_notification_endpoint(self, vin: str) -> dict[str, Any] | None: return resp[0]["notifications"] async def get_driving_statistics_endpoint( - self, vin: str, from_date: str, interval: str | None = None - ) -> dict[str, Any] | None: + self, vin: str, from_date: str, interval: Optional[str] = None + ) -> Optional[dict[str, Any]]: """Get driving statistic""" return await self.controller.request( method="GET", @@ -170,7 +169,7 @@ async def get_trip_endpoint(self, vin: str, trip_id: str) -> Trips: async def set_lock_unlock_vehicle_endpoint( self, vin: str, action: str - ) -> dict[str, str] | None: + ) -> Optional[dict[str, str]]: """Lock vehicle.""" return await self.controller.request( method="POST", @@ -181,7 +180,7 @@ async def set_lock_unlock_vehicle_endpoint( async def get_lock_unlock_request_status( self, vin: str, request_id: str - ) -> dict[str, Any] | None: + ) -> Optional[dict[str, Any]]: """Check lock/unlock status given a request ID""" return await self.controller.request( method="GET", diff --git a/mytoyota/client.py b/mytoyota/client.py index 69d77a82..07d7ca0b 100644 --- a/mytoyota/client.py +++ b/mytoyota/client.py @@ -11,6 +11,7 @@ from __future__ import annotations import logging +from typing import Optional from mytoyota.api import Api from mytoyota.const import SUPPORTED_REGIONS @@ -41,7 +42,7 @@ def __init__( locale: str = "en-gb", region: str = "europe", brand: str = "T", - uuid: str | None = None, + uuid: Optional[str] = None, controller_class=Controller, disable_locale_check: bool = False, ) -> None: diff --git a/mytoyota/controller.py b/mytoyota/controller.py index 8ae82671..fd7dae95 100644 --- a/mytoyota/controller.py +++ b/mytoyota/controller.py @@ -1,8 +1,8 @@ """Toyota Connected Services Controller """ -import logging from datetime import datetime, timedelta from http import HTTPStatus -from typing import Any +import logging +from typing import Any, Optional, Union from urllib import parse # For parse query string, can this be done with httpx? import httpx @@ -31,7 +31,7 @@ def __init__( username: str, password: str, brand: str, - uuid: str | None = None, + uuid: Optional[str] = None, ) -> None: self._locale: str = locale self._region: str = region @@ -39,8 +39,8 @@ def __init__( self._password: str = password self._brand: str = brand self._uuid: str = uuid - self._token: str | None = None - self._token_expiration: datetime | None = None + self._token: Optional[str] = None + self._token_expiration: Optional[datetime] = None @property def _authorize_endpoint(self) -> str: @@ -64,7 +64,7 @@ def _authenticate_endpoint(self) -> str: @property # TODO Dont think this is required outside of the controller anymore. - def uuid(self) -> str | None: + def uuid(self) -> Optional[str]: """Return uuid.""" return self._uuid @@ -177,10 +177,10 @@ async def request_raw( self, # pylint: disable=too-many-branches method: str, endpoint: str, - base_url: str | None = None, - body: dict[str, Any] | None = None, - params: dict[str, Any] | None = None, - headers: dict[str, Any] | None = None, + base_url: Optional[str] = None, + body: Optional[dict[str, Any]] = None, + params: Optional[dict[str, Any]] = None, + headers: Optional[dict[str, Any]] = None, ) -> httpx.Response: """Shared request method""" if method not in ("GET", "POST", "PUT", "DELETE"): @@ -248,10 +248,10 @@ async def request_json( self, method: str, endpoint: str, - base_url: str | None = None, - body: dict[str, Any] | None = None, - params: dict[str, Any] | None = None, - headers: dict[str, Any] | None = None, + base_url: Optional[str] = None, + body: Optional[dict[str, Any]] = None, + params: Optional[dict[str, Any]] = None, + headers: Optional[dict[str, Any]] = None, ): response = await self.request_raw( method, endpoint, base_url, body, params, headers @@ -263,11 +263,11 @@ async def request( self, method: str, endpoint: str, - base_url: str | None = None, - body: dict[str, Any] | None = None, - params: dict[str, Any] | None = None, - headers: dict[str, Any] | None = None, - ) -> dict[str, Any] | list[Any] | None: + base_url: Optional[str] = None, + body: Optional[dict[str, Any]] = None, + params: Optional[dict[str, Any]] = None, + headers: Optional[dict[str, Any]] = None, + ) -> Optional[Union[dict[str, Any], list[Any]]]: # TODO possibly remove if/when fully pydantic response = await self.request_raw( method, endpoint, base_url, body, params, headers diff --git a/mytoyota/models/dashboard.py b/mytoyota/models/dashboard.py index b938fc7b..3f753f25 100644 --- a/mytoyota/models/dashboard.py +++ b/mytoyota/models/dashboard.py @@ -1,4 +1,6 @@ """Models for vehicle sensors.""" +from typing import Optional + from mytoyota.models.data import VehicleData from mytoyota.utils.conversions import convert_to_miles @@ -14,7 +16,7 @@ def is_metric(self) -> bool: return False @property - def odometer(self) -> int | None: + def odometer(self) -> Optional[int]: """Shows the odometer distance.""" if self._data["odometer"]["unit"] == "mi": return self._data["odometer"]["value"] @@ -22,12 +24,12 @@ def odometer(self) -> int | None: return convert_to_miles(self._data["odometer"]["value"]) @property - def fuel_level(self) -> float | None: + def fuel_level(self) -> Optional[float]: """Shows the fuellevel of the vehicle.""" return self._data["fuelLevel"] @property - def fuel_range(self) -> float | None: + def fuel_range(self) -> Optional[float]: """Shows the range if available.""" if self._data["fuelRange"]["unit"] == "mi": return self._data["odometer"]["value"] @@ -35,7 +37,7 @@ def fuel_range(self) -> float | None: return convert_to_miles(self._data["fuelRange"]["value"]) @property - def battery_level(self) -> float | None: + def battery_level(self) -> Optional[float]: """Shows the battery level if a hybrid.""" if "batteryLevel" in self._data: return self._data["batteryLevel"] @@ -43,7 +45,7 @@ def battery_level(self) -> float | None: return None @property - def battery_range(self) -> float | None: + def battery_range(self) -> Optional[float]: """Shows the battery range if a hybrid.""" if "evRange" in self._data: if self._data["evRange"]["unit"] == "mi": @@ -54,7 +56,7 @@ def battery_range(self) -> float | None: return None @property - def battery_range_with_aircon(self) -> float | None: + def battery_range_with_aircon(self) -> Optional[float]: """Shows the battery range with aircon on, if a hybrid.""" if "evRangeWithAc" in self._data: if self._data["evRangeWithAc"]["unit"] == "mi": @@ -65,7 +67,7 @@ def battery_range_with_aircon(self) -> float | None: return None @property - def charging_status(self) -> str | None: + def charging_status(self) -> Optional[str]: """Shows the charging status if a hybrid.""" if "chargingStatus" in self._data: return self._data["chargingStatus"] @@ -73,7 +75,7 @@ def charging_status(self) -> str | None: return None @property - def remaining_charge_time(self) -> int | None: + def remaining_charge_time(self) -> Optional[int]: """Shows the remaining time to a full charge, if a hybrid.""" # TODO: What units? if "remainingChargeTime" in self._data: diff --git a/mytoyota/models/endpoints/trip.py b/mytoyota/models/endpoints/trip.py index 66163491..36076110 100644 --- a/mytoyota/models/endpoints/trip.py +++ b/mytoyota/models/endpoints/trip.py @@ -1,7 +1,9 @@ -from pydantic import BaseModel, Field from datetime import date, datetime +from typing import Optional from uuid import UUID +from pydantic import BaseModel, Field + class _Pagination(BaseModel): currentPage: int @@ -27,7 +29,7 @@ class _Scores(BaseModel): advice: int = Field(ge=0, le=100, default=0) braking: int = Field(ge=0, le=100) constantSpeed: int = Field(ge=0, le=100, default=0) - global_: int | None = Field(ge=0, le=100, alias="global", default=None) + global_: Optional[int] = Field(ge=0, le=100, alias="global", default=None) class _Summary(BaseModel): @@ -59,7 +61,7 @@ class _HDC(BaseModel): class _MonthSummary(BaseModel): - hdc: _HDC | None = Field(default=None) # Only available on EV cars + hdc: Optional[_HDC] = Field(default=None) # Only available on EV cars # histograms not imported month: int = Field(..., ge=1, le=12) scores: _Scores @@ -81,7 +83,7 @@ class _TripSummary(_Summary): class _Trip(BaseModel): # behaviours not imported category: int - hdc: _HDC | None = Field(default=None) # Only available on EV cars + hdc: Optional[_HDC] = Field(default=None) # Only available on EV cars id: UUID scores: _Scores summary: _TripSummary diff --git a/mytoyota/models/hvac.py b/mytoyota/models/hvac.py index 029cab00..61f3fef7 100644 --- a/mytoyota/models/hvac.py +++ b/mytoyota/models/hvac.py @@ -1,12 +1,12 @@ """Models for vehicle sensors.""" from __future__ import annotations -from typing import Any +from typing import Any, Optional, Union from mytoyota.models.data import VehicleData -def get_attr_in_dict(data: dict[str, float], attr: str) -> float | None: +def get_attr_in_dict(data: dict[str, float], attr: str) -> Optional[float]: """Get a specific attribute from a dict""" return data.get(attr) @@ -22,7 +22,7 @@ def __init__(self, data: dict[str, Any], legacy: bool = False) -> None: self.legacy = legacy @property - def current_temperature(self) -> float | None: + def current_temperature(self) -> Optional[float]: """Current temperature.""" if self.legacy: return self._data.get("InsideTemperature") @@ -31,77 +31,77 @@ def current_temperature(self) -> float | None: ) @property - def target_temperature(self) -> float | None: + def target_temperature(self) -> Optional[float]: """Target temperature.""" if self.legacy: return self._data.get("SettingTemperature") return get_attr_in_dict(self._data.get("targetTemperature", {}), "value") @property - def started_at(self) -> str | None: + def started_at(self) -> Optional[str]: """Hvac started at.""" if self.legacy: return None return self._data.get("startedAt") @property - def status(self) -> str | None: + def status(self) -> Optional[str]: """Hvac status.""" if self.legacy: return None return self._data.get("status") @property - def type(self) -> str | None: + def type(self) -> Optional[str]: """Hvac type.""" if self.legacy: return None return self._data.get("type") @property - def duration(self) -> str | None: + def duration(self) -> Optional[str]: """Hvac duration.""" if self.legacy: return None return self._data.get("duration") @property - def options(self) -> dict | list | None: + def options(self) -> Optional[Union[dict, list]]: """Hvac options.""" if self.legacy: return None return self._data.get("options") @property - def command_id(self) -> str | int | None: + def command_id(self) -> Optional[Union[str, int]]: """Hvac command id.""" if self.legacy: return None return self._data.get("commandId") @property - def front_defogger_is_on(self) -> bool | None: + def front_defogger_is_on(self) -> Optional[bool]: """If the front defogger is on.""" if self.legacy: return self._data.get("FrontDefoggerStatus") == 1 return None @property - def rear_defogger_is_on(self) -> bool | None: + def rear_defogger_is_on(self) -> Optional[bool]: """If the rear defogger is on.""" if self.legacy: return self._data.get("RearDefoggerStatus") == 1 return None @property - def blower_on(self) -> int | None: + def blower_on(self) -> Optional[int]: """Hvac blower setting.""" if self.legacy: return self._data.get("BlowerStatus") return None @property - def last_updated(self) -> str | None: + def last_updated(self) -> Optional[str]: """Hvac last updated.""" if self.legacy: return None diff --git a/mytoyota/models/location.py b/mytoyota/models/location.py index 7c04b3c0..38810b30 100644 --- a/mytoyota/models/location.py +++ b/mytoyota/models/location.py @@ -1,5 +1,6 @@ """Models for vehicle location.""" from datetime import datetime +from typing import Optional from mytoyota.models.data import VehicleData @@ -18,7 +19,7 @@ def longitude(self) -> float: return float(self._data.get("longitude", 0.0)) @property - def timestamp(self) -> datetime | None: + def timestamp(self) -> Optional[datetime]: """Timestamp.""" return self._data.get("locationAcquisitionDatetime") diff --git a/mytoyota/models/sensors.py b/mytoyota/models/sensors.py index e61cba87..9c97ae9e 100644 --- a/mytoyota/models/sensors.py +++ b/mytoyota/models/sensors.py @@ -1,6 +1,8 @@ """Models for vehicle sensors.""" from __future__ import annotations +from typing import Optional + from mytoyota.models.data import VehicleData @@ -8,17 +10,17 @@ class Door(VehicleData): """Door/hood data model.""" @property - def warning(self) -> bool | None: + def warning(self) -> Optional[bool]: """If warning exists for the door.""" return self._data.get("warning") @property - def closed(self) -> bool | None: + def closed(self) -> Optional[bool]: """If the door is closed.""" return self._data.get("closed") @property - def locked(self) -> bool | None: + def locked(self) -> Optional[bool]: """If the door is locked.""" return self._data.get("locked") @@ -27,7 +29,7 @@ class Doors(VehicleData): """Trunk/doors/hood data model.""" @property - def warning(self) -> bool | None: + def warning(self) -> Optional[bool]: """If warning exists for one of the doors.""" return self._data.get("warning") @@ -61,12 +63,12 @@ class Window(VehicleData): """Window data model.""" @property - def warning(self) -> bool | None: + def warning(self) -> Optional[bool]: """If a warning exists for the window.""" return self._data.get("warning") @property - def state(self) -> str | None: + def state(self) -> Optional[str]: """Window state.""" return self._data.get("state") @@ -75,7 +77,7 @@ class Windows(VehicleData): """Windows data model.""" @property - def warning(self) -> bool | None: + def warning(self) -> Optional[bool]: """If a warning exists for one of the windows.""" return self._data.get("warning") @@ -104,12 +106,12 @@ class Light(VehicleData): """Vehicle light data model.""" @property - def warning(self) -> bool | None: + def warning(self) -> Optional[bool]: """If a warning exists for the light.""" return self._data.get("warning") @property - def off(self) -> bool | None: + def off(self) -> Optional[bool]: """If the light is off.""" return self._data.get("off") @@ -118,7 +120,7 @@ class Lights(VehicleData): """Vehicle lights data model.""" @property - def warning(self) -> bool | None: + def warning(self) -> Optional[bool]: """If a warning exists for one of the lights.""" return self._data.get("warning") @@ -142,12 +144,12 @@ class Key(VehicleData): """Keyfob data model.""" @property - def warning(self) -> bool | None: + def warning(self) -> Optional[bool]: """If a warning exists for the key..""" return self._data.get("warning") @property - def in_car(self) -> bool | None: + def in_car(self) -> Optional[bool]: """If the key is in the car.""" return self._data.get("inCar") @@ -156,12 +158,12 @@ class Sensors(VehicleData): """Vehicle sensors data model.""" @property - def overallstatus(self) -> str | None: + def overallstatus(self) -> Optional[str]: """If a warning exists for any of the sensors.""" return self._data.get("overallStatus") @property - def last_updated(self) -> str | None: + def last_updated(self) -> Optional[str]: """Last time data was recieved from the car.""" return self._data.get("timestamp") diff --git a/mytoyota/models/trip.py b/mytoyota/models/trip.py index f9798ca3..1ce69c99 100644 --- a/mytoyota/models/trip.py +++ b/mytoyota/models/trip.py @@ -2,6 +2,7 @@ from __future__ import annotations from datetime import datetime +from typing import Optional from mytoyota.models.data import VehicleData @@ -75,7 +76,7 @@ def start_address(self) -> str: return self._data.get("startAddress", "") @property - def start_time_gmt(self) -> datetime.datetime | None: + def start_time_gmt(self) -> Optional[datetime.datetime]: """Trip Start time GMT.""" start_time_str = self._data.get("startTimeGmt", None) if not start_time_str: @@ -83,7 +84,7 @@ def start_time_gmt(self) -> datetime.datetime | None: return datetime.strptime(start_time_str, "%Y-%m-%dT%H:%M:%SZ") @property - def end_time_gmt(self) -> datetime.datetime | None: + def end_time_gmt(self) -> Optional[datetime.datetime]: """Trip End time GMT.""" end_time_str = self._data.get("endTimeGmt", None) if not end_time_str: @@ -96,6 +97,6 @@ def end_address(self) -> str: return self._data.get("endAddress", "") @property - def classification_type(self) -> int | None: + def classification_type(self) -> Optional[int]: """Trip Classification type.""" return self._data.get("classificationType", None) diff --git a/mytoyota/models/vehicle.py b/mytoyota/models/vehicle.py index fa6ef89e..4fd6c614 100644 --- a/mytoyota/models/vehicle.py +++ b/mytoyota/models/vehicle.py @@ -3,7 +3,7 @@ import copy from functools import partial import logging -from typing import Any +from typing import Any, Optional from mytoyota.api import Api from mytoyota.models.dashboard import Dashboard @@ -78,7 +78,9 @@ def __init__( if ep[1](): self._endpoint_collect.append((ep[0], ep[2])) - def _supported(self, extendedCapability: str | None, feature: str | None) -> bool: + def _supported( + self, extendedCapability: Optional[str], feature: Optional[str] + ) -> bool: # If both set to None then nothing to check for if extendedCapability is None and feature is None: return True @@ -106,12 +108,12 @@ async def parallel_wrapper( self._endpoint_data[name] = data @property - def vin(self) -> str | None: + def vin(self) -> Optional[str]: """Vehicle's vinnumber.""" return self._vehicle_info.get("vin") @property - def alias(self) -> str | None: + def alias(self) -> Optional[str]: """Vehicle's alias.""" return self._vehicle_info.get("nickName", "Not set") @@ -141,7 +143,7 @@ def fueltype(self) -> str: return "Unknown" @property - def details(self) -> dict[str, Any] | None: + def details(self) -> Optional[dict[str, Any]]: """Formats vehicle info into a dict.""" det: dict[str, Any] = {} for i in sorted(self._vehicle_info): @@ -151,14 +153,14 @@ def details(self) -> dict[str, Any] | None: return det if det else None @property - def location(self) -> ParkingLocation | None: + def location(self) -> Optional[ParkingLocation]: """Last parking location.""" if "location" in self._endpoint_data: return ParkingLocation(self._endpoint_data["location"]["vehicleLocation"]) return None - def notifications(self, include_read: bool = False) -> list[Notification] | None: + def notifications(self, include_read: bool = False) -> Optional[list[Notification]]: if "notifications" in self._endpoint_data: ret = [] for notification in self._endpoint_data["notifications"]: @@ -173,13 +175,13 @@ def notifications(self, include_read: bool = False) -> list[Notification] | None return None @property - def hvac(self) -> Hvac | None: + def hvac(self) -> Optional[Hvac]: """Vehicle hvac.""" # This info is available need to find the endpoint. return None @property - def dashboard(self) -> Dashboard | None: + def dashboard(self) -> Optional[Dashboard]: """Vehicle dashboard.""" # Depending on car the required information is split across multiple endpoints # All cars seen have the status endpoint. This contains total milage.