From b4bac0f7a0a881ece3b3bd06dbe8531a67f8c923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Fri, 28 Aug 2020 14:50:32 +0300 Subject: [PATCH] Exception chaining and wrapping improvements (#39320) * Remove unnecessary exception re-wraps * Preserve exception chains on re-raise We slap "from cause" to almost all possible cases here. In some cases it could conceivably be better to do "from None" if we really want to hide the cause. However those should be in the minority, and "from cause" should be an improvement over the corresponding raise without a "from" in all cases anyway. The only case where we raise from None here is in plex, where the exception for an original invalid SSL cert is not the root cause for failure to validate a newly fetched one. Follow local convention on exception variable names if there is a consistent one, otherwise `err` to match with majority of codebase. * Fix mistaken re-wrap in homematicip_cloud/hap.py Missed the difference between HmipConnectionError and HmipcConnectionError. * Do not hide original error on plex new cert validation error Original is not the cause for the new one, but showing old in the traceback is useful nevertheless. --- homeassistant/auth/mfa_modules/__init__.py | 4 ++- homeassistant/auth/providers/__init__.py | 4 ++- homeassistant/auth/providers/command_line.py | 2 +- homeassistant/components/abode/__init__.py | 2 +- .../components/accuweather/__init__.py | 2 +- .../components/agent_dvr/__init__.py | 4 +-- homeassistant/components/airly/__init__.py | 2 +- .../components/airvisual/__init__.py | 4 +-- homeassistant/components/alexa/handlers.py | 6 ++-- homeassistant/components/almond/__init__.py | 2 +- .../components/ambient_station/__init__.py | 2 +- homeassistant/components/api/__init__.py | 4 +-- .../components/asterisk_mbox/mailbox.py | 2 +- homeassistant/components/atag/__init__.py | 2 +- homeassistant/components/aten_pe/switch.py | 2 +- homeassistant/components/august/__init__.py | 6 ++-- homeassistant/components/august/gateway.py | 2 +- homeassistant/components/auth/indieauth.py | 4 +-- homeassistant/components/awair/__init__.py | 4 +-- homeassistant/components/axis/device.py | 16 +++++----- homeassistant/components/blink/config_flow.py | 4 +-- homeassistant/components/bmp280/sensor.py | 2 +- homeassistant/components/bond/config_flow.py | 12 +++---- homeassistant/components/broadlink/device.py | 4 +-- homeassistant/components/broadlink/remote.py | 8 ++--- homeassistant/components/broadlink/updater.py | 2 +- homeassistant/components/brother/__init__.py | 2 +- homeassistant/components/camera/__init__.py | 4 +-- .../components/cert_expiry/__init__.py | 2 +- .../components/cert_expiry/helper.py | 20 +++++++----- homeassistant/components/citybikes/sensor.py | 8 ++--- homeassistant/components/control4/__init__.py | 2 +- homeassistant/components/control4/light.py | 4 +-- homeassistant/components/daikin/__init__.py | 8 ++--- homeassistant/components/deconz/gateway.py | 12 +++---- homeassistant/components/deluge/sensor.py | 4 +-- homeassistant/components/deluge/switch.py | 4 +-- .../components/device_automation/__init__.py | 10 +++--- .../devolo_home_control/__init__.py | 4 +-- homeassistant/components/dexcom/__init__.py | 6 ++-- homeassistant/components/directv/__init__.py | 4 +-- .../components/dlna_dmr/media_player.py | 4 +-- homeassistant/components/doorbird/__init__.py | 4 +-- .../components/doorbird/config_flow.py | 8 ++--- homeassistant/components/ebox/sensor.py | 2 +- homeassistant/components/ebusd/__init__.py | 2 +- homeassistant/components/ecobee/util.py | 10 +++--- homeassistant/components/ecobee/weather.py | 4 +-- homeassistant/components/everlights/light.py | 4 +-- .../components/flick_electric/config_flow.py | 8 ++--- homeassistant/components/flo/__init__.py | 4 +-- homeassistant/components/flo/config_flow.py | 2 +- homeassistant/components/flo/device.py | 2 +- homeassistant/components/flume/__init__.py | 4 +-- homeassistant/components/flume/config_flow.py | 8 ++--- .../components/flunearyou/__init__.py | 4 +-- homeassistant/components/foobot/sensor.py | 4 +-- .../components/garmin_connect/__init__.py | 2 +- homeassistant/components/gios/__init__.py | 2 +- homeassistant/components/glances/__init__.py | 4 +-- .../components/glances/config_flow.py | 4 +-- homeassistant/components/gogogate2/common.py | 4 ++- .../components/griddy/config_flow.py | 4 +-- homeassistant/components/guardian/util.py | 2 +- homeassistant/components/harmony/__init__.py | 4 +-- homeassistant/components/hassio/auth.py | 4 +-- homeassistant/components/heos/__init__.py | 4 +-- .../components/hisense_aehw4a1/__init__.py | 4 +-- .../components/hlk_sw16/config_flow.py | 6 ++-- .../homeassistant/triggers/time_pattern.py | 4 +-- .../components/homematicip_cloud/hap.py | 8 ++--- .../components/horizon/media_player.py | 2 +- homeassistant/components/hp_ilo/sensor.py | 2 +- homeassistant/components/http/forwarded.py | 4 +-- homeassistant/components/http/view.py | 14 ++++---- homeassistant/components/hue/bridge.py | 16 +++++----- homeassistant/components/hue/light.py | 6 ++-- homeassistant/components/hue/sensor_base.py | 6 ++-- .../hunterdouglas_powerview/__init__.py | 4 +-- .../hunterdouglas_powerview/config_flow.py | 4 +-- homeassistant/components/iammeter/sensor.py | 8 ++--- .../components/iaqualink/__init__.py | 2 +- homeassistant/components/icloud/account.py | 7 ++-- homeassistant/components/image/__init__.py | 8 ++--- homeassistant/components/influxdb/__init__.py | 24 +++++++------- homeassistant/components/influxdb/sensor.py | 2 +- homeassistant/components/insteon/schemas.py | 8 ++--- .../components/intesishome/climate.py | 6 ++-- homeassistant/components/ipp/__init__.py | 2 +- .../islamic_prayer_times/__init__.py | 4 +-- .../components/isy994/config_flow.py | 2 +- homeassistant/components/juicenet/__init__.py | 2 +- .../components/juicenet/config_flow.py | 4 +-- .../components/konnected/config_flow.py | 4 +-- homeassistant/components/konnected/panel.py | 2 +- .../components/luftdaten/__init__.py | 4 +-- .../components/media_extractor/__init__.py | 8 ++--- homeassistant/components/met/__init__.py | 2 +- homeassistant/components/mikrotik/hub.py | 10 +++--- .../components/mobile_app/webhook.py | 2 +- homeassistant/components/modbus/sensor.py | 4 +-- .../components/monoprice/__init__.py | 4 +-- .../components/monoprice/config_flow.py | 4 +-- homeassistant/components/mqtt/util.py | 4 +-- homeassistant/components/myq/__init__.py | 4 +-- homeassistant/components/myq/config_flow.py | 8 ++--- homeassistant/components/mysensors/gateway.py | 4 +-- homeassistant/components/mystrom/light.py | 4 +-- homeassistant/components/mystrom/switch.py | 4 +-- homeassistant/components/neato/__init__.py | 6 ++-- .../nederlandse_spoorwegen/sensor.py | 2 +- homeassistant/components/nexia/__init__.py | 4 +-- homeassistant/components/nexia/config_flow.py | 6 ++-- .../components/nightscout/config_flow.py | 4 +-- .../components/niko_home_control/light.py | 2 +- homeassistant/components/notion/__init__.py | 2 +- homeassistant/components/nuheat/__init__.py | 6 ++-- .../components/nuheat/config_flow.py | 16 +++++----- homeassistant/components/numato/__init__.py | 8 ++--- homeassistant/components/nws/config_flow.py | 2 +- .../components/nx584/alarm_control_panel.py | 2 +- homeassistant/components/openuv/__init__.py | 2 +- homeassistant/components/pencom/switch.py | 2 +- homeassistant/components/pi_hole/__init__.py | 4 +-- homeassistant/components/plex/__init__.py | 2 +- homeassistant/components/plugwise/__init__.py | 12 +++---- .../components/plugwise/config_flow.py | 8 ++--- .../components/plum_lightpad/__init__.py | 2 +- .../components/poolsense/__init__.py | 2 +- .../components/powerwall/__init__.py | 8 ++--- .../components/powerwall/config_flow.py | 6 ++-- homeassistant/components/proxy/camera.py | 8 ++--- .../components/qbittorrent/sensor.py | 4 +-- homeassistant/components/rachio/__init__.py | 2 +- .../components/rachio/config_flow.py | 2 +- .../components/rainmachine/__init__.py | 2 +- .../components/raspihats/__init__.py | 6 ++-- homeassistant/components/rfxtrx/__init__.py | 6 ++-- homeassistant/components/ring/config_flow.py | 8 ++--- homeassistant/components/roku/__init__.py | 2 +- homeassistant/components/roomba/__init__.py | 12 +++---- homeassistant/components/rtorrent/sensor.py | 4 +-- homeassistant/components/schluter/climate.py | 2 +- homeassistant/components/sense/__init__.py | 8 ++--- homeassistant/components/sensibo/climate.py | 4 +-- homeassistant/components/shelly/__init__.py | 8 ++--- .../components/simplisafe/__init__.py | 2 +- homeassistant/components/sisyphus/light.py | 4 +-- .../components/sisyphus/media_player.py | 4 +-- .../components/smart_meter_texas/__init__.py | 6 ++-- .../smart_meter_texas/config_flow.py | 6 ++-- homeassistant/components/smarthab/__init__.py | 4 +-- .../components/smartthings/__init__.py | 4 +-- homeassistant/components/sms/config_flow.py | 4 +-- homeassistant/components/solax/sensor.py | 4 +-- homeassistant/components/sonarr/__init__.py | 4 +-- .../components/songpal/media_player.py | 2 +- .../components/speedtestdotnet/__init__.py | 8 ++--- homeassistant/components/spotify/__init__.py | 4 +-- homeassistant/components/stream/__init__.py | 4 +-- homeassistant/components/tado/__init__.py | 2 +- homeassistant/components/tado/config_flow.py | 12 +++---- .../components/tankerkoenig/sensor.py | 4 +-- homeassistant/components/tesla/__init__.py | 2 +- homeassistant/components/tesla/config_flow.py | 4 +-- homeassistant/components/tibber/__init__.py | 4 +-- homeassistant/components/tibber/sensor.py | 4 +-- homeassistant/components/tile/__init__.py | 2 +- homeassistant/components/toon/coordinator.py | 2 +- homeassistant/components/tradfri/__init__.py | 4 +-- .../components/tradfri/config_flow.py | 12 +++---- .../components/transmission/__init__.py | 10 +++--- homeassistant/components/tts/__init__.py | 8 ++--- homeassistant/components/tuya/__init__.py | 4 +-- homeassistant/components/unifi/controller.py | 16 +++++----- homeassistant/components/updater/__init__.py | 8 +++-- homeassistant/components/upnp/__init__.py | 4 +-- homeassistant/components/uvc/camera.py | 4 +-- homeassistant/components/velbus/__init__.py | 2 +- homeassistant/components/waqi/sensor.py | 7 ++-- .../components/websocket_api/auth.py | 2 +- .../components/websocket_api/http.py | 8 ++--- homeassistant/components/wled/__init__.py | 2 +- homeassistant/components/wolflink/__init__.py | 14 ++++---- .../components/workday/binary_sensor.py | 4 +-- .../components/xiaomi_miio/air_quality.py | 4 +-- homeassistant/components/xiaomi_miio/fan.py | 4 +-- homeassistant/components/xiaomi_miio/light.py | 4 +-- .../components/xiaomi_miio/remote.py | 2 +- .../components/xiaomi_miio/sensor.py | 4 +-- .../components/xiaomi_miio/switch.py | 4 +-- homeassistant/components/yi/camera.py | 2 +- homeassistant/components/zha/api.py | 8 ++--- .../components/zha/device_trigger.py | 4 +-- homeassistant/config_entries.py | 4 +-- homeassistant/helpers/config_validation.py | 32 +++++++++---------- homeassistant/helpers/frame.py | 6 ++-- homeassistant/helpers/network.py | 4 +-- homeassistant/helpers/script.py | 12 +++---- homeassistant/helpers/template.py | 4 +-- homeassistant/scripts/check_config.py | 2 +- homeassistant/util/json.py | 10 +++--- homeassistant/util/ruamel_yaml.py | 12 +++---- homeassistant/util/yaml/loader.py | 14 ++++---- 204 files changed, 550 insertions(+), 518 deletions(-) diff --git a/homeassistant/auth/mfa_modules/__init__.py b/homeassistant/auth/mfa_modules/__init__.py index c2ec2260cf2..6e4b189bf74 100644 --- a/homeassistant/auth/mfa_modules/__init__.py +++ b/homeassistant/auth/mfa_modules/__init__.py @@ -150,7 +150,9 @@ async def _load_mfa_module(hass: HomeAssistant, module_name: str) -> types.Modul module = importlib.import_module(module_path) except ImportError as err: _LOGGER.error("Unable to load mfa module %s: %s", module_name, err) - raise HomeAssistantError(f"Unable to load mfa module {module_name}: {err}") + raise HomeAssistantError( + f"Unable to load mfa module {module_name}: {err}" + ) from err if hass.config.skip_pip or not hasattr(module, "REQUIREMENTS"): return module diff --git a/homeassistant/auth/providers/__init__.py b/homeassistant/auth/providers/__init__.py index 35208bd847c..b60fa8eff9c 100644 --- a/homeassistant/auth/providers/__init__.py +++ b/homeassistant/auth/providers/__init__.py @@ -146,7 +146,9 @@ async def load_auth_provider_module( module = importlib.import_module(f"homeassistant.auth.providers.{provider}") except ImportError as err: _LOGGER.error("Unable to load auth provider %s: %s", provider, err) - raise HomeAssistantError(f"Unable to load auth provider {provider}: {err}") + raise HomeAssistantError( + f"Unable to load auth provider {provider}: {err}" + ) from err if hass.config.skip_pip or not hasattr(module, "REQUIREMENTS"): return module diff --git a/homeassistant/auth/providers/command_line.py b/homeassistant/auth/providers/command_line.py index 961e1014c5e..d194d8119d1 100644 --- a/homeassistant/auth/providers/command_line.py +++ b/homeassistant/auth/providers/command_line.py @@ -71,7 +71,7 @@ class CommandLineAuthProvider(AuthProvider): except OSError as err: # happens when command doesn't exist or permission is denied _LOGGER.error("Error while authenticating %r: %s", username, err) - raise InvalidAuthError + raise InvalidAuthError from err if process.returncode != 0: _LOGGER.error( diff --git a/homeassistant/components/abode/__init__.py b/homeassistant/components/abode/__init__.py index 92665bc1890..2ac52c87131 100644 --- a/homeassistant/components/abode/__init__.py +++ b/homeassistant/components/abode/__init__.py @@ -120,7 +120,7 @@ async def async_setup_entry(hass, config_entry): except (AbodeException, ConnectTimeout, HTTPError) as ex: LOGGER.error("Unable to connect to Abode: %s", str(ex)) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from ex for platform in ABODE_PLATFORMS: hass.async_create_task( diff --git a/homeassistant/components/accuweather/__init__.py b/homeassistant/components/accuweather/__init__.py index 1e1a434a036..c8ae14678d5 100644 --- a/homeassistant/components/accuweather/__init__.py +++ b/homeassistant/components/accuweather/__init__.py @@ -127,6 +127,6 @@ class AccuWeatherDataUpdateCoordinator(DataUpdateCoordinator): InvalidApiKeyError, RequestsExceededError, ) as error: - raise UpdateFailed(error) + raise UpdateFailed(error) from error _LOGGER.debug("Requests remaining: %s", self.accuweather.requests_remaining) return {**current, **{ATTR_FORECAST: forecast}} diff --git a/homeassistant/components/agent_dvr/__init__.py b/homeassistant/components/agent_dvr/__init__.py index cc72b1e33ae..878a100684f 100644 --- a/homeassistant/components/agent_dvr/__init__.py +++ b/homeassistant/components/agent_dvr/__init__.py @@ -33,9 +33,9 @@ async def async_setup_entry(hass, config_entry): agent_client = Agent(server_origin, async_get_clientsession(hass)) try: await agent_client.update() - except AgentError: + except AgentError as err: await agent_client.close() - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err if not agent_client.is_available: raise ConfigEntryNotReady diff --git a/homeassistant/components/airly/__init__.py b/homeassistant/components/airly/__init__.py index 85071925357..de09d767b1f 100644 --- a/homeassistant/components/airly/__init__.py +++ b/homeassistant/components/airly/__init__.py @@ -125,7 +125,7 @@ class AirlyDataUpdateCoordinator(DataUpdateCoordinator): try: await measurements.update() except (AirlyError, ClientConnectorError) as error: - raise UpdateFailed(error) + raise UpdateFailed(error) from error values = measurements.current["values"] index = measurements.current["indexes"][0] diff --git a/homeassistant/components/airvisual/__init__.py b/homeassistant/components/airvisual/__init__.py index 3449d5e865f..4e748766425 100644 --- a/homeassistant/components/airvisual/__init__.py +++ b/homeassistant/components/airvisual/__init__.py @@ -227,7 +227,7 @@ async def async_setup_entry(hass, config_entry): try: return await api_coro except AirVisualError as err: - raise UpdateFailed(f"Error while retrieving data: {err}") + raise UpdateFailed(f"Error while retrieving data: {err}") from err coordinator = DataUpdateCoordinator( hass, @@ -263,7 +263,7 @@ async def async_setup_entry(hass, config_entry): include_trends=False, ) except NodeProError as err: - raise UpdateFailed(f"Error while retrieving data: {err}") + raise UpdateFailed(f"Error while retrieving data: {err}") from err coordinator = DataUpdateCoordinator( hass, diff --git a/homeassistant/components/alexa/handlers.py b/homeassistant/components/alexa/handlers.py index 7737016d573..6eeb3235a64 100644 --- a/homeassistant/components/alexa/handlers.py +++ b/homeassistant/components/alexa/handlers.py @@ -1542,8 +1542,10 @@ async def async_api_initialize_camera_stream(hass, config, directive, context): require_ssl=True, require_standard_port=True, ) - except network.NoURLAvailableError: - raise AlexaInvalidValueError("Failed to find suitable URL to serve to Alexa") + except network.NoURLAvailableError as err: + raise AlexaInvalidValueError( + "Failed to find suitable URL to serve to Alexa" + ) from err payload = { "cameraStreams": [ diff --git a/homeassistant/components/almond/__init__.py b/homeassistant/components/almond/__init__.py index 2117f809b04..b9f75ff8c6b 100644 --- a/homeassistant/components/almond/__init__.py +++ b/homeassistant/components/almond/__init__.py @@ -208,7 +208,7 @@ async def _configure_almond_for_ha( msg = err _LOGGER.warning("Unable to configure Almond: %s", msg) await hass.auth.async_remove_refresh_token(refresh_token) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err # Clear all other refresh tokens for token in list(user.refresh_tokens.values()): diff --git a/homeassistant/components/ambient_station/__init__.py b/homeassistant/components/ambient_station/__init__.py index 89b6236d392..b3f4aeec3bd 100644 --- a/homeassistant/components/ambient_station/__init__.py +++ b/homeassistant/components/ambient_station/__init__.py @@ -300,7 +300,7 @@ async def async_setup_entry(hass, config_entry): hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = ambient except WebsocketError as err: _LOGGER.error("Config entry failed: %s", err) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err hass.bus.async_listen_once( EVENT_HOMEASSISTANT_STOP, ambient.client.websocket.disconnect() diff --git a/homeassistant/components/api/__init__.py b/homeassistant/components/api/__init__.py index 001ce5d2a4e..c1f692a76ad 100644 --- a/homeassistant/components/api/__init__.py +++ b/homeassistant/components/api/__init__.py @@ -375,8 +375,8 @@ class APIDomainServicesView(HomeAssistantView): await hass.services.async_call( domain, service, data, True, self.context(request) ) - except (vol.Invalid, ServiceNotFound): - raise HTTPBadRequest() + except (vol.Invalid, ServiceNotFound) as ex: + raise HTTPBadRequest() from ex return self.json(changed_states) diff --git a/homeassistant/components/asterisk_mbox/mailbox.py b/homeassistant/components/asterisk_mbox/mailbox.py index b3863eeb13f..62d817df9a3 100644 --- a/homeassistant/components/asterisk_mbox/mailbox.py +++ b/homeassistant/components/asterisk_mbox/mailbox.py @@ -60,7 +60,7 @@ class AsteriskMailbox(Mailbox): partial(client.mp3, msgid, sync=True) ) except ServerError as err: - raise StreamError(err) + raise StreamError(err) from err async def async_get_messages(self): """Return a list of the current messages.""" diff --git a/homeassistant/components/atag/__init__.py b/homeassistant/components/atag/__init__.py index 237a82f207a..e5d06c08756 100644 --- a/homeassistant/components/atag/__init__.py +++ b/homeassistant/components/atag/__init__.py @@ -66,7 +66,7 @@ class AtagDataUpdateCoordinator(DataUpdateCoordinator): if not await self.atag.update(): raise UpdateFailed("No data received") except AtagException as error: - raise UpdateFailed(error) + raise UpdateFailed(error) from error return self.atag.report diff --git a/homeassistant/components/aten_pe/switch.py b/homeassistant/components/aten_pe/switch.py index e5970fc4d3b..1bf54085064 100644 --- a/homeassistant/components/aten_pe/switch.py +++ b/homeassistant/components/aten_pe/switch.py @@ -55,7 +55,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= outlets = dev.outlets() except AtenPEError as exc: _LOGGER.error("Failed to initialize %s:%s: %s", node, serv, str(exc)) - raise PlatformNotReady + raise PlatformNotReady from exc switches = [] async for outlet in outlets: diff --git a/homeassistant/components/august/__init__.py b/homeassistant/components/august/__init__.py index 9e0222dc81d..e0d7749dcbb 100644 --- a/homeassistant/components/august/__init__.py +++ b/homeassistant/components/august/__init__.py @@ -171,8 +171,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): try: await august_gateway.async_setup(entry.data) return await async_setup_august(hass, entry, august_gateway) - except asyncio.TimeoutError: - raise ConfigEntryNotReady + except asyncio.TimeoutError as err: + raise ConfigEntryNotReady from err async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): @@ -339,7 +339,7 @@ class AugustData(AugustSubscriberMixin): device_name = self._get_device_name(device_id) if device_name is None: device_name = f"DeviceID: {device_id}" - raise HomeAssistantError(f"{device_name}: {err}") + raise HomeAssistantError(f"{device_name}: {err}") from err return ret diff --git a/homeassistant/components/august/gateway.py b/homeassistant/components/august/gateway.py index 272c50ac02a..6918907611f 100644 --- a/homeassistant/components/august/gateway.py +++ b/homeassistant/components/august/gateway.py @@ -102,7 +102,7 @@ class AugustGateway: self._authentication = await self.authenticator.async_authenticate() except ClientError as ex: _LOGGER.error("Unable to connect to August service: %s", str(ex)) - raise CannotConnect + raise CannotConnect from ex if self._authentication.state == AuthenticationState.BAD_PASSWORD: raise InvalidAuth diff --git a/homeassistant/components/auth/indieauth.py b/homeassistant/components/auth/indieauth.py index 0d942bd358d..e823659f62b 100644 --- a/homeassistant/components/auth/indieauth.py +++ b/homeassistant/components/auth/indieauth.py @@ -170,8 +170,8 @@ def _parse_client_id(client_id): try: # parts raises ValueError when port cannot be parsed as int parts.port - except ValueError: - raise ValueError("Client ID contains invalid port") + except ValueError as ex: + raise ValueError("Client ID contains invalid port") from ex # Additionally, hostnames # MUST be domain names or a loopback interface and diff --git a/homeassistant/components/awair/__init__.py b/homeassistant/components/awair/__init__.py index 2ae436bebba..56af5d2b662 100644 --- a/homeassistant/components/awair/__init__.py +++ b/homeassistant/components/awair/__init__.py @@ -102,9 +102,9 @@ class AwairDataUpdateCoordinator(DataUpdateCoordinator): ) ) - raise UpdateFailed(err) + raise UpdateFailed(err) from err except Exception as err: - raise UpdateFailed(err) + raise UpdateFailed(err) from err async def _fetch_air_data(self, device): """Fetch latest air quality data.""" diff --git a/homeassistant/components/axis/device.py b/homeassistant/components/axis/device.py index 18845ce12a3..a22fea23e79 100644 --- a/homeassistant/components/axis/device.py +++ b/homeassistant/components/axis/device.py @@ -186,8 +186,8 @@ class AxisNetworkDevice: password=self.config_entry.data[CONF_PASSWORD], ) - except CannotConnect: - raise ConfigEntryNotReady + except CannotConnect as err: + raise ConfigEntryNotReady from err except Exception: # pylint: disable=broad-except LOGGER.error("Unknown error connecting with Axis device on %s", self.host) @@ -271,14 +271,14 @@ async def get_device(hass, host, port, username, password): return device - except axis.Unauthorized: + except axis.Unauthorized as err: LOGGER.warning("Connected to device at %s but not registered.", host) - raise AuthenticationRequired + raise AuthenticationRequired from err - except (asyncio.TimeoutError, axis.RequestError): + except (asyncio.TimeoutError, axis.RequestError) as err: LOGGER.error("Error connecting to the Axis device at %s", host) - raise CannotConnect + raise CannotConnect from err - except axis.AxisException: + except axis.AxisException as err: LOGGER.exception("Unknown Axis communication error occurred") - raise AuthenticationRequired + raise AuthenticationRequired from err diff --git a/homeassistant/components/blink/config_flow.py b/homeassistant/components/blink/config_flow.py index 63c822cfd1f..d244c316483 100644 --- a/homeassistant/components/blink/config_flow.py +++ b/homeassistant/components/blink/config_flow.py @@ -26,8 +26,8 @@ def validate_input(hass: core.HomeAssistant, auth): """Validate the user input allows us to connect.""" try: auth.startup() - except (LoginError, TokenRefreshFailed): - raise InvalidAuth + except (LoginError, TokenRefreshFailed) as err: + raise InvalidAuth from err if auth.check_key_required(): raise Require2FA diff --git a/homeassistant/components/bmp280/sensor.py b/homeassistant/components/bmp280/sensor.py index 70efbce7d85..3c34408cb62 100644 --- a/homeassistant/components/bmp280/sensor.py +++ b/homeassistant/components/bmp280/sensor.py @@ -54,7 +54,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): "%s. Hint: Check wiring and make sure that the SDO pin is tied to either ground (0x76) or VCC (0x77)", error.args[0], ) - raise PlatformNotReady() + raise PlatformNotReady() from error _LOGGER.error(error) return # use custom name if there's any diff --git a/homeassistant/components/bond/config_flow.py b/homeassistant/components/bond/config_flow.py index ca8965d4d43..49ca559685c 100644 --- a/homeassistant/components/bond/config_flow.py +++ b/homeassistant/components/bond/config_flow.py @@ -28,15 +28,15 @@ async def _validate_input(data: Dict[str, Any]) -> str: version = await bond.version() # call to non-version API is needed to validate authentication await bond.devices() - except ClientConnectionError: - raise InputValidationError("cannot_connect") + except ClientConnectionError as error: + raise InputValidationError("cannot_connect") from error except ClientResponseError as error: if error.status == 401: - raise InputValidationError("invalid_auth") - raise InputValidationError("unknown") - except Exception: + raise InputValidationError("invalid_auth") from error + raise InputValidationError("unknown") from error + except Exception as error: _LOGGER.exception("Unexpected exception") - raise InputValidationError("unknown") + raise InputValidationError("unknown") from error # Return unique ID from the hub to be stored in the config entry. bond_id = version.get("bondid") diff --git a/homeassistant/components/broadlink/device.py b/homeassistant/components/broadlink/device.py index c8751182cb9..d05fdfd4df6 100644 --- a/homeassistant/components/broadlink/device.py +++ b/homeassistant/components/broadlink/device.py @@ -82,8 +82,8 @@ class BroadlinkDevice: await self._async_handle_auth_error() return False - except (DeviceOfflineError, OSError): - raise ConfigEntryNotReady + except (DeviceOfflineError, OSError) as err: + raise ConfigEntryNotReady from err except BroadlinkException as err: _LOGGER.error( diff --git a/homeassistant/components/broadlink/remote.py b/homeassistant/components/broadlink/remote.py index 10c45fec262..7c1ae7349da 100644 --- a/homeassistant/components/broadlink/remote.py +++ b/homeassistant/components/broadlink/remote.py @@ -175,8 +175,8 @@ class BroadlinkRemote(RemoteEntity, RestoreEntity): try: code = self._codes[device][command] - except KeyError: - raise KeyError("Command not found") + except KeyError as err: + raise KeyError("Command not found") from err # For toggle commands, alternate between codes in a list. if isinstance(code, list): @@ -187,8 +187,8 @@ class BroadlinkRemote(RemoteEntity, RestoreEntity): try: return data_packet(code), is_toggle_cmd - except ValueError: - raise ValueError("Invalid code") + except ValueError as err: + raise ValueError("Invalid code") from err @callback def get_flags(self): diff --git a/homeassistant/components/broadlink/updater.py b/homeassistant/components/broadlink/updater.py index a81cde49737..bd124d1e1ac 100644 --- a/homeassistant/components/broadlink/updater.py +++ b/homeassistant/components/broadlink/updater.py @@ -63,7 +63,7 @@ class BroadlinkUpdateManager(ABC): _LOGGER.warning( "Disconnected from the device at %s", self.device.api.host[0] ) - raise UpdateFailed(err) + raise UpdateFailed(err) from err else: if self.available is False: diff --git a/homeassistant/components/brother/__init__.py b/homeassistant/components/brother/__init__.py index 4c69282a996..d4cd5d4a2b5 100644 --- a/homeassistant/components/brother/__init__.py +++ b/homeassistant/components/brother/__init__.py @@ -82,5 +82,5 @@ class BrotherDataUpdateCoordinator(DataUpdateCoordinator): try: await self.brother.async_update() except (ConnectionError, SnmpError, UnsupportedModel) as error: - raise UpdateFailed(error) + raise UpdateFailed(error) from error return self.brother.data diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index bdc94b19eb1..3de47db80d1 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -539,8 +539,8 @@ class CameraMjpegStream(CameraView): if interval < MIN_STREAM_INTERVAL: raise ValueError(f"Stream interval must be be > {MIN_STREAM_INTERVAL}") return await camera.handle_async_still_stream(request, interval) - except ValueError: - raise web.HTTPBadRequest() + except ValueError as err: + raise web.HTTPBadRequest() from err @websocket_api.async_response diff --git a/homeassistant/components/cert_expiry/__init__.py b/homeassistant/components/cert_expiry/__init__.py index 84629353bce..d01e38a2e2c 100644 --- a/homeassistant/components/cert_expiry/__init__.py +++ b/homeassistant/components/cert_expiry/__init__.py @@ -76,7 +76,7 @@ class CertExpiryDataUpdateCoordinator(DataUpdateCoordinator[datetime]): try: timestamp = await get_cert_expiry_timestamp(self.hass, self.host, self.port) except TemporaryFailure as err: - raise UpdateFailed(err.args[0]) + raise UpdateFailed(err.args[0]) from err except ValidationFailure as err: self.cert_error = err self.is_cert_valid = False diff --git a/homeassistant/components/cert_expiry/helper.py b/homeassistant/components/cert_expiry/helper.py index f4caee8abf2..6c49e9e26b9 100644 --- a/homeassistant/components/cert_expiry/helper.py +++ b/homeassistant/components/cert_expiry/helper.py @@ -28,16 +28,20 @@ async def get_cert_expiry_timestamp(hass, hostname, port): """Return the certificate's expiration timestamp.""" try: cert = await hass.async_add_executor_job(get_cert, hostname, port) - except socket.gaierror: - raise ResolveFailed(f"Cannot resolve hostname: {hostname}") - except socket.timeout: - raise ConnectionTimeout(f"Connection timeout with server: {hostname}:{port}") - except ConnectionRefusedError: - raise ConnectionRefused(f"Connection refused by server: {hostname}:{port}") + except socket.gaierror as err: + raise ResolveFailed(f"Cannot resolve hostname: {hostname}") from err + except socket.timeout as err: + raise ConnectionTimeout( + f"Connection timeout with server: {hostname}:{port}" + ) from err + except ConnectionRefusedError as err: + raise ConnectionRefused( + f"Connection refused by server: {hostname}:{port}" + ) from err except ssl.CertificateError as err: - raise ValidationFailure(err.verify_message) + raise ValidationFailure(err.verify_message) from err except ssl.SSLError as err: - raise ValidationFailure(err.args[0]) + raise ValidationFailure(err.args[0]) from err ts_seconds = ssl.cert_time_to_seconds(cert["notAfter"]) return dt.utc_from_timestamp(ts_seconds) diff --git a/homeassistant/components/citybikes/sensor.py b/homeassistant/components/citybikes/sensor.py index 799fe6acc70..924ef2fa6b4 100644 --- a/homeassistant/components/citybikes/sensor.py +++ b/homeassistant/components/citybikes/sensor.py @@ -225,8 +225,8 @@ class CityBikesNetworks: result = network[ATTR_ID] return result - except CityBikesRequestError: - raise PlatformNotReady + except CityBikesRequestError as err: + raise PlatformNotReady from err finally: self.networks_loading.release() @@ -251,11 +251,11 @@ class CityBikesNetwork: ) self.stations = network[ATTR_NETWORK][ATTR_STATIONS_LIST] self.ready.set() - except CityBikesRequestError: + except CityBikesRequestError as err: if now is not None: self.ready.clear() else: - raise PlatformNotReady + raise PlatformNotReady from err class CityBikesStation(Entity): diff --git a/homeassistant/components/control4/__init__.py b/homeassistant/components/control4/__init__.py index 0f27c678e59..41b71162d6c 100644 --- a/homeassistant/components/control4/__init__.py +++ b/homeassistant/components/control4/__init__.py @@ -59,7 +59,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): await account.getAccountBearerToken() except client_exceptions.ClientError as exception: _LOGGER.error("Error connecting to Control4 account API: %s", exception) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from exception except BadCredentials as exception: _LOGGER.error( "Error authenticating with Control4 account API, incorrect username or password: %s", diff --git a/homeassistant/components/control4/light.py b/homeassistant/components/control4/light.py index 2871da34f11..09e05791169 100644 --- a/homeassistant/components/control4/light.py +++ b/homeassistant/components/control4/light.py @@ -45,14 +45,14 @@ async def async_setup_entry( try: return await director_update_data(hass, entry, CONTROL4_NON_DIMMER_VAR) except C4Exception as err: - raise UpdateFailed(f"Error communicating with API: {err}") + raise UpdateFailed(f"Error communicating with API: {err}") from err async def async_update_data_dimmer(): """Fetch data from Control4 director for dimmer lights.""" try: return await director_update_data(hass, entry, CONTROL4_DIMMER_VAR) except C4Exception as err: - raise UpdateFailed(f"Error communicating with API: {err}") + raise UpdateFailed(f"Error communicating with API: {err}") from err non_dimmer_coordinator = DataUpdateCoordinator( hass, diff --git a/homeassistant/components/daikin/__init__.py b/homeassistant/components/daikin/__init__.py index 49a939b8c72..65a3bf28c3b 100644 --- a/homeassistant/components/daikin/__init__.py +++ b/homeassistant/components/daikin/__init__.py @@ -114,12 +114,12 @@ async def daikin_api_setup(hass, host, key, uuid, password): device = await Appliance.factory( host, session, key=key, uuid=uuid, password=password ) - except asyncio.TimeoutError: + except asyncio.TimeoutError as err: _LOGGER.debug("Connection to %s timed out", host) - raise ConfigEntryNotReady - except ClientConnectionError: + raise ConfigEntryNotReady from err + except ClientConnectionError as err: _LOGGER.debug("ClientConnectionError to %s", host) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err except Exception: # pylint: disable=broad-except _LOGGER.error("Unexpected error creating device %s", host) return None diff --git a/homeassistant/components/deconz/gateway.py b/homeassistant/components/deconz/gateway.py index 6ef68b43f64..828f65c9811 100644 --- a/homeassistant/components/deconz/gateway.py +++ b/homeassistant/components/deconz/gateway.py @@ -98,8 +98,8 @@ class DeconzGateway: self.async_connection_status_callback, ) - except CannotConnect: - raise ConfigEntryNotReady + except CannotConnect as err: + raise ConfigEntryNotReady from err except Exception as err: # pylint: disable=broad-except LOGGER.error("Error connecting with deCONZ gateway: %s", err) @@ -254,10 +254,10 @@ async def get_gateway( await deconz.initialize() return deconz - except errors.Unauthorized: + except errors.Unauthorized as err: LOGGER.warning("Invalid key for deCONZ at %s", config[CONF_HOST]) - raise AuthenticationRequired + raise AuthenticationRequired from err - except (asyncio.TimeoutError, errors.RequestError): + except (asyncio.TimeoutError, errors.RequestError) as err: LOGGER.error("Error connecting to deCONZ gateway at %s", config[CONF_HOST]) - raise CannotConnect + raise CannotConnect from err diff --git a/homeassistant/components/deluge/sensor.py b/homeassistant/components/deluge/sensor.py index 4a24e979607..5e8df89c20d 100644 --- a/homeassistant/components/deluge/sensor.py +++ b/homeassistant/components/deluge/sensor.py @@ -58,9 +58,9 @@ def setup_platform(hass, config, add_entities, discovery_info=None): deluge_api = DelugeRPCClient(host, port, username, password) try: deluge_api.connect() - except ConnectionRefusedError: + except ConnectionRefusedError as err: _LOGGER.error("Connection to Deluge Daemon failed") - raise PlatformNotReady + raise PlatformNotReady from err dev = [] for variable in config[CONF_MONITORED_VARIABLES]: dev.append(DelugeSensor(variable, deluge_api, name)) diff --git a/homeassistant/components/deluge/switch.py b/homeassistant/components/deluge/switch.py index 04acf6a9dd9..2aff1b5266c 100644 --- a/homeassistant/components/deluge/switch.py +++ b/homeassistant/components/deluge/switch.py @@ -46,9 +46,9 @@ def setup_platform(hass, config, add_entities, discovery_info=None): deluge_api = DelugeRPCClient(host, port, username, password) try: deluge_api.connect() - except ConnectionRefusedError: + except ConnectionRefusedError as err: _LOGGER.error("Connection to Deluge Daemon failed") - raise PlatformNotReady + raise PlatformNotReady from err add_entities([DelugeSwitch(deluge_api, name)]) diff --git a/homeassistant/components/device_automation/__init__.py b/homeassistant/components/device_automation/__init__.py index 33685b2bc1c..1db4af12f22 100644 --- a/homeassistant/components/device_automation/__init__.py +++ b/homeassistant/components/device_automation/__init__.py @@ -83,12 +83,14 @@ async def async_get_device_automation_platform( try: integration = await async_get_integration_with_requirements(hass, domain) platform = integration.get_platform(platform_name) - except IntegrationNotFound: - raise InvalidDeviceAutomationConfig(f"Integration '{domain}' not found") - except ImportError: + except IntegrationNotFound as err: + raise InvalidDeviceAutomationConfig( + f"Integration '{domain}' not found" + ) from err + except ImportError as err: raise InvalidDeviceAutomationConfig( f"Integration '{domain}' does not support device automation {automation_type}s" - ) + ) from err return platform diff --git a/homeassistant/components/devolo_home_control/__init__.py b/homeassistant/components/devolo_home_control/__init__.py index cfe1549f3c4..c955bf77096 100644 --- a/homeassistant/components/devolo_home_control/__init__.py +++ b/homeassistant/components/devolo_home_control/__init__.py @@ -50,8 +50,8 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool hass.data[DOMAIN]["homecontrol"] = await hass.async_add_executor_job( partial(HomeControl, gateway_id=gateway_id, url=mprm_url) ) - except ConnectionError: - raise ConfigEntryNotReady + except ConnectionError as err: + raise ConfigEntryNotReady from err for platform in PLATFORMS: hass.async_create_task( diff --git a/homeassistant/components/dexcom/__init__.py b/homeassistant/components/dexcom/__init__.py index 6c4f8c071a1..c2eb9bd466d 100644 --- a/homeassistant/components/dexcom/__init__.py +++ b/homeassistant/components/dexcom/__init__.py @@ -43,8 +43,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): ) except AccountError: return False - except SessionError: - raise ConfigEntryNotReady + except SessionError as error: + raise ConfigEntryNotReady from error if not entry.options: hass.config_entries.async_update_entry( @@ -55,7 +55,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): try: return await hass.async_add_executor_job(dexcom.get_current_glucose_reading) except SessionError as error: - raise UpdateFailed(error) + raise UpdateFailed(error) from error hass.data[DOMAIN][entry.entry_id] = { COORDINATOR: DataUpdateCoordinator( diff --git a/homeassistant/components/directv/__init__.py b/homeassistant/components/directv/__init__.py index d01f8bd25c9..af27d19cfb0 100644 --- a/homeassistant/components/directv/__init__.py +++ b/homeassistant/components/directv/__init__.py @@ -59,8 +59,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: try: await dtv.update() - except DIRECTVError: - raise ConfigEntryNotReady + except DIRECTVError as err: + raise ConfigEntryNotReady from err hass.data[DOMAIN][entry.entry_id] = dtv diff --git a/homeassistant/components/dlna_dmr/media_player.py b/homeassistant/components/dlna_dmr/media_player.py index 75d88d59c32..acbd69138d4 100644 --- a/homeassistant/components/dlna_dmr/media_player.py +++ b/homeassistant/components/dlna_dmr/media_player.py @@ -182,8 +182,8 @@ async def async_setup_platform( factory = UpnpFactory(requester, disable_state_variable_validation=True) try: upnp_device = await factory.async_create_device(url) - except (asyncio.TimeoutError, aiohttp.ClientError): - raise PlatformNotReady() + except (asyncio.TimeoutError, aiohttp.ClientError) as err: + raise PlatformNotReady() from err # wrap with DmrDevice dlna_device = DmrDevice(upnp_device, event_handler) diff --git a/homeassistant/components/doorbird/__init__.py b/homeassistant/components/doorbird/__init__.py index 8f9ef2a3ed8..43ab0c96153 100644 --- a/homeassistant/components/doorbird/__init__.py +++ b/homeassistant/components/doorbird/__init__.py @@ -132,10 +132,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): "Authorization rejected by DoorBird for %s@%s", username, device_ip ) return False - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err except OSError as oserr: _LOGGER.error("Failed to setup doorbird at %s: %s", device_ip, oserr) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from oserr if not status[0]: _LOGGER.error( diff --git a/homeassistant/components/doorbird/config_flow.py b/homeassistant/components/doorbird/config_flow.py index 52f94116344..07b753da6ee 100644 --- a/homeassistant/components/doorbird/config_flow.py +++ b/homeassistant/components/doorbird/config_flow.py @@ -40,10 +40,10 @@ async def validate_input(hass: core.HomeAssistant, data): info = await hass.async_add_executor_job(device.info) except urllib.error.HTTPError as err: if err.code == 401: - raise InvalidAuth - raise CannotConnect - except OSError: - raise CannotConnect + raise InvalidAuth from err + raise CannotConnect from err + except OSError as err: + raise CannotConnect from err if not status[0]: raise CannotConnect diff --git a/homeassistant/components/ebox/sensor.py b/homeassistant/components/ebox/sensor.py index a8032a4f78a..7bbddb18e7b 100644 --- a/homeassistant/components/ebox/sensor.py +++ b/homeassistant/components/ebox/sensor.py @@ -81,7 +81,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= await ebox_data.async_update() except PyEboxError as exp: _LOGGER.error("Failed login: %s", exp) - raise PlatformNotReady + raise PlatformNotReady from exp sensors = [] for variable in config[CONF_MONITORED_VARIABLES]: diff --git a/homeassistant/components/ebusd/__init__.py b/homeassistant/components/ebusd/__init__.py index a1a7fc88086..855e62727b5 100644 --- a/homeassistant/components/ebusd/__init__.py +++ b/homeassistant/components/ebusd/__init__.py @@ -110,7 +110,7 @@ class EbusdData: self.value[name] = command_result except RuntimeError as err: _LOGGER.error(err) - raise RuntimeError(err) + raise RuntimeError(err) from err def write(self, call): """Call write methon on ebusd.""" diff --git a/homeassistant/components/ecobee/util.py b/homeassistant/components/ecobee/util.py index 2f5d194fec0..ac30b3bb660 100644 --- a/homeassistant/components/ecobee/util.py +++ b/homeassistant/components/ecobee/util.py @@ -8,8 +8,8 @@ def ecobee_date(date_string): """Validate a date_string as valid for the ecobee API.""" try: datetime.strptime(date_string, "%Y-%m-%d") - except ValueError: - raise vol.Invalid("Date does not match ecobee date format YYYY-MM-DD") + except ValueError as err: + raise vol.Invalid("Date does not match ecobee date format YYYY-MM-DD") from err return date_string @@ -17,6 +17,8 @@ def ecobee_time(time_string): """Validate a time_string as valid for the ecobee API.""" try: datetime.strptime(time_string, "%H:%M:%S") - except ValueError: - raise vol.Invalid("Time does not match ecobee 24-hour time format HH:MM:SS") + except ValueError as err: + raise vol.Invalid( + "Time does not match ecobee 24-hour time format HH:MM:SS" + ) from err return time_string diff --git a/homeassistant/components/ecobee/weather.py b/homeassistant/components/ecobee/weather.py index a7fe8d8a0f8..4ea90d27106 100644 --- a/homeassistant/components/ecobee/weather.py +++ b/homeassistant/components/ecobee/weather.py @@ -50,8 +50,8 @@ class EcobeeWeather(WeatherEntity): try: forecast = self.weather["forecasts"][index] return forecast[param] - except (ValueError, IndexError, KeyError): - raise ValueError + except (IndexError, KeyError) as err: + raise ValueError from err @property def name(self): diff --git a/homeassistant/components/everlights/light.py b/homeassistant/components/everlights/light.py index b1a210b8d15..243bd2913b1 100644 --- a/homeassistant/components/everlights/light.py +++ b/homeassistant/components/everlights/light.py @@ -55,8 +55,8 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= effects = await api.get_all_patterns() - except pyeverlights.ConnectionError: - raise PlatformNotReady + except pyeverlights.ConnectionError as err: + raise PlatformNotReady from err else: lights.append(EverLightsLight(api, pyeverlights.ZONE_1, status, effects)) diff --git a/homeassistant/components/flick_electric/config_flow.py b/homeassistant/components/flick_electric/config_flow.py index 8e6020ebd8a..2dba50cccca 100644 --- a/homeassistant/components/flick_electric/config_flow.py +++ b/homeassistant/components/flick_electric/config_flow.py @@ -48,10 +48,10 @@ class FlickConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): try: with async_timeout.timeout(60): token = await auth.async_get_access_token() - except asyncio.TimeoutError: - raise CannotConnect() - except AuthException: - raise InvalidAuth() + except asyncio.TimeoutError as err: + raise CannotConnect() from err + except AuthException as err: + raise InvalidAuth() from err else: return token is not None diff --git a/homeassistant/components/flo/__init__.py b/homeassistant/components/flo/__init__.py index 6bbadf0e89d..2233b4aa0c3 100644 --- a/homeassistant/components/flo/__init__.py +++ b/homeassistant/components/flo/__init__.py @@ -36,8 +36,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): hass.data[DOMAIN][entry.entry_id]["client"] = client = await async_get_api( entry.data[CONF_USERNAME], entry.data[CONF_PASSWORD], session=session ) - except RequestError: - raise ConfigEntryNotReady + except RequestError as err: + raise ConfigEntryNotReady from err user_info = await client.user.get_info(include_location_info=True) diff --git a/homeassistant/components/flo/config_flow.py b/homeassistant/components/flo/config_flow.py index 24208aa16a8..b509c894068 100644 --- a/homeassistant/components/flo/config_flow.py +++ b/homeassistant/components/flo/config_flow.py @@ -29,7 +29,7 @@ async def validate_input(hass: core.HomeAssistant, data): ) except RequestError as request_error: _LOGGER.error("Error connecting to the Flo API: %s", request_error) - raise CannotConnect + raise CannotConnect from request_error user_info = await api.user.get_info() a_location_id = user_info["locations"][0]["id"] diff --git a/homeassistant/components/flo/device.py b/homeassistant/components/flo/device.py index 179a293ba20..1a01f45b641 100644 --- a/homeassistant/components/flo/device.py +++ b/homeassistant/components/flo/device.py @@ -46,7 +46,7 @@ class FloDeviceDataUpdateCoordinator(DataUpdateCoordinator): *[self._update_device(), self._update_consumption_data()] ) except (RequestError) as error: - raise UpdateFailed(error) + raise UpdateFailed(error) from error @property def location_id(self) -> str: diff --git a/homeassistant/components/flume/__init__.py b/homeassistant/components/flume/__init__.py index 513f77edfb2..b9a5fc17682 100644 --- a/homeassistant/components/flume/__init__.py +++ b/homeassistant/components/flume/__init__.py @@ -67,8 +67,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): http_session=http_session, ) ) - except RequestException: - raise ConfigEntryNotReady + except RequestException as ex: + raise ConfigEntryNotReady from ex except Exception as ex: # pylint: disable=broad-except _LOGGER.error("Invalid credentials for flume: %s", ex) return False diff --git a/homeassistant/components/flume/config_flow.py b/homeassistant/components/flume/config_flow.py index f26be5f1e1d..80f1698a7e6 100644 --- a/homeassistant/components/flume/config_flow.py +++ b/homeassistant/components/flume/config_flow.py @@ -57,10 +57,10 @@ async def validate_input(hass: core.HomeAssistant, data): ) ) flume_devices = await hass.async_add_executor_job(FlumeDeviceList, flume_auth) - except RequestException: - raise CannotConnect - except Exception: # pylint: disable=broad-except - raise InvalidAuth + except RequestException as err: + raise CannotConnect from err + except Exception as err: # pylint: disable=broad-except + raise InvalidAuth from err if not flume_devices or not flume_devices.device_list: raise CannotConnect diff --git a/homeassistant/components/flunearyou/__init__.py b/homeassistant/components/flunearyou/__init__.py index 5e7ebd90cf1..4dae0b3f7cd 100644 --- a/homeassistant/components/flunearyou/__init__.py +++ b/homeassistant/components/flunearyou/__init__.py @@ -52,8 +52,8 @@ def async_get_api_category(sensor_type): if sensor[0] == sensor_type ) ) - except StopIteration: - raise ValueError(f"Can't find category sensor type: {sensor_type}") + except StopIteration as err: + raise ValueError(f"Can't find category sensor type: {sensor_type}") from err async def async_setup(hass, config): diff --git a/homeassistant/components/foobot/sensor.py b/homeassistant/components/foobot/sensor.py index b1d6fefaa3d..3e71963a009 100644 --- a/homeassistant/components/foobot/sensor.py +++ b/homeassistant/components/foobot/sensor.py @@ -82,9 +82,9 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= asyncio.TimeoutError, FoobotClient.TooManyRequests, FoobotClient.InternalError, - ): + ) as err: _LOGGER.exception("Failed to connect to foobot servers") - raise PlatformNotReady + raise PlatformNotReady from err except FoobotClient.ClientError: _LOGGER.error("Failed to fetch data from foobot servers") return diff --git a/homeassistant/components/garmin_connect/__init__.py b/homeassistant/components/garmin_connect/__init__.py index 85e8132bf02..c0a1012f051 100644 --- a/homeassistant/components/garmin_connect/__init__.py +++ b/homeassistant/components/garmin_connect/__init__.py @@ -49,7 +49,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): _LOGGER.error( "Connection error occurred during Garmin Connect login request: %s", err ) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err except Exception: # pylint: disable=broad-except _LOGGER.exception("Unknown error occurred during Garmin Connect login request") return False diff --git a/homeassistant/components/gios/__init__.py b/homeassistant/components/gios/__init__.py index c7e708e3207..ae3030ac88c 100644 --- a/homeassistant/components/gios/__init__.py +++ b/homeassistant/components/gios/__init__.py @@ -69,7 +69,7 @@ class GiosDataUpdateCoordinator(DataUpdateCoordinator): ClientConnectorError, InvalidSensorsData, ) as error: - raise UpdateFailed(error) + raise UpdateFailed(error) from error if not self.gios.data: raise UpdateFailed("Invalid sensors data") return self.gios.data diff --git a/homeassistant/components/glances/__init__.py b/homeassistant/components/glances/__init__.py index d09aa782534..5a0a1f33394 100644 --- a/homeassistant/components/glances/__init__.py +++ b/homeassistant/components/glances/__init__.py @@ -121,9 +121,9 @@ class GlancesData: self.available = True _LOGGER.debug("Successfully connected to Glances") - except exceptions.GlancesApiConnectionError: + except exceptions.GlancesApiConnectionError as err: _LOGGER.debug("Can not connect to Glances") - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err self.add_options() self.set_scan_interval(self.config_entry.options[CONF_SCAN_INTERVAL]) diff --git a/homeassistant/components/glances/config_flow.py b/homeassistant/components/glances/config_flow.py index 3c86fae0357..48352e88543 100644 --- a/homeassistant/components/glances/config_flow.py +++ b/homeassistant/components/glances/config_flow.py @@ -52,8 +52,8 @@ async def validate_input(hass: core.HomeAssistant, data): try: api = get_api(hass, data) await api.get_data() - except glances_api.exceptions.GlancesApiConnectionError: - raise CannotConnect + except glances_api.exceptions.GlancesApiConnectionError as err: + raise CannotConnect from err class GlancesFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): diff --git a/homeassistant/components/gogogate2/common.py b/homeassistant/components/gogogate2/common.py index c69dee662b0..10adc9c61b3 100644 --- a/homeassistant/components/gogogate2/common.py +++ b/homeassistant/components/gogogate2/common.py @@ -69,7 +69,9 @@ def get_data_update_coordinator( async with async_timeout.timeout(3): return await hass.async_add_executor_job(api.info) except Exception as exception: - raise UpdateFailed(f"Error communicating with API: {exception}") + raise UpdateFailed( + f"Error communicating with API: {exception}" + ) from exception config_entry_data[DATA_UPDATE_COORDINATOR] = GogoGateDataUpdateCoordinator( hass, diff --git a/homeassistant/components/griddy/config_flow.py b/homeassistant/components/griddy/config_flow.py index 56284384ee0..675e48cc999 100644 --- a/homeassistant/components/griddy/config_flow.py +++ b/homeassistant/components/griddy/config_flow.py @@ -28,8 +28,8 @@ async def validate_input(hass: core.HomeAssistant, data): await AsyncGriddy( client_session, settlement_point=data[CONF_LOADZONE] ).async_getnow() - except (asyncio.TimeoutError, ClientError): - raise CannotConnect + except (asyncio.TimeoutError, ClientError) as err: + raise CannotConnect from err # Return info that you want to store in the config entry. return {"title": f"Load Zone {data[CONF_LOADZONE]}"} diff --git a/homeassistant/components/guardian/util.py b/homeassistant/components/guardian/util.py index bd83307afb7..ad2a074564c 100644 --- a/homeassistant/components/guardian/util.py +++ b/homeassistant/components/guardian/util.py @@ -45,5 +45,5 @@ class GuardianDataUpdateCoordinator(DataUpdateCoordinator[dict]): try: resp = await self._api_coro() except GuardianError as err: - raise UpdateFailed(err) + raise UpdateFailed(err) from err return resp["data"] diff --git a/homeassistant/components/harmony/__init__.py b/homeassistant/components/harmony/__init__.py index 540e39f8f44..5bc4a132914 100644 --- a/homeassistant/components/harmony/__init__.py +++ b/homeassistant/components/harmony/__init__.py @@ -45,8 +45,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): name, entry.unique_id, address, activity, harmony_conf_file, delay_secs ) connected_ok = await device.connect() - except (asyncio.TimeoutError, ValueError, AttributeError): - raise ConfigEntryNotReady + except (asyncio.TimeoutError, ValueError, AttributeError) as err: + raise ConfigEntryNotReady from err if not connected_ok: raise ConfigEntryNotReady diff --git a/homeassistant/components/hassio/auth.py b/homeassistant/components/hassio/auth.py index fb2b1dc757c..23b91ac40bc 100644 --- a/homeassistant/components/hassio/auth.py +++ b/homeassistant/components/hassio/auth.py @@ -111,7 +111,7 @@ class HassIOPasswordReset(HassIOBaseAuth): await provider.async_change_password( data[ATTR_USERNAME], data[ATTR_PASSWORD] ) - except auth_ha.InvalidUser: - raise HTTPNotFound() + except auth_ha.InvalidUser as err: + raise HTTPNotFound() from err return web.Response(status=HTTP_OK) diff --git a/homeassistant/components/heos/__init__.py b/homeassistant/components/heos/__init__.py index a76a29b2ed5..81f9fd9dd0e 100644 --- a/homeassistant/components/heos/__init__.py +++ b/homeassistant/components/heos/__init__.py @@ -75,7 +75,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): except HeosError as error: await controller.disconnect() _LOGGER.debug("Unable to connect to controller %s: %s", host, error) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from error # Disconnect when shutting down async def disconnect_controller(event): @@ -99,7 +99,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): except HeosError as error: await controller.disconnect() _LOGGER.debug("Unable to retrieve players and sources: %s", error) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from error controller_manager = ControllerManager(hass, controller) await controller_manager.connect_listeners() diff --git a/homeassistant/components/hisense_aehw4a1/__init__.py b/homeassistant/components/hisense_aehw4a1/__init__.py index a2412a2fed4..725b294c00f 100644 --- a/homeassistant/components/hisense_aehw4a1/__init__.py +++ b/homeassistant/components/hisense_aehw4a1/__init__.py @@ -22,8 +22,8 @@ def coerce_ip(value): raise vol.Invalid("Must define an IP address") try: ipaddress.IPv4Network(value) - except ValueError: - raise vol.Invalid("Not a valid IP address") + except ValueError as err: + raise vol.Invalid("Not a valid IP address") from err return value diff --git a/homeassistant/components/hlk_sw16/config_flow.py b/homeassistant/components/hlk_sw16/config_flow.py index 0a9ac79d1b7..5064b00a7ad 100644 --- a/homeassistant/components/hlk_sw16/config_flow.py +++ b/homeassistant/components/hlk_sw16/config_flow.py @@ -49,8 +49,8 @@ async def validate_input(hass: HomeAssistant, user_input): try: client = await connect_client(hass, user_input) - except asyncio.TimeoutError: - raise CannotConnect + except asyncio.TimeoutError as err: + raise CannotConnect from err try: def disconnect_callback(): @@ -62,7 +62,7 @@ async def validate_input(hass: HomeAssistant, user_input): except CannotConnect: client.disconnect_callback = None client.stop() - raise CannotConnect + raise else: client.disconnect_callback = None client.stop() diff --git a/homeassistant/components/homeassistant/triggers/time_pattern.py b/homeassistant/components/homeassistant/triggers/time_pattern.py index ecca4ed444c..41294268ae8 100644 --- a/homeassistant/components/homeassistant/triggers/time_pattern.py +++ b/homeassistant/components/homeassistant/triggers/time_pattern.py @@ -40,8 +40,8 @@ class TimePattern: if not (0 <= number <= self.maximum): raise vol.Invalid(f"must be a value between 0 and {self.maximum}") - except ValueError: - raise vol.Invalid("invalid time_pattern value") + except ValueError as err: + raise vol.Invalid("invalid time_pattern value") from err return value diff --git a/homeassistant/components/homematicip_cloud/hap.py b/homeassistant/components/homematicip_cloud/hap.py index 431b05e692a..78f1d57ac93 100644 --- a/homeassistant/components/homematicip_cloud/hap.py +++ b/homeassistant/components/homematicip_cloud/hap.py @@ -92,8 +92,8 @@ class HomematicipHAP: self.config_entry.data.get(HMIPC_AUTHTOKEN), self.config_entry.data.get(HMIPC_NAME), ) - except HmipcConnectionError: - raise ConfigEntryNotReady + except HmipcConnectionError as err: + raise ConfigEntryNotReady from err except Exception as err: # pylint: disable=broad-except _LOGGER.error("Error connecting with HomematicIP Cloud: %s", err) return False @@ -247,8 +247,8 @@ class HomematicipHAP: try: await home.init(hapid) await home.get_current_state() - except HmipConnectionError: - raise HmipcConnectionError + except HmipConnectionError as err: + raise HmipcConnectionError from err home.on_update(self.async_update) home.on_create(self.async_create_entity) hass.loop.create_task(self.async_connect()) diff --git a/homeassistant/components/horizon/media_player.py b/homeassistant/components/horizon/media_player.py index 0ed98f73a38..5b9fb656938 100644 --- a/homeassistant/components/horizon/media_player.py +++ b/homeassistant/components/horizon/media_player.py @@ -71,7 +71,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): except OSError as msg: # occurs if horizon box is offline _LOGGER.error("Connection to %s at %s failed: %s", name, host, msg) - raise PlatformNotReady + raise PlatformNotReady from msg _LOGGER.info("Connection to %s at %s established", name, host) diff --git a/homeassistant/components/hp_ilo/sensor.py b/homeassistant/components/hp_ilo/sensor.py index 888fa2423ad..1cb65292c7d 100644 --- a/homeassistant/components/hp_ilo/sensor.py +++ b/homeassistant/components/hp_ilo/sensor.py @@ -191,4 +191,4 @@ class HpIloData: hpilo.IloCommunicationError, hpilo.IloLoginFailed, ) as error: - raise ValueError(f"Unable to init HP ILO, {error}") + raise ValueError(f"Unable to init HP ILO, {error}") from error diff --git a/homeassistant/components/http/forwarded.py b/homeassistant/components/http/forwarded.py index 4d9ec69a018..bf6bb811a81 100644 --- a/homeassistant/components/http/forwarded.py +++ b/homeassistant/components/http/forwarded.py @@ -91,11 +91,11 @@ def async_setup_forwarded(app, trusted_proxies): forwarded_for_split = list(reversed(forwarded_for_headers[0].split(","))) try: forwarded_for = [ip_address(addr.strip()) for addr in forwarded_for_split] - except ValueError: + except ValueError as err: _LOGGER.error( "Invalid IP address in X-Forwarded-For: %s", forwarded_for_headers[0] ) - raise HTTPBadRequest + raise HTTPBadRequest from err # Find the last trusted index in the X-Forwarded-For list forwarded_for_index = 0 diff --git a/homeassistant/components/http/view.py b/homeassistant/components/http/view.py index 7766d5a0cb9..354159f13be 100644 --- a/homeassistant/components/http/view.py +++ b/homeassistant/components/http/view.py @@ -52,7 +52,7 @@ class HomeAssistantView: msg = json.dumps(result, cls=JSONEncoder, allow_nan=False).encode("UTF-8") except (ValueError, TypeError) as err: _LOGGER.error("Unable to serialize to JSON: %s\n%s", err, result) - raise HTTPInternalServerError + raise HTTPInternalServerError from err response = web.Response( body=msg, content_type=CONTENT_TYPE_JSON, @@ -127,12 +127,12 @@ def request_handler_factory(view: HomeAssistantView, handler: Callable) -> Calla if asyncio.iscoroutine(result): result = await result - except vol.Invalid: - raise HTTPBadRequest() - except exceptions.ServiceNotFound: - raise HTTPInternalServerError() - except exceptions.Unauthorized: - raise HTTPUnauthorized() + except vol.Invalid as err: + raise HTTPBadRequest() from err + except exceptions.ServiceNotFound as err: + raise HTTPInternalServerError() from err + except exceptions.Unauthorized as err: + raise HTTPUnauthorized() from err if isinstance(result, web.StreamResponse): # The method handler returned a ready-made Response, how nice of it diff --git a/homeassistant/components/hue/bridge.py b/homeassistant/components/hue/bridge.py index 545c980591e..3eb894552ab 100644 --- a/homeassistant/components/hue/bridge.py +++ b/homeassistant/components/hue/bridge.py @@ -94,9 +94,9 @@ class HueBridge: create_config_flow(hass, host) return False - except CannotConnect: + except CannotConnect as err: LOGGER.error("Error connecting to the Hue bridge at %s", host) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err except Exception: # pylint: disable=broad-except LOGGER.exception("Unknown error connecting with Hue bridge at %s", host) @@ -269,18 +269,18 @@ async def authenticate_bridge(hass: core.HomeAssistant, bridge: aiohue.Bridge): # Initialize bridge (and validate our username) await bridge.initialize() - except (aiohue.LinkButtonNotPressed, aiohue.Unauthorized): - raise AuthenticationRequired + except (aiohue.LinkButtonNotPressed, aiohue.Unauthorized) as err: + raise AuthenticationRequired from err except ( asyncio.TimeoutError, client_exceptions.ClientOSError, client_exceptions.ServerDisconnectedError, client_exceptions.ContentTypeError, - ): - raise CannotConnect - except aiohue.AiohueException: + ) as err: + raise CannotConnect from err + except aiohue.AiohueException as err: LOGGER.exception("Unknown Hue linking error occurred") - raise AuthenticationRequired + raise AuthenticationRequired from err async def _update_listener(hass, entry): diff --git a/homeassistant/components/hue/light.py b/homeassistant/components/hue/light.py index c8d7de55ce8..9d055ad6066 100644 --- a/homeassistant/components/hue/light.py +++ b/homeassistant/components/hue/light.py @@ -159,11 +159,11 @@ async def async_safe_fetch(bridge, fetch_method): try: with async_timeout.timeout(4): return await bridge.async_request_call(fetch_method) - except aiohue.Unauthorized: + except aiohue.Unauthorized as err: await bridge.handle_unauthorized_error() - raise UpdateFailed("Unauthorized") + raise UpdateFailed("Unauthorized") from err except (aiohue.AiohueException,) as err: - raise UpdateFailed(f"Hue error: {err}") + raise UpdateFailed(f"Hue error: {err}") from err @callback diff --git a/homeassistant/components/hue/sensor_base.py b/homeassistant/components/hue/sensor_base.py index af8986e0212..263140464aa 100644 --- a/homeassistant/components/hue/sensor_base.py +++ b/homeassistant/components/hue/sensor_base.py @@ -61,11 +61,11 @@ class SensorManager: return await self.bridge.async_request_call( self.bridge.api.sensors.update ) - except Unauthorized: + except Unauthorized as err: await self.bridge.handle_unauthorized_error() - raise UpdateFailed("Unauthorized") + raise UpdateFailed("Unauthorized") from err except AiohueException as err: - raise UpdateFailed(f"Hue error: {err}") + raise UpdateFailed(f"Hue error: {err}") from err async def async_register_component(self, platform, async_add_entities): """Register async_add_entities methods for components.""" diff --git a/homeassistant/components/hunterdouglas_powerview/__init__.py b/homeassistant/components/hunterdouglas_powerview/__init__.py index 3f78726bf30..c87097dc7af 100644 --- a/homeassistant/components/hunterdouglas_powerview/__init__.py +++ b/homeassistant/components/hunterdouglas_powerview/__init__.py @@ -128,9 +128,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): shade_data = _async_map_data_by_id( (await shades.get_resources())[SHADE_DATA] ) - except HUB_EXCEPTIONS: + except HUB_EXCEPTIONS as err: _LOGGER.error("Connection error to PowerView hub: %s", hub_address) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err if not device_info: _LOGGER.error("Unable to initialize PowerView hub: %s", hub_address) diff --git a/homeassistant/components/hunterdouglas_powerview/config_flow.py b/homeassistant/components/hunterdouglas_powerview/config_flow.py index 1e47b9ec3fe..2bbdcfea3a6 100644 --- a/homeassistant/components/hunterdouglas_powerview/config_flow.py +++ b/homeassistant/components/hunterdouglas_powerview/config_flow.py @@ -33,8 +33,8 @@ async def validate_input(hass: core.HomeAssistant, data): try: async with async_timeout.timeout(10): device_info = await async_get_device_info(pv_request) - except HUB_EXCEPTIONS: - raise CannotConnect + except HUB_EXCEPTIONS as err: + raise CannotConnect from err if not device_info: raise CannotConnect diff --git a/homeassistant/components/iammeter/sensor.py b/homeassistant/components/iammeter/sensor.py index b043a6e9832..e2bf879e326 100644 --- a/homeassistant/components/iammeter/sensor.py +++ b/homeassistant/components/iammeter/sensor.py @@ -41,16 +41,16 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= try: with async_timeout.timeout(PLATFORM_TIMEOUT): api = await real_time_api(config_host, config_port) - except (IamMeterError, asyncio.TimeoutError): + except (IamMeterError, asyncio.TimeoutError) as err: _LOGGER.error("Device is not ready") - raise PlatformNotReady + raise PlatformNotReady from err async def async_update_data(): try: with async_timeout.timeout(PLATFORM_TIMEOUT): return await api.get_data() - except (IamMeterError, asyncio.TimeoutError): - raise UpdateFailed + except (IamMeterError, asyncio.TimeoutError) as err: + raise UpdateFailed from err coordinator = DataUpdateCoordinator( hass, diff --git a/homeassistant/components/iaqualink/__init__.py b/homeassistant/components/iaqualink/__init__.py index 97ddd95f50c..d0667aab72a 100644 --- a/homeassistant/components/iaqualink/__init__.py +++ b/homeassistant/components/iaqualink/__init__.py @@ -96,7 +96,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> None aiohttp.client_exceptions.ClientConnectorError, ) as aio_exception: _LOGGER.warning("Exception raised while attempting to login: %s", aio_exception) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from aio_exception systems = await aqualink.get_systems() systems = list(systems.values()) diff --git a/homeassistant/components/icloud/account.py b/homeassistant/components/icloud/account.py index d039b270bb8..683d59e9281 100644 --- a/homeassistant/components/icloud/account.py +++ b/homeassistant/components/icloud/account.py @@ -119,9 +119,12 @@ class IcloudAccount: api_devices = self.api.devices # Gets device owners infos user_info = api_devices.response["userInfo"] - except (PyiCloudServiceNotActivatedException, PyiCloudNoDevicesException): + except ( + PyiCloudServiceNotActivatedException, + PyiCloudNoDevicesException, + ) as err: _LOGGER.error("No iCloud device found") - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err self._owner_fullname = f"{user_info['firstName']} {user_info['lastName']}" diff --git a/homeassistant/components/image/__init__.py b/homeassistant/components/image/__init__.py index 91085ce4e64..d08be3e9127 100644 --- a/homeassistant/components/image/__init__.py +++ b/homeassistant/components/image/__init__.py @@ -92,8 +92,8 @@ class ImageStorageCollection(collection.StorageCollection): # Verify we can read the image try: image = Image.open(uploaded_file.file) - except UnidentifiedImageError: - raise vol.Invalid("Unable to identify image file") + except UnidentifiedImageError as err: + raise vol.Invalid("Unable to identify image file") from err # Reset content uploaded_file.file.seek(0) @@ -170,8 +170,8 @@ class ImageServeView(HomeAssistantView): parts = image_size.split("x", 1) width = int(parts[0]) height = int(parts[1]) - except (ValueError, IndexError): - raise web.HTTPBadRequest + except (ValueError, IndexError) as err: + raise web.HTTPBadRequest from err if not width or width != height or width not in VALID_SIZES: raise web.HTTPBadRequest diff --git a/homeassistant/components/influxdb/__init__.py b/homeassistant/components/influxdb/__init__.py index 60939741894..db49e119235 100644 --- a/homeassistant/components/influxdb/__init__.py +++ b/homeassistant/components/influxdb/__init__.py @@ -324,22 +324,22 @@ def get_influx_connection(conf, test_write=False, test_read=False): try: write_api.write(bucket=bucket, record=json) except (urllib3.exceptions.HTTPError, OSError) as exc: - raise ConnectionError(CONNECTION_ERROR % exc) + raise ConnectionError(CONNECTION_ERROR % exc) from exc except ApiException as exc: if exc.status == CODE_INVALID_INPUTS: - raise ValueError(WRITE_ERROR % (json, exc)) - raise ConnectionError(CLIENT_ERROR_V2 % exc) + raise ValueError(WRITE_ERROR % (json, exc)) from exc + raise ConnectionError(CLIENT_ERROR_V2 % exc) from exc def query_v2(query, _=None): """Query V2 influx.""" try: return query_api.query(query) except (urllib3.exceptions.HTTPError, OSError) as exc: - raise ConnectionError(CONNECTION_ERROR % exc) + raise ConnectionError(CONNECTION_ERROR % exc) from exc except ApiException as exc: if exc.status == CODE_INVALID_INPUTS: - raise ValueError(QUERY_ERROR % (query, exc)) - raise ConnectionError(CLIENT_ERROR_V2 % exc) + raise ValueError(QUERY_ERROR % (query, exc)) from exc + raise ConnectionError(CLIENT_ERROR_V2 % exc) from exc def close_v2(): """Close V2 influx client.""" @@ -399,11 +399,11 @@ def get_influx_connection(conf, test_write=False, test_read=False): exceptions.InfluxDBServerError, OSError, ) as exc: - raise ConnectionError(CONNECTION_ERROR % exc) + raise ConnectionError(CONNECTION_ERROR % exc) from exc except exceptions.InfluxDBClientError as exc: if exc.code == CODE_INVALID_INPUTS: - raise ValueError(WRITE_ERROR % (json, exc)) - raise ConnectionError(CLIENT_ERROR_V1 % exc) + raise ValueError(WRITE_ERROR % (json, exc)) from exc + raise ConnectionError(CLIENT_ERROR_V1 % exc) from exc def query_v1(query, database=None): """Query V1 influx.""" @@ -414,11 +414,11 @@ def get_influx_connection(conf, test_write=False, test_read=False): exceptions.InfluxDBServerError, OSError, ) as exc: - raise ConnectionError(CONNECTION_ERROR % exc) + raise ConnectionError(CONNECTION_ERROR % exc) from exc except exceptions.InfluxDBClientError as exc: if exc.code == CODE_INVALID_INPUTS: - raise ValueError(QUERY_ERROR % (query, exc)) - raise ConnectionError(CLIENT_ERROR_V1 % exc) + raise ValueError(QUERY_ERROR % (query, exc)) from exc + raise ConnectionError(CLIENT_ERROR_V1 % exc) from exc def close_v1(): """Close the V1 Influx client.""" diff --git a/homeassistant/components/influxdb/sensor.py b/homeassistant/components/influxdb/sensor.py index 60e2a1088ca..eb5b0ce6091 100644 --- a/homeassistant/components/influxdb/sensor.py +++ b/homeassistant/components/influxdb/sensor.py @@ -147,7 +147,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): influx = get_influx_connection(config, test_read=True) except ConnectionError as exc: _LOGGER.error(exc) - raise PlatformNotReady() + raise PlatformNotReady() from exc entities = [] if CONF_QUERIES_FLUX in config: diff --git a/homeassistant/components/insteon/schemas.py b/homeassistant/components/insteon/schemas.py index 5a293fb2e52..a6c4b4627bc 100644 --- a/homeassistant/components/insteon/schemas.py +++ b/homeassistant/components/insteon/schemas.py @@ -173,8 +173,8 @@ def normalize_byte_entry_to_int(entry: [int, bytes, str]): raise ValueError("Not a valid hex code") try: entry = unhexlify(entry) - except HexError: - raise ValueError("Not a valid hex code") + except HexError as err: + raise ValueError("Not a valid hex code") from err return int.from_bytes(entry, byteorder="big") @@ -184,8 +184,8 @@ def add_device_override(config_data, new_override): address = str(Address(new_override[CONF_ADDRESS])) cat = normalize_byte_entry_to_int(new_override[CONF_CAT]) subcat = normalize_byte_entry_to_int(new_override[CONF_SUBCAT]) - except ValueError: - raise ValueError("Incorrect values") + except ValueError as err: + raise ValueError("Incorrect values") from err overrides = config_data.get(CONF_OVERRIDE, []) curr_override = {} diff --git a/homeassistant/components/intesishome/climate.py b/homeassistant/components/intesishome/climate.py index 781117e8b71..57912d7d24d 100644 --- a/homeassistant/components/intesishome/climate.py +++ b/homeassistant/components/intesishome/climate.py @@ -107,9 +107,9 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= except IHAuthenticationError: _LOGGER.error("Invalid username or password") return - except IHConnectionError: + except IHConnectionError as ex: _LOGGER.error("Error connecting to the %s server", device_type) - raise PlatformNotReady + raise PlatformNotReady from ex ih_devices = controller.get_devices() if ih_devices: @@ -199,7 +199,7 @@ class IntesisAC(ClimateEntity): await self._controller.connect() except IHConnectionError as ex: _LOGGER.error("Exception connecting to IntesisHome: %s", ex) - raise PlatformNotReady + raise PlatformNotReady from ex @property def name(self): diff --git a/homeassistant/components/ipp/__init__.py b/homeassistant/components/ipp/__init__.py index 07d1258d735..1f9a616dc4f 100644 --- a/homeassistant/components/ipp/__init__.py +++ b/homeassistant/components/ipp/__init__.py @@ -121,7 +121,7 @@ class IPPDataUpdateCoordinator(DataUpdateCoordinator[IPPPrinter]): try: return await self.ipp.printer() except IPPError as error: - raise UpdateFailed(f"Invalid response from API: {error}") + raise UpdateFailed(f"Invalid response from API: {error}") from error class IPPEntity(Entity): diff --git a/homeassistant/components/islamic_prayer_times/__init__.py b/homeassistant/components/islamic_prayer_times/__init__.py index 5f47c7dc372..d7ded256f73 100644 --- a/homeassistant/components/islamic_prayer_times/__init__.py +++ b/homeassistant/components/islamic_prayer_times/__init__.py @@ -174,8 +174,8 @@ class IslamicPrayerClient: try: await self.hass.async_add_executor_job(self.get_new_prayer_times) - except (exceptions.InvalidResponseError, ConnError): - raise ConfigEntryNotReady + except (exceptions.InvalidResponseError, ConnError) as err: + raise ConfigEntryNotReady from err await self.async_update() self.config_entry.add_update_listener(self.async_options_updated) diff --git a/homeassistant/components/isy994/config_flow.py b/homeassistant/components/isy994/config_flow.py index 0ed1d7e6833..bc589a3aa11 100644 --- a/homeassistant/components/isy994/config_flow.py +++ b/homeassistant/components/isy994/config_flow.py @@ -98,7 +98,7 @@ def _fetch_isy_configuration( webroot=webroot, ) except ValueError as err: - raise InvalidAuth(err.args[0]) + raise InvalidAuth(err.args[0]) from err return Configuration(log=_LOGGER, xml=isy_conn.get_config()) diff --git a/homeassistant/components/juicenet/__init__.py b/homeassistant/components/juicenet/__init__.py index d333b9f913b..080df7be6bf 100644 --- a/homeassistant/components/juicenet/__init__.py +++ b/homeassistant/components/juicenet/__init__.py @@ -63,7 +63,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): return False except aiohttp.ClientError as error: _LOGGER.error("Could not reach the JuiceNet API %s", error) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from error if not juicenet.devices: _LOGGER.error("No JuiceNet devices found for this account") diff --git a/homeassistant/components/juicenet/config_flow.py b/homeassistant/components/juicenet/config_flow.py index 3f089300025..5ea7e4f267a 100644 --- a/homeassistant/components/juicenet/config_flow.py +++ b/homeassistant/components/juicenet/config_flow.py @@ -28,10 +28,10 @@ async def validate_input(hass: core.HomeAssistant, data): await juicenet.get_devices() except TokenError as error: _LOGGER.error("Token Error %s", error) - raise InvalidAuth + raise InvalidAuth from error except aiohttp.ClientError as error: _LOGGER.error("Error connecting %s", error) - raise CannotConnect + raise CannotConnect from error # Return info that you want to store in the config entry. return {"title": "JuiceNet"} diff --git a/homeassistant/components/konnected/config_flow.py b/homeassistant/components/konnected/config_flow.py index 88888da44f8..4e8d13c999e 100644 --- a/homeassistant/components/konnected/config_flow.py +++ b/homeassistant/components/konnected/config_flow.py @@ -186,8 +186,8 @@ class KonnectedFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): try: status = await get_status(self.hass, host, port) self.data[CONF_ID] = status.get("chipId", status["mac"].replace(":", "")) - except (CannotConnect, KeyError): - raise CannotConnect + except (CannotConnect, KeyError) as err: + raise CannotConnect from err else: self.data[CONF_MODEL] = status.get("model", KONN_MODEL) self.data[CONF_ACCESS_TOKEN] = "".join( diff --git a/homeassistant/components/konnected/panel.py b/homeassistant/components/konnected/panel.py index bd91bf3adbc..76e75159290 100644 --- a/homeassistant/components/konnected/panel.py +++ b/homeassistant/components/konnected/panel.py @@ -390,4 +390,4 @@ async def get_status(hass, host, port): except client.ClientError as err: _LOGGER.error("Exception trying to get panel status: %s", err) - raise CannotConnect + raise CannotConnect from err diff --git a/homeassistant/components/luftdaten/__init__.py b/homeassistant/components/luftdaten/__init__.py index f7ed2d72f16..ed93d4a9791 100644 --- a/homeassistant/components/luftdaten/__init__.py +++ b/homeassistant/components/luftdaten/__init__.py @@ -148,8 +148,8 @@ async def async_setup_entry(hass, config_entry): ) await luftdaten.async_update() hass.data[DOMAIN][DATA_LUFTDATEN_CLIENT][config_entry.entry_id] = luftdaten - except LuftdatenError: - raise ConfigEntryNotReady + except LuftdatenError as err: + raise ConfigEntryNotReady from err hass.async_create_task( hass.config_entries.async_forward_entry_setup(config_entry, "sensor") diff --git a/homeassistant/components/media_extractor/__init__.py b/homeassistant/components/media_extractor/__init__.py index af5ada7d2c9..a223385d8e8 100644 --- a/homeassistant/components/media_extractor/__init__.py +++ b/homeassistant/components/media_extractor/__init__.py @@ -103,9 +103,9 @@ class MediaExtractor: try: all_media = ydl.extract_info(self.get_media_url(), process=False) - except DownloadError: + except DownloadError as err: # This exception will be logged by youtube-dl itself - raise MEDownloadException() + raise MEDownloadException() from err if "entries" in all_media: _LOGGER.warning("Playlists are not supported, looking for the first video") @@ -123,9 +123,9 @@ class MediaExtractor: try: ydl.params["format"] = query requested_stream = ydl.process_ie_result(selected_media, download=False) - except (ExtractorError, DownloadError): + except (ExtractorError, DownloadError) as err: _LOGGER.error("Could not extract stream for the query: %s", query) - raise MEQueryException() + raise MEQueryException() from err return requested_stream["url"] diff --git a/homeassistant/components/met/__init__.py b/homeassistant/components/met/__init__.py index ae994bfc396..1f5502170e4 100644 --- a/homeassistant/components/met/__init__.py +++ b/homeassistant/components/met/__init__.py @@ -83,7 +83,7 @@ class MetDataUpdateCoordinator(DataUpdateCoordinator): try: return await self.weather.fetch_data() except Exception as err: - raise UpdateFailed(f"Update failed: {err}") + raise UpdateFailed(f"Update failed: {err}") from err def track_home(self): """Start tracking changes to HA home setting.""" diff --git a/homeassistant/components/mikrotik/hub.py b/homeassistant/components/mikrotik/hub.py index 1dc6041b535..fb120aa29c7 100644 --- a/homeassistant/components/mikrotik/hub.py +++ b/homeassistant/components/mikrotik/hub.py @@ -253,7 +253,7 @@ class MikrotikData: socket.timeout, ) as api_error: _LOGGER.error("Mikrotik %s connection error %s", self._host, api_error) - raise CannotConnect + raise CannotConnect from api_error except librouteros.exceptions.ProtocolError as api_error: _LOGGER.warning( "Mikrotik %s failed to retrieve data. cmd=[%s] Error: %s", @@ -367,8 +367,8 @@ class MikrotikHub: api = await self.hass.async_add_executor_job( get_api, self.hass, self.config_entry.data ) - except CannotConnect: - raise ConfigEntryNotReady + except CannotConnect as api_error: + raise ConfigEntryNotReady from api_error except LoginError: return False @@ -415,5 +415,5 @@ def get_api(hass, entry): ) as api_error: _LOGGER.error("Mikrotik %s error: %s", entry[CONF_HOST], api_error) if "invalid user name or password" in str(api_error): - raise LoginError - raise CannotConnect + raise LoginError from api_error + raise CannotConnect from api_error diff --git a/homeassistant/components/mobile_app/webhook.py b/homeassistant/components/mobile_app/webhook.py index 8820d08a518..01db11a04e3 100644 --- a/homeassistant/components/mobile_app/webhook.py +++ b/homeassistant/components/mobile_app/webhook.py @@ -219,7 +219,7 @@ async def webhook_call_service(hass, config_entry, data): config_entry.data[ATTR_DEVICE_NAME], ex, ) - raise HTTPBadRequest() + raise HTTPBadRequest() from ex return empty_okay_response() diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index 8bf5f6f3115..9b367292fcf 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -58,8 +58,8 @@ def number(value: Any) -> Union[int, float]: try: value = float(value) return value - except (TypeError, ValueError): - raise vol.Invalid(f"invalid number {value}") + except (TypeError, ValueError) as err: + raise vol.Invalid(f"invalid number {value}") from err PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( diff --git a/homeassistant/components/monoprice/__init__.py b/homeassistant/components/monoprice/__init__.py index 9bceff1531c..06883ddc8a8 100644 --- a/homeassistant/components/monoprice/__init__.py +++ b/homeassistant/components/monoprice/__init__.py @@ -34,9 +34,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): try: monoprice = await hass.async_add_executor_job(get_monoprice, port) - except SerialException: + except SerialException as err: _LOGGER.error("Error connecting to Monoprice controller at %s", port) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err # double negative to handle absence of value first_run = not bool(entry.data.get(CONF_NOT_FIRST_RUN)) diff --git a/homeassistant/components/monoprice/config_flow.py b/homeassistant/components/monoprice/config_flow.py index ddaafd01d8c..05158144916 100644 --- a/homeassistant/components/monoprice/config_flow.py +++ b/homeassistant/components/monoprice/config_flow.py @@ -55,9 +55,9 @@ async def validate_input(hass: core.HomeAssistant, data): """ try: await get_async_monoprice(data[CONF_PORT], hass.loop) - except SerialException: + except SerialException as err: _LOGGER.error("Error connecting to Monoprice controller") - raise CannotConnect + raise CannotConnect from err sources = _sources_from_config(data) diff --git a/homeassistant/components/mqtt/util.py b/homeassistant/components/mqtt/util.py index 568dbabd7b0..651fe48fe3d 100644 --- a/homeassistant/components/mqtt/util.py +++ b/homeassistant/components/mqtt/util.py @@ -21,8 +21,8 @@ def valid_topic(value: Any) -> str: value = cv.string(value) try: raw_value = value.encode("utf-8") - except UnicodeError: - raise vol.Invalid("MQTT topic name/filter must be valid UTF-8 string.") + except UnicodeError as err: + raise vol.Invalid("MQTT topic name/filter must be valid UTF-8 string.") from err if not raw_value: raise vol.Invalid("MQTT topic name/filter must not be empty.") if len(raw_value) > 65535: diff --git a/homeassistant/components/myq/__init__.py b/homeassistant/components/myq/__init__.py index fc1d374fe43..959000da3b3 100644 --- a/homeassistant/components/myq/__init__.py +++ b/homeassistant/components/myq/__init__.py @@ -37,8 +37,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): except InvalidCredentialsError as err: _LOGGER.error("There was an error while logging in: %s", err) return False - except MyQError: - raise ConfigEntryNotReady + except MyQError as err: + raise ConfigEntryNotReady from err coordinator = DataUpdateCoordinator( hass, diff --git a/homeassistant/components/myq/config_flow.py b/homeassistant/components/myq/config_flow.py index 4fd267f1b21..d06f01342a1 100644 --- a/homeassistant/components/myq/config_flow.py +++ b/homeassistant/components/myq/config_flow.py @@ -28,10 +28,10 @@ async def validate_input(hass: core.HomeAssistant, data): try: await pymyq.login(data[CONF_USERNAME], data[CONF_PASSWORD], websession) - except InvalidCredentialsError: - raise InvalidAuth - except MyQError: - raise CannotConnect + except InvalidCredentialsError as err: + raise InvalidAuth from err + except MyQError as err: + raise CannotConnect from err return {"title": data[CONF_USERNAME]} diff --git a/homeassistant/components/mysensors/gateway.py b/homeassistant/components/mysensors/gateway.py index 56c1562eea0..3bb6326f78d 100644 --- a/homeassistant/components/mysensors/gateway.py +++ b/homeassistant/components/mysensors/gateway.py @@ -54,8 +54,8 @@ def is_socket_address(value): try: socket.getaddrinfo(value, None) return value - except OSError: - raise vol.Invalid("Device is not a valid domain name or ip address") + except OSError as err: + raise vol.Invalid("Device is not a valid domain name or ip address") from err def get_mysensors_gateway(hass, gateway_id): diff --git a/homeassistant/components/mystrom/light.py b/homeassistant/components/mystrom/light.py index 2762792e133..510245ea859 100644 --- a/homeassistant/components/mystrom/light.py +++ b/homeassistant/components/mystrom/light.py @@ -52,9 +52,9 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= if bulb.bulb_type != "rgblamp": _LOGGER.error("Device %s (%s) is not a myStrom bulb", host, mac) return - except MyStromConnectionError: + except MyStromConnectionError as err: _LOGGER.warning("No route to myStrom bulb: %s", host) - raise PlatformNotReady() + raise PlatformNotReady() from err async_add_entities([MyStromLight(bulb, name, mac)], True) diff --git a/homeassistant/components/mystrom/switch.py b/homeassistant/components/mystrom/switch.py index ab1207658ab..6332760f189 100644 --- a/homeassistant/components/mystrom/switch.py +++ b/homeassistant/components/mystrom/switch.py @@ -30,9 +30,9 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= try: plug = _MyStromSwitch(host) await plug.get_state() - except MyStromConnectionError: + except MyStromConnectionError as err: _LOGGER.error("No route to myStrom plug: %s", host) - raise PlatformNotReady() + raise PlatformNotReady() from err async_add_entities([MyStromSwitch(plug, name)]) diff --git a/homeassistant/components/neato/__init__.py b/homeassistant/components/neato/__init__.py index 311f5ff5f42..9775dc592fd 100644 --- a/homeassistant/components/neato/__init__.py +++ b/homeassistant/components/neato/__init__.py @@ -101,9 +101,9 @@ async def async_setup_entry(hass, entry): try: await hass.async_add_executor_job(hub.update_robots) - except NeatoRobotException: + except NeatoRobotException as ex: _LOGGER.debug("Failed to connect to Neato API") - raise ConfigEntryNotReady + raise ConfigEntryNotReady from ex hass.data[NEATO_LOGIN] = hub @@ -156,7 +156,7 @@ class NeatoHub: _LOGGER.error("Invalid credentials") else: _LOGGER.error("Unable to connect to Neato API") - raise ConfigEntryNotReady + raise ConfigEntryNotReady from ex self.logged_in = False return diff --git a/homeassistant/components/nederlandse_spoorwegen/sensor.py b/homeassistant/components/nederlandse_spoorwegen/sensor.py index dd43227a5ab..3d15e3c4d9b 100644 --- a/homeassistant/components/nederlandse_spoorwegen/sensor.py +++ b/homeassistant/components/nederlandse_spoorwegen/sensor.py @@ -57,7 +57,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): requests.exceptions.HTTPError, ) as error: _LOGGER.error("Could not connect to the internet: %s", error) - raise PlatformNotReady() + raise PlatformNotReady() from error except RequestParametersError as error: _LOGGER.error("Could not fetch stations, please check configuration: %s", error) return diff --git a/homeassistant/components/nexia/__init__.py b/homeassistant/components/nexia/__init__.py index 122f00f7b59..25dce69417c 100644 --- a/homeassistant/components/nexia/__init__.py +++ b/homeassistant/components/nexia/__init__.py @@ -79,7 +79,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): ) except ConnectTimeout as ex: _LOGGER.error("Unable to connect to Nexia service: %s", ex) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from ex except HTTPError as http_ex: if ( http_ex.response.status_code >= HTTP_BAD_REQUEST @@ -90,7 +90,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): ) return False _LOGGER.error("HTTP error from Nexia service: %s", http_ex) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from http_ex async def _async_update_data(): """Fetch data from API endpoint.""" diff --git a/homeassistant/components/nexia/config_flow.py b/homeassistant/components/nexia/config_flow.py index d71a5470c98..b5163d88f63 100644 --- a/homeassistant/components/nexia/config_flow.py +++ b/homeassistant/components/nexia/config_flow.py @@ -39,15 +39,15 @@ async def validate_input(hass: core.HomeAssistant, data): await hass.async_add_executor_job(nexia_home.login) except ConnectTimeout as ex: _LOGGER.error("Unable to connect to Nexia service: %s", ex) - raise CannotConnect + raise CannotConnect from ex except HTTPError as http_ex: _LOGGER.error("HTTP error from Nexia service: %s", http_ex) if ( http_ex.response.status_code >= HTTP_BAD_REQUEST and http_ex.response.status_code < HTTP_INTERNAL_SERVER_ERROR ): - raise InvalidAuth - raise CannotConnect + raise InvalidAuth from http_ex + raise CannotConnect from http_ex if not nexia_home.get_name(): raise InvalidAuth diff --git a/homeassistant/components/nightscout/config_flow.py b/homeassistant/components/nightscout/config_flow.py index 699ce39355f..bd33bc8dcb4 100644 --- a/homeassistant/components/nightscout/config_flow.py +++ b/homeassistant/components/nightscout/config_flow.py @@ -23,8 +23,8 @@ async def _validate_input(data): try: api = NightscoutAPI(url) status = await api.get_server_status() - except (ClientError, AsyncIOTimeoutError, OSError): - raise InputValidationError("cannot_connect") + except (ClientError, AsyncIOTimeoutError, OSError) as error: + raise InputValidationError("cannot_connect") from error # Return info to be stored in the config entry. return {"title": status.name} diff --git a/homeassistant/components/niko_home_control/light.py b/homeassistant/components/niko_home_control/light.py index 4875e2e1e57..c5bc33b7e5e 100644 --- a/homeassistant/components/niko_home_control/light.py +++ b/homeassistant/components/niko_home_control/light.py @@ -31,7 +31,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= await niko_data.async_update() except OSError as err: _LOGGER.error("Unable to access %s (%s)", host, err) - raise PlatformNotReady + raise PlatformNotReady from err async_add_entities( [NikoHomeControlLight(light, niko_data) for light in nhc.list_actions()], True diff --git a/homeassistant/components/notion/__init__.py b/homeassistant/components/notion/__init__.py index 1c8fc650803..72b6ac610db 100644 --- a/homeassistant/components/notion/__init__.py +++ b/homeassistant/components/notion/__init__.py @@ -85,7 +85,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: return False except NotionError as err: _LOGGER.error("Config entry failed: %s", err) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err async def async_update(): """Get the latest data from the Notion API.""" diff --git a/homeassistant/components/nuheat/__init__.py b/homeassistant/components/nuheat/__init__.py index 4c7455be3c0..80765d88866 100644 --- a/homeassistant/components/nuheat/__init__.py +++ b/homeassistant/components/nuheat/__init__.py @@ -81,8 +81,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): try: await hass.async_add_executor_job(api.authenticate) - except requests.exceptions.Timeout: - raise ConfigEntryNotReady + except requests.exceptions.Timeout as ex: + raise ConfigEntryNotReady from ex except requests.exceptions.HTTPError as ex: if ( ex.response.status_code > HTTP_BAD_REQUEST @@ -90,7 +90,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): ): _LOGGER.error("Failed to login to nuheat: %s", ex) return False - raise ConfigEntryNotReady + raise ConfigEntryNotReady from ex except Exception as ex: # pylint: disable=broad-except _LOGGER.error("Failed to login to nuheat: %s", ex) return False diff --git a/homeassistant/components/nuheat/config_flow.py b/homeassistant/components/nuheat/config_flow.py index bdbdfe22ea3..dc72438ce5e 100644 --- a/homeassistant/components/nuheat/config_flow.py +++ b/homeassistant/components/nuheat/config_flow.py @@ -36,27 +36,27 @@ async def validate_input(hass: core.HomeAssistant, data): try: await hass.async_add_executor_job(api.authenticate) - except requests.exceptions.Timeout: - raise CannotConnect + except requests.exceptions.Timeout as ex: + raise CannotConnect from ex except requests.exceptions.HTTPError as ex: if ( ex.response.status_code > HTTP_BAD_REQUEST and ex.response.status_code < HTTP_INTERNAL_SERVER_ERROR ): - raise InvalidAuth - raise CannotConnect + raise InvalidAuth from ex + raise CannotConnect from ex # # The underlying module throws a generic exception on login failure # - except Exception: # pylint: disable=broad-except - raise InvalidAuth + except Exception as ex: # pylint: disable=broad-except + raise InvalidAuth from ex try: thermostat = await hass.async_add_executor_job( api.get_thermostat, data[CONF_SERIAL_NUMBER] ) - except requests.exceptions.HTTPError: - raise InvalidThermostat + except requests.exceptions.HTTPError as ex: + raise InvalidThermostat from ex return {"title": thermostat.room, "serial_number": thermostat.serial_number} diff --git a/homeassistant/components/numato/__init__.py b/homeassistant/components/numato/__init__.py index e5eeaa31846..8efc56e12fe 100644 --- a/homeassistant/components/numato/__init__.py +++ b/homeassistant/components/numato/__init__.py @@ -57,8 +57,8 @@ def float_range(rng): coe = vol.Coerce(float) coe(rng[0]) coe(rng[1]) - except vol.CoerceInvalid: - raise vol.Invalid(f"Only int or float values are allowed: {rng}") + except vol.CoerceInvalid as err: + raise vol.Invalid(f"Only int or float values are allowed: {rng}") from err if len(rng) != 2: raise vol.Invalid(f"Only two numbers allowed in a range: {rng}") if rng[0] > rng[1]: @@ -70,8 +70,8 @@ def adc_port_number(num): """Validate input number to be in the range of ADC enabled ports.""" try: num = int(num) - except (ValueError): - raise vol.Invalid(f"Port numbers must be integers: {num}") + except ValueError as err: + raise vol.Invalid(f"Port numbers must be integers: {num}") from err if num not in range(1, 8): raise vol.Invalid(f"Only port numbers from 1 to 7 are ADC capable: {num}") return num diff --git a/homeassistant/components/nws/config_flow.py b/homeassistant/components/nws/config_flow.py index ebef7418d98..12ab09abaae 100644 --- a/homeassistant/components/nws/config_flow.py +++ b/homeassistant/components/nws/config_flow.py @@ -34,7 +34,7 @@ async def validate_input(hass: core.HomeAssistant, data): await nws.set_station(station) except aiohttp.ClientError as err: _LOGGER.error("Could not connect: %s", err) - raise CannotConnect + raise CannotConnect from err return {"title": nws.station} diff --git a/homeassistant/components/nx584/alarm_control_panel.py b/homeassistant/components/nx584/alarm_control_panel.py index 7ce882e3c82..2df7cd1bb4b 100644 --- a/homeassistant/components/nx584/alarm_control_panel.py +++ b/homeassistant/components/nx584/alarm_control_panel.py @@ -60,7 +60,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= "Unable to connect to %(host)s: %(reason)s", dict(host=url, reason=ex), ) - raise PlatformNotReady + raise PlatformNotReady from ex entity = NX584Alarm(name, alarm_client, url) async_add_entities([entity]) diff --git a/homeassistant/components/openuv/__init__.py b/homeassistant/components/openuv/__init__.py index a9ebd77b5a6..5161011dd4c 100644 --- a/homeassistant/components/openuv/__init__.py +++ b/homeassistant/components/openuv/__init__.py @@ -80,7 +80,7 @@ async def async_setup_entry(hass, config_entry): hass.data[DOMAIN][DATA_OPENUV_CLIENT][config_entry.entry_id] = openuv except OpenUvError as err: _LOGGER.error("Config entry failed: %s", err) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err for component in PLATFORMS: hass.async_create_task( diff --git a/homeassistant/components/pencom/switch.py b/homeassistant/components/pencom/switch.py index 0fcdd056b15..7f193bc09a1 100644 --- a/homeassistant/components/pencom/switch.py +++ b/homeassistant/components/pencom/switch.py @@ -47,7 +47,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): hub = Pencompy(host, port, boards=boards) except OSError as error: _LOGGER.error("Could not connect to pencompy: %s", error) - raise PlatformNotReady + raise PlatformNotReady from error # Add devices. devs = [] diff --git a/homeassistant/components/pi_hole/__init__.py b/homeassistant/components/pi_hole/__init__.py index 5e7fc723cc4..a1aa0f819f8 100644 --- a/homeassistant/components/pi_hole/__init__.py +++ b/homeassistant/components/pi_hole/__init__.py @@ -95,14 +95,14 @@ async def async_setup_entry(hass, entry): await api.get_data() except HoleError as ex: _LOGGER.warning("Failed to connect: %s", ex) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from ex async def async_update_data(): """Fetch data from API endpoint.""" try: await api.get_data() except HoleError as err: - raise UpdateFailed(f"Failed to communicating with API: {err}") + raise UpdateFailed(f"Failed to communicating with API: {err}") from err coordinator = DataUpdateCoordinator( hass, diff --git a/homeassistant/components/plex/__init__.py b/homeassistant/components/plex/__init__.py index 85d4b43b532..3552823677d 100644 --- a/homeassistant/components/plex/__init__.py +++ b/homeassistant/components/plex/__init__.py @@ -91,7 +91,7 @@ async def async_setup_entry(hass, entry): server_config[CONF_URL], error, ) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from error except ( plexapi.exceptions.BadRequest, plexapi.exceptions.Unauthorized, diff --git a/homeassistant/components/plugwise/__init__.py b/homeassistant/components/plugwise/__init__.py index efb97f51c41..7e43a68b9e8 100644 --- a/homeassistant/components/plugwise/__init__.py +++ b/homeassistant/components/plugwise/__init__.py @@ -50,13 +50,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: _LOGGER.error("Invalid Smile ID") return False - except Smile.PlugwiseError: + except Smile.PlugwiseError as err: _LOGGER.error("Error while communicating to device") - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err - except asyncio.TimeoutError: + except asyncio.TimeoutError as err: _LOGGER.error("Timeout while connecting to Smile") - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err update_interval = timedelta(seconds=60) if api.smile_type == "power": @@ -68,8 +68,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async with async_timeout.timeout(10): await api.full_update_device() return True - except Smile.XMLDataMissingError: - raise UpdateFailed("Smile update failed") + except Smile.XMLDataMissingError as err: + raise UpdateFailed("Smile update failed") from err coordinator = DataUpdateCoordinator( hass, diff --git a/homeassistant/components/plugwise/config_flow.py b/homeassistant/components/plugwise/config_flow.py index b02bb3cb92b..1f86394775a 100644 --- a/homeassistant/components/plugwise/config_flow.py +++ b/homeassistant/components/plugwise/config_flow.py @@ -48,10 +48,10 @@ async def validate_input(hass: core.HomeAssistant, data): try: await api.connect() - except Smile.InvalidAuthentication: - raise InvalidAuth - except Smile.PlugwiseError: - raise CannotConnect + except Smile.InvalidAuthentication as err: + raise InvalidAuth from err + except Smile.PlugwiseError as err: + raise CannotConnect from err return api diff --git a/homeassistant/components/plum_lightpad/__init__.py b/homeassistant/components/plum_lightpad/__init__.py index 8e7596bd7e0..2a7ce4497bb 100644 --- a/homeassistant/components/plum_lightpad/__init__.py +++ b/homeassistant/components/plum_lightpad/__init__.py @@ -62,7 +62,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): return False except (ConnectTimeout, HTTPError) as ex: _LOGGER.error("Unable to connect to Plum cloud: %s", ex) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from ex hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.entry_id] = plum diff --git a/homeassistant/components/poolsense/__init__.py b/homeassistant/components/poolsense/__init__.py index bb41541b434..c3577982dc0 100644 --- a/homeassistant/components/poolsense/__init__.py +++ b/homeassistant/components/poolsense/__init__.py @@ -136,6 +136,6 @@ class PoolSenseDataUpdateCoordinator(DataUpdateCoordinator): data = await self.poolsense.get_poolsense_data() except (PoolSenseError) as error: _LOGGER.error("PoolSense query did not complete.") - raise UpdateFailed(error) + raise UpdateFailed(error) from error return data diff --git a/homeassistant/components/powerwall/__init__.py b/homeassistant/components/powerwall/__init__.py index 9c1ea7afe53..2dc19a0771d 100644 --- a/homeassistant/components/powerwall/__init__.py +++ b/homeassistant/components/powerwall/__init__.py @@ -113,9 +113,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): await hass.async_add_executor_job(power_wall.detect_and_pin_version) await hass.async_add_executor_job(_fetch_powerwall_data, power_wall) powerwall_data = await hass.async_add_executor_job(call_base_info, power_wall) - except PowerwallUnreachableError: + except PowerwallUnreachableError as err: http_session.close() - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err except APIChangedError as err: http_session.close() await _async_handle_api_changed_error(hass, err) @@ -133,8 +133,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): return await hass.async_add_executor_job( _fetch_powerwall_data, power_wall ) - except PowerwallUnreachableError: - raise UpdateFailed("Unable to fetch data from powerwall") + except PowerwallUnreachableError as err: + raise UpdateFailed("Unable to fetch data from powerwall") from err except APIChangedError as err: await _async_handle_api_changed_error(hass, err) hass.data[DOMAIN][entry.entry_id][POWERWALL_API_CHANGED] = True diff --git a/homeassistant/components/powerwall/config_flow.py b/homeassistant/components/powerwall/config_flow.py index 8c313b79024..fd44949e386 100644 --- a/homeassistant/components/powerwall/config_flow.py +++ b/homeassistant/components/powerwall/config_flow.py @@ -25,12 +25,12 @@ async def validate_input(hass: core.HomeAssistant, data): try: await hass.async_add_executor_job(power_wall.detect_and_pin_version) site_info = await hass.async_add_executor_job(power_wall.get_site_info) - except PowerwallUnreachableError: - raise CannotConnect + except PowerwallUnreachableError as err: + raise CannotConnect from err except APIChangedError as err: # Only log the exception without the traceback _LOGGER.error(str(err)) - raise WrongVersion + raise WrongVersion from err # Return info that you want to store in the config entry. return {"title": site_info.site_name} diff --git a/homeassistant/components/proxy/camera.py b/homeassistant/components/proxy/camera.py index 7aa83d30ae4..754f09fa199 100644 --- a/homeassistant/components/proxy/camera.py +++ b/homeassistant/components/proxy/camera.py @@ -70,9 +70,9 @@ def _precheck_image(image, opts): raise ValueError() try: img = Image.open(io.BytesIO(image)) - except OSError: + except OSError as err: _LOGGER.warning("Failed to open image") - raise ValueError() + raise ValueError() from err imgfmt = str(img.format) if imgfmt not in ("PNG", "JPEG"): _LOGGER.warning("Image is of unsupported type: %s", imgfmt) @@ -272,8 +272,8 @@ class ProxyCamera(Camera): image = await async_get_image(self.hass, self._proxied_camera) if not image: return None - except HomeAssistantError: - raise asyncio.CancelledError() + except HomeAssistantError as err: + raise asyncio.CancelledError() from err if self._mode == MODE_RESIZE: job = _resize_image diff --git a/homeassistant/components/qbittorrent/sensor.py b/homeassistant/components/qbittorrent/sensor.py index 4bf982bbbce..cd67355d883 100644 --- a/homeassistant/components/qbittorrent/sensor.py +++ b/homeassistant/components/qbittorrent/sensor.py @@ -51,9 +51,9 @@ def setup_platform(hass, config, add_entities, discovery_info=None): except LoginRequired: _LOGGER.error("Invalid authentication") return - except RequestException: + except RequestException as err: _LOGGER.error("Connection failed") - raise PlatformNotReady + raise PlatformNotReady from err name = config.get(CONF_NAME) diff --git a/homeassistant/components/rachio/__init__.py b/homeassistant/components/rachio/__init__.py index b84ccb8fa5d..8310a12d51c 100644 --- a/homeassistant/components/rachio/__init__.py +++ b/homeassistant/components/rachio/__init__.py @@ -117,7 +117,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): # and there is not a reasonable timeout here so it can block for a long time except RACHIO_API_EXCEPTIONS as error: _LOGGER.error("Could not reach the Rachio API: %s", error) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from error # Check for Rachio controller devices if not person.controllers: diff --git a/homeassistant/components/rachio/config_flow.py b/homeassistant/components/rachio/config_flow.py index df9ead463f7..f262843d4ad 100644 --- a/homeassistant/components/rachio/config_flow.py +++ b/homeassistant/components/rachio/config_flow.py @@ -46,7 +46,7 @@ async def validate_input(hass: core.HomeAssistant, data): # Yes we really do get all these exceptions (hopefully rachiopy switches to requests) except RACHIO_API_EXCEPTIONS as error: _LOGGER.error("Could not reach the Rachio API: %s", error) - raise CannotConnect + raise CannotConnect from error # Return info that you want to store in the config entry. return {"title": username} diff --git a/homeassistant/components/rainmachine/__init__.py b/homeassistant/components/rainmachine/__init__.py index 239878d0219..544a79c42df 100644 --- a/homeassistant/components/rainmachine/__init__.py +++ b/homeassistant/components/rainmachine/__init__.py @@ -144,7 +144,7 @@ async def async_setup_entry(hass, config_entry): ) except RainMachineError as err: _LOGGER.error("An error occurred: %s", err) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err else: # regenmaschine can load multiple controllers at once, but we only grab the one # we loaded above: diff --git a/homeassistant/components/raspihats/__init__.py b/homeassistant/components/raspihats/__init__.py index e6fd3d7bb59..c9e862a0672 100644 --- a/homeassistant/components/raspihats/__init__.py +++ b/homeassistant/components/raspihats/__init__.py @@ -214,7 +214,7 @@ class I2CHatsManager(threading.Thread): value = i2c_hat.di.value return (value >> channel) & 0x01 except ResponseException as ex: - raise I2CHatsException(str(ex)) + raise I2CHatsException(str(ex)) from ex def write_dq(self, address, channel, value): """Write a value to a I2C-HAT digital output.""" @@ -228,7 +228,7 @@ class I2CHatsManager(threading.Thread): try: i2c_hat.dq.channels[channel] = value except ResponseException as ex: - raise I2CHatsException(str(ex)) + raise I2CHatsException(str(ex)) from ex def read_dq(self, address, channel): """Read a value from a I2C-HAT digital output.""" @@ -242,4 +242,4 @@ class I2CHatsManager(threading.Thread): try: return i2c_hat.dq.channels[channel] except ResponseException as ex: - raise I2CHatsException(str(ex)) + raise I2CHatsException(str(ex)) from ex diff --git a/homeassistant/components/rfxtrx/__init__.py b/homeassistant/components/rfxtrx/__init__.py index 8b0f4364e09..947a945eee7 100644 --- a/homeassistant/components/rfxtrx/__init__.py +++ b/homeassistant/components/rfxtrx/__init__.py @@ -90,8 +90,10 @@ def _bytearray_string(data): val = cv.string(data) try: return bytearray.fromhex(val) - except ValueError: - raise vol.Invalid("Data must be a hex string with multiple of two characters") + except ValueError as err: + raise vol.Invalid( + "Data must be a hex string with multiple of two characters" + ) from err def _ensure_device(value): diff --git a/homeassistant/components/ring/config_flow.py b/homeassistant/components/ring/config_flow.py index 607e4f1937b..87b2026882c 100644 --- a/homeassistant/components/ring/config_flow.py +++ b/homeassistant/components/ring/config_flow.py @@ -24,10 +24,10 @@ async def validate_input(hass: core.HomeAssistant, data): data["password"], data.get("2fa"), ) - except MissingTokenError: - raise Require2FA - except AccessDeniedError: - raise InvalidAuth + except MissingTokenError as err: + raise Require2FA from err + except AccessDeniedError as err: + raise InvalidAuth from err return token diff --git a/homeassistant/components/roku/__init__.py b/homeassistant/components/roku/__init__.py index 1baff67f580..b02ad6430e9 100644 --- a/homeassistant/components/roku/__init__.py +++ b/homeassistant/components/roku/__init__.py @@ -146,7 +146,7 @@ class RokuDataUpdateCoordinator(DataUpdateCoordinator[Device]): return data except RokuError as error: - raise UpdateFailed(f"Invalid response from API: {error}") + raise UpdateFailed(f"Invalid response from API: {error}") from error class RokuEntity(Entity): diff --git a/homeassistant/components/roomba/__init__.py b/homeassistant/components/roomba/__init__.py index f2daaa0fbf8..192dc4de537 100644 --- a/homeassistant/components/roomba/__init__.py +++ b/homeassistant/components/roomba/__init__.py @@ -104,8 +104,8 @@ async def async_setup_entry(hass, config_entry): try: if not await async_connect_or_timeout(hass, roomba): return False - except CannotConnect: - raise exceptions.ConfigEntryNotReady + except CannotConnect as err: + raise exceptions.ConfigEntryNotReady from err hass.data[DOMAIN][config_entry.entry_id] = { ROOMBA_SESSION: roomba, @@ -136,14 +136,14 @@ async def async_connect_or_timeout(hass, roomba): if name: break await asyncio.sleep(1) - except RoombaConnectionError: + except RoombaConnectionError as err: _LOGGER.error("Error to connect to vacuum") - raise CannotConnect - except asyncio.TimeoutError: + raise CannotConnect from err + except asyncio.TimeoutError as err: # api looping if user or password incorrect and roomba exist await async_disconnect_or_timeout(hass, roomba) _LOGGER.error("Timeout expired") - raise CannotConnect + raise CannotConnect from err return {ROOMBA_SESSION: roomba, CONF_NAME: name} diff --git a/homeassistant/components/rtorrent/sensor.py b/homeassistant/components/rtorrent/sensor.py index cd27b33271f..3976d8985cd 100644 --- a/homeassistant/components/rtorrent/sensor.py +++ b/homeassistant/components/rtorrent/sensor.py @@ -59,9 +59,9 @@ def setup_platform(hass, config, add_entities, discovery_info=None): try: rtorrent = xmlrpc.client.ServerProxy(url) - except (xmlrpc.client.ProtocolError, ConnectionRefusedError): + except (xmlrpc.client.ProtocolError, ConnectionRefusedError) as ex: _LOGGER.error("Connection to rtorrent daemon failed") - raise PlatformNotReady + raise PlatformNotReady from ex dev = [] for variable in config[CONF_MONITORED_VARIABLES]: dev.append(RTorrentSensor(variable, rtorrent, name)) diff --git a/homeassistant/components/schluter/climate.py b/homeassistant/components/schluter/climate.py index 88630cb99db..e41c733e83a 100644 --- a/homeassistant/components/schluter/climate.py +++ b/homeassistant/components/schluter/climate.py @@ -40,7 +40,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= api.get_thermostats, session_id ) except RequestException as err: - raise UpdateFailed(f"Error communicating with Schluter API: {err}") + raise UpdateFailed(f"Error communicating with Schluter API: {err}") from err if thermostats is None: return {} diff --git a/homeassistant/components/sense/__init__.py b/homeassistant/components/sense/__init__.py index f295b0d926c..17d0074c836 100644 --- a/homeassistant/components/sense/__init__.py +++ b/homeassistant/components/sense/__init__.py @@ -104,14 +104,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): except SenseAuthenticationException: _LOGGER.error("Could not authenticate with sense server") return False - except SENSE_TIMEOUT_EXCEPTIONS: - raise ConfigEntryNotReady + except SENSE_TIMEOUT_EXCEPTIONS as err: + raise ConfigEntryNotReady from err sense_devices_data = SenseDevicesData() try: sense_discovered_devices = await gateway.get_discovered_device_data() - except SENSE_TIMEOUT_EXCEPTIONS: - raise ConfigEntryNotReady + except SENSE_TIMEOUT_EXCEPTIONS as err: + raise ConfigEntryNotReady from err trends_coordinator = DataUpdateCoordinator( hass, diff --git a/homeassistant/components/sensibo/climate.py b/homeassistant/components/sensibo/climate.py index 29aa0c5380e..26276650752 100644 --- a/homeassistant/components/sensibo/climate.py +++ b/homeassistant/components/sensibo/climate.py @@ -100,9 +100,9 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= aiohttp.client_exceptions.ClientConnectorError, asyncio.TimeoutError, pysensibo.SensiboError, - ): + ) as err: _LOGGER.exception("Failed to connect to Sensibo servers") - raise PlatformNotReady + raise PlatformNotReady from err if not devices: return diff --git a/homeassistant/components/shelly/__init__.py b/homeassistant/components/shelly/__init__.py index 4829aeb49f2..f9b936898a1 100644 --- a/homeassistant/components/shelly/__init__.py +++ b/homeassistant/components/shelly/__init__.py @@ -37,8 +37,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): device = await aioshelly.Device.create( entry.data["host"], aiohttp_client.async_get_clientsession(hass) ) - except (asyncio.TimeoutError, OSError): - raise ConfigEntryNotReady + except (asyncio.TimeoutError, OSError) as err: + raise ConfigEntryNotReady from err wrapper = hass.data[DOMAIN][entry.entry_id] = ShellyDeviceWrapper( hass, entry, device @@ -78,8 +78,8 @@ class ShellyDeviceWrapper(update_coordinator.DataUpdateCoordinator): try: async with async_timeout.timeout(5): return await self.device.update() - except aiocoap_error.Error: - raise update_coordinator.UpdateFailed("Error fetching data") + except aiocoap_error.Error as err: + raise update_coordinator.UpdateFailed("Error fetching data") from err @property def model(self): diff --git a/homeassistant/components/simplisafe/__init__.py b/homeassistant/components/simplisafe/__init__.py index 07b4942ad34..4b843d6eebe 100644 --- a/homeassistant/components/simplisafe/__init__.py +++ b/homeassistant/components/simplisafe/__init__.py @@ -238,7 +238,7 @@ async def async_setup_entry(hass, config_entry): return False except SimplipyError as err: LOGGER.error("Config entry failed: %s", err) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err _async_save_refresh_token(hass, config_entry, api.refresh_token) diff --git a/homeassistant/components/sisyphus/light.py b/homeassistant/components/sisyphus/light.py index ce0c37174ef..6d5fa2fc835 100644 --- a/homeassistant/components/sisyphus/light.py +++ b/homeassistant/components/sisyphus/light.py @@ -20,8 +20,8 @@ async def async_setup_platform(hass, config, add_entities, discovery_info=None): try: table_holder = hass.data[DATA_SISYPHUS][host] table = await table_holder.get_table() - except aiohttp.ClientError: - raise PlatformNotReady() + except aiohttp.ClientError as err: + raise PlatformNotReady() from err add_entities([SisyphusLight(table_holder.name, table)], update_before_add=True) diff --git a/homeassistant/components/sisyphus/media_player.py b/homeassistant/components/sisyphus/media_player.py index dbc350453b7..27d470ce885 100644 --- a/homeassistant/components/sisyphus/media_player.py +++ b/homeassistant/components/sisyphus/media_player.py @@ -50,8 +50,8 @@ async def async_setup_platform(hass, config, add_entities, discovery_info=None): try: table_holder = hass.data[DATA_SISYPHUS][host] table = await table_holder.get_table() - except aiohttp.ClientError: - raise PlatformNotReady() + except aiohttp.ClientError as err: + raise PlatformNotReady() from err add_entities([SisyphusPlayer(table_holder.name, host, table)], True) diff --git a/homeassistant/components/smart_meter_texas/__init__.py b/homeassistant/components/smart_meter_texas/__init__.py index e286bfb2557..7b1c6cfa9b7 100644 --- a/homeassistant/components/smart_meter_texas/__init__.py +++ b/homeassistant/components/smart_meter_texas/__init__.py @@ -51,8 +51,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): except SmartMeterTexasAuthError: _LOGGER.error("Username or password was not accepted") return False - except asyncio.TimeoutError: - raise ConfigEntryNotReady + except asyncio.TimeoutError as error: + raise ConfigEntryNotReady from error await smart_meter_texas_data.setup() @@ -113,7 +113,7 @@ class SmartMeterTexasData: try: await meter.read_meter(self.client) except (SmartMeterTexasAPIError, SmartMeterTexasAuthError) as error: - raise UpdateFailed(error) + raise UpdateFailed(error) from error return self.meters diff --git a/homeassistant/components/smart_meter_texas/config_flow.py b/homeassistant/components/smart_meter_texas/config_flow.py index ce62be73c41..211957dac9d 100644 --- a/homeassistant/components/smart_meter_texas/config_flow.py +++ b/homeassistant/components/smart_meter_texas/config_flow.py @@ -35,10 +35,10 @@ async def validate_input(hass: core.HomeAssistant, data): try: await client.authenticate() - except (asyncio.TimeoutError, ClientError, SmartMeterTexasAPIError): - raise CannotConnect + except (asyncio.TimeoutError, ClientError, SmartMeterTexasAPIError) as error: + raise CannotConnect from error except SmartMeterTexasAuthError as error: - raise InvalidAuth(error) + raise InvalidAuth(error) from error # Return info that you want to store in the config entry. return {"title": account.username} diff --git a/homeassistant/components/smarthab/__init__.py b/homeassistant/components/smarthab/__init__.py index cc6499f9c8d..2d22841660a 100644 --- a/homeassistant/components/smarthab/__init__.py +++ b/homeassistant/components/smarthab/__init__.py @@ -59,9 +59,9 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): try: await hub.async_login(username, password) - except pysmarthab.RequestFailedException: + except pysmarthab.RequestFailedException as err: _LOGGER.exception("Error while trying to reach SmartHab API") - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err # Pass hub object to child platforms hass.data[DOMAIN][entry.entry_id] = {DATA_HUB: hub} diff --git a/homeassistant/components/smartthings/__init__.py b/homeassistant/components/smartthings/__init__.py index 48e56e74f70..974cde35faf 100644 --- a/homeassistant/components/smartthings/__init__.py +++ b/homeassistant/components/smartthings/__init__.py @@ -166,10 +166,10 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): remove_entry = True else: _LOGGER.debug(ex, exc_info=True) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from ex except (ClientConnectionError, RuntimeWarning) as ex: _LOGGER.debug(ex, exc_info=True) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from ex if remove_entry: hass.async_create_task(hass.config_entries.async_remove(entry.entry_id)) diff --git a/homeassistant/components/sms/config_flow.py b/homeassistant/components/sms/config_flow.py index 148360416a2..52f3a403ed1 100644 --- a/homeassistant/components/sms/config_flow.py +++ b/homeassistant/components/sms/config_flow.py @@ -27,8 +27,8 @@ async def get_imei_from_config(hass: core.HomeAssistant, data): raise CannotConnect try: imei = await gateway.get_imei_async() - except gammu.GSMError: # pylint: disable=no-member - raise CannotConnect + except gammu.GSMError as err: # pylint: disable=no-member + raise CannotConnect from err finally: await gateway.terminate_async() diff --git a/homeassistant/components/solax/sensor.py b/homeassistant/components/solax/sensor.py index 8eb61560e63..3084aefd97c 100644 --- a/homeassistant/components/solax/sensor.py +++ b/homeassistant/components/solax/sensor.py @@ -64,11 +64,11 @@ class RealTimeDataEndpoint: try: api_response = await self.api.get_data() self.ready.set() - except InverterError: + except InverterError as err: if now is not None: self.ready.clear() return - raise PlatformNotReady + raise PlatformNotReady from err data = api_response.data for sensor in self.sensors: if sensor.key in data: diff --git a/homeassistant/components/sonarr/__init__.py b/homeassistant/components/sonarr/__init__.py index 4228d6c8400..601509aa575 100644 --- a/homeassistant/components/sonarr/__init__.py +++ b/homeassistant/components/sonarr/__init__.py @@ -69,8 +69,8 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool try: await sonarr.update() - except SonarrError: - raise ConfigEntryNotReady + except SonarrError as err: + raise ConfigEntryNotReady from err undo_listener = entry.add_update_listener(_async_update_listener) diff --git a/homeassistant/components/songpal/media_player.py b/homeassistant/components/songpal/media_player.py index ae633055b83..2a0bde306b7 100644 --- a/homeassistant/components/songpal/media_player.py +++ b/homeassistant/components/songpal/media_player.py @@ -77,7 +77,7 @@ async def async_setup_entry( except (SongpalException, asyncio.TimeoutError) as ex: _LOGGER.warning("[%s(%s)] Unable to connect", name, endpoint) _LOGGER.debug("Unable to get methods from songpal: %s", ex) - raise PlatformNotReady + raise PlatformNotReady from ex songpal_entity = SongpalEntity(name, device) async_add_entities([songpal_entity], True) diff --git a/homeassistant/components/speedtestdotnet/__init__.py b/homeassistant/components/speedtestdotnet/__init__.py index 3d257174328..57557d4558a 100644 --- a/homeassistant/components/speedtestdotnet/__init__.py +++ b/homeassistant/components/speedtestdotnet/__init__.py @@ -169,8 +169,8 @@ class SpeedTestDataCoordinator(DataUpdateCoordinator): """Update Speedtest data.""" try: return await self.hass.async_add_executor_job(self.update_data) - except (speedtest.ConfigRetrievalError, speedtest.NoMatchedServers): - raise UpdateFailed + except (speedtest.ConfigRetrievalError, speedtest.NoMatchedServers) as err: + raise UpdateFailed from err async def async_set_options(self): """Set options for entry.""" @@ -189,8 +189,8 @@ class SpeedTestDataCoordinator(DataUpdateCoordinator): """Set up SpeedTest.""" try: self.api = await self.hass.async_add_executor_job(speedtest.Speedtest) - except speedtest.ConfigRetrievalError: - raise ConfigEntryNotReady + except speedtest.ConfigRetrievalError as err: + raise ConfigEntryNotReady from err async def request_update(call): """Request update.""" diff --git a/homeassistant/components/spotify/__init__.py b/homeassistant/components/spotify/__init__.py index d28875032da..3f1452742f1 100644 --- a/homeassistant/components/spotify/__init__.py +++ b/homeassistant/components/spotify/__init__.py @@ -70,8 +70,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: try: current_user = await hass.async_add_executor_job(spotify.me) - except SpotifyException: - raise ConfigEntryNotReady + except SpotifyException as err: + raise ConfigEntryNotReady from err hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.entry_id] = { diff --git a/homeassistant/components/stream/__init__.py b/homeassistant/components/stream/__init__.py index 520e3047439..476b64b9650 100644 --- a/homeassistant/components/stream/__init__.py +++ b/homeassistant/components/stream/__init__.py @@ -74,8 +74,8 @@ def request_stream(hass, stream_source, *, fmt="hls", keepalive=False, options=N stream.access_token = secrets.token_hex() stream.start() return hass.data[DOMAIN][ATTR_ENDPOINTS][fmt].format(stream.access_token) - except Exception: - raise HomeAssistantError("Unable to get stream") + except Exception as err: + raise HomeAssistantError("Unable to get stream") from err async def async_setup(hass, config): diff --git a/homeassistant/components/tado/__init__.py b/homeassistant/components/tado/__init__.py index 37e92ff5b4f..9927db80a65 100644 --- a/homeassistant/components/tado/__init__.py +++ b/homeassistant/components/tado/__init__.py @@ -95,7 +95,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): if ex.response.status_code > 400 and ex.response.status_code < 500: _LOGGER.error("Failed to login to tado: %s", ex) return False - raise ConfigEntryNotReady + raise ConfigEntryNotReady from ex # Do first update await hass.async_add_executor_job(tadoconnector.update) diff --git a/homeassistant/components/tado/config_flow.py b/homeassistant/components/tado/config_flow.py index fb60b820ab9..0c45cc809af 100644 --- a/homeassistant/components/tado/config_flow.py +++ b/homeassistant/components/tado/config_flow.py @@ -30,14 +30,14 @@ async def validate_input(hass: core.HomeAssistant, data): Tado, data[CONF_USERNAME], data[CONF_PASSWORD] ) tado_me = await hass.async_add_executor_job(tado.getMe) - except KeyError: - raise InvalidAuth - except RuntimeError: - raise CannotConnect + except KeyError as ex: + raise InvalidAuth from ex + except RuntimeError as ex: + raise CannotConnect from ex except requests.exceptions.HTTPError as ex: if ex.response.status_code > 400 and ex.response.status_code < 500: - raise InvalidAuth - raise CannotConnect + raise InvalidAuth from ex + raise CannotConnect from ex if "homes" not in tado_me or len(tado_me["homes"]) == 0: raise NoHomes diff --git a/homeassistant/components/tankerkoenig/sensor.py b/homeassistant/components/tankerkoenig/sensor.py index d78b5eb2641..b6c80de69b7 100644 --- a/homeassistant/components/tankerkoenig/sensor.py +++ b/homeassistant/components/tankerkoenig/sensor.py @@ -35,8 +35,8 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= """Fetch data from API endpoint.""" try: return await tankerkoenig.fetch_data() - except LookupError: - raise UpdateFailed("Failed to fetch data") + except LookupError as err: + raise UpdateFailed("Failed to fetch data") from err coordinator = DataUpdateCoordinator( hass, diff --git a/homeassistant/components/tesla/__init__.py b/homeassistant/components/tesla/__init__.py index bc2a09788e5..9b8962ae196 100644 --- a/homeassistant/components/tesla/__init__.py +++ b/homeassistant/components/tesla/__init__.py @@ -244,7 +244,7 @@ class TeslaDataUpdateCoordinator(DataUpdateCoordinator): async with async_timeout.timeout(30): return await self.controller.update() except TeslaException as err: - raise UpdateFailed(f"Error communicating with API: {err}") + raise UpdateFailed(f"Error communicating with API: {err}") from err class TeslaDevice(Entity): diff --git a/homeassistant/components/tesla/config_flow.py b/homeassistant/components/tesla/config_flow.py index f9a218d2f5f..9e46a30972f 100644 --- a/homeassistant/components/tesla/config_flow.py +++ b/homeassistant/components/tesla/config_flow.py @@ -142,9 +142,9 @@ async def validate_input(hass: core.HomeAssistant, data): except TeslaException as ex: if ex.code == 401: _LOGGER.error("Invalid credentials: %s", ex) - raise InvalidAuth() + raise InvalidAuth() from ex _LOGGER.error("Unable to communicate with Tesla API: %s", ex) - raise CannotConnect() + raise CannotConnect() from ex _LOGGER.debug("Credentials successfully connected to the Tesla API") return config diff --git a/homeassistant/components/tibber/__init__.py b/homeassistant/components/tibber/__init__.py index 657be67c7fc..b4b29a84297 100644 --- a/homeassistant/components/tibber/__init__.py +++ b/homeassistant/components/tibber/__init__.py @@ -64,8 +64,8 @@ async def async_setup_entry(hass, entry): try: await tibber_connection.update_info() - except asyncio.TimeoutError: - raise ConfigEntryNotReady + except asyncio.TimeoutError as err: + raise ConfigEntryNotReady from err except aiohttp.ClientError as err: _LOGGER.error("Error connecting to Tibber: %s ", err) return False diff --git a/homeassistant/components/tibber/sensor.py b/homeassistant/components/tibber/sensor.py index 323267cae6f..939c6d1597d 100644 --- a/homeassistant/components/tibber/sensor.py +++ b/homeassistant/components/tibber/sensor.py @@ -32,10 +32,10 @@ async def async_setup_entry(hass, entry, async_add_entities): await home.update_info() except asyncio.TimeoutError as err: _LOGGER.error("Timeout connecting to Tibber home: %s ", err) - raise PlatformNotReady() + raise PlatformNotReady() from err except aiohttp.ClientError as err: _LOGGER.error("Error connecting to Tibber home: %s ", err) - raise PlatformNotReady() + raise PlatformNotReady() from err if home.has_active_subscription: dev.append(TibberSensorElPrice(home)) if home.has_real_time_consumption: diff --git a/homeassistant/components/tile/__init__.py b/homeassistant/components/tile/__init__.py index 4f6411ed368..58295c98bef 100644 --- a/homeassistant/components/tile/__init__.py +++ b/homeassistant/components/tile/__init__.py @@ -48,7 +48,7 @@ async def async_setup_entry(hass, config_entry): LOGGER.info("Tile session expired; creating a new one") await client.async_init() except TileError as err: - raise UpdateFailed(f"Error while retrieving data: {err}") + raise UpdateFailed(f"Error while retrieving data: {err}") from err coordinator = DataUpdateCoordinator( hass, diff --git a/homeassistant/components/toon/coordinator.py b/homeassistant/components/toon/coordinator.py index fa4cf52a630..359cb5b0ffb 100644 --- a/homeassistant/components/toon/coordinator.py +++ b/homeassistant/components/toon/coordinator.py @@ -141,4 +141,4 @@ class ToonDataUpdateCoordinator(DataUpdateCoordinator[Status]): try: return await self.toon.update() except ToonError as error: - raise UpdateFailed(f"Invalid response from API: {error}") + raise UpdateFailed(f"Invalid response from API: {error}") from error diff --git a/homeassistant/components/tradfri/__init__.py b/homeassistant/components/tradfri/__init__.py index cef22c636c1..7074532e097 100644 --- a/homeassistant/components/tradfri/__init__.py +++ b/homeassistant/components/tradfri/__init__.py @@ -113,9 +113,9 @@ async def async_setup_entry(hass, entry): try: gateway_info = await api(gateway.get_gateway_info()) - except RequestError: + except RequestError as err: await factory.shutdown() - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err hass.data.setdefault(KEY_API, {})[entry.entry_id] = api hass.data.setdefault(KEY_GATEWAY, {})[entry.entry_id] = gateway diff --git a/homeassistant/components/tradfri/config_flow.py b/homeassistant/components/tradfri/config_flow.py index e438fd20170..e72291c8d88 100644 --- a/homeassistant/components/tradfri/config_flow.py +++ b/homeassistant/components/tradfri/config_flow.py @@ -166,10 +166,10 @@ async def authenticate(hass, host, security_code): try: with async_timeout.timeout(5): key = await api_factory.generate_psk(security_code) - except RequestError: - raise AuthError("invalid_security_code") - except asyncio.TimeoutError: - raise AuthError("timeout") + except RequestError as err: + raise AuthError("invalid_security_code") from err + except asyncio.TimeoutError as err: + raise AuthError("timeout") from err return await get_gateway_info(hass, host, identity, key) @@ -185,10 +185,10 @@ async def get_gateway_info(hass, host, identity, key): gateway_info_result = await api(gateway.get_gateway_info()) await factory.shutdown() - except (OSError, RequestError): + except (OSError, RequestError) as err: # We're also catching OSError as PyTradfri doesn't catch that one yet # Upstream PR: https://github.com/ggravlingen/pytradfri/pull/189 - raise AuthError("cannot_connect") + raise AuthError("cannot_connect") from err return { CONF_HOST: host, diff --git a/homeassistant/components/transmission/__init__.py b/homeassistant/components/transmission/__init__.py index 2fd7e60cf31..00fc2d1b3b5 100644 --- a/homeassistant/components/transmission/__init__.py +++ b/homeassistant/components/transmission/__init__.py @@ -136,13 +136,13 @@ async def get_api(hass, entry): except TransmissionError as error: if "401: Unauthorized" in str(error): _LOGGER.error("Credentials for Transmission client are not valid") - raise AuthenticationError + raise AuthenticationError from error if "111: Connection refused" in str(error): _LOGGER.error("Connecting to the Transmission client %s failed", host) - raise CannotConnect + raise CannotConnect from error _LOGGER.error(error) - raise UnknownError + raise UnknownError from error class TransmissionClient: @@ -166,8 +166,8 @@ class TransmissionClient: try: self.tm_api = await get_api(self.hass, self.config_entry.data) - except CannotConnect: - raise ConfigEntryNotReady + except CannotConnect as error: + raise ConfigEntryNotReady from error except (AuthenticationError, UnknownError): return False diff --git a/homeassistant/components/tts/__init__.py b/homeassistant/components/tts/__init__.py index d1e2d910790..0f758d4a2eb 100644 --- a/homeassistant/components/tts/__init__.py +++ b/homeassistant/components/tts/__init__.py @@ -254,14 +254,14 @@ class SpeechManager: _init_tts_cache_dir, self.hass, cache_dir ) except OSError as err: - raise HomeAssistantError(f"Can't init cache dir {err}") + raise HomeAssistantError(f"Can't init cache dir {err}") from err try: cache_files = await self.hass.async_add_executor_job( _get_cache_files, self.cache_dir ) except OSError as err: - raise HomeAssistantError(f"Can't read cache dir {err}") + raise HomeAssistantError(f"Can't read cache dir {err}") from err if cache_files: self.file_cache.update(cache_files) @@ -408,9 +408,9 @@ class SpeechManager: try: data = await self.hass.async_add_executor_job(load_speech) - except OSError: + except OSError as err: del self.file_cache[key] - raise HomeAssistantError(f"Can't read {voice_file}") + raise HomeAssistantError(f"Can't read {voice_file}") from err self._async_store_to_memcache(key, filename, data) diff --git a/homeassistant/components/tuya/__init__.py b/homeassistant/components/tuya/__init__.py index 6524c026fcf..9d8bb873836 100644 --- a/homeassistant/components/tuya/__init__.py +++ b/homeassistant/components/tuya/__init__.py @@ -95,8 +95,8 @@ async def async_setup_entry(hass, entry): await hass.async_add_executor_job( tuya.init, username, password, country_code, platform ) - except (TuyaNetException, TuyaServerException): - raise ConfigEntryNotReady() + except (TuyaNetException, TuyaServerException) as exc: + raise ConfigEntryNotReady() from exc except TuyaAPIException as exc: _LOGGER.error( diff --git a/homeassistant/components/unifi/controller.py b/homeassistant/components/unifi/controller.py index 3a3229415ab..7c30a34f58f 100644 --- a/homeassistant/components/unifi/controller.py +++ b/homeassistant/components/unifi/controller.py @@ -295,8 +295,8 @@ class UniFiController: description = await self.api.site_description() self._site_role = description[0]["site_role"] - except CannotConnect: - raise ConfigEntryNotReady + except CannotConnect as err: + raise ConfigEntryNotReady from err except Exception as err: # pylint: disable=broad-except LOGGER.error("Unknown error connecting with UniFi controller: %s", err) @@ -428,14 +428,14 @@ async def get_controller( await controller.login() return controller - except aiounifi.Unauthorized: + except aiounifi.Unauthorized as err: LOGGER.warning("Connected to UniFi at %s but not registered.", host) - raise AuthenticationRequired + raise AuthenticationRequired from err - except (asyncio.TimeoutError, aiounifi.RequestError): + except (asyncio.TimeoutError, aiounifi.RequestError) as err: LOGGER.error("Error connecting to the UniFi controller at %s", host) - raise CannotConnect + raise CannotConnect from err - except aiounifi.AiounifiException: + except aiounifi.AiounifiException as err: LOGGER.exception("Unknown UniFi communication error occurred") - raise AuthenticationRequired + raise AuthenticationRequired from err diff --git a/homeassistant/components/updater/__init__.py b/homeassistant/components/updater/__init__.py index f3c9483e4a8..3d7b8b626c9 100644 --- a/homeassistant/components/updater/__init__.py +++ b/homeassistant/components/updater/__init__.py @@ -148,13 +148,15 @@ async def get_newest_version(hass, huuid, include_components): try: res = await req.json() - except ValueError: + except ValueError as err: raise update_coordinator.UpdateFailed( "Received invalid JSON from Home Assistant Update" - ) + ) from err try: res = RESPONSE_SCHEMA(res) return res["version"], res["release-notes"] except vol.Invalid as err: - raise update_coordinator.UpdateFailed(f"Got unexpected response: {err}") + raise update_coordinator.UpdateFailed( + f"Got unexpected response: {err}" + ) from err diff --git a/homeassistant/components/upnp/__init__.py b/homeassistant/components/upnp/__init__.py index 8479bd06518..52cada89333 100644 --- a/homeassistant/components/upnp/__init__.py +++ b/homeassistant/components/upnp/__init__.py @@ -109,8 +109,8 @@ async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry) st = config_entry.data.get(CONFIG_ENTRY_ST) # pylint: disable=invalid-name try: device = await async_discover_and_construct(hass, udn, st) - except asyncio.TimeoutError: - raise ConfigEntryNotReady + except asyncio.TimeoutError as err: + raise ConfigEntryNotReady from err if not device: _LOGGER.info("Unable to create UPnP/IGD, aborting") diff --git a/homeassistant/components/uvc/camera.py b/homeassistant/components/uvc/camera.py index 3e0363f4f35..e07fac28d1f 100644 --- a/homeassistant/components/uvc/camera.py +++ b/homeassistant/components/uvc/camera.py @@ -58,10 +58,10 @@ def setup_platform(hass, config, add_entities, discovery_info=None): return False except nvr.NvrError as ex: _LOGGER.error("NVR refuses to talk to me: %s", str(ex)) - raise PlatformNotReady + raise PlatformNotReady from ex except requests.exceptions.ConnectionError as ex: _LOGGER.error("Unable to connect to NVR: %s", str(ex)) - raise PlatformNotReady + raise PlatformNotReady from ex add_entities( [ diff --git a/homeassistant/components/velbus/__init__.py b/homeassistant/components/velbus/__init__.py index 72ffda48b57..a859567e219 100644 --- a/homeassistant/components/velbus/__init__.py +++ b/homeassistant/components/velbus/__init__.py @@ -70,7 +70,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): controller.scan(callback) except velbus.util.VelbusException as err: _LOGGER.error("An error occurred: %s", err) - raise ConfigEntryNotReady + raise ConfigEntryNotReady from err def syn_clock(self, service=None): try: diff --git a/homeassistant/components/waqi/sensor.py b/homeassistant/components/waqi/sensor.py index 90e55ea08a0..ec18880b5ba 100644 --- a/homeassistant/components/waqi/sensor.py +++ b/homeassistant/components/waqi/sensor.py @@ -84,9 +84,12 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= & set(station_filter) ): dev.append(waqi_sensor) - except (aiohttp.client_exceptions.ClientConnectorError, asyncio.TimeoutError): + except ( + aiohttp.client_exceptions.ClientConnectorError, + asyncio.TimeoutError, + ) as err: _LOGGER.exception("Failed to connect to WAQI servers") - raise PlatformNotReady + raise PlatformNotReady from err async_add_entities(dev, True) diff --git a/homeassistant/components/websocket_api/auth.py b/homeassistant/components/websocket_api/auth.py index f5b29f49b1e..3c795902900 100644 --- a/homeassistant/components/websocket_api/auth.py +++ b/homeassistant/components/websocket_api/auth.py @@ -62,7 +62,7 @@ class AuthPhase: ) self._logger.warning(error_msg) self._send_message(auth_invalid_message(error_msg)) - raise Disconnect + raise Disconnect from err if "access_token" in msg: self._logger.debug("Received access_token") diff --git a/homeassistant/components/websocket_api/http.py b/homeassistant/components/websocket_api/http.py index ab412e06583..7c56fcbc606 100644 --- a/homeassistant/components/websocket_api/http.py +++ b/homeassistant/components/websocket_api/http.py @@ -180,9 +180,9 @@ class WebSocketHandler: try: with async_timeout.timeout(10): msg = await wsock.receive() - except asyncio.TimeoutError: + except asyncio.TimeoutError as err: disconnect_warn = "Did not receive auth message within 10 seconds" - raise Disconnect + raise Disconnect from err if msg.type in (WSMsgType.CLOSE, WSMsgType.CLOSING): raise Disconnect @@ -193,9 +193,9 @@ class WebSocketHandler: try: msg_data = msg.json() - except ValueError: + except ValueError as err: disconnect_warn = "Received invalid JSON." - raise Disconnect + raise Disconnect from err self._logger.debug("Received %s", msg_data) connection = await auth.async_handle(msg_data) diff --git a/homeassistant/components/wled/__init__.py b/homeassistant/components/wled/__init__.py index 76b61dd7808..5da55d0e3bd 100644 --- a/homeassistant/components/wled/__init__.py +++ b/homeassistant/components/wled/__init__.py @@ -136,7 +136,7 @@ class WLEDDataUpdateCoordinator(DataUpdateCoordinator[WLEDDevice]): try: return await self.wled.update(full_update=not self.last_update_success) except WLEDError as error: - raise UpdateFailed(f"Invalid response from API: {error}") + raise UpdateFailed(f"Invalid response from API: {error}") from error class WLEDEntity(Entity): diff --git a/homeassistant/components/wolflink/__init__.py b/homeassistant/components/wolflink/__init__.py index cce9d542446..9a272c502a0 100644 --- a/homeassistant/components/wolflink/__init__.py +++ b/homeassistant/components/wolflink/__init__.py @@ -53,9 +53,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): values = await wolf_client.fetch_value(gateway_id, device_id, parameters) return {v.value_id: v.value for v in values} except ConnectError as exception: - raise UpdateFailed(f"Error communicating with API: {exception}") - except InvalidAuth: - raise UpdateFailed("Invalid authentication during update.") + raise UpdateFailed( + f"Error communicating with API: {exception}" + ) from exception + except InvalidAuth as exception: + raise UpdateFailed("Invalid authentication during update.") from exception coordinator = DataUpdateCoordinator( hass, @@ -98,6 +100,6 @@ async def fetch_parameters(client: WolfClient, gateway_id: int, device_id: int): fetched_parameters = await client.fetch_parameters(gateway_id, device_id) return [param for param in fetched_parameters if param.name != "Reglertyp"] except ConnectError as exception: - raise UpdateFailed(f"Error communicating with API: {exception}") - except InvalidAuth: - raise UpdateFailed("Invalid authentication during update.") + raise UpdateFailed(f"Error communicating with API: {exception}") from exception + except InvalidAuth as exception: + raise UpdateFailed("Invalid authentication during update.") from exception diff --git a/homeassistant/components/workday/binary_sensor.py b/homeassistant/components/workday/binary_sensor.py index 1613f10d66a..8f8b794515e 100644 --- a/homeassistant/components/workday/binary_sensor.py +++ b/homeassistant/components/workday/binary_sensor.py @@ -36,10 +36,10 @@ def valid_country(value: Any) -> str: try: raw_value = value.encode("utf-8") - except UnicodeError: + except UnicodeError as err: raise vol.Invalid( "The country name or the abbreviation must be a valid UTF-8 string." - ) + ) from err if not raw_value: raise vol.Invalid("Country name or the abbreviation must not be empty.") if value not in all_supported_countries: diff --git a/homeassistant/components/xiaomi_miio/air_quality.py b/homeassistant/components/xiaomi_miio/air_quality.py index 7da4da9c05d..baeb0bf39e5 100644 --- a/homeassistant/components/xiaomi_miio/air_quality.py +++ b/homeassistant/components/xiaomi_miio/air_quality.py @@ -53,8 +53,8 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= try: device_info = await hass.async_add_executor_job(miio_device.info) - except DeviceException: - raise PlatformNotReady + except DeviceException as ex: + raise PlatformNotReady from ex model = device_info.model unique_id = f"{model}-{device_info.mac_address}" diff --git a/homeassistant/components/xiaomi_miio/fan.py b/homeassistant/components/xiaomi_miio/fan.py index 6be4831b6e0..3382ca910c3 100644 --- a/homeassistant/components/xiaomi_miio/fan.py +++ b/homeassistant/components/xiaomi_miio/fan.py @@ -523,8 +523,8 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= device_info.firmware_version, device_info.hardware_version, ) - except DeviceException: - raise PlatformNotReady + except DeviceException as ex: + raise PlatformNotReady from ex if model in PURIFIER_MIOT: air_purifier = AirPurifierMiot(host, token) diff --git a/homeassistant/components/xiaomi_miio/light.py b/homeassistant/components/xiaomi_miio/light.py index 967ea8043f3..a148b98ee22 100644 --- a/homeassistant/components/xiaomi_miio/light.py +++ b/homeassistant/components/xiaomi_miio/light.py @@ -150,8 +150,8 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= device_info.firmware_version, device_info.hardware_version, ) - except DeviceException: - raise PlatformNotReady + except DeviceException as ex: + raise PlatformNotReady from ex if model == "philips.light.sread1": light = PhilipsEyecare(host, token) diff --git a/homeassistant/components/xiaomi_miio/remote.py b/homeassistant/components/xiaomi_miio/remote.py index 9c8d06e0b0d..c88b2d3663c 100644 --- a/homeassistant/components/xiaomi_miio/remote.py +++ b/homeassistant/components/xiaomi_miio/remote.py @@ -86,7 +86,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= ) except DeviceException as ex: _LOGGER.error("Device unavailable or token incorrect: %s", ex) - raise PlatformNotReady + raise PlatformNotReady from ex if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} diff --git a/homeassistant/components/xiaomi_miio/sensor.py b/homeassistant/components/xiaomi_miio/sensor.py index 4b1442a8c55..924d6d8a23d 100644 --- a/homeassistant/components/xiaomi_miio/sensor.py +++ b/homeassistant/components/xiaomi_miio/sensor.py @@ -122,8 +122,8 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= device_info.hardware_version, ) device = XiaomiAirQualityMonitor(name, air_quality_monitor, model, unique_id) - except DeviceException: - raise PlatformNotReady + except DeviceException as ex: + raise PlatformNotReady from ex hass.data[DATA_KEY][host] = device async_add_entities([device], update_before_add=True) diff --git a/homeassistant/components/xiaomi_miio/switch.py b/homeassistant/components/xiaomi_miio/switch.py index d8552244ce8..26ffb7e578f 100644 --- a/homeassistant/components/xiaomi_miio/switch.py +++ b/homeassistant/components/xiaomi_miio/switch.py @@ -139,8 +139,8 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= device_info.firmware_version, device_info.hardware_version, ) - except DeviceException: - raise PlatformNotReady + except DeviceException as ex: + raise PlatformNotReady from ex if model in ["chuangmi.plug.v1", "chuangmi.plug.v3"]: plug = ChuangmiPlug(host, token, model=model) diff --git a/homeassistant/components/yi/camera.py b/homeassistant/components/yi/camera.py index 4273b5294ed..e669f530197 100644 --- a/homeassistant/components/yi/camera.py +++ b/homeassistant/components/yi/camera.py @@ -90,7 +90,7 @@ class YiCamera(Camera): await ftp.connect(self.host) await ftp.login(self.user, self.passwd) except (ConnectionRefusedError, StatusCodeError) as err: - raise PlatformNotReady(err) + raise PlatformNotReady(err) from err try: await ftp.change_directory(self.path) diff --git a/homeassistant/components/zha/api.py b/homeassistant/components/zha/api.py index 1ba9ada5413..bdfeb7815c5 100644 --- a/homeassistant/components/zha/api.py +++ b/homeassistant/components/zha/api.py @@ -316,8 +316,8 @@ def cv_group_member(value: Any) -> GroupMember: group_member = GroupMember( ieee=EUI64.convert(value["ieee"]), endpoint_id=value["endpoint_id"] ) - except KeyError: - raise vol.Invalid("Not a group member") + except KeyError as err: + raise vol.Invalid("Not a group member") from err return group_member @@ -724,8 +724,8 @@ def is_cluster_binding(value: Any) -> ClusterBinding: id=value["id"], endpoint_id=value["endpoint_id"], ) - except KeyError: - raise vol.Invalid("Not a cluster binding") + except KeyError as err: + raise vol.Invalid("Not a cluster binding") from err return cluster_binding diff --git a/homeassistant/components/zha/device_trigger.py b/homeassistant/components/zha/device_trigger.py index e92d0fb3028..9d04d36f748 100644 --- a/homeassistant/components/zha/device_trigger.py +++ b/homeassistant/components/zha/device_trigger.py @@ -29,8 +29,8 @@ async def async_validate_trigger_config(hass, config): trigger = (config[CONF_TYPE], config[CONF_SUBTYPE]) try: zha_device = await async_get_zha_device(hass, config[CONF_DEVICE_ID]) - except (KeyError, AttributeError): - raise InvalidDeviceAutomationConfig + except (KeyError, AttributeError) as err: + raise InvalidDeviceAutomationConfig from err if ( zha_device.device_automation_triggers is None or trigger not in zha_device.device_automation_triggers diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index 878d162c2ff..f708f138f88 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -516,9 +516,9 @@ class ConfigEntriesFlowManager(data_entry_flow.FlowManager): """ try: integration = await loader.async_get_integration(self.hass, handler_key) - except loader.IntegrationNotFound: + except loader.IntegrationNotFound as err: _LOGGER.error("Cannot find integration %s", handler_key) - raise data_entry_flow.UnknownHandler + raise data_entry_flow.UnknownHandler from err # Make sure requirements and dependencies of component are resolved await async_process_deps_reqs(self.hass, self._hass_config, integration) diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index 46b309815ab..394500b5170 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -173,8 +173,8 @@ def isdevice(value: Any) -> str: try: os.stat(value) return str(value) - except OSError: - raise vol.Invalid(f"No device at {value} found") + except OSError as err: + raise vol.Invalid(f"No device at {value} found") from err def matches_regex(regex: str) -> Callable[[Any], str]: @@ -201,12 +201,12 @@ def is_regex(value: Any) -> Pattern[Any]: try: r = re.compile(value) return r - except TypeError: + except TypeError as err: raise vol.Invalid( f"value {value} is of the wrong type for a regular expression" - ) - except re.error: - raise vol.Invalid(f"value {value} is not a valid regular expression") + ) from err + except re.error as err: + raise vol.Invalid(f"value {value} is not a valid regular expression") from err def isfile(value: Any) -> str: @@ -331,8 +331,8 @@ def time(value: Any) -> time_sys: try: time_val = dt_util.parse_time(value) - except TypeError: - raise vol.Invalid("Not a parseable type") + except TypeError as err: + raise vol.Invalid("Not a parseable type") from err if time_val is None: raise vol.Invalid(f"Invalid time specified: {value}") @@ -347,8 +347,8 @@ def date(value: Any) -> date_sys: try: date_val = dt_util.parse_date(value) - except TypeError: - raise vol.Invalid("Not a parseable type") + except TypeError as err: + raise vol.Invalid("Not a parseable type") from err if date_val is None: raise vol.Invalid("Could not parse date") @@ -380,8 +380,8 @@ def time_period_str(value: str) -> timedelta: second = float(parsed[2]) except IndexError: second = 0 - except ValueError: - raise vol.Invalid(TIME_PERIOD_ERROR.format(value)) + except ValueError as err: + raise vol.Invalid(TIME_PERIOD_ERROR.format(value)) from err offset = timedelta(hours=hour, minutes=minute, seconds=second) @@ -395,8 +395,8 @@ def time_period_seconds(value: Union[float, str]) -> timedelta: """Validate and transform seconds to a time offset.""" try: return timedelta(seconds=float(value)) - except (ValueError, TypeError): - raise vol.Invalid(f"Expected seconds, got {value}") + except (ValueError, TypeError) as err: + raise vol.Invalid(f"Expected seconds, got {value}") from err time_period = vol.Any(time_period_str, time_period_seconds, timedelta, time_period_dict) @@ -525,7 +525,7 @@ def template(value: Optional[Any]) -> template_helper.Template: template_value.ensure_valid() return cast(template_helper.Template, template_value) except TemplateError as ex: - raise vol.Invalid(f"invalid template ({ex})") + raise vol.Invalid(f"invalid template ({ex})") from ex def dynamic_template(value: Optional[Any]) -> template_helper.Template: @@ -543,7 +543,7 @@ def dynamic_template(value: Optional[Any]) -> template_helper.Template: template_value.ensure_valid() return cast(template_helper.Template, template_value) except TemplateError as ex: - raise vol.Invalid(f"invalid template ({ex})") + raise vol.Invalid(f"invalid template ({ex})") from ex def template_complex(value: Any) -> Any: diff --git a/homeassistant/helpers/frame.py b/homeassistant/helpers/frame.py index 35f7b3fab9f..def2508ff92 100644 --- a/homeassistant/helpers/frame.py +++ b/homeassistant/helpers/frame.py @@ -54,9 +54,11 @@ def report(what: str) -> None: """ try: integration_frame = get_integration_frame() - except MissingIntegrationFrame: + except MissingIntegrationFrame as err: # Did not source from an integration? Hard error. - raise RuntimeError(f"Detected code that {what}. Please report this issue.") + raise RuntimeError( + f"Detected code that {what}. Please report this issue." + ) from err report_integration(what, integration_frame) diff --git a/homeassistant/helpers/network.py b/homeassistant/helpers/network.py index 471cabd0032..d40fd9fad2b 100644 --- a/homeassistant/helpers/network.py +++ b/homeassistant/helpers/network.py @@ -199,8 +199,8 @@ def _get_cloud_url(hass: HomeAssistant, require_current_request: bool = False) - if "cloud" in hass.config.components: try: cloud_url = yarl.URL(cast(str, hass.components.cloud.async_remote_ui_url())) - except hass.components.cloud.CloudNotAvailable: - raise NoURLAvailableError + except hass.components.cloud.CloudNotAvailable as err: + raise NoURLAvailableError from err if not require_current_request or cloud_url.host == _get_request_host(): return normalize_url(str(cloud_url)) diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 7148f633dfb..ad0536ff3f9 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -264,7 +264,7 @@ class _ScriptRun: ex, level=logging.ERROR, ) - raise _StopScript + raise _StopScript from ex async def _async_delay_step(self): """Handle delay.""" @@ -327,10 +327,10 @@ class _ScriptRun: try: async with timeout(delay) as to_context: await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) - except asyncio.TimeoutError: + except asyncio.TimeoutError as ex: if not self._action.get(CONF_CONTINUE_ON_TIMEOUT, True): self._log(_TIMEOUT_MSG) - raise _StopScript + raise _StopScript from ex self._variables["wait"]["remaining"] = 0.0 finally: for task in tasks: @@ -502,7 +502,7 @@ class _ScriptRun: ex, level=logging.ERROR, ) - raise _StopScript + raise _StopScript from ex extra_msg = f" of {count}" for iteration in range(1, count + 1): set_repeat_var(iteration, count) @@ -600,10 +600,10 @@ class _ScriptRun: try: async with timeout(delay) as to_context: await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) - except asyncio.TimeoutError: + except asyncio.TimeoutError as ex: if not self._action.get(CONF_CONTINUE_ON_TIMEOUT, True): self._log(_TIMEOUT_MSG) - raise _StopScript + raise _StopScript from ex self._variables["wait"]["remaining"] = 0.0 finally: for task in tasks: diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index 2403967e3cf..fddd32c8760 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -232,7 +232,7 @@ class Template: try: self._compiled_code = self._env.compile(self.template) except jinja2.exceptions.TemplateSyntaxError as err: - raise TemplateError(err) + raise TemplateError(err) from err def extract_entities( self, variables: TemplateVarsType = None @@ -272,7 +272,7 @@ class Template: try: return compiled.render(kwargs).strip() except jinja2.TemplateError as err: - raise TemplateError(err) + raise TemplateError(err) from err @callback def async_render_to_info( diff --git a/homeassistant/scripts/check_config.py b/homeassistant/scripts/check_config.py index 487d97ffdd8..8d0235413db 100644 --- a/homeassistant/scripts/check_config.py +++ b/homeassistant/scripts/check_config.py @@ -45,7 +45,7 @@ def color(the_color, *args, reset=None): return parse_colors(the_color) return parse_colors(the_color) + " ".join(args) + escape_codes[reset or "reset"] except KeyError as k: - raise ValueError(f"Invalid color {k!s} in {the_color}") + raise ValueError(f"Invalid color {k!s} in {the_color}") from k def run(script_args: List) -> int: diff --git a/homeassistant/util/json.py b/homeassistant/util/json.py index 7b6da837c49..e906462a250 100644 --- a/homeassistant/util/json.py +++ b/homeassistant/util/json.py @@ -35,10 +35,10 @@ def load_json( _LOGGER.debug("JSON file not found: %s", filename) except ValueError as error: _LOGGER.exception("Could not parse JSON content: %s", filename) - raise HomeAssistantError(error) + raise HomeAssistantError(error) from error except OSError as error: _LOGGER.exception("JSON file reading failed: %s", filename) - raise HomeAssistantError(error) + raise HomeAssistantError(error) from error return {} if default is None else default @@ -55,10 +55,10 @@ def save_json( """ try: json_data = json.dumps(data, indent=4, cls=encoder) - except TypeError: + except TypeError as error: msg = f"Failed to serialize to JSON: {filename}. Bad data at {format_unserializable_data(find_paths_unserializable_data(data))}" _LOGGER.error(msg) - raise SerializationError(msg) + raise SerializationError(msg) from error tmp_filename = "" tmp_path = os.path.split(filename)[0] @@ -74,7 +74,7 @@ def save_json( os.replace(tmp_filename, filename) except OSError as error: _LOGGER.exception("Saving JSON file failed: %s", filename) - raise WriteError(error) + raise WriteError(error) from error finally: if os.path.exists(tmp_filename): try: diff --git a/homeassistant/util/ruamel_yaml.py b/homeassistant/util/ruamel_yaml.py index 8635de00fe4..496ca377936 100644 --- a/homeassistant/util/ruamel_yaml.py +++ b/homeassistant/util/ruamel_yaml.py @@ -70,7 +70,7 @@ def object_to_yaml(data: JSON_TYPE) -> str: return result except YAMLError as exc: _LOGGER.error("YAML error: %s", exc) - raise HomeAssistantError(exc) + raise HomeAssistantError(exc) from exc def yaml_to_object(data: str) -> JSON_TYPE: @@ -81,7 +81,7 @@ def yaml_to_object(data: str) -> JSON_TYPE: return result except YAMLError as exc: _LOGGER.error("YAML error: %s", exc) - raise HomeAssistantError(exc) + raise HomeAssistantError(exc) from exc def load_yaml(fname: str, round_trip: bool = False) -> JSON_TYPE: @@ -102,10 +102,10 @@ def load_yaml(fname: str, round_trip: bool = False) -> JSON_TYPE: return yaml.load(conf_file) or OrderedDict() except YAMLError as exc: _LOGGER.error("YAML error in %s: %s", fname, exc) - raise HomeAssistantError(exc) + raise HomeAssistantError(exc) from exc except UnicodeDecodeError as exc: _LOGGER.error("Unable to read file %s: %s", fname, exc) - raise HomeAssistantError(exc) + raise HomeAssistantError(exc) from exc def save_yaml(fname: str, data: JSON_TYPE) -> None: @@ -132,10 +132,10 @@ def save_yaml(fname: str, data: JSON_TYPE) -> None: pass except YAMLError as exc: _LOGGER.error(str(exc)) - raise HomeAssistantError(exc) + raise HomeAssistantError(exc) from exc except OSError as exc: _LOGGER.exception("Saving YAML file %s failed: %s", fname, exc) - raise WriteError(exc) + raise WriteError(exc) from exc finally: if os.path.exists(tmp_fname): try: diff --git a/homeassistant/util/yaml/loader.py b/homeassistant/util/yaml/loader.py index a58480e26b7..7e954f21e1a 100644 --- a/homeassistant/util/yaml/loader.py +++ b/homeassistant/util/yaml/loader.py @@ -61,10 +61,10 @@ def load_yaml(fname: str) -> JSON_TYPE: return yaml.load(conf_file, Loader=SafeLineLoader) or OrderedDict() except yaml.YAMLError as exc: _LOGGER.error(str(exc)) - raise HomeAssistantError(exc) + raise HomeAssistantError(exc) from exc except UnicodeDecodeError as exc: _LOGGER.error("Unable to read file %s: %s", fname, exc) - raise HomeAssistantError(exc) + raise HomeAssistantError(exc) from exc @overload @@ -109,8 +109,10 @@ def _include_yaml(loader: SafeLineLoader, node: yaml.nodes.Node) -> JSON_TYPE: fname = os.path.join(os.path.dirname(loader.name), node.value) try: return _add_reference(load_yaml(fname), loader, node) - except FileNotFoundError: - raise HomeAssistantError(f"{node.start_mark}: Unable to read file {fname}.") + except FileNotFoundError as exc: + raise HomeAssistantError( + f"{node.start_mark}: Unable to read file {fname}." + ) from exc def _is_file_valid(name: str) -> bool: @@ -195,12 +197,12 @@ def _ordered_dict(loader: SafeLineLoader, node: yaml.nodes.MappingNode) -> Order try: hash(key) - except TypeError: + except TypeError as exc: fname = getattr(loader.stream, "name", "") raise yaml.MarkedYAMLError( context=f'invalid key: "{key}"', context_mark=yaml.Mark(fname, 0, line, -1, None, None), - ) + ) from exc if key in seen: fname = getattr(loader.stream, "name", "")