class_docstr: Figures out what linkable specs are valid for a given metric.
  
  e.g. Can you query the metric "bookings" by "listing__country_latest"?
docstr: Constructor.
  
  Args:
      semantic_manifest: the model to use.
      semantic_model_lookup: used to look up entities for a semantic model.
      max_entity_links: the maximum number of joins to do when computing valid elements.
docstr_tok: ["Constructor",".","Args",":","semantic_manifest",":","the","model","to","use",".","semantic_model_lookup",":","used","to","look","up","entities","for","a","semantic","model",".","max_entity_links",":","the","maximum","number","of","joins","to","do","when","computing","valid","elements","."]
code: def __init__(
      self,
      semantic_manifest: SemanticManifest,
      semantic_model_lookup: SemanticModelAccessor,
      max_entity_links: int,
  ) -> None:
      """Constructor.
  
      Args:
          semantic_manifest: the model to use.
          semantic_model_lookup: used to look up entities for a semantic model.
          max_entity_links: the maximum number of joins to do when computing valid elements.
      """
      self._semantic_manifest = semantic_manifest
      self._semantic_model_lookup = semantic_model_lookup
      # Sort semantic models by name for consistency in building derived objects.
      self._semantic_models = sorted(
          self._semantic_manifest.semantic_models, key=lambda x: x.name
      )
      self._join_evaluator = SemanticModelJoinEvaluator(
          semantic_model_lookup
      )
  
      assert max_entity_links >= 0
      self._max_entity_links = max_entity_links
  
      # Map measures / entities to semantic models that contain them.
      self._entity_to_semantic_model: Dict[
          str, List[SemanticModel]
      ] = defaultdict(list)
      self._measure_to_semantic_model: Dict[
          str, List[SemanticModel]
      ] = defaultdict(list)
  
      for semantic_model in self._semantic_models:
          for entity in semantic_model.entities:
              self._entity_to_semantic_model[
                  entity.reference.element_name
              ].append(semantic_model)
  
      self._metric_to_linkable_element_sets: Dict[
          str, List[LinkableElementSet]
      ] = {}
  
      start_time = time.time()
      for metric in self._semantic_manifest.metrics:
          linkable_sets_for_measure = []
          for measure in metric.measure_references:
              # Cumulative metrics currently can't be queried by other time granularities.
              if metric.type is MetricType.CUMULATIVE:
                  linkable_sets_for_measure.append(
                      self._get_linkable_element_set_for_measure(
                          measure
                      ).filter(
                          with_any_of=LinkableElementProperties.all_properties(),
                          without_all_of=frozenset(
                              {
                                  LinkableElementProperties.METRIC_TIME,
                                  LinkableElementProperties.DERIVED_TIME_GRANULARITY,
                              }
                          ),
                      )
                  )
              elif (
                  metric.type is MetricType.SIMPLE
                  or metric.type is MetricType.DERIVED
                  or metric.type is MetricType.RATIO
              ):
                  linkable_sets_for_measure.append(
                      self._get_linkable_element_set_for_measure(
                          measure
                      )
                  )
              elif metric.type is MetricType.CONVERSION:
                  conversion_type_params = (
                      metric.type_params.conversion_type_params
                  )
                  assert (
                      conversion_type_params
                  ), "A conversion metric should have type_params.conversion_type_params defined."
                  if (
                      measure
                      == conversion_type_params.base_measure.measure_reference
                  ):
                      # Only can query against the base measure's linkable elements
                      # as it joins everything back to the base measure data set so
                      # there is no way of getting the conversion elements
                      linkable_sets_for_measure.append(
                          self._get_linkable_element_set_for_measure(
                              measure
                          )
                      )
              else:
                  assert_values_exhausted(metric.type)
  
          self._metric_to_linkable_element_sets[
              metric.name
          ] = linkable_sets_for_measure
  
      # If no metrics are specified, the query interface supports distinct dimension values from a single semantic
      # model.
      linkable_element_sets_to_merge: List[LinkableElementSet] = []
  
      for semantic_model in semantic_manifest.semantic_models:
          linkable_element_sets_to_merge.append(
              ValidLinkableSpecResolver._get_elements_in_semantic_model(
                  semantic_model
              )
          )
  
      self._no_metric_linkable_element_set = (
          LinkableElementSet.merge_by_path_key(
              linkable_element_sets_to_merge
          )
      )
  
      logger.info(
          f"Building valid group-by-item indexes took: {time.time() - start_time:.2f}s"
      )
  
imports: from __future__ import annotations
  import logging
  import time
  from collections import defaultdict
  from dataclasses import dataclass
  from typing import Dict, FrozenSet, List, Optional, Sequence, Set, Tuple
  from dbt_semantic_interfaces.enum_extension import assert_values_exhausted
  from dbt_semantic_interfaces.pretty_print import pformat_big_objects
  from dbt_semantic_interfaces.protocols.dimension import Dimension, DimensionType
  from dbt_semantic_interfaces.protocols.semantic_manifest import SemanticManifest
  from dbt_semantic_interfaces.protocols.semantic_model import SemanticModel
  from dbt_semantic_interfaces.references import DimensionReference, MeasureReference, MetricReference, SemanticModelReference, TimeDimensionReference
  from dbt_semantic_interfaces.type_enums import MetricType
  from dbt_semantic_interfaces.type_enums.date_part import DatePart
  from dbt_semantic_interfaces.type_enums.time_granularity import TimeGranularity
  from metricflow.dataset.dataset import DataSet
  from metricflow.errors.errors import UnknownMetricLinkingError
  from metricflow.model.semantics.linkable_element_properties import LinkableElementProperties
  from metricflow.model.semantics.semantic_model_join_evaluator import SemanticModelJoinEvaluator
  from metricflow.model.semantics.semantic_model_lookup import SemanticModelLookup
  from metricflow.protocols.semantics import SemanticModelAccessor
  from metricflow.specs.specs import DEFAULT_TIME_GRANULARITY, DimensionSpec, EntityReference, EntitySpec, LinkableSpecSet, TimeDimensionSpec
label_desc: Use image node_id 1 to create a new ValidLinkableSpecResolver object  with example: obj = ValidLinkableSpecResolver(semantic_manifest, semantic_model_lookup, max_entity_links)