class_docstr: Test invocation of a custom component object.
class_docstr_tok: ["Test","invocation","of","a","custom","component","object","."]
docstr: UNLIKE OTHER WIDGET TYPES, a component with a user-supplied `key` will have a stable widget ID
  even when the component's other parameters change.
  
  This is important because a component's iframe gets unmounted and remounted - wiping all its
  internal state - when the component's ID changes. We want to be able to pass new data to a
  component's frontend without causing a remount.
docstr_tok: ["UNLIKE","OTHER","WIDGET","TYPES",",","a","component","with","a","user-supplied","`","key","`","will","have","a","stable","widget","ID","even","when","the","component","'s","other","parameters","change",".","This","is","important","because","a","component","'s","iframe","gets","unmounted","and","remounted","-","wiping","all","its","internal","state","-","when","the","component","'s","ID","changes",".","We","want","to","be","able","to","pass","new","data","to","a","component","'s","frontend","without","causing","a","remount","."]
code: def test_widget_id_with_key(self):
      """UNLIKE OTHER WIDGET TYPES, a component with a user-supplied `key` will have a stable widget ID
      even when the component's other parameters change.
  
      This is important because a component's iframe gets unmounted and remounted - wiping all its
      internal state - when the component's ID changes. We want to be able to pass new data to a
      component's frontend without causing a remount.
      """
  
      # Create a component instance with a key and some custom data
      self.test_component(key="key", some_data=345)
      proto1 = (
          self.get_delta_from_queue().new_element.component_instance
      )
      self.assertJSONEqual(
          {"key": "key", "default": None, "some_data": 345},
          proto1.json_args,
      )
  
      # Clear some ScriptRunCtx data so that we can re-register the same component
      # without getting a DuplicateWidgetID error
      self.script_run_ctx.widget_user_keys_this_run.clear()
      self.script_run_ctx.widget_ids_this_run.clear()
  
      # Create a second component instance with the same key, and different custom data
      self.test_component(key="key", some_data=678, more_data="foo")
      proto2 = (
          self.get_delta_from_queue().new_element.component_instance
      )
      self.assertJSONEqual(
          {
              "key": "key",
              "default": None,
              "some_data": 678,
              "more_data": "foo",
          },
          proto2.json_args,
      )
  
      # The two component instances should have the same ID, *despite having different
      # data passed to them.*
      self.assertEqual(proto1.id, proto2.id)
  
imports: import json
  import os
  import unittest
  from typing import Any
  from unittest import mock
  from unittest.mock import MagicMock, patch
  import pandas
  import pytest
  import streamlit
  import streamlit.components.v1
  from streamlit.components.v1 import component_arrow
  from streamlit.components.v1.components import ComponentRegistry, CustomComponent
  from streamlit.errors import DuplicateWidgetID, StreamlitAPIException
  from streamlit.proto.Components_pb2 import SpecialArg
  from streamlit.type_util import to_bytes
  from tests.delta_generator_test_case import DeltaGeneratorTestCase
label_desc: Use image node_id 10 for calling the InvokeComponentTest obj's underlying member method code with example usage: obj.test_widget_id_with_key() without return types