class_docstr: Builds a dataflow plan to satisfy a given query.
class_docstr_tok: ["Builds","a","dataflow","plan","to","satisfy","a","given","query","."]
code: def _build_plan(
      self,
      query_spec: MetricFlowQuerySpec,
      output_sql_table: Optional[SqlTable],
      output_selection_specs: Optional[InstanceSpecSet],
      optimizers: Sequence[DataflowPlanOptimizer],
  ) -> DataflowPlan:
      for metric_spec in query_spec.metric_specs:
          if (
              len(metric_spec.filter_specs) > 0
              or metric_spec.offset_to_grain is not None
              or metric_spec.offset_window is not None
              or metric_spec.alias is not None
          ):
              raise ValueError(
                  f"The metric specs in the query spec should not contain any metric modifiers. Got: {metric_spec}"
              )
  
      if query_spec.filter_spec_resolution_lookup is None:
          resolved_spec_lookup = (
              FilterSpecResolutionLookUp.empty_instance()
          )
      else:
          resolved_spec_lookup = (
              query_spec.filter_spec_resolution_lookup
          )
  
      filter_spec_factory = WhereSpecFactory(
          column_association_resolver=self._column_association_resolver,
          spec_resolution_lookup=resolved_spec_lookup,
      )
  
      query_level_filter_specs = tuple(
          filter_spec_factory.create_from_where_filter_intersection(
              filter_location=WhereFilterLocation.for_query(
                  tuple(
                      metric_spec.reference
                      for metric_spec in query_spec.metric_specs
                  )
              ),
              filter_intersection=query_spec.filter_intersection,
          )
      )
  
      metrics_output_node = self._build_metrics_output_node(
          metric_specs=tuple(
              MetricSpec(
                  element_name=metric_spec.element_name,
                  filter_specs=query_level_filter_specs,
              )
              for metric_spec in query_spec.metric_specs
          ),
          queried_linkable_specs=query_spec.linkable_specs,
          filter_spec_factory=filter_spec_factory,
          time_range_constraint=query_spec.time_range_constraint,
      )
  
      sink_node = DataflowPlanBuilder.build_sink_node(
          parent_node=metrics_output_node,
          order_by_specs=query_spec.order_by_specs,
          output_sql_table=output_sql_table,
          limit=query_spec.limit,
          output_selection_specs=output_selection_specs,
      )
  
      plan_id = IdGeneratorRegistry.for_class(
          DataflowPlanBuilder
      ).create_id(DATAFLOW_PLAN_PREFIX)
  
      plan = DataflowPlan(
          plan_id=plan_id, sink_output_nodes=[sink_node]
      )
      for optimizer in optimizers:
          logger.info(f"Applying {optimizer.__class__.__name__}")
          try:
              plan = optimizer.optimize(plan)
          except Exception:
              logger.exception(
                  f"Got an exception applying {optimizer.__class__.__name__}"
              )
  
      return plan
  
imports: from __future__ import annotations
  import logging
  import time
  from dataclasses import dataclass
  from typing import Dict, List, Optional, Sequence, Set, Tuple, Union
  from dbt_semantic_interfaces.enum_extension import assert_values_exhausted
  from dbt_semantic_interfaces.implementations.metric import PydanticMetricTimeWindow
  from dbt_semantic_interfaces.pretty_print import pformat_big_objects
  from dbt_semantic_interfaces.protocols.metric import ConstantPropertyInput, ConversionTypeParams, MetricInputMeasure, MetricTimeWindow, MetricType
  from dbt_semantic_interfaces.references import MeasureReference, MetricReference, TimeDimensionReference
  from dbt_semantic_interfaces.type_enums.time_granularity import TimeGranularity
  from dbt_semantic_interfaces.validations.unique_valid_name import MetricFlowReservedKeywords
  from metricflow.dag.id_generation import DATAFLOW_PLAN_PREFIX, IdGeneratorRegistry
  from metricflow.dataflow.builder.node_data_set import DataflowPlanNodeOutputDataSetResolver
  from metricflow.dataflow.builder.node_evaluator import JoinLinkableInstancesRecipe, LinkableInstanceSatisfiabilityEvaluation, NodeEvaluatorForLinkableInstances
  from metricflow.dataflow.dataflow_plan import AddGeneratedUuidColumnNode, AggregateMeasuresNode, BaseOutput, CombineAggregatedOutputsNode, ComputeMetricsNode, ConstrainTimeRangeNode, DataflowPlan, FilterElementsNode, JoinConversionEventsNode, JoinDescription, JoinOverTimeRangeNode, JoinToBaseOutputNode, JoinToTimeSpineNode, MinMaxNode, OrderByLimitNode, ReadSqlSourceNode, SemiAdditiveJoinNode, SinkOutput, WhereConstraintNode, WriteToResultDataframeNode, WriteToResultTableNode
  from metricflow.dataflow.dataflow_plan_to_text import dataflow_dag_as_text
  from metricflow.dataflow.optimizer.dataflow_plan_optimizer import DataflowPlanOptimizer
  from metricflow.dataflow.sql_table import SqlTable
  from metricflow.dataset.dataset import DataSet
  from metricflow.errors.errors import UnableToSatisfyQueryError
  from metricflow.filters.time_constraint import TimeRangeConstraint
  from metricflow.mf_logging.pretty_print import mf_pformat
  from metricflow.mf_logging.runtime import log_runtime
  from metricflow.model.semantic_manifest_lookup import SemanticManifestLookup
  from metricflow.plan_conversion.column_resolver import DunderColumnAssociationResolver
  from metricflow.plan_conversion.node_processor import PreJoinNodeProcessor
  from metricflow.query.group_by_item.filter_spec_resolution.filter_location import WhereFilterLocation
  from metricflow.query.group_by_item.filter_spec_resolution.filter_spec_lookup import FilterSpecResolutionLookUp
  from metricflow.specs.column_assoc import ColumnAssociationResolver
  from metricflow.specs.specs import ConstantPropertySpec, CumulativeMeasureDescription, EntitySpec, InstanceSpecSet, JoinToTimeSpineDescription, LinkableInstanceSpec, LinkableSpecSet, LinklessEntitySpec, MeasureSpec, MetadataSpec, MetricFlowQuerySpec, MetricInputMeasureSpec, MetricSpec, NonAdditiveDimensionSpec, OrderBySpec, TimeDimensionSpec, WhereFilterSpec
  from metricflow.specs.where_filter_transform import WhereSpecFactory
  from metricflow.sql.sql_plan import SqlJoinType
label_desc: Use image node_id 3 for calling the DataflowPlanBuilder obj's underlying member method code with example usage: obj._build_plan(query_spec, output_sql_table, output_selection_specs, optimizers) and returns: plan