class_docstr: A lazy execution plan for a Dataset.
class_docstr_tok: ["A","lazy","execution","plan","for","a","Dataset","."]
docstr: Get the unified schema of the blocks.
  
  Args:
      blocks: the blocks to get schema
      fetch_if_missing: Whether to execute the blocks to fetch the schema.
docstr_tok: ["Get","the","unified","schema","of","the","blocks",".","Args",":","blocks",":","the","blocks","to","get","schema","fetch_if_missing",":","Whether","to","execute","the","blocks","to","fetch","the","schema","."]
code: def _get_unified_blocks_schema(
      self, blocks: BlockList, fetch_if_missing: bool = False
  ) -> Union[type, "pyarrow.lib.Schema"]:
      """Get the unified schema of the blocks.
  
      Args:
          blocks: the blocks to get schema
          fetch_if_missing: Whether to execute the blocks to fetch the schema.
      """
  
      # Ensure the first block has schema information available in the metadata.
      # Otherwise, this will trigger computation on the first block
      # for a schema read.
      if isinstance(blocks, LazyBlockList):
          blocks.ensure_metadata_for_first_block()
  
      metadata = blocks.get_metadata(fetch_if_missing=False)
  
      unified_schema = unify_block_metadata_schema(metadata)
      if unified_schema is not None:
          return unified_schema
      if not fetch_if_missing:
          return None
      # Synchronously fetch the schema.
      # For lazy block lists, this launches read tasks and fetches block metadata
      # until we find the first valid block schema. This is to minimize new
      # computations when fetching the schema.
      for _, m in blocks.iter_blocks_with_metadata():
          if m.schema is not None and (
              m.num_rows is None or m.num_rows > 0
          ):
              return m.schema
      return None
  
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 11 for calling the ExecutionPlan obj's underlying member method code with example usage: obj._get_unified_blocks_schema(blocks, fetch_if_missing) and returns: None, unified_schema, None, m