code: def _get_tileable_infos(
      self,
  ) -> Dict[TileableType, _TileableDetailInfo]:
      cache = self._init_cache()
  
      tileable_to_stage_infos: Dict[
          TileableType, List[_TileableStageInfo]
      ] = dict()
      for processor in self._task_id_to_processor.values():
          tile_context = processor.tile_context
          for (
              tileable,
              infos,
          ) in tile_context.get_tileable_tile_infos().items():
              tileable_to_stage_infos[tileable] = []
              if tileable in cache:
                  # cached
                  continue
              for info in infos:
                  chunks = [
                      c
                      for c in info.generated_chunks
                      if not isinstance(c.op, Fetch)
                  ]
                  try:
                      subtask_ids = {
                          st.subtask_id
                          for st in processor.get_subtasks(chunks)
                      }
                  except KeyError:  # pragma: no cover
                      subtask_ids = None
                  stage_info = _TileableStageInfo(
                      progress=info.tile_progress,
                      subtask_ids=subtask_ids,
                  )
                  tileable_to_stage_infos[tileable].append(stage_info)
  
      tileable_to_defails = dict()
      subtask_id_to_results = self._get_all_subtask_results()
      for tileable, infos in tileable_to_stage_infos.items():
          if tileable in cache:
              # cached
              tileable_to_defails[tileable] = cache[tileable]
              continue
  
          statuses = set()
          progress = 0.0 if not isinstance(tileable.op, Fetch) else 1.0
          n_subtask = 0
          for stage_info in infos:
              tile_progress = stage_info.progress
              stage_progress = 0.0
              if stage_info.subtask_ids is None:
                  continue
              for subtask_id in stage_info.subtask_ids:
                  try:
                      result = subtask_id_to_results[subtask_id]
                      stage_progress += result.progress * tile_progress
                      statuses.add(result.status)
                  except KeyError:
                      # pending
                      statuses.add(SubtaskStatus.pending)
              n_subtask += len(stage_info.subtask_ids)
              if stage_info.subtask_ids:
                  progress += stage_progress / len(
                      stage_info.subtask_ids
                  )
              else:
                  progress += tile_progress
  
          # calc status
          if (
              not statuses or statuses == {SubtaskStatus.succeeded}
          ) and abs(progress - 1.0) < 1e-3:
              status = SubtaskStatus.succeeded
          elif statuses == {SubtaskStatus.cancelled}:
              status = SubtaskStatus.cancelled
          elif statuses == {SubtaskStatus.pending}:
              status = SubtaskStatus.pending
          elif SubtaskStatus.errored in statuses:
              status = SubtaskStatus.errored
          else:
              status = SubtaskStatus.running
  
          props = tileable.op.to_kv(
              exclude_fields=("_key", "_id"),
              accept_value_types=(int, float, str),
          )
          info = _TileableDetailInfo(
              progress=progress,
              subtask_count=n_subtask,
              status=status.value,
              properties=props,
          )
          tileable_to_defails[tileable] = info
          if status.is_done and tileable not in cache:
              cache[tileable] = info
  
      return tileable_to_defails
  
imports: import asyncio
  import dataclasses
  import importlib
  import logging
  from typing import Any, Dict, Optional, Set, Type, List
  from ....None import oscar
  from ....config import Config
  from ....core import TileContext
  from ....core.operand import Fetch
  from ....typing import TileableType
  from ....utils import build_fetch
  from ...subtask import SubtaskResult, SubtaskStatus, SubtaskGraph
  from ..core import Task, TaskStatus, MapReduceInfo
  from ..execution.api import TaskExecutor
  from .preprocessor import TaskPreprocessor
  from .processor import TaskProcessor
label_desc: Use image node_id 3 for calling the _TaskInfoProcessorMixin obj's underlying member method code with example usage: obj._get_tileable_infos() and returns: tileable_to_defails