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

Code before:
        logger: logging.Logger,
        entry: ConfigEntry | None,
        update_interval: timedelta,
        api: TodoistAPIAsync,
        token: str,
    ) -> None:
        """Initialize the Todoist coordinator."""
        super().__init__(
            hass,
            logger,
            config_entry=entry,
            name="Todoist",
            update_interval=update_interval,
        )
        self.api = api
        self._projects: list[Project] | None = None
        self._labels: list[Label] | None = None
        self.token = token

    async def _async_update_data(self) -> list[Task]:
        """Fetch tasks from the Todoist API."""
        try:
            tasks_async = await self.api.get_tasks(limit=200)
            return await flatten_async_pages(tasks_async)
        except Exception as err:
            raise UpdateFailed(f"Error communicating with API: {err}") from err

    async def async_get_projects(self) -> list[Project]:
        """Return todoist projects fetched at most once."""
        if self._projects is None:
            projects_async = await self.api.get_projects(limit=200)
            self._projects = await flatten_async_pages(projects_async)
        return self._projects

    async def async_get_sections(self, project_id: str) -> list[Section]:
        """Return todoist sections for a given project ID."""
        sections_async = await self.api.get_sections(project_id=project_id, limit=200)
        return await flatten_async_pages(sections_async)

    async def async_get_labels(self) -> list[Label]:
        """Return todoist labels fetched at most once."""
        if self._labels is None:
            labels_async = await self.api.get_labels(limit=200)
            self._labels = await flatten_async_pages(labels_async)
        return self._labels


Review comment (suggestion):
I also realized that the actual call was getting executed in `flatten_async_pages`, so the exception wasn't getting caught and re-raised here.  So I moved that call into the try block here.

Code after:
    def __init__(
        self,
        hass: HomeAssistant,
        logger: logging.Logger,
        entry: ConfigEntry | None,
        update_interval: timedelta,
        api: TodoistAPIAsync,
        token: str,
    ) -> None:
        """Initialize the Todoist coordinator."""
        super().__init__(
            hass,
            logger,
            config_entry=entry,
            name="Todoist",
            update_interval=update_interval,
        )
        self.api = api
        self._projects: list[Project] | None = None
        self._labels: list[Label] | None = None
        self.token = token

    async def _async_update_data(self) -> list[Task]:
        """Fetch tasks from the Todoist API."""
        try:
            tasks_async = await self.api.get_tasks(limit=MAX_PAGE_SIZE)
            return await flatten_async_pages(tasks_async)
        except asyncio.CancelledError:
            raise
        except Exception as err:
            raise UpdateFailed(f"Error communicating with API: {err}") from err

    async def async_get_projects(self) -> list[Project]:
        """Return todoist projects fetched at most once."""
        if self._projects is None:
            projects_async = await self.api.get_projects(limit=MAX_PAGE_SIZE)
            self._projects = await flatten_async_pages(projects_async)
        return self._projects

    async def async_get_sections(self, project_id: str) -> list[Section]:
        """Return todoist sections for a given project ID."""
        sections_async = await self.api.get_sections(
            project_id=project_id, limit=MAX_PAGE_SIZE
        )
        return await flatten_async_pages(sections_async)

    async def async_get_labels(self) -> list[Label]:
        """Return todoist labels fetched at most once."""
        if self._labels is None:
            labels_async = await self.api.get_labels(limit=MAX_PAGE_SIZE)
            self._labels = await flatten_async_pages(labels_async)