code: def test_module_caching(self, _fob):
      lso = local_sources_watcher.LocalSourcesWatcher(SCRIPT_PATH)
      lso.register_file_change_callback(NOOP_CALLBACK)
  
      register = MagicMock()
      lso._register_necessary_watchers = register
  
      # Updates modules on first run
      lso.update_watched_modules()
      register.assert_called_once()
  
      # Skips update when module list hasn't changed
      register.reset_mock()
      lso.update_watched_modules()
      register.assert_not_called()
  
      # Invalidates cache when a new module is imported
      register.reset_mock()
      sys.modules["DUMMY_MODULE_2"] = DUMMY_MODULE_2
      lso.update_watched_modules()
      register.assert_called_once()
  
      # Skips update when new module is part of cache
      register.reset_mock()
      lso.update_watched_modules()
      register.assert_not_called()
  
imports: import os
  import sys
  import unittest
  from unittest.mock import MagicMock, patch
  import tests.streamlit.watcher.test_data.dummy_module1
  import tests.streamlit.watcher.test_data.dummy_module2
  import tests.streamlit.watcher.test_data.misbehaved_module
  import tests.streamlit.watcher.test_data.nested_module_child
  import tests.streamlit.watcher.test_data.nested_module_parent
  from streamlit import config
  from streamlit.watcher import local_sources_watcher
  from streamlit.watcher.path_watcher import NoOpPathWatcher, watchdog_available
label_desc: Use image node_id 12 for calling the LocalSourcesWatcherTest obj's underlying member method code with example usage: obj.test_module_caching(_fob) without return types