code: def to_feature_list(
      self,
      tokenizer,
      max_seq_length,
      doc_stride,
      max_query_length,
      set_type,
  ):
      is_training = set_type == PHASE.TRAIN
      features = []
      if is_training and not self.is_impossible:
          # Get start and end position
          start_position = self.start_position
          end_position = self.end_position
  
          # If the answer cannot be found in the text, then skip this example.
          actual_text = " ".join(
              self.doc_tokens[start_position : (end_position + 1)]
          )
          cleaned_answer_text = " ".join(
              whitespace_tokenize(self.answer_text)
          )
          if actual_text.find(cleaned_answer_text) == -1:
              logger.warning(
                  "Could not find answer: '%s' vs. '%s'",
                  actual_text,
                  cleaned_answer_text,
              )
              return []
  
      tok_to_orig_index = []
      orig_to_tok_index = []
      all_doc_tokens = []
      for i, token in enumerate(self.doc_tokens):
          orig_to_tok_index.append(len(all_doc_tokens))
          if tokenizer.__class__.__name__ in [
              "RobertaTokenizer",
              "LongformerTokenizer",
              "BartTokenizer",
              "RobertaTokenizerFast",
              "LongformerTokenizerFast",
              "BartTokenizerFast",
          ]:
              sub_tokens = tokenizer.tokenize(
                  token, add_prefix_space=True
              )
          else:
              sub_tokens = tokenizer.tokenize(token)
          for sub_token in sub_tokens:
              tok_to_orig_index.append(i)
              all_doc_tokens.append(sub_token)
  
      if is_training and not self.is_impossible:
          tok_start_position = orig_to_tok_index[self.start_position]
          if self.end_position < len(self.doc_tokens) - 1:
              tok_end_position = (
                  orig_to_tok_index[self.end_position + 1] - 1
              )
          else:
              tok_end_position = len(all_doc_tokens) - 1
  
          (tok_start_position, tok_end_position) = _improve_answer_span(
              all_doc_tokens,
              tok_start_position,
              tok_end_position,
              tokenizer,
              self.answer_text,
          )
  
      spans = []
  
      truncated_query = tokenizer.encode(
          self.question_text,
          add_special_tokens=False,
          truncation=True,
          max_length=max_query_length,
      )
  
      # Tokenizers who insert 2 SEP tokens in-between <context> & <question>
      #   need to have special handling
      # in the way they compute mask of added tokens.
      tokenizer_type = (
          type(tokenizer).__name__.replace("Tokenizer", "").lower()
      )
      sequence_added_tokens = (
          tokenizer.model_max_length
          - tokenizer.max_len_single_sentence
          + 1
          if tokenizer_type in MULTI_SEP_TOKENS_TOKENIZERS_SET
          else tokenizer.model_max_length
          - tokenizer.max_len_single_sentence
      )
      sequence_pair_added_tokens = (
          tokenizer.model_max_length - tokenizer.max_len_sentences_pair
      )
  
      span_doc_tokens = all_doc_tokens
      while len(spans) * doc_stride < len(all_doc_tokens):
          # Define the side we want to truncate / pad and the text/pair sorting
          if tokenizer.padding_side == "right":
              texts = truncated_query
              pairs = span_doc_tokens
              truncation = TruncationStrategy.ONLY_SECOND.value
          else:
              texts = span_doc_tokens
              pairs = truncated_query
              truncation = TruncationStrategy.ONLY_FIRST.value
  
          encoded_dict = (
              tokenizer.encode_plus(  # TODO(thom) update this logic
                  texts,
                  pairs,
                  truncation=truncation,
                  padding="max_length",
                  max_length=max_seq_length,
                  return_overflowing_tokens=True,
                  stride=max_seq_length
                  - doc_stride
                  - len(truncated_query)
                  - sequence_pair_added_tokens,
                  return_token_type_ids=True,
              )
          )
  
          paragraph_len = min(
              len(all_doc_tokens) - len(spans) * doc_stride,
              max_seq_length
              - len(truncated_query)
              - sequence_pair_added_tokens,
          )
  
          if tokenizer.pad_token_id in encoded_dict["input_ids"]:
              if tokenizer.padding_side == "right":
                  non_padded_ids = encoded_dict["input_ids"][
                      : encoded_dict["input_ids"].index(
                          tokenizer.pad_token_id
                      )
                  ]
              else:
                  last_padding_id_position = (
                      len(encoded_dict["input_ids"])
                      - 1
                      - encoded_dict["input_ids"][::-1].index(
                          tokenizer.pad_token_id
                      )
                  )
                  non_padded_ids = encoded_dict["input_ids"][
                      last_padding_id_position + 1 :
                  ]
  
          else:
              non_padded_ids = encoded_dict["input_ids"]
  
          tokens = tokenizer.convert_ids_to_tokens(non_padded_ids)
  
          token_to_orig_map = {}
          for i in range(paragraph_len):
              index = (
                  len(truncated_query) + sequence_added_tokens + i
                  if tokenizer.padding_side == "right"
                  else i
              )
              token_to_orig_map[index] = tok_to_orig_index[
                  len(spans) * doc_stride + i
              ]
  
          encoded_dict["paragraph_len"] = paragraph_len
          encoded_dict["tokens"] = tokens
          encoded_dict["token_to_orig_map"] = token_to_orig_map
          encoded_dict["truncated_query_with_special_tokens_length"] = (
              len(truncated_query) + sequence_added_tokens
          )
          encoded_dict["token_is_max_context"] = {}
          encoded_dict["start"] = len(spans) * doc_stride
          encoded_dict["length"] = paragraph_len
  
          spans.append(encoded_dict)
  
          if "overflowing_tokens" not in encoded_dict or (
              "overflowing_tokens" in encoded_dict
              and len(encoded_dict["overflowing_tokens"]) == 0
          ):
              break
          span_doc_tokens = encoded_dict["overflowing_tokens"]
  
      for doc_span_index in range(len(spans)):
          for j in range(spans[doc_span_index]["paragraph_len"]):
              is_max_context = _new_check_is_max_context(
                  spans, doc_span_index, doc_span_index * doc_stride + j
              )
              index = (
                  j
                  if tokenizer.padding_side == "left"
                  else spans[doc_span_index][
                      "truncated_query_with_special_tokens_length"
                  ]
                  + j
              )
              spans[doc_span_index]["token_is_max_context"][
                  index
              ] = is_max_context
  
      for span in spans:
          # Identify the position of the CLS token
          cls_index = span["input_ids"].index(tokenizer.cls_token_id)
  
          # p_mask: mask with 1 for token than cannot be in the answer (0 for token
          # which can be in an answer)
          # Original TF implementation also keep the classification token (set to 0)
          p_mask = np.ones_like(span["token_type_ids"])
          if tokenizer.padding_side == "right":
              p_mask[len(truncated_query) + sequence_added_tokens :] = 0
          else:
              p_mask[
                  -len(span["tokens"]) : -(
                      len(truncated_query) + sequence_added_tokens
                  )
              ] = 0
  
          pad_token_indices = np.where(
              span["input_ids"] == tokenizer.pad_token_id
          )
          special_token_indices = np.asarray(
              tokenizer.get_special_tokens_mask(
                  span["input_ids"], already_has_special_tokens=True
              )
          ).nonzero()
  
          p_mask[pad_token_indices] = 1
          p_mask[special_token_indices] = 1
  
          # Set the cls index to 0: the CLS index can be used for impossible answers
          p_mask[cls_index] = 0
  
          span_is_impossible = self.is_impossible
          start_position = 0
          end_position = 0
          if is_training and not span_is_impossible:
              # For training, if our document chunk does not contain an annotation
              # we throw it out, since there is nothing to predict.
              doc_start = span["start"]
              doc_end = span["start"] + span["length"] - 1
              out_of_span = False
  
              # noinspection PyUnboundLocalVariable
              if not (
                  tok_start_position >= doc_start
                  and tok_end_position <= doc_end
              ):
                  out_of_span = True
  
              if out_of_span:
                  start_position = cls_index
                  end_position = cls_index
  
                  # We store "is_impossible" at an example level instead
                  # noinspection PyUnusedLocal
                  span_is_impossible = True
              else:
                  if tokenizer.padding_side == "left":
                      doc_offset = 0
                  else:
                      doc_offset = (
                          len(truncated_query) + sequence_added_tokens
                      )
  
                  start_position = (
                      tok_start_position - doc_start + doc_offset
                  )
                  end_position = (
                      tok_end_position - doc_start + doc_offset
                  )
  
          features.append(
              DataRow(
                  unique_id="",
                  qas_id=self.qas_id,
                  tokens=span["tokens"],
                  token_to_orig_map=span["token_to_orig_map"],
                  token_is_max_context=span["token_is_max_context"],
                  input_ids=np.array(span["input_ids"]),
                  input_mask=np.array(span["attention_mask"]),
                  segment_ids=np.array(span["token_type_ids"]),
                  cls_index=np.array(cls_index),
                  p_mask=np.array(p_mask.tolist()),
                  paragraph_len=span["paragraph_len"],
                  start_position=start_position,
                  end_position=end_position,
                  answers=self.answers,
                  doc_tokens=self.doc_tokens,
              )
          )
      return features
  
imports: import json
  import numpy
  import torch
  from dataclasses import dataclass
  from typing import Union, List, Dict, Optional
  from transformers.models.bert.tokenization_bert import whitespace_tokenize
  from transformers.tokenization_utils_base import TruncationStrategy
  from jiant.tasks.lib.templates.squad_style import utils
  from jiant.shared.constants import PHASE
  from jiant.tasks.core import BaseExample, BaseDataRow, BatchMixin, Task, TaskTypes
  from jiant.utils.python.datastructures import ExtendedDataClassMixin
  from jiant.utils.display import maybe_tqdm
  import logging
label_desc: Use image node_id 3 for calling the Example obj's underlying member method code with example usage: obj.to_feature_list(tokenizer, max_seq_length, doc_stride, max_query_length, set_type) and returns: features, list