code: def _get_tileable_subtasks(
      self, tileable_id: str, with_input_output: bool
  ):
      returned_subtasks = dict()
      subtask_id_to_types = dict()
  
      subtask_details = dict()
      subtask_graph = subtask_results = subtask_snapshots = None
      for processor in self._task_id_to_processor.values():
          tileable_to_subtasks = processor.get_tileable_to_subtasks()
          tileable_id_to_tileable = processor.tileable_id_to_tileable
          for stage in processor.stage_processors:
              if tileable_id in tileable_id_to_tileable:
                  tileable = tileable_id_to_tileable[tileable_id]
                  returned_subtasks = {
                      subtask.subtask_id: subtask
                      for subtask in tileable_to_subtasks[tileable]
                  }
                  subtask_graph = stage.subtask_graph
                  subtask_results = stage.subtask_results
                  subtask_snapshots = stage.subtask_snapshots
                  break
          if returned_subtasks:
              break
  
      if subtask_graph is None:  # pragma: no cover
          return {}
  
      if with_input_output:
          for subtask in list(returned_subtasks.values()):
              for pred in subtask_graph.iter_predecessors(subtask):
                  if (
                      pred.subtask_id in returned_subtasks
                  ):  # pragma: no cover
                      continue
                  returned_subtasks[pred.subtask_id] = pred
                  subtask_id_to_types[pred.subtask_id] = "Input"
              for succ in subtask_graph.iter_successors(subtask):
                  if (
                      succ.subtask_id in returned_subtasks
                  ):  # pragma: no cover
                      continue
                  returned_subtasks[succ.subtask_id] = succ
                  subtask_id_to_types[succ.subtask_id] = "Output"
  
      for subtask in returned_subtasks.values():
          subtask_result = subtask_results.get(
              subtask,
              subtask_snapshots.get(
                  subtask,
                  SubtaskResult(
                      progress=0.0,
                      status=SubtaskStatus.pending,
                      stage_id=subtask.stage_id,
                  ),
              ),
          )
          subtask_details[subtask.subtask_id] = {
              "name": subtask.subtask_name,
              "status": subtask_result.status.value,
              "progress": subtask_result.progress,
              "nodeType": subtask_id_to_types.get(
                  subtask.subtask_id, "Calculation"
              ),
          }
  
      for subtask in returned_subtasks.values():
          pred_ids = []
          for pred in subtask_graph.iter_predecessors(subtask):
              if pred.subtask_id in returned_subtasks:
                  pred_ids.append(pred.subtask_id)
          subtask_details[subtask.subtask_id][
              "fromSubtaskIds"
          ] = pred_ids
      return subtask_details
  
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 5 for calling the _TaskInfoProcessorMixin obj's underlying member method code with example usage: obj._get_tileable_subtasks(tileable_id, with_input_output) and returns: subtask_details, dict