code: def record_event(self, ev, key=None):
      # get a copy of all event attributes because these may change
      # as the event is passed around; we want to know exactly what the event
      # looked like when it reached this callback.
      names = [name for name in dir(ev) if name[0] != "_"]
      attrs = {}
      for name in names:
          val = getattr(ev, name)
          if name == "source":
              attrs[name] = val
          elif name == "sources":
              attrs[name] = val[:]
          else:
              try:
                  attrs[name] = copy.deepcopy(val)
              except Exception:
                  try:
                      attrs[name] = copy.copy(val)
                  except Exception:
                      attrs[name] = val
      if key is None:
          self.result = ev, attrs
      else:
          if not hasattr(self, "result") or self.result is None:
              self.result = {}
          self.result[key] = ev, attrs
  
imports: import unittest
  import copy
  import functools
  from vispy.util.event import Event, EventEmitter
  from vispy.testing import run_tests_if_main, assert_raises, assert_equal
label_desc: Use image node_id 23 for calling the TestEmitters obj's underlying member method code with example usage: obj.record_event(ev, key) without return types