class_docstr: A helper class that represents a string that can be attacked.
  
  Models that take multiple sentences as input separate them by ``SPLIT_TOKEN``.
  Attacks "see" the entire input, joined into one string, without the split token.
  
  ``AttackedText`` instances that were perturbed from other ``AttackedText``
  objects contain a pointer to the previous text
  (``attack_attrs["previous_attacked_text"]``), so that the full chain of
  perturbations might be reconstructed by using this key to form a linked
  list.
  
  Args:
     text (string): The string that this AttackedText represents
     attack_attrs (dict): Dictionary of various attributes stored
         during the course of an attack.
class_docstr_tok: ["A","helper","class","that","represents","a","string","that","can","be","attacked",".","Models","that","take","multiple","sentences","as","input","separate","them","by","``","SPLIT_TOKEN","``",".","Attacks","``","see","''","the","entire","input",",","joined","into","one","string",",","without","the","split","token",".","``","AttackedText","``","instances","that","were","perturbed","from","other","``","AttackedText","``","objects","contain","a","pointer","to","the","previous","text","(","``","attack_attrs","[","``","previous_attacked_text","''","]","``",")",",","so","that","the","full","chain","of","perturbations","might","be","reconstructed","by","using","this","key","to","form","a","linked","list",".","Args",":","text","(","string",")",":","The","string","that","this","AttackedText","represents","attack_attrs","(","dict",")",":","Dictionary","of","various","attributes","stored","during","the","course","of","an","attack","."]
code: def __init__(self, text_input, attack_attrs=None):
      # Read in ``text_input`` as a string or OrderedDict.
      if isinstance(text_input, str):
          self._text_input = OrderedDict([("text", text_input)])
      elif isinstance(text_input, OrderedDict):
          self._text_input = text_input
      else:
          raise TypeError(
              f"Invalid text_input type {type(text_input)} (required str or OrderedDict)"
          )
      # Process input lazily.
      self._words = None
      self._words_per_input = None
      self._pos_tags = None
      self._ner_tags = None
      # Format text inputs.
      self._text_input = OrderedDict(
          [(k, v) for k, v in self._text_input.items()]
      )
      if attack_attrs is None:
          self.attack_attrs = dict()
      elif isinstance(attack_attrs, dict):
          self.attack_attrs = attack_attrs
      else:
          raise TypeError(
              f"Invalid type for attack_attrs: {type(attack_attrs)}"
          )
      # Indices of words from the *original* text. Allows us to map
      # indices between original text and this text, and vice-versa.
      self.attack_attrs.setdefault(
          "original_index_map", np.arange(self.num_words)
      )
      # A list of all indices in *this* text that have been modified.
      self.attack_attrs.setdefault("modified_indices", set())
  
imports: from __future__ import annotations
  from collections import OrderedDict
  import math
  from typing import Dict, Iterable, List, Optional, Set, Tuple
  import flair
  from flair.data import Sentence
  import numpy
  import torch
  import textattack
  from .utils import device, words_from_text
label_desc: Use image node_id 1 to create a new AttackedText object  with example: obj = AttackedText(text_input, attack_attrs)