@@ -944,13 +944,14 @@ async def test_module_watcher_stop(
944944 await asyncio .sleep (INTERVAL )
945945
946946 # Stop the watcher
947- assert k .module_watcher is not None
948- assert not k .module_watcher .should_exit .is_set ()
947+ watcher = k .autoreload_manager .watcher
948+ assert watcher is not None
949+ assert not watcher .should_exit .is_set ()
949950
950- k . module_watcher .stop ()
951+ watcher .stop ()
951952
952953 # should_exit should be set
953- assert k . module_watcher .should_exit .is_set ()
954+ assert watcher .should_exit .is_set ()
954955
955956 async def test_module_watcher_processes_flag (
956957 self , execution_kernel : Kernel , exec_req : ExecReqProvider
@@ -965,9 +966,10 @@ async def test_module_watcher_processes_flag(
965966 # Give watcher time to start
966967 await asyncio .sleep (INTERVAL )
967968
968- assert k .module_watcher is not None
969+ watcher = k .autoreload_manager .watcher
970+ assert watcher is not None
969971 # Initially should be set (no run in flight)
970- assert k . module_watcher .run_is_processed .is_set ()
972+ assert watcher .run_is_processed .is_set ()
971973
972974
973975class TestModuleWatcherEdgeCases :
@@ -1075,3 +1077,83 @@ async def test_module_watcher_cache_invalidation(
10751077
10761078 # The cache should handle the modified imports correctly
10771079 assert not k .graph .cells [er_1 .cell_id ].stale
1080+
1081+
1082+ class TestAutoreloadManagerLifecycle :
1083+ """Tests for AutoreloadManager responding to runtime.auto_reload changes."""
1084+
1085+ async def test_mode_swap_replaces_watcher (
1086+ self , execution_kernel : Kernel , exec_req : ExecReqProvider
1087+ ):
1088+ del exec_req
1089+ k = execution_kernel
1090+ config = copy .deepcopy (DEFAULT_CONFIG )
1091+
1092+ config ["runtime" ]["auto_reload" ] = "lazy"
1093+ k .set_user_config (UpdateUserConfigCommand (config = config ))
1094+ lazy_watcher = k .autoreload_manager .watcher
1095+ assert lazy_watcher is not None
1096+ assert lazy_watcher .mode == "lazy"
1097+
1098+ config ["runtime" ]["auto_reload" ] = "autorun"
1099+ k .set_user_config (UpdateUserConfigCommand (config = config ))
1100+ autorun_watcher = k .autoreload_manager .watcher
1101+ assert autorun_watcher is not None
1102+ assert autorun_watcher .mode == "autorun"
1103+ assert autorun_watcher is not lazy_watcher
1104+ assert lazy_watcher .should_exit .is_set ()
1105+
1106+ async def test_reloader_persists_across_mode_swap (
1107+ self , execution_kernel : Kernel , exec_req : ExecReqProvider
1108+ ):
1109+ """Switching between lazy and autorun must not throw away the
1110+ reloader's mtime state — otherwise every swap would force a reload
1111+ of all already-tracked modules."""
1112+ del exec_req
1113+ k = execution_kernel
1114+ config = copy .deepcopy (DEFAULT_CONFIG )
1115+
1116+ config ["runtime" ]["auto_reload" ] = "lazy"
1117+ k .set_user_config (UpdateUserConfigCommand (config = config ))
1118+ reloader = k .autoreload_manager .reloader
1119+ assert reloader is not None
1120+
1121+ config ["runtime" ]["auto_reload" ] = "autorun"
1122+ k .set_user_config (UpdateUserConfigCommand (config = config ))
1123+ assert k .autoreload_manager .reloader is reloader
1124+
1125+ async def test_disable_clears_manager_state (
1126+ self , execution_kernel : Kernel , exec_req : ExecReqProvider
1127+ ):
1128+ del exec_req
1129+ k = execution_kernel
1130+ config = copy .deepcopy (DEFAULT_CONFIG )
1131+
1132+ config ["runtime" ]["auto_reload" ] = "lazy"
1133+ k .set_user_config (UpdateUserConfigCommand (config = config ))
1134+ assert k .autoreload_manager .watcher is not None
1135+ assert k .autoreload_manager .reloader is not None
1136+
1137+ config ["runtime" ]["auto_reload" ] = "off"
1138+ k .set_user_config (UpdateUserConfigCommand (config = config ))
1139+ assert k .autoreload_manager .watcher is None
1140+ assert k .autoreload_manager .reloader is None
1141+
1142+ async def test_run_rearms_watcher_run_is_processed (
1143+ self , execution_kernel : Kernel , exec_req : ExecReqProvider
1144+ ):
1145+ """The on_finish hook fires for every kernel run, not just
1146+ `_run_stale_cells`. This is a deliberate semantic change from the
1147+ pre-extraction code, which only set the flag at the end of stale-cell
1148+ runs."""
1149+ k = execution_kernel
1150+ config = copy .deepcopy (DEFAULT_CONFIG )
1151+ config ["runtime" ]["auto_reload" ] = "lazy"
1152+ k .set_user_config (UpdateUserConfigCommand (config = config ))
1153+
1154+ watcher = k .autoreload_manager .watcher
1155+ assert watcher is not None
1156+
1157+ watcher .run_is_processed .clear ()
1158+ await k .run ([exec_req .get ("x = 1" )])
1159+ assert watcher .run_is_processed .is_set ()
0 commit comments