Skip to content

Commit 2faab1b

Browse files
committed
Call module auto loader from Streamlit's path watcher
1 parent 8172c1f commit 2faab1b

File tree

2 files changed

+43
-16
lines changed

2 files changed

+43
-16
lines changed

packages/kernel/py/stlite-lib/stlite_lib/server/server.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ def __init__(self, main_script_path: str, app_home_dir: str | None = None) -> No
6161

6262
self._runtime.stats_mgr.register_provider(self._media_file_storage)
6363

64-
async def start(self) -> None:
64+
async def start(
65+
self, file_change_callback: Callable[[str], None] | None = None
66+
) -> None:
6567
"""Start the server.
6668
6769
When this returns, Streamlit is ready to accept new sessions.
@@ -72,7 +74,7 @@ async def start(self) -> None:
7274
home_dir_contextvar.set(self.app_home_dir)
7375

7476
# In stlite, we deal with WebSocket separately.
75-
self._websocket_handler = WebSocketHandler(self._runtime)
77+
self._websocket_handler = WebSocketHandler(self._runtime, file_change_callback)
7678

7779
# Based on the original impl at https://github.com/streamlit/streamlit/blob/1.18.1/lib/streamlit/web/server/server.py#L221 # noqa: E501
7880
base = "" # The original impl reads the `server.baseUrlPath` config, but we use a fixed empty string. # noqa: E501
@@ -258,10 +260,19 @@ class WebSocketHandler(SessionClient):
258260

259261
_callback: Callable[[bytes | str, bool], None] | None
260262

261-
def __init__(self, runtime: Runtime) -> None:
263+
def __init__(
264+
self,
265+
runtime: Runtime,
266+
file_change_callback: Callable[[str], None] | None = None,
267+
) -> None:
262268
self._runtime = runtime
263269
self._session_id = None
264270

271+
# File change callback needs to be registered in this handler's `open()`
272+
# because the callback is registered via the `AppSession` instance
273+
# which is created after the connection is established in `open()`.
274+
self._file_change_callback = file_change_callback
275+
265276
def write_forward_msg(self, msg: ForwardMsg) -> None:
266277
"""Send a ForwardMsg to the browser."""
267278
if self._callback is None:
@@ -282,6 +293,24 @@ def open(self, on_message: Callable[[bytes | str, bool], None]) -> None:
282293
existing_session_id=existing_session_id,
283294
)
284295

296+
if self._file_change_callback:
297+
session_info = self._runtime._session_mgr.get_session_info(self._session_id)
298+
if session_info is None:
299+
_LOGGER.warning(
300+
"No session info found. Cannot register file change callback."
301+
)
302+
return
303+
session = session_info.session
304+
if session is None:
305+
_LOGGER.warning(
306+
"No session found. Cannot register file change callback."
307+
)
308+
return
309+
_LOGGER.debug("Registering file change callback for session %s", session.id)
310+
session._local_sources_watcher.register_file_change_callback(
311+
self._file_change_callback
312+
)
313+
285314
def on_close(self) -> None:
286315
if not self._session_id:
287316
return

packages/kernel/src/worker-runtime.ts

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -369,13 +369,23 @@ __bootstrap__`); // This last line evaluates to the function so it is returned f
369369
);
370370
console.debug("Set up the Streamlit configuration");
371371

372+
const fileChangeCallback = moduleAutoLoad
373+
? (filePath: string) => {
374+
console.debug("File changed", filePath);
375+
if (filePath.endsWith(".py")) {
376+
const fileData = pyodide.FS.readFile(filePath, { encoding: "utf8" });
377+
dispatchModuleAutoLoading(pyodide, onModuleAutoLoad, [fileData]);
378+
}
379+
}
380+
: undefined;
381+
372382
console.debug("Booting up the Streamlit server");
373383
const Server = pyodide.pyimport("stlite_lib.server.Server");
374384
const httpServer = Server(
375385
canonicalEntrypoint,
376386
appId ? getAppHomeDir(appId) : null,
377387
);
378-
await httpServer.start();
388+
await httpServer.start(fileChangeCallback);
379389
console.debug("Booted up the Streamlit server");
380390

381391
return {
@@ -607,18 +617,6 @@ export function startWorkerEnv(
607617
const { path: rawPath, data: fileData, opts } = msg.data;
608618
const path = resolveAppPath(appId, rawPath);
609619

610-
if (
611-
moduleAutoLoad &&
612-
typeof fileData === "string" &&
613-
path.endsWith(".py")
614-
) {
615-
// Auto-install must be dispatched before writing the file
616-
// because its promise should be set before saving the file triggers rerunning.
617-
console.debug(`Auto install the requirements in ${path}`);
618-
619-
dispatchModuleAutoLoading(pyodide, onModuleAutoLoad, [fileData]);
620-
}
621-
622620
console.debug(`Write a file "${path}"`);
623621
writeFileWithParents(pyodide, path, fileData, opts);
624622
reply({

0 commit comments

Comments
 (0)