def get_winodict(
    lines: Sequence[WinogradExample],
    create_word_fn: CreateWordFn,
    spacy_model: str,
) -> Iterator[WinoDictExample]:
  """Builds WinoDict dataset based on Winograd examples."""
  nlp = spacy.load(spacy_model)
  # Examples are grouped by the option set and the group (original id prefix) if
  # available. This is used to identify the example pairs from the original set.
  grouped_examples = collections.defaultdict(list)
  for example in sorted(lines, key=lambda e: e.idx):
    key = (example.group_key, (example.option1, example.option2))
    grouped_examples[key].append(example)

  counter = collections.Counter()
  for (_, options), examples in sorted(grouped_examples.items()):
    if len(examples) % 2:
      counter[f'odd number of examples ({len(examples)})'] += 1
      continue
    # In WinoGrande this already identifies the pair completely, in Winograd
    # since we don't have a group key, we still rely on the order of the
    # examples to identify the pair, since they have consecutive ids. Sadly
    # id % 2 is not a good group key either since one example has length three.
    for idx in range(0, len(examples), 2):
      example1 = examples[idx]
      example2 = examples[idx + 1]
      sentence, words = _get_diff(example1.sentence, example2.sentence, _WORD)
      assert example1.pronoun == example2.pronoun

      correct_index = (example1.label, example2.label)
      if correct_index == (0, 1):
        pass
      elif correct_index == (1, 0):
        options = (options[1], options[0])
      else:
        raise ValueError(
            f'Invalid correct_index value {correct_index} for {example1}')

      if _OPTION in words[0]:
        counter['pivot contains the option'] += 1
        continue
      if len(words[0].split()) != 1 or len(words[1].split()) != 1:
        counter['pivot contains multiple tokens'] += 1
        continue

      try:
        word1_analysis = _analyze(nlp, sentence, words[0], options[0], words[1],
                                  create_word_fn)
      except ValueError as e:
        counter[str(e)] += 1
        logging.info('Skipping "%s" due to analysis error %s in %s', words[0],
                     e, example1)
        continue

      try:
        word2_analysis = _analyze(nlp, sentence, words[1], options[1], words[0],
                                  create_word_fn)
      except ValueError as e:
        counter[str(e)] += 1
        logging.info('Skipping "%s" due to analysis error %s in %s', words[1],
                     e, example2)
        continue

      yield WinoDictExample(
          source=example1.source,
          sentence=sentence,
          pronoun=example1.pronoun,
          answer1=WinoDictAnswer(
              idx=example1.idx,
              word=words[0],
              option=options[0],
              **word1_analysis),
          answer2=WinoDictAnswer(
              idx=example2.idx,
              word=words[1],
              option=options[1],
              **word2_analysis),
      )

  logging.info('Counters:\n%s',
               '\n'.join(f'{k}:{v}' for k, v in counter.most_common()))
Builds WinoDict dataset based on Winograd examples.
language/wino_dict/utils.py