class_docstr: Holds utility methods to work with a tokenized text and entity spans.
  
  Spans must be tuples containing the label (str), start char idx (int), and end char idx (int).
  
  Args:
      text: The text the spans refer to.
      tokens: The tokens of the text.
docstr: Convert IOB or BILOU tags to spans.
  
  Overlapping spans are NOT supported!
  
  Args:
      tags: The IOB or BILOU tags.
  
  Returns:
      A list of spans.
  
  Raises:
      ValueError: If the list of tags has not the same length as the list of tokens,
          or tags are not in the IOB or BILOU format.
docstr_tok: ["Convert","IOB","or","BILOU","tags","to","spans",".","Overlapping","spans","are","NOT","supported","!","Args",":","tags",":","The","IOB","or","BILOU","tags",".","Returns",":","A","list","of","spans",".","Raises",":","ValueError",":","If","the","list","of","tags","has","not","the","same","length","as","the","list","of","tokens",",","or","tags","are","not","in","the","IOB","or","BILOU","format","."]
code: def from_tags(self, tags: List[str]) -> List[Tuple[str, int, int]]:
      """Convert IOB or BILOU tags to spans.
  
      Overlapping spans are NOT supported!
  
      Args:
          tags: The IOB or BILOU tags.
  
      Returns:
          A list of spans.
  
      Raises:
          ValueError: If the list of tags has not the same length as the list of tokens,
              or tags are not in the IOB or BILOU format.
      """
  
      def get_prefix_and_entity(
          tag_str: str,
      ) -> Tuple[str, Optional[str]]:
          if tag_str == "O":
              return tag_str, None
          splits = tag_str.split("-")
          return splits[0], "-".join(splits[1:])
  
      if len(tags) != len(self.tokens):
          raise ValueError(
              "The list of tags must have the same length as the list of tokens!"
          )
  
      spans, start_idx = [], None
      for idx, tag in enumerate(tags):
          prefix, entity = get_prefix_and_entity(tag)
  
          if prefix == "O":
              continue
  
          if prefix == "U":
              start_idx, end_idx = self._token_to_char_idx[idx]
              spans.append((entity, start_idx, end_idx))
              start_idx = None
              continue
  
          if prefix == "L":
              # If no start prefix, we just assume "L" == "U":
              if start_idx is None:
                  start_idx, end_idx = self._token_to_char_idx[idx]
              else:
                  _, end_idx = self._token_to_char_idx[idx]
              spans.append((entity, start_idx, end_idx))
              start_idx = None
              continue
  
          if prefix == "B":
              start_idx, end_idx = self._token_to_char_idx[idx]
          elif prefix == "I":
              # If "B" is missing, we just assume "I" starts the span
              if start_idx is None:
                  start_idx = self._token_to_char_idx[idx][0]
              end_idx = self._token_to_char_idx[idx][1]
          else:
              raise ValueError(
                  "Tags are not in the IOB or BILOU format!"
              )
  
          try:
              next_tag = tags[idx + 1]
          # Reached last tag, add span
          except IndexError:
              spans.append((entity, start_idx, end_idx))
              break
  
          next_prefix, next_entity = get_prefix_and_entity(next_tag)
          # span continues
          if next_prefix in ["I", "L"] and next_entity == entity:
              continue
          # span ends
          spans.append((entity, start_idx, end_idx))
          start_idx = None
  
      return spans
  
file_path: argilla/src/argilla/utils/span_utils.py
imports: from typing import Dict, List, Optional, Tuple
label_desc: Use image node_id 9 for calling the SpanUtils obj's underlying member method code with example usage: obj.from_tags(tags) and returns: spans, splits,  str, tag_str,  None