docstr: Repeat transitions to build a list of trees from the input batches.
  
  The data_iterator should be anything which returns the data for a parse task via next()
  build_batch_fn is a function that turns that data into State objects
  This will be called to generate batches of size batch_size until the data is exhausted
  
  The return is a list of tuples: (gold_tree, [(predicted, score) ...])
  gold_tree will be left blank if the data did not include gold trees
  currently score is always 1.0, but the interface may be expanded
  to get a score from the result of the parsing
  
  transition_choice: which method of the model to use for
  choosing the next transition
  
  TODO: refactor with base_model
docstr_tok: ["Repeat","transitions","to","build","a","list","of","trees","from","the","input","batches",".","The","data_iterator","should","be","anything","which","returns","the","data","for","a","parse","task","via","next","(",")","build_batch_fn","is","a","function","that","turns","that","data","into","State","objects","This","will","be","called","to","generate","batches","of","size","batch_size","until","the","data","is","exhausted","The","return","is","a","list","of","tuples",":","(","gold_tree",",","[","(","predicted",",","score",")","...","]",")","gold_tree","will","be","left","blank","if","the","data","did","not","include","gold","trees","currently","score","is","always","1.0",",","but","the","interface","may","be","expanded","to","get","a","score","from","the","result","of","the","parsing","transition_choice",":","which","method","of","the","model","to","use","for","choosing","the","next","transition","TODO",":","refactor","with","base_model"]
code: def parse_sentences(
      self,
      data_iterator,
      build_batch_fn,
      batch_size,
      transition_choice,
      keep_state=False,
      keep_constituents=False,
      keep_scores=False,
  ):
      """
      Repeat transitions to build a list of trees from the input batches.
  
      The data_iterator should be anything which returns the data for a parse task via next()
      build_batch_fn is a function that turns that data into State objects
      This will be called to generate batches of size batch_size until the data is exhausted
  
      The return is a list of tuples: (gold_tree, [(predicted, score) ...])
      gold_tree will be left blank if the data did not include gold trees
      currently score is always 1.0, but the interface may be expanded
      to get a score from the result of the parsing
  
      transition_choice: which method of the model to use for
      choosing the next transition
  
      TODO: refactor with base_model
      """
      treebank = []
      treebank_indices = []
      # this will produce tuples of states
      # batch size lists of num models tuples
      state_batch = build_batch_fn(batch_size, data_iterator)
      batch_indices = list(range(len(state_batch)))
      horizon_iterator = iter([])
  
      if keep_constituents:
          constituents = defaultdict(list)
  
      while len(state_batch) > 0:
          # print(batch_indices)
          pred_scores, transitions, scores = transition_choice(
              state_batch
          )
          # num models lists of batch size states
          state_batch = list(zip(*state_batch))
          state_batch = [
              parse_transitions.bulk_apply(model, states, transitions)
              for model, states in zip(self.models, state_batch)
          ]
  
          remove = set()
          for idx, state in enumerate(state_batch[0]):
              if state.finished(self.models[0]):
                  predicted_tree = state.get_tree(self.models[0])
                  if self.reverse_sentence():
                      predicted_tree = predicted_tree.reverse()
                  gold_tree = state.gold_tree
                  # TODO: could easily store the score here
                  # not sure what it means to store the state,
                  # since each model is tracking its own state
                  treebank.append(
                      ParseResult(
                          gold_tree,
                          [ScoredTree(predicted_tree, None)],
                          None,
                          None,
                      )
                  )
                  treebank_indices.append(batch_indices[idx])
                  remove.add(idx)
  
          # batch size lists of num models tuples
          state_batch = list(zip(*state_batch))
  
          if len(remove) > 0:
              # remove a whole tuple of states at once
              state_batch = [
                  state
                  for idx, state in enumerate(state_batch)
                  if idx not in remove
              ]
              batch_indices = [
                  batch_idx
                  for idx, batch_idx in enumerate(batch_indices)
                  if idx not in remove
              ]
  
          for _ in range(batch_size - len(state_batch)):
              horizon_state = next(horizon_iterator, None)
              if not horizon_state:
                  horizon_batch = build_batch_fn(
                      batch_size, data_iterator
                  )
                  if len(horizon_batch) == 0:
                      break
                  horizon_iterator = iter(horizon_batch)
                  horizon_state = next(horizon_iterator, None)
  
              state_batch.append(horizon_state)
              batch_indices.append(len(treebank) + len(state_batch))
  
      treebank = utils.unsort(treebank, treebank_indices)
      return treebank
  
imports: import argparse
  import logging
  import os
  import torch
  from stanza.models.common import utils
  from stanza.models.common.foundation_cache import FoundationCache
  from stanza.models.constituency import parse_transitions
  from stanza.models.constituency import retagging
  from stanza.models.constituency import tree_reader
  from stanza.models.constituency.trainer import Trainer, run_dev_set, parse_text, parse_dir
  from stanza.models.constituency.utils import add_predict_output_args, postprocess_predict_output_args, retag_trees
  from stanza.resources.common import DEFAULT_MODEL_DIR
  from stanza.server.parser_eval import EvaluateParser, ParseResult, ScoredTree
  from stanza.utils.default_paths import get_default_paths
label_desc: Use image node_id 8 for calling the Ensemble obj's underlying member method code with example usage: obj.parse_sentences(data_iterator, build_batch_fn, batch_size, transition_choice, keep_state, keep_constituents, keep_scores) and returns: treebank