code: def updateClass(old, new, debug):
      ## Track town all instances and subclasses of old
      refs = gc.get_referrers(old)
      for ref in refs:
          try:
              if isinstance(ref, old) and ref.__class__ is old:
                  ref.__class__ = new
                  if debug:
                      print("    Changed class for %s" % safeStr(ref))
              elif (
                  inspect.isclass(ref)
                  and issubclass(ref, old)
                  and old in ref.__bases__
              ):
                  ind = ref.__bases__.index(old)
  
                  ## Does not work:
                  # ref.__bases__ = ref.__bases__[:ind] + (new,) + ref.__bases__[ind+1:]
                  ## reason: Even though we change the code on methods, they remain bound
                  ## to their old classes (changing im_class is not allowed). Instead,
                  ## we have to update the __bases__ such that this class will be allowed
                  ## as an argument to older methods.
  
                  ## This seems to work. Is there any reason not to?
                  ## Note that every time we reload, the class hierarchy becomes more complex.
                  ## (and I presume this may slow things down?)
                  newBases = (
                      ref.__bases__[:ind]
                      + (new, old)
                      + ref.__bases__[ind + 1 :]
                  )
                  try:
                      ref.__bases__ = newBases
                  except TypeError:
                      print(
                          "    Error setting bases for class %s" % ref
                      )
                      print(
                          "        old bases: %s" % repr(ref.__bases__)
                      )
                      print("        new bases: %s" % repr(newBases))
                      raise
                  if debug:
                      print(
                          "    Changed superclass for %s" % safeStr(ref)
                      )
              # else:
              # if debug:
              # print "    Ignoring reference", type(ref)
          except Exception:
              print(
                  "Error updating reference (%s) for class change (%s -> %s)"
                  % (safeStr(ref), safeStr(old), safeStr(new))
              )
              raise
  
      ## update all class methods to use new code.
      ## Generally this is not needed since instances already know about the new class,
      ## but it fixes a few specific cases (pyqt signals, for one)
      for attr in dir(old):
          oa = getattr(old, attr)
          if inspect.isfunction(oa) or inspect.ismethod(oa):
              # note python2 has unbound methods, whereas python3 just uses plain functions
              try:
                  na = getattr(new, attr)
              except AttributeError:
                  if debug:
                      print(
                          "    Skipping method update for %s; new class does not have this attribute"
                          % attr
                      )
                  continue
  
              ofunc = getattr(
                  oa, "__func__", oa
              )  # in py2 we have to get the __func__ from unbound method,
              nfunc = getattr(
                  na, "__func__", na
              )  # in py3 the attribute IS the function
  
              if ofunc is not nfunc:
                  depth = updateFunction(ofunc, nfunc, debug)
                  if not hasattr(nfunc, "__previous_reload_method__"):
                      nfunc.__previous_reload_method__ = (
                          oa  # important for managing signal connection
                      )
                      # oa.__class__ = new  ## bind old method to new class  ## not allowed
                  if debug:
                      extra = ""
                      if depth > 0:
                          extra = " (and %d previous versions)" % depth
                      print("    Updating method %s%s" % (attr, extra))
  
      ## And copy in new functions that didn't exist previously
      for attr in dir(new):
          if attr == "__previous_reload_version__":
              continue
          if not hasattr(old, attr):
              if debug:
                  print("    Adding missing attribute %s" % attr)
              setattr(old, attr, getattr(new, attr))
  
      ## finally, update any previous versions still hanging around..
      if hasattr(old, "__previous_reload_version__"):
          updateClass(old.__previous_reload_version__, new, debug)
  
file_path: pyqtgraph/pyqtgraph/reload.py
imports: from __future__ import print_function
  import gc
  import inspect
  import os
  import sys
  import traceback
  import types
  from .debug import printExc
label_desc: Use image node_id 4 for calling a global function with example usage: updateClass(old, new, debug) without return types