class_docstr: A node (aka task) in the DAG representation of the execution plan.
  
  In the DAG, a node's parents represent the tasks that need to be run before the node can run. Using the term task
  for these nodes as it seems more intuitive.
docstr: Constructor.
  
  Args:
      task_id: the ID for the node
      parent_nodes: the nodes that should be executed before this one.
docstr_tok: ["Constructor",".","Args",":","task_id",":","the","ID","for","the","node","parent_nodes",":","the","nodes","that","should","be","executed","before","this","one","."]
code: def __init__(
      self, task_id: NodeId, parent_nodes: List[ExecutionPlanTask]
  ) -> None:
      """Constructor.
  
      Args:
          task_id: the ID for the node
          parent_nodes: the nodes that should be executed before this one.
      """
      self._parent_nodes = parent_nodes
      super().__init__(node_id=task_id)
  
imports: from __future__ import annotations
  import logging
  import textwrap
  import time
  from abc import ABC, abstractmethod
  from dataclasses import dataclass
  from typing import List, Optional, Sequence, Tuple
  import jinja2
  import pandas
  from metricflow.dag.id_generation import EXEC_NODE_READ_SQL_QUERY, EXEC_NODE_WRITE_TO_TABLE
  from metricflow.dag.mf_dag import DagId, DagNode, DisplayedProperty, MetricFlowDag, NodeId
  from metricflow.dataflow.sql_table import SqlTable
  from metricflow.protocols.sql_client import SqlClient
  from metricflow.sql.sql_bind_parameters import SqlBindParameters
  from metricflow.sql_request.sql_request_attributes import SqlJsonTag
  from metricflow.visitor import Visitable
label_desc: Use image node_id 1 to create a new ExecutionPlanTask object from inherited base classes: DagNode, Visitable, ABC with example: obj = ExecutionPlanTask(task_id, parent_nodes)