class_docstr: Provides a stateful method that returns the number of potential extra
  empty lines needed before and after the currently processed line.
  
  Note: this tracker works on lines that haven't been split yet.  It assumes
  the prefix of the first leaf consists of optional newlines.  Those newlines
  are consumed by `maybe_empty_lines()` and included in the computation.
class_docstr_tok: ["Provides","a","stateful","method","that","returns","the","number","of","potential","extra","empty","lines","needed","before","and","after","the","currently","processed","line",".","Note",":","this","tracker","works","on","lines","that","have","n't","been","split","yet",".","It","assumes","the","prefix","of","the","first","leaf","consists","of","optional","newlines",".","Those","newlines","are","consumed","by","`","maybe_empty_lines","(",")","`","and","included","in","the","computation","."]
code: def _maybe_empty_lines_for_class_or_def(  # noqa: C901
      self, current_line: Line, before: int, user_had_newline: bool
  ) -> Tuple[int, int]:
      if not current_line.is_decorator:
          self.previous_defs.append(current_line)
      if self.previous_line is None:
          # Don't insert empty lines before the first line in the file.
          return 0, 0
  
      if self.previous_line.is_decorator:
          if self.mode.is_pyi and current_line.is_stub_class:
              # Insert an empty line after a decorated stub class
              return 0, 1
  
          return 0, 0
  
      if self.previous_line.depth < current_line.depth and (
          self.previous_line.is_class or self.previous_line.is_def
      ):
          if (
              self.mode.is_pyi
              or not Preview.allow_empty_first_line_in_block
          ):
              return 0, 0
          else:
              return 1 if user_had_newline else 0, 0
  
      comment_to_add_newlines: Optional[LinesBlock] = None
      if (
          self.previous_line.is_comment
          and self.previous_line.depth == current_line.depth
          and before == 0
      ):
          slc = self.semantic_leading_comment
          if (
              slc is not None
              and slc.previous_block is not None
              and not slc.previous_block.original_line.is_class
              and not slc.previous_block.original_line.opens_block
              and slc.before <= 1
          ):
              comment_to_add_newlines = slc
          else:
              return 0, 0
  
      if self.mode.is_pyi:
          if current_line.is_class or self.previous_line.is_class:
              if self.previous_line.depth < current_line.depth:
                  newlines = 0
              elif self.previous_line.depth > current_line.depth:
                  newlines = 1
              elif (
                  current_line.is_stub_class
                  and self.previous_line.is_stub_class
              ):
                  # No blank line between classes with an empty body
                  newlines = 0
              else:
                  newlines = 1
          # Remove case `self.previous_line.depth > current_line.depth` below when
          # this becomes stable.
          #
          # Don't inspect the previous line if it's part of the body of the previous
          # statement in the same level, we always want a blank line if there's
          # something with a body preceding.
          elif (
              Preview.blank_line_between_nested_and_def_stub_file
              in current_line.mode
              and self.previous_line.depth > current_line.depth
          ):
              newlines = 1
          elif (
              current_line.is_def or current_line.is_decorator
          ) and not self.previous_line.is_def:
              if current_line.depth:
                  # In classes empty lines between attributes and methods should
                  # be preserved.
                  newlines = min(1, before)
              else:
                  # Blank line between a block of functions (maybe with preceding
                  # decorators) and a block of non-functions
                  newlines = 1
          elif self.previous_line.depth > current_line.depth:
              newlines = 1
          else:
              newlines = 0
      else:
          newlines = 1 if current_line.depth else 2
          # If a user has left no space after a dummy implementation, don't insert
          # new lines. This is useful for instance for @overload or Protocols.
          if (
              Preview.dummy_implementations in self.mode
              and self.previous_line.is_stub_def
              and not user_had_newline
          ):
              newlines = 0
      if comment_to_add_newlines is not None:
          previous_block = comment_to_add_newlines.previous_block
          if previous_block is not None:
              comment_to_add_newlines.before = (
                  max(comment_to_add_newlines.before, newlines)
                  - previous_block.after
              )
              newlines = 0
      return newlines, 0
  
imports: import itertools
  import math
  from dataclasses import dataclass, field
  from typing import Callable, Dict, Iterator, List, Optional, Sequence, Tuple, TypeVar, Union, cast
  from black.brackets import COMMA_PRIORITY, DOT_PRIORITY, BracketTracker
  from black.mode import Mode, Preview
  from black.nodes import BRACKETS, CLOSING_BRACKETS, OPENING_BRACKETS, STANDALONE_COMMENT, TEST_DESCENDANTS, child_towards, is_docstring, is_import, is_multiline_string, is_one_sequence_between, is_type_comment, is_type_ignore_comment, is_with_or_async_with_stmt, make_simple_prefix, replace_child, syms, whitespace
  from black.strings import str_width
  from blib2to3.pgen2 import token
  from blib2to3.pytree import Leaf, Node
label_desc: Use image node_id 3 for calling the EmptyLineTracker obj's underlying member method code with example usage: obj._maybe_empty_lines_for_class_or_def(current_line, before, user_had_newline) and returns: newlines,  int, int,  int, int,  int, int,  int, int,  int, unknown,  int, int,  int