Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

[BUG] Dash.run(debug=True, backend="fastapi") reload subprocess silently ignores reload_dirs/reload_excludes kwargs

未关闭
#3,962 1 条评论 1 个 reaction 已指派 1 人 在 GitHub 查看

@T4rk1n 已经在做这个了。

开始于 2026年8月27日。

评估

这个 Issue 还没有评估数据。

描述

bug P2 size: 1

Summary

When using the FastAPI backend, app.run(host=..., port=..., debug=True, **kwargs) (main-thread, non-Jupyter path) triggers dash/backends/_fastapi.py::FastAPIBackend.run(), which spawns python -m uvicorn <module>:<app>.server --reload as a subprocess. Extra kwargs such as reload_dirs=[...] or reload_excludes=[...] are accepted by Dash.run(..., **flask_run_options) without error and flow straight into FastAPIBackend.run()'s **kwargs — but only kwargs.get("reload") is ever read there; every other reload-related kwarg is silently dropped when building the subprocess's CLI args. The comment directly above the subprocess.Popen(...) call even says:

# Add any other kwargs as CLI args if needed
proc = subprocess.Popen(uvicorn_args, env=env)

...but nothing implements it.

Practical effect: without an explicit --reload-dir, uvicorn/watchfiles fall back to watching the entire current working directory. In any project run with cwd above the app's own package (e.g. a monorepo, or simply python path/to/app/index.py invoked from a parent directory), the reload subprocess ends up recursively watching unrelated directories — including a shared virtualenv (.venv/site-packages/...) — so any unrelated package file being touched triggers a full, spurious app reload.

Reproduction

# repro.py -- run as `python repro.py` from a directory ABOVE this file,
# e.g.:
#   mkdir -p repo_root/app_dir && cd repo_root
#   (place this file at repo_root/app_dir/repro.py)
#   python app_dir/repro.py
from dash import Dash, html

app = Dash(__name__, backend="fastapi")
app.layout = html.Div("hello")

if __name__ == "__main__":
    app.run(
        host="127.0.0.1",
        port=8050,
        debug=True,
        reload_dirs=["app_dir"],
        reload_excludes=["app_dir/tests/*"],
    )
  • Expected: the spawned uvicorn --reload subprocess only watches app_dir/, excluding app_dir/tests/*.
  • Actual: reload_dirs/reload_excludes are silently ignored. The subprocess inherits the parent's cwd (repo_root/) and uvicorn defaults reload_dirs to [Path.cwd()], so it watches repo_root/ recursively -- including repo_root/.venv if one exists there.

Root cause

dash/backends/_fastapi.py, FastAPIBackend.run() (dash 4.4.1):

def run(self, dash_app: Dash, host, port, debug, **kwargs):
    ...
    uvicorn_args = [
        sys.executable, "-m", "uvicorn", app_path,
        "--host", str(host), "--port", str(port),
    ]
    if kwargs.get("reload"):
        uvicorn_args.append("--reload")

    dev_tools = dash_app._dev_tools
    config = dict(
        {"debug": debug} if debug else {"debug": False},
        **{f"dev_tools_{k}": v for k, v in dev_tools.items()},
    )
    env = os.environ.copy()
    env[_ENV_CONFIG] = json.dumps(config)

    # Add any other kwargs as CLI args if needed

    proc = subprocess.Popen(uvicorn_args, env=env)
    proc.wait()

Only kwargs["reload"] is ever consulted. reload_dirs, reload_excludes, reload_includes (and anything else a caller passes through app.run(...)) reach this function but are never translated into --reload-dir / --reload-exclude / --reload-include CLI args for the child process.

Suggested fix

Forward at least the reload-scoping kwargs onto uvicorn_args, e.g.:

for d in kwargs.get("reload_dirs") or []:
    uvicorn_args += ["--reload-dir", str(d)]
for p in kwargs.get("reload_excludes") or []:
    uvicorn_args += ["--reload-exclude", str(p)]
for p in kwargs.get("reload_includes") or []:
    uvicorn_args += ["--reload-include", str(p)]

Since this is silent today (no error, no warning), a caller has no way to discover the gap short of reading this source file directly. At minimum, forwarding these three would close the gap for the common case; more generally it might be worth warning on any kwarg that isn't recognized/forwarded here.

Environment

  • dash 4.4.1 (dash[fastapi], backend="fastapi")
  • uvicorn 0.52.0
  • Windows 11, Python 3.11 (the affected code path is not inside a platform-specific branch, so this should reproduce on any OS)

Related

Possibly adjacent to #3818 / #3912 (uvicorn --reload subprocess handling in the FastAPI backend also has callback double-registration issues there), but this is a distinct symptom -- silently dropped reload-scoping kwargs / overly broad default watch scope, not callback duplication.

主要语言
Python
星标
24.4k
派生
2.3k
平均合并
1 天 21 小时
30 天内合并 PR
19

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

plotly/dash 的其他 Issue

查看 plotly/dash 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。