class_docstr: Helps to evaluate if linkable instances can be obtained using the given node, with joins if necessary.
  
  For example, consider a "start_node" containing the "bookings" measure, "is_instant" dimension, and "listing_id"
  entity with nodes_available_for_joins including a node with the "listing_id" entity, and the "country"
  dimension.
  
  We want to know if we can get "bookings", "is_instant", "listing_id__country" using the start_node. The result
  should be that we know: "is_instant" is available locally (i.e. in the same node), and if we join another node
  containing "listing_id" and "country" by "listing_id", we can get "listing_id__country".
  
  Since it's used on the left side of the join, the items in the "start_node" are sometimes labeled "left".
class_docstr_tok: ["Helps","to","evaluate","if","linkable","instances","can","be","obtained","using","the","given","node",",","with","joins","if","necessary",".","For","example",",","consider","a","``","start_node","''","containing","the","``","bookings","''","measure",",","``","is_instant","''","dimension",",","and","``","listing_id","''","entity","with","nodes_available_for_joins","including","a","node","with","the","``","listing_id","''","entity",",","and","the","``","country","''","dimension",".","We","want","to","know","if","we","can","get","``","bookings","''",",","``","is_instant","''",",","``","listing_id__country","''","using","the","start_node",".","The","result","should","be","that","we","know",":","``","is_instant","''","is","available","locally","(","i.e",".","in","the","same","node",")",",","and","if","we","join","another","node","containing","``","listing_id","''","and","``","country","''","by","``","listing_id","''",",","we","can","get","``","listing_id__country","''",".","Since","it","'s","used","on","the","left","side","of","the","join",",","the","items","in","the","``","start_node","''","are","sometimes","labeled","``","left","''","."]
docstr: Update / filter candidates_for_join based on linkable instance specs that we have already satisfied.
  
  Those linkable instances are no longer needed because those were satisfied previously by joining a node
  containing some needed linkable instances to the "start_node". This method will then remove the satisfied
  linkable instances from the candidate recipes, and if a candidate recipe doesn't have any linkable instances
  that can help satisfy the query, it is removed.
docstr_tok: ["Update","\/","filter","candidates_for_join","based","on","linkable","instance","specs","that","we","have","already","satisfied",".","Those","linkable","instances","are","no","longer","needed","because","those","were","satisfied","previously","by","joining","a","node","containing","some","needed","linkable","instances","to","the","``","start_node","''",".","This","method","will","then","remove","the","satisfied","linkable","instances","from","the","candidate","recipes",",","and","if","a","candidate","recipe","does","n't","have","any","linkable","instances","that","can","help","satisfy","the","query",",","it","is","removed","."]
code: def _update_candidates_that_can_satisfy_linkable_specs(
      candidates_for_join: List[JoinLinkableInstancesRecipe],
      already_satisfisfied_linkable_specs: List[LinkableInstanceSpec],
      join_type: SqlJoinType,
  ) -> List[JoinLinkableInstancesRecipe]:
      """Update / filter candidates_for_join based on linkable instance specs that we have already satisfied.
  
      Those linkable instances are no longer needed because those were satisfied previously by joining a node
      containing some needed linkable instances to the "start_node". This method will then remove the satisfied
      linkable instances from the candidate recipes, and if a candidate recipe doesn't have any linkable instances
      that can help satisfy the query, it is removed.
      """
      updated_candidate_data_sets: List[
          JoinLinkableInstancesRecipe
      ] = []
      for candidate_for_join in candidates_for_join:
          updated_satisfiable_linkable_specs = list(
              set(candidate_for_join.satisfiable_linkable_specs)
              - set(already_satisfisfied_linkable_specs)
          )
  
          if len(updated_satisfiable_linkable_specs) > 0:
              updated_candidate_data_sets.append(
                  JoinLinkableInstancesRecipe(
                      node_to_join=candidate_for_join.node_to_join,
                      join_on_entity=candidate_for_join.join_on_entity,
                      satisfiable_linkable_specs=updated_satisfiable_linkable_specs,
                      join_on_partition_dimensions=candidate_for_join.join_on_partition_dimensions,
                      join_on_partition_time_dimensions=candidate_for_join.join_on_partition_time_dimensions,
                      validity_window=candidate_for_join.validity_window,
                      join_type=join_type,
                  )
              )
      return sorted(
          updated_candidate_data_sets,
          key=lambda x: len(x.satisfiable_linkable_specs),
          reverse=True,
      )
  
imports: from __future__ import annotations
  import itertools
  import logging
  from dataclasses import dataclass
  from typing import List, Optional, Sequence, Tuple
  from dbt_semantic_interfaces.pretty_print import pformat_big_objects
  from metricflow.dataflow.builder.node_data_set import DataflowPlanNodeOutputDataSetResolver
  from metricflow.dataflow.builder.partitions import PartitionJoinResolver
  from metricflow.dataflow.dataflow_plan import BaseOutput, FilterElementsNode, JoinDescription, PartitionDimensionJoinDescription, PartitionTimeDimensionJoinDescription, ValidityWindowJoinDescription
  from metricflow.dataset.sql_dataset import SqlDataSet
  from metricflow.instances import InstanceSet
  from metricflow.model.semantics.semantic_model_join_evaluator import SemanticModelJoinEvaluator
  from metricflow.plan_conversion.instance_converters import CreateValidityWindowJoinDescription
  from metricflow.protocols.semantics import SemanticModelAccessor
  from metricflow.specs.specs import InstanceSpecSet, LinkableInstanceSpec, LinklessEntitySpec
  from metricflow.sql.sql_plan import SqlJoinType
label_desc: Use image node_id 3 for calling the NodeEvaluatorForLinkableInstances obj's underlying member method code with example usage: obj._update_candidates_that_can_satisfy_linkable_specs(candidates_for_join, already_satisfisfied_linkable_specs, join_type) and returns: sorted