Repository: home-assistant/core
File: homeassistant/components/yardian/coordinator.py (Python)

Code before:
        )

    async def _async_update_data(self) -> YardianCombinedState:
        """Fetch data from Yardian device."""
        try:
            async with asyncio.timeout(10):
                _LOGGER.debug(
                    "Fetching Yardian device state for %s (controller=%s)",
                    self._name,
                    type(self.controller).__name__,
                )
                # Fetch device state and operation info; specific exceptions are
                # handled by the outer block to avoid double-logging.
                dev_state = await self.controller.fetch_device_state()
                oper_info = await self.controller.fetch_oper_info()
                oper_keys = list(oper_info.keys()) if hasattr(oper_info, "keys") else []
                _LOGGER.debug(
                    "Fetched Yardian data: zones=%s active=%s oper_keys=%s",
                    len(getattr(dev_state, "zones", [])),
                    len(getattr(dev_state, "active_zones", [])),
                    oper_keys,
                )
                return YardianCombinedState(
                    zones=dev_state.zones,
                    active_zones=dev_state.active_zones,
                    oper_info=oper_info,
                )

        except TimeoutError as e:
            raise UpdateFailed("Timeout communicating with device") from e
        except NotAuthorizedException as e:
            # Trigger reauth flow according to HA best practices
            raise ConfigEntryAuthFailed("Invalid access token") from e
        except NetworkException as e:
            raise UpdateFailed("Failed to communicate with device") from e
        except asyncio.CancelledError:
            raise
        except Exception as e:  # safety net for tests to surface failure reason
            _LOGGER.exception("Unexpected error while fetching Yardian data")
            raise UpdateFailed(f"Unexpected error: {type(e).__name__}: {e}") from e


Review comment (suggestion):
we don't catch base `Exception` outside of the Config Flow

Code after:
            manufacturer=MANUFACTURER,
            model=self._model,
            serial_number=self._serial,
        )

    async def _async_update_data(self) -> YardianCoordinatorData:
        """Fetch data from Yardian device."""
        _LOGGER.debug(
            "Fetching Yardian device state for %s (controller=%s)",
            self._name,
            type(self.controller).__name__,
        )
        try:
            async with asyncio.timeout(10):
                # Fetch device state and operation info; specific exceptions are
                # handled by the outer block to avoid double-logging.
                dev_state = await self.controller.fetch_device_state()
                oper_info = await self.controller.fetch_oper_info()

        except TimeoutError as e:
            raise UpdateFailed("Timeout communicating with device") from e
        except NotAuthorizedException as e:
            raise ConfigEntryError("Invalid access token") from e
        except NetworkException as e:
            raise UpdateFailed("Failed to communicate with device") from e
        except Exception as e:  # safety net for tests to surface failure reason
            _LOGGER.exception("Unexpected error while fetching Yardian data")
            raise UpdateFailed(f"Unexpected error: {type(e).__name__}: {e}") from e

        _LOGGER.debug(
            "Fetched Yardian data: zones=%s active=%s oper_keys=%s",
            len(dev_state.zones),
            len(dev_state.active_zones),
            list(oper_info.keys()),
        )

        return YardianCoordinatorData(
            zones=[
                YardianZone(
                    name=str(zone_info[0]),
                    is_enabled=zone_info[1] == 1,
                )
                for zone_info in dev_state.zones
            ],
            active_zones=set(dev_state.active_zones),
            oper_info=oper_info,
        )