diff --git a/dash/backends/_fastapi.py b/dash/backends/_fastapi.py index 232b71cce5..210f942a39 100644 --- a/dash/backends/_fastapi.py +++ b/dash/backends/_fastapi.py @@ -508,6 +508,12 @@ def run(self, dash_app: Dash, host, port, debug, **kwargs): # pylint: disable=R ] if kwargs.get("reload"): uvicorn_args.append("--reload") + for directory in kwargs.get("reload_dirs") or []: + uvicorn_args.extend(["--reload-dir", str(directory)]) + for pattern in kwargs.get("reload_excludes") or []: + uvicorn_args.extend(["--reload-exclude", str(pattern)]) + for pattern in kwargs.get("reload_includes") or []: + uvicorn_args.extend(["--reload-include", str(pattern)]) dev_tools = dash_app._dev_tools # pylint: disable=W0212 config = dict( diff --git a/tests/backend_tests/test_preconfig_backends.py b/tests/backend_tests/test_preconfig_backends.py index 2e4b28ea1c..2c492658e4 100644 --- a/tests/backend_tests/test_preconfig_backends.py +++ b/tests/backend_tests/test_preconfig_backends.py @@ -353,3 +353,53 @@ def test_fastapi_catchall_request_context(dash_duo): resp = requests.get(f"{dash_duo.server_url}/some/non-dash/path", timeout=5) assert resp.status_code == 200 + + +def test_fastapi_run_forwards_reload_scope(): + """Forward reload include, exclude, and directory options to uvicorn.""" + import inspect + import os + from types import SimpleNamespace + from unittest.mock import patch + from fastapi import FastAPI + from dash.backends._fastapi import FastAPIDashServer + + server = FastAPIDashServer(FastAPI()) + + class DashApp: + _dev_tools = {} + + app = DashApp() + caller_frame = inspect.currentframe() + stack_frame = SimpleNamespace( + filename=os.path.join(os.getcwd(), "tests", "backend_tests", "test.py"), + frame=caller_frame, + ) + + with patch("dash.backends._fastapi.subprocess.Popen") as popen, patch( + "dash.backends._fastapi.inspect.stack", return_value=[None, None, stack_frame] + ): + server.run( + dash_app=app, + host="127.0.0.1", + port=8050, + debug=False, + reload=True, + reload_dirs=["app", "src"], + reload_excludes=["tests/*"], + reload_includes=["*.py"], + ) + + args = popen.call_args.args[0] + assert args[-9:] == [ + "--reload", + "--reload-dir", + "app", + "--reload-dir", + "src", + "--reload-exclude", + "tests/*", + "--reload-include", + "*.py", + ] + popen.return_value.wait.assert_called_once_with()