File tree Expand file tree Collapse file tree 2 files changed +46
-2
lines changed
Expand file tree Collapse file tree 2 files changed +46
-2
lines changed Original file line number Diff line number Diff line change 11"""Miscellaneous functions for the experimental package."""
22
33import asyncio
4+ import contextlib
5+ import sys
6+ import threading
47from collections .abc import Callable
8+ from pathlib import Path
59from typing import Any
610
711
@@ -23,3 +27,27 @@ async def run_in_thread(func: Callable) -> Any:
2327 msg = "func must be a non-async function"
2428 raise ValueError (msg )
2529 return await asyncio .get_event_loop ().run_in_executor (None , func )
30+
31+
32+ # Global lock for thread-safe sys.path manipulation
33+ _sys_path_lock = threading .RLock ()
34+
35+
36+ @contextlib .contextmanager
37+ def with_cwd_in_syspath ():
38+ """Temporarily add current working directory to sys.path in a thread-safe manner.
39+
40+ This context manager temporarily prepends the current working directory to sys.path,
41+ ensuring that modules in the current directory can be imported. The original sys.path
42+ is restored when exiting the context.
43+
44+ Yields:
45+ None
46+ """
47+ with _sys_path_lock :
48+ orig_sys_path = sys .path .copy ()
49+ sys .path .insert (0 , str (Path .cwd ()))
50+ try :
51+ yield
52+ finally :
53+ sys .path [:] = orig_sys_path
Original file line number Diff line number Diff line change @@ -334,13 +334,14 @@ def npm_escape_hatch() -> bool:
334334
335335
336336def _check_app_name (config : Config ):
337- """Check if the app name is set in the config .
337+ """Check if the app name is valid and matches the folder structure .
338338
339339 Args:
340340 config: The config object.
341341
342342 Raises:
343- RuntimeError: If the app name is not set in the config.
343+ RuntimeError: If the app name is not set, folder doesn't exist, or doesn't match config.
344+ ModuleNotFoundError: If the app_name is not importable (i.e., not a valid Python package, folder structure being wrong).
344345 """
345346 if not config .app_name :
346347 msg = (
@@ -349,6 +350,21 @@ def _check_app_name(config: Config):
349350 )
350351 raise RuntimeError (msg )
351352
353+ from reflex .utils .misc import with_cwd_in_syspath
354+
355+ with with_cwd_in_syspath ():
356+ try :
357+ mod_spec = importlib .util .find_spec (config .module )
358+ except ModuleNotFoundError :
359+ mod_spec = None
360+ if mod_spec is None :
361+ msg = f"Module { config .module } not found. "
362+ if config .app_module_import is not None :
363+ msg += f"Ensure app_module_import='{ config .app_module_import } ' in rxconfig.py matches your folder structure."
364+ else :
365+ msg += f"Ensure app_name='{ config .app_name } ' in rxconfig.py matches your folder structure."
366+ raise ModuleNotFoundError (msg )
367+
352368
353369def get_app (reload : bool = False ) -> ModuleType :
354370 """Get the app module based on the default config.
You can’t perform that action at this time.
0 commit comments