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.
This commit is contained in:
Ville Skyttä 2020-08-28 14:50:32 +03:00 committed by GitHub
parent d768fd4de9
commit b4bac0f7a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
204 changed files with 550 additions and 518 deletions

View File

@ -150,7 +150,9 @@ async def _load_mfa_module(hass: HomeAssistant, module_name: str) -> types.Modul
module = importlib.import_module(module_path) module = importlib.import_module(module_path)
except ImportError as err: except ImportError as err:
_LOGGER.error("Unable to load mfa module %s: %s", module_name, 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"): if hass.config.skip_pip or not hasattr(module, "REQUIREMENTS"):
return module return module

View File

@ -146,7 +146,9 @@ async def load_auth_provider_module(
module = importlib.import_module(f"homeassistant.auth.providers.{provider}") module = importlib.import_module(f"homeassistant.auth.providers.{provider}")
except ImportError as err: except ImportError as err:
_LOGGER.error("Unable to load auth provider %s: %s", provider, 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"): if hass.config.skip_pip or not hasattr(module, "REQUIREMENTS"):
return module return module

View File

@ -71,7 +71,7 @@ class CommandLineAuthProvider(AuthProvider):
except OSError as err: except OSError as err:
# happens when command doesn't exist or permission is denied # happens when command doesn't exist or permission is denied
_LOGGER.error("Error while authenticating %r: %s", username, err) _LOGGER.error("Error while authenticating %r: %s", username, err)
raise InvalidAuthError raise InvalidAuthError from err
if process.returncode != 0: if process.returncode != 0:
_LOGGER.error( _LOGGER.error(

View File

@ -120,7 +120,7 @@ async def async_setup_entry(hass, config_entry):
except (AbodeException, ConnectTimeout, HTTPError) as ex: except (AbodeException, ConnectTimeout, HTTPError) as ex:
LOGGER.error("Unable to connect to Abode: %s", str(ex)) LOGGER.error("Unable to connect to Abode: %s", str(ex))
raise ConfigEntryNotReady raise ConfigEntryNotReady from ex
for platform in ABODE_PLATFORMS: for platform in ABODE_PLATFORMS:
hass.async_create_task( hass.async_create_task(

View File

@ -127,6 +127,6 @@ class AccuWeatherDataUpdateCoordinator(DataUpdateCoordinator):
InvalidApiKeyError, InvalidApiKeyError,
RequestsExceededError, RequestsExceededError,
) as error: ) as error:
raise UpdateFailed(error) raise UpdateFailed(error) from error
_LOGGER.debug("Requests remaining: %s", self.accuweather.requests_remaining) _LOGGER.debug("Requests remaining: %s", self.accuweather.requests_remaining)
return {**current, **{ATTR_FORECAST: forecast}} return {**current, **{ATTR_FORECAST: forecast}}

View File

@ -33,9 +33,9 @@ async def async_setup_entry(hass, config_entry):
agent_client = Agent(server_origin, async_get_clientsession(hass)) agent_client = Agent(server_origin, async_get_clientsession(hass))
try: try:
await agent_client.update() await agent_client.update()
except AgentError: except AgentError as err:
await agent_client.close() await agent_client.close()
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
if not agent_client.is_available: if not agent_client.is_available:
raise ConfigEntryNotReady raise ConfigEntryNotReady

View File

@ -125,7 +125,7 @@ class AirlyDataUpdateCoordinator(DataUpdateCoordinator):
try: try:
await measurements.update() await measurements.update()
except (AirlyError, ClientConnectorError) as error: except (AirlyError, ClientConnectorError) as error:
raise UpdateFailed(error) raise UpdateFailed(error) from error
values = measurements.current["values"] values = measurements.current["values"]
index = measurements.current["indexes"][0] index = measurements.current["indexes"][0]

View File

@ -227,7 +227,7 @@ async def async_setup_entry(hass, config_entry):
try: try:
return await api_coro return await api_coro
except AirVisualError as err: except AirVisualError as err:
raise UpdateFailed(f"Error while retrieving data: {err}") raise UpdateFailed(f"Error while retrieving data: {err}") from err
coordinator = DataUpdateCoordinator( coordinator = DataUpdateCoordinator(
hass, hass,
@ -263,7 +263,7 @@ async def async_setup_entry(hass, config_entry):
include_trends=False, include_trends=False,
) )
except NodeProError as err: except NodeProError as err:
raise UpdateFailed(f"Error while retrieving data: {err}") raise UpdateFailed(f"Error while retrieving data: {err}") from err
coordinator = DataUpdateCoordinator( coordinator = DataUpdateCoordinator(
hass, hass,

View File

@ -1542,8 +1542,10 @@ async def async_api_initialize_camera_stream(hass, config, directive, context):
require_ssl=True, require_ssl=True,
require_standard_port=True, require_standard_port=True,
) )
except network.NoURLAvailableError: except network.NoURLAvailableError as err:
raise AlexaInvalidValueError("Failed to find suitable URL to serve to Alexa") raise AlexaInvalidValueError(
"Failed to find suitable URL to serve to Alexa"
) from err
payload = { payload = {
"cameraStreams": [ "cameraStreams": [

View File

@ -208,7 +208,7 @@ async def _configure_almond_for_ha(
msg = err msg = err
_LOGGER.warning("Unable to configure Almond: %s", msg) _LOGGER.warning("Unable to configure Almond: %s", msg)
await hass.auth.async_remove_refresh_token(refresh_token) await hass.auth.async_remove_refresh_token(refresh_token)
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
# Clear all other refresh tokens # Clear all other refresh tokens
for token in list(user.refresh_tokens.values()): for token in list(user.refresh_tokens.values()):

View File

@ -300,7 +300,7 @@ async def async_setup_entry(hass, config_entry):
hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = ambient hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = ambient
except WebsocketError as err: except WebsocketError as err:
_LOGGER.error("Config entry failed: %s", err) _LOGGER.error("Config entry failed: %s", err)
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
hass.bus.async_listen_once( hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_STOP, ambient.client.websocket.disconnect() EVENT_HOMEASSISTANT_STOP, ambient.client.websocket.disconnect()

View File

@ -375,8 +375,8 @@ class APIDomainServicesView(HomeAssistantView):
await hass.services.async_call( await hass.services.async_call(
domain, service, data, True, self.context(request) domain, service, data, True, self.context(request)
) )
except (vol.Invalid, ServiceNotFound): except (vol.Invalid, ServiceNotFound) as ex:
raise HTTPBadRequest() raise HTTPBadRequest() from ex
return self.json(changed_states) return self.json(changed_states)

View File

@ -60,7 +60,7 @@ class AsteriskMailbox(Mailbox):
partial(client.mp3, msgid, sync=True) partial(client.mp3, msgid, sync=True)
) )
except ServerError as err: except ServerError as err:
raise StreamError(err) raise StreamError(err) from err
async def async_get_messages(self): async def async_get_messages(self):
"""Return a list of the current messages.""" """Return a list of the current messages."""

View File

@ -66,7 +66,7 @@ class AtagDataUpdateCoordinator(DataUpdateCoordinator):
if not await self.atag.update(): if not await self.atag.update():
raise UpdateFailed("No data received") raise UpdateFailed("No data received")
except AtagException as error: except AtagException as error:
raise UpdateFailed(error) raise UpdateFailed(error) from error
return self.atag.report return self.atag.report

View File

@ -55,7 +55,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
outlets = dev.outlets() outlets = dev.outlets()
except AtenPEError as exc: except AtenPEError as exc:
_LOGGER.error("Failed to initialize %s:%s: %s", node, serv, str(exc)) _LOGGER.error("Failed to initialize %s:%s: %s", node, serv, str(exc))
raise PlatformNotReady raise PlatformNotReady from exc
switches = [] switches = []
async for outlet in outlets: async for outlet in outlets:

View File

@ -171,8 +171,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
try: try:
await august_gateway.async_setup(entry.data) await august_gateway.async_setup(entry.data)
return await async_setup_august(hass, entry, august_gateway) return await async_setup_august(hass, entry, august_gateway)
except asyncio.TimeoutError: except asyncio.TimeoutError as err:
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
@ -339,7 +339,7 @@ class AugustData(AugustSubscriberMixin):
device_name = self._get_device_name(device_id) device_name = self._get_device_name(device_id)
if device_name is None: if device_name is None:
device_name = f"DeviceID: {device_id}" device_name = f"DeviceID: {device_id}"
raise HomeAssistantError(f"{device_name}: {err}") raise HomeAssistantError(f"{device_name}: {err}") from err
return ret return ret

View File

@ -102,7 +102,7 @@ class AugustGateway:
self._authentication = await self.authenticator.async_authenticate() self._authentication = await self.authenticator.async_authenticate()
except ClientError as ex: except ClientError as ex:
_LOGGER.error("Unable to connect to August service: %s", str(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: if self._authentication.state == AuthenticationState.BAD_PASSWORD:
raise InvalidAuth raise InvalidAuth

View File

@ -170,8 +170,8 @@ def _parse_client_id(client_id):
try: try:
# parts raises ValueError when port cannot be parsed as int # parts raises ValueError when port cannot be parsed as int
parts.port parts.port
except ValueError: except ValueError as ex:
raise ValueError("Client ID contains invalid port") raise ValueError("Client ID contains invalid port") from ex
# Additionally, hostnames # Additionally, hostnames
# MUST be domain names or a loopback interface and # MUST be domain names or a loopback interface and

View File

@ -102,9 +102,9 @@ class AwairDataUpdateCoordinator(DataUpdateCoordinator):
) )
) )
raise UpdateFailed(err) raise UpdateFailed(err) from err
except Exception as err: except Exception as err:
raise UpdateFailed(err) raise UpdateFailed(err) from err
async def _fetch_air_data(self, device): async def _fetch_air_data(self, device):
"""Fetch latest air quality data.""" """Fetch latest air quality data."""

View File

@ -186,8 +186,8 @@ class AxisNetworkDevice:
password=self.config_entry.data[CONF_PASSWORD], password=self.config_entry.data[CONF_PASSWORD],
) )
except CannotConnect: except CannotConnect as err:
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
except Exception: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
LOGGER.error("Unknown error connecting with Axis device on %s", self.host) 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 return device
except axis.Unauthorized: except axis.Unauthorized as err:
LOGGER.warning("Connected to device at %s but not registered.", host) 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) 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") LOGGER.exception("Unknown Axis communication error occurred")
raise AuthenticationRequired raise AuthenticationRequired from err

View File

@ -26,8 +26,8 @@ def validate_input(hass: core.HomeAssistant, auth):
"""Validate the user input allows us to connect.""" """Validate the user input allows us to connect."""
try: try:
auth.startup() auth.startup()
except (LoginError, TokenRefreshFailed): except (LoginError, TokenRefreshFailed) as err:
raise InvalidAuth raise InvalidAuth from err
if auth.check_key_required(): if auth.check_key_required():
raise Require2FA raise Require2FA

View File

@ -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)", "%s. Hint: Check wiring and make sure that the SDO pin is tied to either ground (0x76) or VCC (0x77)",
error.args[0], error.args[0],
) )
raise PlatformNotReady() raise PlatformNotReady() from error
_LOGGER.error(error) _LOGGER.error(error)
return return
# use custom name if there's any # use custom name if there's any

View File

@ -28,15 +28,15 @@ async def _validate_input(data: Dict[str, Any]) -> str:
version = await bond.version() version = await bond.version()
# call to non-version API is needed to validate authentication # call to non-version API is needed to validate authentication
await bond.devices() await bond.devices()
except ClientConnectionError: except ClientConnectionError as error:
raise InputValidationError("cannot_connect") raise InputValidationError("cannot_connect") from error
except ClientResponseError as error: except ClientResponseError as error:
if error.status == 401: if error.status == 401:
raise InputValidationError("invalid_auth") raise InputValidationError("invalid_auth") from error
raise InputValidationError("unknown") raise InputValidationError("unknown") from error
except Exception: except Exception as error:
_LOGGER.exception("Unexpected exception") _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. # Return unique ID from the hub to be stored in the config entry.
bond_id = version.get("bondid") bond_id = version.get("bondid")

View File

@ -82,8 +82,8 @@ class BroadlinkDevice:
await self._async_handle_auth_error() await self._async_handle_auth_error()
return False return False
except (DeviceOfflineError, OSError): except (DeviceOfflineError, OSError) as err:
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
except BroadlinkException as err: except BroadlinkException as err:
_LOGGER.error( _LOGGER.error(

View File

@ -175,8 +175,8 @@ class BroadlinkRemote(RemoteEntity, RestoreEntity):
try: try:
code = self._codes[device][command] code = self._codes[device][command]
except KeyError: except KeyError as err:
raise KeyError("Command not found") raise KeyError("Command not found") from err
# For toggle commands, alternate between codes in a list. # For toggle commands, alternate between codes in a list.
if isinstance(code, list): if isinstance(code, list):
@ -187,8 +187,8 @@ class BroadlinkRemote(RemoteEntity, RestoreEntity):
try: try:
return data_packet(code), is_toggle_cmd return data_packet(code), is_toggle_cmd
except ValueError: except ValueError as err:
raise ValueError("Invalid code") raise ValueError("Invalid code") from err
@callback @callback
def get_flags(self): def get_flags(self):

View File

@ -63,7 +63,7 @@ class BroadlinkUpdateManager(ABC):
_LOGGER.warning( _LOGGER.warning(
"Disconnected from the device at %s", self.device.api.host[0] "Disconnected from the device at %s", self.device.api.host[0]
) )
raise UpdateFailed(err) raise UpdateFailed(err) from err
else: else:
if self.available is False: if self.available is False:

View File

@ -82,5 +82,5 @@ class BrotherDataUpdateCoordinator(DataUpdateCoordinator):
try: try:
await self.brother.async_update() await self.brother.async_update()
except (ConnectionError, SnmpError, UnsupportedModel) as error: except (ConnectionError, SnmpError, UnsupportedModel) as error:
raise UpdateFailed(error) raise UpdateFailed(error) from error
return self.brother.data return self.brother.data

View File

@ -539,8 +539,8 @@ class CameraMjpegStream(CameraView):
if interval < MIN_STREAM_INTERVAL: if interval < MIN_STREAM_INTERVAL:
raise ValueError(f"Stream interval must be be > {MIN_STREAM_INTERVAL}") raise ValueError(f"Stream interval must be be > {MIN_STREAM_INTERVAL}")
return await camera.handle_async_still_stream(request, interval) return await camera.handle_async_still_stream(request, interval)
except ValueError: except ValueError as err:
raise web.HTTPBadRequest() raise web.HTTPBadRequest() from err
@websocket_api.async_response @websocket_api.async_response

View File

@ -76,7 +76,7 @@ class CertExpiryDataUpdateCoordinator(DataUpdateCoordinator[datetime]):
try: try:
timestamp = await get_cert_expiry_timestamp(self.hass, self.host, self.port) timestamp = await get_cert_expiry_timestamp(self.hass, self.host, self.port)
except TemporaryFailure as err: except TemporaryFailure as err:
raise UpdateFailed(err.args[0]) raise UpdateFailed(err.args[0]) from err
except ValidationFailure as err: except ValidationFailure as err:
self.cert_error = err self.cert_error = err
self.is_cert_valid = False self.is_cert_valid = False

View File

@ -28,16 +28,20 @@ async def get_cert_expiry_timestamp(hass, hostname, port):
"""Return the certificate's expiration timestamp.""" """Return the certificate's expiration timestamp."""
try: try:
cert = await hass.async_add_executor_job(get_cert, hostname, port) cert = await hass.async_add_executor_job(get_cert, hostname, port)
except socket.gaierror: except socket.gaierror as err:
raise ResolveFailed(f"Cannot resolve hostname: {hostname}") raise ResolveFailed(f"Cannot resolve hostname: {hostname}") from err
except socket.timeout: except socket.timeout as err:
raise ConnectionTimeout(f"Connection timeout with server: {hostname}:{port}") raise ConnectionTimeout(
except ConnectionRefusedError: f"Connection timeout with server: {hostname}:{port}"
raise ConnectionRefused(f"Connection refused by 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: except ssl.CertificateError as err:
raise ValidationFailure(err.verify_message) raise ValidationFailure(err.verify_message) from err
except ssl.SSLError as 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"]) ts_seconds = ssl.cert_time_to_seconds(cert["notAfter"])
return dt.utc_from_timestamp(ts_seconds) return dt.utc_from_timestamp(ts_seconds)

View File

@ -225,8 +225,8 @@ class CityBikesNetworks:
result = network[ATTR_ID] result = network[ATTR_ID]
return result return result
except CityBikesRequestError: except CityBikesRequestError as err:
raise PlatformNotReady raise PlatformNotReady from err
finally: finally:
self.networks_loading.release() self.networks_loading.release()
@ -251,11 +251,11 @@ class CityBikesNetwork:
) )
self.stations = network[ATTR_NETWORK][ATTR_STATIONS_LIST] self.stations = network[ATTR_NETWORK][ATTR_STATIONS_LIST]
self.ready.set() self.ready.set()
except CityBikesRequestError: except CityBikesRequestError as err:
if now is not None: if now is not None:
self.ready.clear() self.ready.clear()
else: else:
raise PlatformNotReady raise PlatformNotReady from err
class CityBikesStation(Entity): class CityBikesStation(Entity):

View File

@ -59,7 +59,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
await account.getAccountBearerToken() await account.getAccountBearerToken()
except client_exceptions.ClientError as exception: except client_exceptions.ClientError as exception:
_LOGGER.error("Error connecting to Control4 account API: %s", exception) _LOGGER.error("Error connecting to Control4 account API: %s", exception)
raise ConfigEntryNotReady raise ConfigEntryNotReady from exception
except BadCredentials as exception: except BadCredentials as exception:
_LOGGER.error( _LOGGER.error(
"Error authenticating with Control4 account API, incorrect username or password: %s", "Error authenticating with Control4 account API, incorrect username or password: %s",

View File

@ -45,14 +45,14 @@ async def async_setup_entry(
try: try:
return await director_update_data(hass, entry, CONTROL4_NON_DIMMER_VAR) return await director_update_data(hass, entry, CONTROL4_NON_DIMMER_VAR)
except C4Exception as err: 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(): async def async_update_data_dimmer():
"""Fetch data from Control4 director for dimmer lights.""" """Fetch data from Control4 director for dimmer lights."""
try: try:
return await director_update_data(hass, entry, CONTROL4_DIMMER_VAR) return await director_update_data(hass, entry, CONTROL4_DIMMER_VAR)
except C4Exception as err: 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( non_dimmer_coordinator = DataUpdateCoordinator(
hass, hass,

View File

@ -114,12 +114,12 @@ async def daikin_api_setup(hass, host, key, uuid, password):
device = await Appliance.factory( device = await Appliance.factory(
host, session, key=key, uuid=uuid, password=password host, session, key=key, uuid=uuid, password=password
) )
except asyncio.TimeoutError: except asyncio.TimeoutError as err:
_LOGGER.debug("Connection to %s timed out", host) _LOGGER.debug("Connection to %s timed out", host)
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
except ClientConnectionError: except ClientConnectionError as err:
_LOGGER.debug("ClientConnectionError to %s", host) _LOGGER.debug("ClientConnectionError to %s", host)
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
except Exception: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
_LOGGER.error("Unexpected error creating device %s", host) _LOGGER.error("Unexpected error creating device %s", host)
return None return None

View File

@ -98,8 +98,8 @@ class DeconzGateway:
self.async_connection_status_callback, self.async_connection_status_callback,
) )
except CannotConnect: except CannotConnect as err:
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
except Exception as err: # pylint: disable=broad-except except Exception as err: # pylint: disable=broad-except
LOGGER.error("Error connecting with deCONZ gateway: %s", err) LOGGER.error("Error connecting with deCONZ gateway: %s", err)
@ -254,10 +254,10 @@ async def get_gateway(
await deconz.initialize() await deconz.initialize()
return deconz return deconz
except errors.Unauthorized: except errors.Unauthorized as err:
LOGGER.warning("Invalid key for deCONZ at %s", config[CONF_HOST]) 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]) LOGGER.error("Error connecting to deCONZ gateway at %s", config[CONF_HOST])
raise CannotConnect raise CannotConnect from err

View File

@ -58,9 +58,9 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
deluge_api = DelugeRPCClient(host, port, username, password) deluge_api = DelugeRPCClient(host, port, username, password)
try: try:
deluge_api.connect() deluge_api.connect()
except ConnectionRefusedError: except ConnectionRefusedError as err:
_LOGGER.error("Connection to Deluge Daemon failed") _LOGGER.error("Connection to Deluge Daemon failed")
raise PlatformNotReady raise PlatformNotReady from err
dev = [] dev = []
for variable in config[CONF_MONITORED_VARIABLES]: for variable in config[CONF_MONITORED_VARIABLES]:
dev.append(DelugeSensor(variable, deluge_api, name)) dev.append(DelugeSensor(variable, deluge_api, name))

View File

@ -46,9 +46,9 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
deluge_api = DelugeRPCClient(host, port, username, password) deluge_api = DelugeRPCClient(host, port, username, password)
try: try:
deluge_api.connect() deluge_api.connect()
except ConnectionRefusedError: except ConnectionRefusedError as err:
_LOGGER.error("Connection to Deluge Daemon failed") _LOGGER.error("Connection to Deluge Daemon failed")
raise PlatformNotReady raise PlatformNotReady from err
add_entities([DelugeSwitch(deluge_api, name)]) add_entities([DelugeSwitch(deluge_api, name)])

View File

@ -83,12 +83,14 @@ async def async_get_device_automation_platform(
try: try:
integration = await async_get_integration_with_requirements(hass, domain) integration = await async_get_integration_with_requirements(hass, domain)
platform = integration.get_platform(platform_name) platform = integration.get_platform(platform_name)
except IntegrationNotFound: except IntegrationNotFound as err:
raise InvalidDeviceAutomationConfig(f"Integration '{domain}' not found") raise InvalidDeviceAutomationConfig(
except ImportError: f"Integration '{domain}' not found"
) from err
except ImportError as err:
raise InvalidDeviceAutomationConfig( raise InvalidDeviceAutomationConfig(
f"Integration '{domain}' does not support device automation {automation_type}s" f"Integration '{domain}' does not support device automation {automation_type}s"
) ) from err
return platform return platform

View File

@ -50,8 +50,8 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool
hass.data[DOMAIN]["homecontrol"] = await hass.async_add_executor_job( hass.data[DOMAIN]["homecontrol"] = await hass.async_add_executor_job(
partial(HomeControl, gateway_id=gateway_id, url=mprm_url) partial(HomeControl, gateway_id=gateway_id, url=mprm_url)
) )
except ConnectionError: except ConnectionError as err:
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
for platform in PLATFORMS: for platform in PLATFORMS:
hass.async_create_task( hass.async_create_task(

View File

@ -43,8 +43,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
) )
except AccountError: except AccountError:
return False return False
except SessionError: except SessionError as error:
raise ConfigEntryNotReady raise ConfigEntryNotReady from error
if not entry.options: if not entry.options:
hass.config_entries.async_update_entry( hass.config_entries.async_update_entry(
@ -55,7 +55,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
try: try:
return await hass.async_add_executor_job(dexcom.get_current_glucose_reading) return await hass.async_add_executor_job(dexcom.get_current_glucose_reading)
except SessionError as error: except SessionError as error:
raise UpdateFailed(error) raise UpdateFailed(error) from error
hass.data[DOMAIN][entry.entry_id] = { hass.data[DOMAIN][entry.entry_id] = {
COORDINATOR: DataUpdateCoordinator( COORDINATOR: DataUpdateCoordinator(

View File

@ -59,8 +59,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
try: try:
await dtv.update() await dtv.update()
except DIRECTVError: except DIRECTVError as err:
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
hass.data[DOMAIN][entry.entry_id] = dtv hass.data[DOMAIN][entry.entry_id] = dtv

View File

@ -182,8 +182,8 @@ async def async_setup_platform(
factory = UpnpFactory(requester, disable_state_variable_validation=True) factory = UpnpFactory(requester, disable_state_variable_validation=True)
try: try:
upnp_device = await factory.async_create_device(url) upnp_device = await factory.async_create_device(url)
except (asyncio.TimeoutError, aiohttp.ClientError): except (asyncio.TimeoutError, aiohttp.ClientError) as err:
raise PlatformNotReady() raise PlatformNotReady() from err
# wrap with DmrDevice # wrap with DmrDevice
dlna_device = DmrDevice(upnp_device, event_handler) dlna_device = DmrDevice(upnp_device, event_handler)

View File

@ -132,10 +132,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
"Authorization rejected by DoorBird for %s@%s", username, device_ip "Authorization rejected by DoorBird for %s@%s", username, device_ip
) )
return False return False
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
except OSError as oserr: except OSError as oserr:
_LOGGER.error("Failed to setup doorbird at %s: %s", device_ip, oserr) _LOGGER.error("Failed to setup doorbird at %s: %s", device_ip, oserr)
raise ConfigEntryNotReady raise ConfigEntryNotReady from oserr
if not status[0]: if not status[0]:
_LOGGER.error( _LOGGER.error(

View File

@ -40,10 +40,10 @@ async def validate_input(hass: core.HomeAssistant, data):
info = await hass.async_add_executor_job(device.info) info = await hass.async_add_executor_job(device.info)
except urllib.error.HTTPError as err: except urllib.error.HTTPError as err:
if err.code == 401: if err.code == 401:
raise InvalidAuth raise InvalidAuth from err
raise CannotConnect raise CannotConnect from err
except OSError: except OSError as err:
raise CannotConnect raise CannotConnect from err
if not status[0]: if not status[0]:
raise CannotConnect raise CannotConnect

View File

@ -81,7 +81,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
await ebox_data.async_update() await ebox_data.async_update()
except PyEboxError as exp: except PyEboxError as exp:
_LOGGER.error("Failed login: %s", exp) _LOGGER.error("Failed login: %s", exp)
raise PlatformNotReady raise PlatformNotReady from exp
sensors = [] sensors = []
for variable in config[CONF_MONITORED_VARIABLES]: for variable in config[CONF_MONITORED_VARIABLES]:

View File

@ -110,7 +110,7 @@ class EbusdData:
self.value[name] = command_result self.value[name] = command_result
except RuntimeError as err: except RuntimeError as err:
_LOGGER.error(err) _LOGGER.error(err)
raise RuntimeError(err) raise RuntimeError(err) from err
def write(self, call): def write(self, call):
"""Call write methon on ebusd.""" """Call write methon on ebusd."""

View File

@ -8,8 +8,8 @@ def ecobee_date(date_string):
"""Validate a date_string as valid for the ecobee API.""" """Validate a date_string as valid for the ecobee API."""
try: try:
datetime.strptime(date_string, "%Y-%m-%d") datetime.strptime(date_string, "%Y-%m-%d")
except ValueError: except ValueError as err:
raise vol.Invalid("Date does not match ecobee date format YYYY-MM-DD") raise vol.Invalid("Date does not match ecobee date format YYYY-MM-DD") from err
return date_string return date_string
@ -17,6 +17,8 @@ def ecobee_time(time_string):
"""Validate a time_string as valid for the ecobee API.""" """Validate a time_string as valid for the ecobee API."""
try: try:
datetime.strptime(time_string, "%H:%M:%S") datetime.strptime(time_string, "%H:%M:%S")
except ValueError: except ValueError as err:
raise vol.Invalid("Time does not match ecobee 24-hour time format HH:MM:SS") raise vol.Invalid(
"Time does not match ecobee 24-hour time format HH:MM:SS"
) from err
return time_string return time_string

View File

@ -50,8 +50,8 @@ class EcobeeWeather(WeatherEntity):
try: try:
forecast = self.weather["forecasts"][index] forecast = self.weather["forecasts"][index]
return forecast[param] return forecast[param]
except (ValueError, IndexError, KeyError): except (IndexError, KeyError) as err:
raise ValueError raise ValueError from err
@property @property
def name(self): def name(self):

View File

@ -55,8 +55,8 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
effects = await api.get_all_patterns() effects = await api.get_all_patterns()
except pyeverlights.ConnectionError: except pyeverlights.ConnectionError as err:
raise PlatformNotReady raise PlatformNotReady from err
else: else:
lights.append(EverLightsLight(api, pyeverlights.ZONE_1, status, effects)) lights.append(EverLightsLight(api, pyeverlights.ZONE_1, status, effects))

View File

@ -48,10 +48,10 @@ class FlickConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
try: try:
with async_timeout.timeout(60): with async_timeout.timeout(60):
token = await auth.async_get_access_token() token = await auth.async_get_access_token()
except asyncio.TimeoutError: except asyncio.TimeoutError as err:
raise CannotConnect() raise CannotConnect() from err
except AuthException: except AuthException as err:
raise InvalidAuth() raise InvalidAuth() from err
else: else:
return token is not None return token is not None

View File

@ -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( hass.data[DOMAIN][entry.entry_id]["client"] = client = await async_get_api(
entry.data[CONF_USERNAME], entry.data[CONF_PASSWORD], session=session entry.data[CONF_USERNAME], entry.data[CONF_PASSWORD], session=session
) )
except RequestError: except RequestError as err:
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
user_info = await client.user.get_info(include_location_info=True) user_info = await client.user.get_info(include_location_info=True)

View File

@ -29,7 +29,7 @@ async def validate_input(hass: core.HomeAssistant, data):
) )
except RequestError as request_error: except RequestError as request_error:
_LOGGER.error("Error connecting to the Flo API: %s", 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() user_info = await api.user.get_info()
a_location_id = user_info["locations"][0]["id"] a_location_id = user_info["locations"][0]["id"]

View File

@ -46,7 +46,7 @@ class FloDeviceDataUpdateCoordinator(DataUpdateCoordinator):
*[self._update_device(), self._update_consumption_data()] *[self._update_device(), self._update_consumption_data()]
) )
except (RequestError) as error: except (RequestError) as error:
raise UpdateFailed(error) raise UpdateFailed(error) from error
@property @property
def location_id(self) -> str: def location_id(self) -> str:

View File

@ -67,8 +67,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
http_session=http_session, http_session=http_session,
) )
) )
except RequestException: except RequestException as ex:
raise ConfigEntryNotReady raise ConfigEntryNotReady from ex
except Exception as ex: # pylint: disable=broad-except except Exception as ex: # pylint: disable=broad-except
_LOGGER.error("Invalid credentials for flume: %s", ex) _LOGGER.error("Invalid credentials for flume: %s", ex)
return False return False

View File

@ -57,10 +57,10 @@ async def validate_input(hass: core.HomeAssistant, data):
) )
) )
flume_devices = await hass.async_add_executor_job(FlumeDeviceList, flume_auth) flume_devices = await hass.async_add_executor_job(FlumeDeviceList, flume_auth)
except RequestException: except RequestException as err:
raise CannotConnect raise CannotConnect from err
except Exception: # pylint: disable=broad-except except Exception as err: # pylint: disable=broad-except
raise InvalidAuth raise InvalidAuth from err
if not flume_devices or not flume_devices.device_list: if not flume_devices or not flume_devices.device_list:
raise CannotConnect raise CannotConnect

View File

@ -52,8 +52,8 @@ def async_get_api_category(sensor_type):
if sensor[0] == sensor_type if sensor[0] == sensor_type
) )
) )
except StopIteration: except StopIteration as err:
raise ValueError(f"Can't find category sensor type: {sensor_type}") raise ValueError(f"Can't find category sensor type: {sensor_type}") from err
async def async_setup(hass, config): async def async_setup(hass, config):

View File

@ -82,9 +82,9 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
asyncio.TimeoutError, asyncio.TimeoutError,
FoobotClient.TooManyRequests, FoobotClient.TooManyRequests,
FoobotClient.InternalError, FoobotClient.InternalError,
): ) as err:
_LOGGER.exception("Failed to connect to foobot servers") _LOGGER.exception("Failed to connect to foobot servers")
raise PlatformNotReady raise PlatformNotReady from err
except FoobotClient.ClientError: except FoobotClient.ClientError:
_LOGGER.error("Failed to fetch data from foobot servers") _LOGGER.error("Failed to fetch data from foobot servers")
return return

View File

@ -49,7 +49,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
_LOGGER.error( _LOGGER.error(
"Connection error occurred during Garmin Connect login request: %s", err "Connection error occurred during Garmin Connect login request: %s", err
) )
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
except Exception: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unknown error occurred during Garmin Connect login request") _LOGGER.exception("Unknown error occurred during Garmin Connect login request")
return False return False

View File

@ -69,7 +69,7 @@ class GiosDataUpdateCoordinator(DataUpdateCoordinator):
ClientConnectorError, ClientConnectorError,
InvalidSensorsData, InvalidSensorsData,
) as error: ) as error:
raise UpdateFailed(error) raise UpdateFailed(error) from error
if not self.gios.data: if not self.gios.data:
raise UpdateFailed("Invalid sensors data") raise UpdateFailed("Invalid sensors data")
return self.gios.data return self.gios.data

View File

@ -121,9 +121,9 @@ class GlancesData:
self.available = True self.available = True
_LOGGER.debug("Successfully connected to Glances") _LOGGER.debug("Successfully connected to Glances")
except exceptions.GlancesApiConnectionError: except exceptions.GlancesApiConnectionError as err:
_LOGGER.debug("Can not connect to Glances") _LOGGER.debug("Can not connect to Glances")
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
self.add_options() self.add_options()
self.set_scan_interval(self.config_entry.options[CONF_SCAN_INTERVAL]) self.set_scan_interval(self.config_entry.options[CONF_SCAN_INTERVAL])

View File

@ -52,8 +52,8 @@ async def validate_input(hass: core.HomeAssistant, data):
try: try:
api = get_api(hass, data) api = get_api(hass, data)
await api.get_data() await api.get_data()
except glances_api.exceptions.GlancesApiConnectionError: except glances_api.exceptions.GlancesApiConnectionError as err:
raise CannotConnect raise CannotConnect from err
class GlancesFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): class GlancesFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):

View File

@ -69,7 +69,9 @@ def get_data_update_coordinator(
async with async_timeout.timeout(3): async with async_timeout.timeout(3):
return await hass.async_add_executor_job(api.info) return await hass.async_add_executor_job(api.info)
except Exception as exception: 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( config_entry_data[DATA_UPDATE_COORDINATOR] = GogoGateDataUpdateCoordinator(
hass, hass,

View File

@ -28,8 +28,8 @@ async def validate_input(hass: core.HomeAssistant, data):
await AsyncGriddy( await AsyncGriddy(
client_session, settlement_point=data[CONF_LOADZONE] client_session, settlement_point=data[CONF_LOADZONE]
).async_getnow() ).async_getnow()
except (asyncio.TimeoutError, ClientError): except (asyncio.TimeoutError, ClientError) as err:
raise CannotConnect raise CannotConnect from err
# Return info that you want to store in the config entry. # Return info that you want to store in the config entry.
return {"title": f"Load Zone {data[CONF_LOADZONE]}"} return {"title": f"Load Zone {data[CONF_LOADZONE]}"}

View File

@ -45,5 +45,5 @@ class GuardianDataUpdateCoordinator(DataUpdateCoordinator[dict]):
try: try:
resp = await self._api_coro() resp = await self._api_coro()
except GuardianError as err: except GuardianError as err:
raise UpdateFailed(err) raise UpdateFailed(err) from err
return resp["data"] return resp["data"]

View File

@ -45,8 +45,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
name, entry.unique_id, address, activity, harmony_conf_file, delay_secs name, entry.unique_id, address, activity, harmony_conf_file, delay_secs
) )
connected_ok = await device.connect() connected_ok = await device.connect()
except (asyncio.TimeoutError, ValueError, AttributeError): except (asyncio.TimeoutError, ValueError, AttributeError) as err:
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
if not connected_ok: if not connected_ok:
raise ConfigEntryNotReady raise ConfigEntryNotReady

View File

@ -111,7 +111,7 @@ class HassIOPasswordReset(HassIOBaseAuth):
await provider.async_change_password( await provider.async_change_password(
data[ATTR_USERNAME], data[ATTR_PASSWORD] data[ATTR_USERNAME], data[ATTR_PASSWORD]
) )
except auth_ha.InvalidUser: except auth_ha.InvalidUser as err:
raise HTTPNotFound() raise HTTPNotFound() from err
return web.Response(status=HTTP_OK) return web.Response(status=HTTP_OK)

View File

@ -75,7 +75,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
except HeosError as error: except HeosError as error:
await controller.disconnect() await controller.disconnect()
_LOGGER.debug("Unable to connect to controller %s: %s", host, error) _LOGGER.debug("Unable to connect to controller %s: %s", host, error)
raise ConfigEntryNotReady raise ConfigEntryNotReady from error
# Disconnect when shutting down # Disconnect when shutting down
async def disconnect_controller(event): async def disconnect_controller(event):
@ -99,7 +99,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
except HeosError as error: except HeosError as error:
await controller.disconnect() await controller.disconnect()
_LOGGER.debug("Unable to retrieve players and sources: %s", error) _LOGGER.debug("Unable to retrieve players and sources: %s", error)
raise ConfigEntryNotReady raise ConfigEntryNotReady from error
controller_manager = ControllerManager(hass, controller) controller_manager = ControllerManager(hass, controller)
await controller_manager.connect_listeners() await controller_manager.connect_listeners()

View File

@ -22,8 +22,8 @@ def coerce_ip(value):
raise vol.Invalid("Must define an IP address") raise vol.Invalid("Must define an IP address")
try: try:
ipaddress.IPv4Network(value) ipaddress.IPv4Network(value)
except ValueError: except ValueError as err:
raise vol.Invalid("Not a valid IP address") raise vol.Invalid("Not a valid IP address") from err
return value return value

View File

@ -49,8 +49,8 @@ async def validate_input(hass: HomeAssistant, user_input):
try: try:
client = await connect_client(hass, user_input) client = await connect_client(hass, user_input)
except asyncio.TimeoutError: except asyncio.TimeoutError as err:
raise CannotConnect raise CannotConnect from err
try: try:
def disconnect_callback(): def disconnect_callback():
@ -62,7 +62,7 @@ async def validate_input(hass: HomeAssistant, user_input):
except CannotConnect: except CannotConnect:
client.disconnect_callback = None client.disconnect_callback = None
client.stop() client.stop()
raise CannotConnect raise
else: else:
client.disconnect_callback = None client.disconnect_callback = None
client.stop() client.stop()

View File

@ -40,8 +40,8 @@ class TimePattern:
if not (0 <= number <= self.maximum): if not (0 <= number <= self.maximum):
raise vol.Invalid(f"must be a value between 0 and {self.maximum}") raise vol.Invalid(f"must be a value between 0 and {self.maximum}")
except ValueError: except ValueError as err:
raise vol.Invalid("invalid time_pattern value") raise vol.Invalid("invalid time_pattern value") from err
return value return value

View File

@ -92,8 +92,8 @@ class HomematicipHAP:
self.config_entry.data.get(HMIPC_AUTHTOKEN), self.config_entry.data.get(HMIPC_AUTHTOKEN),
self.config_entry.data.get(HMIPC_NAME), self.config_entry.data.get(HMIPC_NAME),
) )
except HmipcConnectionError: except HmipcConnectionError as err:
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
except Exception as err: # pylint: disable=broad-except except Exception as err: # pylint: disable=broad-except
_LOGGER.error("Error connecting with HomematicIP Cloud: %s", err) _LOGGER.error("Error connecting with HomematicIP Cloud: %s", err)
return False return False
@ -247,8 +247,8 @@ class HomematicipHAP:
try: try:
await home.init(hapid) await home.init(hapid)
await home.get_current_state() await home.get_current_state()
except HmipConnectionError: except HmipConnectionError as err:
raise HmipcConnectionError raise HmipcConnectionError from err
home.on_update(self.async_update) home.on_update(self.async_update)
home.on_create(self.async_create_entity) home.on_create(self.async_create_entity)
hass.loop.create_task(self.async_connect()) hass.loop.create_task(self.async_connect())

View File

@ -71,7 +71,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
except OSError as msg: except OSError as msg:
# occurs if horizon box is offline # occurs if horizon box is offline
_LOGGER.error("Connection to %s at %s failed: %s", name, host, msg) _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) _LOGGER.info("Connection to %s at %s established", name, host)

View File

@ -191,4 +191,4 @@ class HpIloData:
hpilo.IloCommunicationError, hpilo.IloCommunicationError,
hpilo.IloLoginFailed, hpilo.IloLoginFailed,
) as error: ) as error:
raise ValueError(f"Unable to init HP ILO, {error}") raise ValueError(f"Unable to init HP ILO, {error}") from error

View File

@ -91,11 +91,11 @@ def async_setup_forwarded(app, trusted_proxies):
forwarded_for_split = list(reversed(forwarded_for_headers[0].split(","))) forwarded_for_split = list(reversed(forwarded_for_headers[0].split(",")))
try: try:
forwarded_for = [ip_address(addr.strip()) for addr in forwarded_for_split] forwarded_for = [ip_address(addr.strip()) for addr in forwarded_for_split]
except ValueError: except ValueError as err:
_LOGGER.error( _LOGGER.error(
"Invalid IP address in X-Forwarded-For: %s", forwarded_for_headers[0] "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 # Find the last trusted index in the X-Forwarded-For list
forwarded_for_index = 0 forwarded_for_index = 0

View File

@ -52,7 +52,7 @@ class HomeAssistantView:
msg = json.dumps(result, cls=JSONEncoder, allow_nan=False).encode("UTF-8") msg = json.dumps(result, cls=JSONEncoder, allow_nan=False).encode("UTF-8")
except (ValueError, TypeError) as err: except (ValueError, TypeError) as err:
_LOGGER.error("Unable to serialize to JSON: %s\n%s", err, result) _LOGGER.error("Unable to serialize to JSON: %s\n%s", err, result)
raise HTTPInternalServerError raise HTTPInternalServerError from err
response = web.Response( response = web.Response(
body=msg, body=msg,
content_type=CONTENT_TYPE_JSON, content_type=CONTENT_TYPE_JSON,
@ -127,12 +127,12 @@ def request_handler_factory(view: HomeAssistantView, handler: Callable) -> Calla
if asyncio.iscoroutine(result): if asyncio.iscoroutine(result):
result = await result result = await result
except vol.Invalid: except vol.Invalid as err:
raise HTTPBadRequest() raise HTTPBadRequest() from err
except exceptions.ServiceNotFound: except exceptions.ServiceNotFound as err:
raise HTTPInternalServerError() raise HTTPInternalServerError() from err
except exceptions.Unauthorized: except exceptions.Unauthorized as err:
raise HTTPUnauthorized() raise HTTPUnauthorized() from err
if isinstance(result, web.StreamResponse): if isinstance(result, web.StreamResponse):
# The method handler returned a ready-made Response, how nice of it # The method handler returned a ready-made Response, how nice of it

View File

@ -94,9 +94,9 @@ class HueBridge:
create_config_flow(hass, host) create_config_flow(hass, host)
return False return False
except CannotConnect: except CannotConnect as err:
LOGGER.error("Error connecting to the Hue bridge at %s", host) LOGGER.error("Error connecting to the Hue bridge at %s", host)
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
except Exception: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
LOGGER.exception("Unknown error connecting with Hue bridge at %s", host) 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) # Initialize bridge (and validate our username)
await bridge.initialize() await bridge.initialize()
except (aiohue.LinkButtonNotPressed, aiohue.Unauthorized): except (aiohue.LinkButtonNotPressed, aiohue.Unauthorized) as err:
raise AuthenticationRequired raise AuthenticationRequired from err
except ( except (
asyncio.TimeoutError, asyncio.TimeoutError,
client_exceptions.ClientOSError, client_exceptions.ClientOSError,
client_exceptions.ServerDisconnectedError, client_exceptions.ServerDisconnectedError,
client_exceptions.ContentTypeError, client_exceptions.ContentTypeError,
): ) as err:
raise CannotConnect raise CannotConnect from err
except aiohue.AiohueException: except aiohue.AiohueException as err:
LOGGER.exception("Unknown Hue linking error occurred") LOGGER.exception("Unknown Hue linking error occurred")
raise AuthenticationRequired raise AuthenticationRequired from err
async def _update_listener(hass, entry): async def _update_listener(hass, entry):

View File

@ -159,11 +159,11 @@ async def async_safe_fetch(bridge, fetch_method):
try: try:
with async_timeout.timeout(4): with async_timeout.timeout(4):
return await bridge.async_request_call(fetch_method) return await bridge.async_request_call(fetch_method)
except aiohue.Unauthorized: except aiohue.Unauthorized as err:
await bridge.handle_unauthorized_error() await bridge.handle_unauthorized_error()
raise UpdateFailed("Unauthorized") raise UpdateFailed("Unauthorized") from err
except (aiohue.AiohueException,) as err: except (aiohue.AiohueException,) as err:
raise UpdateFailed(f"Hue error: {err}") raise UpdateFailed(f"Hue error: {err}") from err
@callback @callback

View File

@ -61,11 +61,11 @@ class SensorManager:
return await self.bridge.async_request_call( return await self.bridge.async_request_call(
self.bridge.api.sensors.update self.bridge.api.sensors.update
) )
except Unauthorized: except Unauthorized as err:
await self.bridge.handle_unauthorized_error() await self.bridge.handle_unauthorized_error()
raise UpdateFailed("Unauthorized") raise UpdateFailed("Unauthorized") from err
except AiohueException as 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): async def async_register_component(self, platform, async_add_entities):
"""Register async_add_entities methods for components.""" """Register async_add_entities methods for components."""

View File

@ -128,9 +128,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
shade_data = _async_map_data_by_id( shade_data = _async_map_data_by_id(
(await shades.get_resources())[SHADE_DATA] (await shades.get_resources())[SHADE_DATA]
) )
except HUB_EXCEPTIONS: except HUB_EXCEPTIONS as err:
_LOGGER.error("Connection error to PowerView hub: %s", hub_address) _LOGGER.error("Connection error to PowerView hub: %s", hub_address)
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
if not device_info: if not device_info:
_LOGGER.error("Unable to initialize PowerView hub: %s", hub_address) _LOGGER.error("Unable to initialize PowerView hub: %s", hub_address)

View File

@ -33,8 +33,8 @@ async def validate_input(hass: core.HomeAssistant, data):
try: try:
async with async_timeout.timeout(10): async with async_timeout.timeout(10):
device_info = await async_get_device_info(pv_request) device_info = await async_get_device_info(pv_request)
except HUB_EXCEPTIONS: except HUB_EXCEPTIONS as err:
raise CannotConnect raise CannotConnect from err
if not device_info: if not device_info:
raise CannotConnect raise CannotConnect

View File

@ -41,16 +41,16 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
try: try:
with async_timeout.timeout(PLATFORM_TIMEOUT): with async_timeout.timeout(PLATFORM_TIMEOUT):
api = await real_time_api(config_host, config_port) 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") _LOGGER.error("Device is not ready")
raise PlatformNotReady raise PlatformNotReady from err
async def async_update_data(): async def async_update_data():
try: try:
with async_timeout.timeout(PLATFORM_TIMEOUT): with async_timeout.timeout(PLATFORM_TIMEOUT):
return await api.get_data() return await api.get_data()
except (IamMeterError, asyncio.TimeoutError): except (IamMeterError, asyncio.TimeoutError) as err:
raise UpdateFailed raise UpdateFailed from err
coordinator = DataUpdateCoordinator( coordinator = DataUpdateCoordinator(
hass, hass,

View File

@ -96,7 +96,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> None
aiohttp.client_exceptions.ClientConnectorError, aiohttp.client_exceptions.ClientConnectorError,
) as aio_exception: ) as aio_exception:
_LOGGER.warning("Exception raised while attempting to login: %s", 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 = await aqualink.get_systems()
systems = list(systems.values()) systems = list(systems.values())

View File

@ -119,9 +119,12 @@ class IcloudAccount:
api_devices = self.api.devices api_devices = self.api.devices
# Gets device owners infos # Gets device owners infos
user_info = api_devices.response["userInfo"] user_info = api_devices.response["userInfo"]
except (PyiCloudServiceNotActivatedException, PyiCloudNoDevicesException): except (
PyiCloudServiceNotActivatedException,
PyiCloudNoDevicesException,
) as err:
_LOGGER.error("No iCloud device found") _LOGGER.error("No iCloud device found")
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
self._owner_fullname = f"{user_info['firstName']} {user_info['lastName']}" self._owner_fullname = f"{user_info['firstName']} {user_info['lastName']}"

View File

@ -92,8 +92,8 @@ class ImageStorageCollection(collection.StorageCollection):
# Verify we can read the image # Verify we can read the image
try: try:
image = Image.open(uploaded_file.file) image = Image.open(uploaded_file.file)
except UnidentifiedImageError: except UnidentifiedImageError as err:
raise vol.Invalid("Unable to identify image file") raise vol.Invalid("Unable to identify image file") from err
# Reset content # Reset content
uploaded_file.file.seek(0) uploaded_file.file.seek(0)
@ -170,8 +170,8 @@ class ImageServeView(HomeAssistantView):
parts = image_size.split("x", 1) parts = image_size.split("x", 1)
width = int(parts[0]) width = int(parts[0])
height = int(parts[1]) height = int(parts[1])
except (ValueError, IndexError): except (ValueError, IndexError) as err:
raise web.HTTPBadRequest raise web.HTTPBadRequest from err
if not width or width != height or width not in VALID_SIZES: if not width or width != height or width not in VALID_SIZES:
raise web.HTTPBadRequest raise web.HTTPBadRequest

View File

@ -324,22 +324,22 @@ def get_influx_connection(conf, test_write=False, test_read=False):
try: try:
write_api.write(bucket=bucket, record=json) write_api.write(bucket=bucket, record=json)
except (urllib3.exceptions.HTTPError, OSError) as exc: except (urllib3.exceptions.HTTPError, OSError) as exc:
raise ConnectionError(CONNECTION_ERROR % exc) raise ConnectionError(CONNECTION_ERROR % exc) from exc
except ApiException as exc: except ApiException as exc:
if exc.status == CODE_INVALID_INPUTS: if exc.status == CODE_INVALID_INPUTS:
raise ValueError(WRITE_ERROR % (json, exc)) raise ValueError(WRITE_ERROR % (json, exc)) from exc
raise ConnectionError(CLIENT_ERROR_V2 % exc) raise ConnectionError(CLIENT_ERROR_V2 % exc) from exc
def query_v2(query, _=None): def query_v2(query, _=None):
"""Query V2 influx.""" """Query V2 influx."""
try: try:
return query_api.query(query) return query_api.query(query)
except (urllib3.exceptions.HTTPError, OSError) as exc: except (urllib3.exceptions.HTTPError, OSError) as exc:
raise ConnectionError(CONNECTION_ERROR % exc) raise ConnectionError(CONNECTION_ERROR % exc) from exc
except ApiException as exc: except ApiException as exc:
if exc.status == CODE_INVALID_INPUTS: if exc.status == CODE_INVALID_INPUTS:
raise ValueError(QUERY_ERROR % (query, exc)) raise ValueError(QUERY_ERROR % (query, exc)) from exc
raise ConnectionError(CLIENT_ERROR_V2 % exc) raise ConnectionError(CLIENT_ERROR_V2 % exc) from exc
def close_v2(): def close_v2():
"""Close V2 influx client.""" """Close V2 influx client."""
@ -399,11 +399,11 @@ def get_influx_connection(conf, test_write=False, test_read=False):
exceptions.InfluxDBServerError, exceptions.InfluxDBServerError,
OSError, OSError,
) as exc: ) as exc:
raise ConnectionError(CONNECTION_ERROR % exc) raise ConnectionError(CONNECTION_ERROR % exc) from exc
except exceptions.InfluxDBClientError as exc: except exceptions.InfluxDBClientError as exc:
if exc.code == CODE_INVALID_INPUTS: if exc.code == CODE_INVALID_INPUTS:
raise ValueError(WRITE_ERROR % (json, exc)) raise ValueError(WRITE_ERROR % (json, exc)) from exc
raise ConnectionError(CLIENT_ERROR_V1 % exc) raise ConnectionError(CLIENT_ERROR_V1 % exc) from exc
def query_v1(query, database=None): def query_v1(query, database=None):
"""Query V1 influx.""" """Query V1 influx."""
@ -414,11 +414,11 @@ def get_influx_connection(conf, test_write=False, test_read=False):
exceptions.InfluxDBServerError, exceptions.InfluxDBServerError,
OSError, OSError,
) as exc: ) as exc:
raise ConnectionError(CONNECTION_ERROR % exc) raise ConnectionError(CONNECTION_ERROR % exc) from exc
except exceptions.InfluxDBClientError as exc: except exceptions.InfluxDBClientError as exc:
if exc.code == CODE_INVALID_INPUTS: if exc.code == CODE_INVALID_INPUTS:
raise ValueError(QUERY_ERROR % (query, exc)) raise ValueError(QUERY_ERROR % (query, exc)) from exc
raise ConnectionError(CLIENT_ERROR_V1 % exc) raise ConnectionError(CLIENT_ERROR_V1 % exc) from exc
def close_v1(): def close_v1():
"""Close the V1 Influx client.""" """Close the V1 Influx client."""

View File

@ -147,7 +147,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
influx = get_influx_connection(config, test_read=True) influx = get_influx_connection(config, test_read=True)
except ConnectionError as exc: except ConnectionError as exc:
_LOGGER.error(exc) _LOGGER.error(exc)
raise PlatformNotReady() raise PlatformNotReady() from exc
entities = [] entities = []
if CONF_QUERIES_FLUX in config: if CONF_QUERIES_FLUX in config:

View File

@ -173,8 +173,8 @@ def normalize_byte_entry_to_int(entry: [int, bytes, str]):
raise ValueError("Not a valid hex code") raise ValueError("Not a valid hex code")
try: try:
entry = unhexlify(entry) entry = unhexlify(entry)
except HexError: except HexError as err:
raise ValueError("Not a valid hex code") raise ValueError("Not a valid hex code") from err
return int.from_bytes(entry, byteorder="big") 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])) address = str(Address(new_override[CONF_ADDRESS]))
cat = normalize_byte_entry_to_int(new_override[CONF_CAT]) cat = normalize_byte_entry_to_int(new_override[CONF_CAT])
subcat = normalize_byte_entry_to_int(new_override[CONF_SUBCAT]) subcat = normalize_byte_entry_to_int(new_override[CONF_SUBCAT])
except ValueError: except ValueError as err:
raise ValueError("Incorrect values") raise ValueError("Incorrect values") from err
overrides = config_data.get(CONF_OVERRIDE, []) overrides = config_data.get(CONF_OVERRIDE, [])
curr_override = {} curr_override = {}

View File

@ -107,9 +107,9 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
except IHAuthenticationError: except IHAuthenticationError:
_LOGGER.error("Invalid username or password") _LOGGER.error("Invalid username or password")
return return
except IHConnectionError: except IHConnectionError as ex:
_LOGGER.error("Error connecting to the %s server", device_type) _LOGGER.error("Error connecting to the %s server", device_type)
raise PlatformNotReady raise PlatformNotReady from ex
ih_devices = controller.get_devices() ih_devices = controller.get_devices()
if ih_devices: if ih_devices:
@ -199,7 +199,7 @@ class IntesisAC(ClimateEntity):
await self._controller.connect() await self._controller.connect()
except IHConnectionError as ex: except IHConnectionError as ex:
_LOGGER.error("Exception connecting to IntesisHome: %s", ex) _LOGGER.error("Exception connecting to IntesisHome: %s", ex)
raise PlatformNotReady raise PlatformNotReady from ex
@property @property
def name(self): def name(self):

View File

@ -121,7 +121,7 @@ class IPPDataUpdateCoordinator(DataUpdateCoordinator[IPPPrinter]):
try: try:
return await self.ipp.printer() return await self.ipp.printer()
except IPPError as error: 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): class IPPEntity(Entity):

View File

@ -174,8 +174,8 @@ class IslamicPrayerClient:
try: try:
await self.hass.async_add_executor_job(self.get_new_prayer_times) await self.hass.async_add_executor_job(self.get_new_prayer_times)
except (exceptions.InvalidResponseError, ConnError): except (exceptions.InvalidResponseError, ConnError) as err:
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
await self.async_update() await self.async_update()
self.config_entry.add_update_listener(self.async_options_updated) self.config_entry.add_update_listener(self.async_options_updated)

View File

@ -98,7 +98,7 @@ def _fetch_isy_configuration(
webroot=webroot, webroot=webroot,
) )
except ValueError as err: 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()) return Configuration(log=_LOGGER, xml=isy_conn.get_config())

View File

@ -63,7 +63,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
return False return False
except aiohttp.ClientError as error: except aiohttp.ClientError as error:
_LOGGER.error("Could not reach the JuiceNet API %s", error) _LOGGER.error("Could not reach the JuiceNet API %s", error)
raise ConfigEntryNotReady raise ConfigEntryNotReady from error
if not juicenet.devices: if not juicenet.devices:
_LOGGER.error("No JuiceNet devices found for this account") _LOGGER.error("No JuiceNet devices found for this account")

View File

@ -28,10 +28,10 @@ async def validate_input(hass: core.HomeAssistant, data):
await juicenet.get_devices() await juicenet.get_devices()
except TokenError as error: except TokenError as error:
_LOGGER.error("Token Error %s", error) _LOGGER.error("Token Error %s", error)
raise InvalidAuth raise InvalidAuth from error
except aiohttp.ClientError as error: except aiohttp.ClientError as error:
_LOGGER.error("Error connecting %s", 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 info that you want to store in the config entry.
return {"title": "JuiceNet"} return {"title": "JuiceNet"}

View File

@ -186,8 +186,8 @@ class KonnectedFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
try: try:
status = await get_status(self.hass, host, port) status = await get_status(self.hass, host, port)
self.data[CONF_ID] = status.get("chipId", status["mac"].replace(":", "")) self.data[CONF_ID] = status.get("chipId", status["mac"].replace(":", ""))
except (CannotConnect, KeyError): except (CannotConnect, KeyError) as err:
raise CannotConnect raise CannotConnect from err
else: else:
self.data[CONF_MODEL] = status.get("model", KONN_MODEL) self.data[CONF_MODEL] = status.get("model", KONN_MODEL)
self.data[CONF_ACCESS_TOKEN] = "".join( self.data[CONF_ACCESS_TOKEN] = "".join(

View File

@ -390,4 +390,4 @@ async def get_status(hass, host, port):
except client.ClientError as err: except client.ClientError as err:
_LOGGER.error("Exception trying to get panel status: %s", err) _LOGGER.error("Exception trying to get panel status: %s", err)
raise CannotConnect raise CannotConnect from err

View File

@ -148,8 +148,8 @@ async def async_setup_entry(hass, config_entry):
) )
await luftdaten.async_update() await luftdaten.async_update()
hass.data[DOMAIN][DATA_LUFTDATEN_CLIENT][config_entry.entry_id] = luftdaten hass.data[DOMAIN][DATA_LUFTDATEN_CLIENT][config_entry.entry_id] = luftdaten
except LuftdatenError: except LuftdatenError as err:
raise ConfigEntryNotReady raise ConfigEntryNotReady from err
hass.async_create_task( hass.async_create_task(
hass.config_entries.async_forward_entry_setup(config_entry, "sensor") hass.config_entries.async_forward_entry_setup(config_entry, "sensor")

View File

@ -103,9 +103,9 @@ class MediaExtractor:
try: try:
all_media = ydl.extract_info(self.get_media_url(), process=False) 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 # This exception will be logged by youtube-dl itself
raise MEDownloadException() raise MEDownloadException() from err
if "entries" in all_media: if "entries" in all_media:
_LOGGER.warning("Playlists are not supported, looking for the first video") _LOGGER.warning("Playlists are not supported, looking for the first video")
@ -123,9 +123,9 @@ class MediaExtractor:
try: try:
ydl.params["format"] = query ydl.params["format"] = query
requested_stream = ydl.process_ie_result(selected_media, download=False) 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) _LOGGER.error("Could not extract stream for the query: %s", query)
raise MEQueryException() raise MEQueryException() from err
return requested_stream["url"] return requested_stream["url"]

View File

@ -83,7 +83,7 @@ class MetDataUpdateCoordinator(DataUpdateCoordinator):
try: try:
return await self.weather.fetch_data() return await self.weather.fetch_data()
except Exception as err: except Exception as err:
raise UpdateFailed(f"Update failed: {err}") raise UpdateFailed(f"Update failed: {err}") from err
def track_home(self): def track_home(self):
"""Start tracking changes to HA home setting.""" """Start tracking changes to HA home setting."""

View File

@ -253,7 +253,7 @@ class MikrotikData:
socket.timeout, socket.timeout,
) as api_error: ) as api_error:
_LOGGER.error("Mikrotik %s connection error %s", self._host, 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: except librouteros.exceptions.ProtocolError as api_error:
_LOGGER.warning( _LOGGER.warning(
"Mikrotik %s failed to retrieve data. cmd=[%s] Error: %s", "Mikrotik %s failed to retrieve data. cmd=[%s] Error: %s",
@ -367,8 +367,8 @@ class MikrotikHub:
api = await self.hass.async_add_executor_job( api = await self.hass.async_add_executor_job(
get_api, self.hass, self.config_entry.data get_api, self.hass, self.config_entry.data
) )
except CannotConnect: except CannotConnect as api_error:
raise ConfigEntryNotReady raise ConfigEntryNotReady from api_error
except LoginError: except LoginError:
return False return False
@ -415,5 +415,5 @@ def get_api(hass, entry):
) as api_error: ) as api_error:
_LOGGER.error("Mikrotik %s error: %s", entry[CONF_HOST], api_error) _LOGGER.error("Mikrotik %s error: %s", entry[CONF_HOST], api_error)
if "invalid user name or password" in str(api_error): if "invalid user name or password" in str(api_error):
raise LoginError raise LoginError from api_error
raise CannotConnect raise CannotConnect from api_error

View File

@ -219,7 +219,7 @@ async def webhook_call_service(hass, config_entry, data):
config_entry.data[ATTR_DEVICE_NAME], config_entry.data[ATTR_DEVICE_NAME],
ex, ex,
) )
raise HTTPBadRequest() raise HTTPBadRequest() from ex
return empty_okay_response() return empty_okay_response()

Some files were not shown because too many files have changed in this diff Show More