code: def test_session_close_session_with_callbacks(self, sentinel):
      s = sentinel(0)
  
      manager = PerspectiveManager()
      session = manager.new_session()
      client_id = session.client_id
  
      # create a table and view using manager
      make_table = {
          "id": 1,
          "name": "table1",
          "cmd": "table",
          "args": [data],
      }
      session.process(make_table, self.post)
  
      make_view = {
          "id": 2,
          "table_name": "table1",
          "view_name": "view1",
          "cmd": "view",
      }
      session.process(make_view, self.post)
  
      # make sure the client ID is attached to the new view
      assert len(manager._views.keys()) == 1
      assert manager._get_view("view1")._client_id == client_id
  
      def callback(updated):
          assert updated["port_id"] == 0
          s.set(s.get() + 100)
  
      # simulate a client that holds callbacks by id
      callbacks = {3: callback}
  
      def post_update(msg):
          # when `on_update` is triggered, this callback gets the message
          # and has to decide which callback to trigger.
          message = json.loads(msg)
          assert message["id"] is not None
          if message["id"] == 3:
              # trigger callback
              assert message["data"] == {"port_id": 0}
              callbacks[message["id"]](message["data"])
  
      # hook into the created view and pass it the callback
      make_on_update = {
          "id": 3,
          "name": "view1",
          "cmd": "view_method",
          "subscribe": True,
          "method": "on_update",
          "callback_id": "callback_1",
      }
      session.process(make_on_update, post_update)
  
      # call updates
      update1 = {
          "id": 4,
          "name": "table1",
          "cmd": "table_method",
          "method": "update",
          "args": [{"a": [4], "b": ["d"]}],
      }
      update2 = {
          "id": 5,
          "name": "table1",
          "cmd": "table_method",
          "method": "update",
          "args": [{"a": [5], "b": ["e"]}],
      }
  
      session.process(update1, self.post)
      session.process(update2, self.post)
  
      assert s.get() == 200
  
      # close the session
      session.close()
  
      # make sure the view is gone - but not the table
      assert "table1" in manager._tables
      assert manager._views == {}
      assert len(manager._callback_cache) == 0
  
file_path: perspective/python/perspective/perspective/tests/manager/test_session.py
imports: import json
  import random
  from perspective import Table, PerspectiveManager
label_desc: Use image node_id 5 for calling the TestPerspectiveSession obj's underlying member method code with example usage: obj.test_session_close_session_with_callbacks(sentinel) without return types