code: def _truncate_explanation(
      input_lines: List[str],
      max_lines: Optional[int] = None,
      max_chars: Optional[int] = None,
  ) -> List[str]:
      """Truncate given list of strings that makes up the assertion explanation.
  
      Truncates to either 8 lines, or 640 characters - whichever the input reaches
      first, taking the truncation explanation into account. The remaining lines
      will be replaced by a usage message.
      """
      if max_lines is None:
          max_lines = DEFAULT_MAX_LINES
      if max_chars is None:
          max_chars = DEFAULT_MAX_CHARS
  
      # Check if truncation required
      input_char_count = len("".join(input_lines))
      # The length of the truncation explanation depends on the number of lines
      # removed but is at least 68 characters:
      # The real value is
      # 64 (for the base message:
      # '...\n...Full output truncated (1 line hidden), use '-vv' to show")'
      # )
      # + 1 (for plural)
      # + int(math.log10(len(input_lines) - max_lines)) (number of hidden line, at least 1)
      # + 3 for the '...' added to the truncated line
      # But if there's more than 100 lines it's very likely that we're going to
      # truncate, so we don't need the exact value using log10.
      tolerable_max_chars = (
          max_chars
          + 70  # 64 + 1 (for plural) + 2 (for '99') + 3 for '...'
      )
      # The truncation explanation add two lines to the output
      tolerable_max_lines = max_lines + 2
      if (
          len(input_lines) <= tolerable_max_lines
          and input_char_count <= tolerable_max_chars
      ):
          return input_lines
      # Truncate first to max_lines, and then truncate to max_chars if necessary
      truncated_explanation = input_lines[:max_lines]
      truncated_char = True
      # We reevaluate the need to truncate chars following removal of some lines
      if len("".join(truncated_explanation)) > tolerable_max_chars:
          truncated_explanation = _truncate_by_char_count(
              truncated_explanation, max_chars
          )
      else:
          truncated_char = False
  
      truncated_line_count = len(input_lines) - len(
          truncated_explanation
      )
      if truncated_explanation[-1]:
          # Add ellipsis and take into account part-truncated final line
          truncated_explanation[-1] = truncated_explanation[-1] + "..."
          if truncated_char:
              # It's possible that we did not remove any char from this line
              truncated_line_count += 1
      else:
          # Add proper ellipsis when we were able to fit a full line exactly
          truncated_explanation[-1] = "..."
      return truncated_explanation + [
          "",
          f"...Full output truncated ({truncated_line_count} line"
          f"{'' if truncated_line_count == 1 else 's'} hidden), {USAGE_MSG}",
      ]
  
file_path: pytest/src/_pytest/assertion/truncate.py
imports: from typing import List
  from typing import Optional
  from _pytest.assertion import util
  from _pytest.config import Config
  from _pytest.nodes import Item
label_desc: Use image node_id 3 for calling a global function with example usage: _truncate_explanation(input_lines, max_lines, max_chars) and returns: unknown, input_lines