class_docstr: A lazy execution plan for a Dataset.
class_docstr_tok: ["A","lazy","execution","plan","for","a","Dataset","."]
docstr: Get the schema after applying all plan stages.
  
  Args:
      fetch_if_missing: Whether to execute the plan to fetch the schema.
  
  Returns:
      The schema of the output dataset.
docstr_tok: ["Get","the","schema","after","applying","all","plan","stages",".","Args",":","fetch_if_missing",":","Whether","to","execute","the","plan","to","fetch","the","schema",".","Returns",":","The","schema","of","the","output","dataset","."]
code: def schema(
      self, fetch_if_missing: bool = False
  ) -> Union[type, "pyarrow.lib.Schema"]:
      """Get the schema after applying all plan stages.
  
      Args:
          fetch_if_missing: Whether to execute the plan to fetch the schema.
  
      Returns:
          The schema of the output dataset.
      """
      from ray.data._internal.logical.operators.all_to_all_operator import (
          RandomizeBlocks,
      )
  
      if self._schema is not None:
          return self._schema
  
      if self._snapshot_blocks is None or (
          self._snapshot_operator is not None
          and self._snapshot_operator.output_dependencies
      ):
          # There remain some operators yet to be executed.
          # Even if a schema is already previously known, it may change,
          # so we try executing to get the most updated schema.
  
          # TODO(swang): There are several other stage types that could
          # inherit the schema or we can compute the schema without having to
          # execute any of the dataset: limit, filter, map_batches for
          # add/drop columns, etc.
          if fetch_if_missing:
              if isinstance(self._logical_plan.dag, RandomizeBlocks):
                  # TODO(ekl): this is a hack to optimize the case where we have a
                  # trailing randomize block stages. That stage has no effect and
                  # so we don't need to execute all blocks to get the schema.
  
                  randomize_blocks_op = self._logical_plan.dag
                  self._logical_plan._dag = (
                      randomize_blocks_op.input_dependencies[0]
                  )
                  try:
                      self.execute()
                  finally:
                      self._logical_plan = randomize_blocks_op
              else:
                  self.execute()
          elif self.needs_eager_execution() or (
              isinstance(self._logical_plan.dag, RandomizeBlocks)
              and self.needs_eager_execution(
                  self._logical_plan.dag.input_dependencies[0]
              )
          ):
              # If the plan is input/read only, we execute it, so snapshot has output.
              # If RandomizeBlocks is the last operator preceded by a input/read
              # only plan, we can also execute it (regardless of the fetch_if_missing)
              # since RandomizeBlocksStage is just changing the order of references
              # (hence super cheap). Calling execute does not trigger read tasks.
              self.execute()
          else:
              return None
      # Snapshot is now guaranteed to be the output of the final stage or None.
      blocks = self._snapshot_blocks
      if not blocks:
          return None
      self._schema = self._get_unified_blocks_schema(
          blocks, fetch_if_missing
      )
      return self._schema
  
imports: import copy
  import itertools
  from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Union
  import ray
  from ray._private.internal_api import get_memory_info_reply, get_state_from_address
  from ray.data._internal.block_list import BlockList
  from ray.data._internal.compute import ActorPoolStrategy, BlockTransform, CallableClass, ComputeStrategy, TaskPoolStrategy, UserDefinedFunction, get_compute, is_task_compute
  from ray.data._internal.dataset_logger import DatasetLogger
  from ray.data._internal.execution.interfaces import TaskContext
  from ray.data._internal.lazy_block_list import LazyBlockList
  from ray.data._internal.logical.interfaces.logical_operator import LogicalOperator
  from ray.data._internal.logical.operators.from_operators import AbstractFrom
  from ray.data._internal.logical.operators.input_data_operator import InputData
  from ray.data._internal.logical.operators.read_operator import Read
  from ray.data._internal.logical.rules.operator_fusion import _are_remote_args_compatible
  from ray.data._internal.stats import DatasetStats, DatasetStatsSummary
  from ray.data._internal.util import create_dataset_tag, unify_block_metadata_schema
  from ray.data.block import Block, BlockMetadata
  from ray.data.context import DataContext
  from ray.types import ObjectRef
  from ray.util.debug import log_once
label_desc: Use image node_id 9 for calling the ExecutionPlan obj's underlying member method code with example usage: obj.schema(fetch_if_missing) and returns: self, self, None, None