text: from unittest.mock import Mock
  
  import pytest
  
  from napari.utils.events import EmitterGroup
  from napari.utils.events.containers import EventedDict
  
  
  @pytest.fixture
  def regular_dict():
      return {"A": 0, "B": 1, "C": 2}
  
  
  @pytest.fixture(params=[EventedDict])
  def test_dict(request, regular_dict):
      test_dict = request.param(regular_dict)
      test_dict.events = Mock(wraps=test_dict.events)
      return test_dict
  
  
  @pytest.mark.parametrize(
      'meth',
      [
          # METHOD, ARGS, EXPECTED EVENTS
          # primary interface
          ('__getitem__', ("A",), ()),  # read
          ('__setitem__', ("A", 3), ('changed',)),  # update
          ('__setitem__', ("D", 3), ('adding', 'added')),  # add new entry
          ('__delitem__', ("A",), ('removing', 'removed')),  # delete
          # inherited interface
          ('key', (3,), ()),
          ('clear', (), ('removing', 'removed') * 3),
          ('pop', ("B",), ('removing', 'removed')),
      ],
      ids=lambda x: x[0],
  )
  def test_dict_interface_parity(test_dict, regular_dict, meth):
      method_name, args, expected = meth
      test_dict_method = getattr(test_dict, method_name)
      assert test_dict == regular_dict
      if hasattr(regular_dict, method_name):
          regular_dict_method = getattr(regular_dict, method_name)
          assert test_dict_method(*args) == regular_dict_method(*args)
          assert test_dict == regular_dict
      else:
          test_dict_method(*args)  # smoke test
  
      for c, expect in zip(test_dict.events.call_args_list, expected):
          event = c.args[0]
          assert event.type == expect
  
  
  def test_copy(test_dict, regular_dict):
      """Copying an evented dict should return a same-class evented dict."""
      new_test = test_dict.copy()
      new_reg = regular_dict.copy()
      assert id(new_test) != id(test_dict)
      assert new_test == test_dict
      assert tuple(new_test) == tuple(test_dict) == tuple(new_reg)
      test_dict.events.assert_not_called()
  
  
  class E:
      def __init__(self):
          self.events = EmitterGroup(test=None)
  
  
  def test_child_events():
      """Test that evented dicts bubble child events."""
      # create a random object that emits events
      e_obj = E()
      root = EventedDict()
      observed = []
      root.events.connect(lambda e: observed.append(e))
      root["A"] = e_obj
      e_obj.events.test(value="hi")
      obs = [(e.type, e.key, getattr(e, 'value', None)) for e in observed]
      expected = [
          ('adding', "A", None),  # before we adding b into root
          ('added', "A", e_obj),  # after b was added into root
          ('test', "A", 'hi'),  # when e_obj emitted an event called "test"
      ]
      for o, e in zip(obs, expected):
          assert o == e
  
  
  def test_evented_dict_subclass():
      """Test that multiple inheritance maintains events from superclass."""
  
      class A:
          events = EmitterGroup(boom=None)
  
      class B(A, EventedDict):
          pass
  
      dct = B({"A": 1, "B": 2})
      assert hasattr(dct, 'events')
      assert 'boom' in dct.events.emitters
      assert dct == {"A": 1, "B": 2}
  