code: def build_haplotype(
      variants, allele_indices, ref, ref_start, ref_end
  ):
      """Builds the haplotype string from variants and its phased gneotypes.
  
      This function takes a list of variants and associated phased genotypes and
      constructs the haplotype sequence implied by variants and its genotypes. For
      example, suppose we have two variants:
  
        ref: CAGC where the first base (C) is at position 10.
        chr20:10 A=>C
        chr20:11 G=>T
        allele_indices: [0, 1]
  
      We would receive arguments here of a list of two variants and a list of the
      allele_indices [0, 1]. We now look up which base is implied for the variant
      (e.g., [0, 1] takes the reference bases from variant 1 at 10 and then the
      first alternate allele of variant 2 at 11). If ref_start is 9, we would then
      construct the haplotype as:
  
      haplotype is 'CATC' derived as follows:
        'C' [ref_prefix, since ref_start=]
        +
        'A' (variant1 has a genotype of 0)
        +
        'T' (variant2 has a genotype of 1)
        +
        'C' [ref_postfix if ref_end == 13]
        = 'CATC'
  
      Args:
        variants: list[nucleus.protos.Variant]: The variants to use in constructing
          the haplotype.
        allele_indices: list[int]: The list of allele_indexes (where 0 means
          reference_bases and > 0 implies alternative bases, following the
          VariantCall genotypes semantics).
        ref: ReferenceRegion. Used to get the reference bases.
        ref_start: int >= 0. The first position (zero-indexed, inclusive) in the
          genome where we want to start constructing our haplotype.
        ref_end: int >= 0 and > ref_start. The last position (zero-indexed,
          exclusive) in the genome where we want to end constructing our haplotype.
  
      Returns:
        A string containing the haplotype bases, or None, if any variant starts
        before ref_start and has a non-reference genotype.
  
      Raises:
        ValueError: If any of the input arguments are malformed or otherwise violate
        the assumptions of this algorithm.
      """
      if len(variants) != len(allele_indices):
          raise ValueError(
              "Expected the same number of variants {} as allele_indices {}".format(
                  len(variants), len(allele_indices)
              )
          )
      if ref_start < 0 or ref_start >= ref_end:
          raise ValueError(
              "expected ref_start {} < ref_end {}".format(
                  ref_start, ref_end
              )
          )
  
      parts = []
      position = ref_start
      for variant, allele_index in zip(variants, allele_indices):
          if variant.start < position:
              if allele_index != 0:
                  return None
          else:
              ref_prefix = ref.bases(position, variant.start)
              allele = _allele_from_index(variant, allele_index)
              if allele_index == 0:
                  # Update our position variable to be the next reference base we want to
                  # use when further constructing our haplotype string. If we are using
                  # the reference base, we start our position at the base after variant
                  # start, whereas if we are using a non-reference base we use the
                  # variant.end.
                  #
                  # This special-case is needed to handle deletion alleles properly. If we
                  # have a deletion (e.g., AA => A with start = 10 and end = 12) then we
                  # only want to skip to position 12 for the next reference bases if we
                  # have have the deletion, otherwise we'd miss the second 'A' base which
                  # is really there (the variant isn't present, after all). Another
                  # consequence of this choice we only want to add the first base of the
                  # reference allele, not the whole string, since this would append all of
                  # deletion bases inappropriately to our haplotype.
                  allele = allele[0]
                  position = variant.start + 1
              else:
                  position = variant.end
              parts.append(ref_prefix + allele)
  
      # We have some bases left to add between the position of our last variant
      # and the ref_end, so append those now.
      if position < ref_end:
          parts.append(ref.bases(position, ref_end))
  
      return "".join(parts)
  
imports: import collections
  import copy
  import enum
  import heapq
  import itertools
  from absl import logging
  from deepvariant.labeler import variant_labeler
  from deepvariant.protos import deepvariant_pb2
  from third_party.nucleus.io import fasta
  from third_party.nucleus.util import ranges
  from third_party.nucleus.util import variant_utils
  from third_party.nucleus.util import variantcall_utils
label_desc: Use image node_id 10 for calling a global function with example usage: build_haplotype(variants, allele_indices, ref, ref_start, ref_end) and returns: str, None