--reload for live devA build-it-yourself guide. Iterating on a registry today means
kill-the-server, edit, restart. This adds --reload to modulearn run
so saving app.py restarts it automatically — the same loop web devs expect.
modulearn run app.py --reload serves the app
and, when you edit and save app.py, the server restarts and the change is live
without you touching the terminal.Plain modulearn run hands uvicorn a live app object
(uvicorn.run(app, …)). Reload can't work that way: uvicorn's reloader restarts your
program in a fresh subprocess, so it needs an import string
("app:app") it can re-import from scratch — and that subprocess must be able to
find your module. Two things make it work:
f"{path.stem}:{attr}".reload_dirs tells uvicorn which folder to watch.app.py's title
while --reload was active flipped /api/meta from reloadcheck
→ RELOADED with no restart, and the log showed
StatReload detected changes in 'app.py'. Reloading…_serveIt resolves the target to an import string, exports PYTHONPATH so the
subprocess can import it, and hands uvicorn the string with reload=True.
def _serve_reload(target, host, port):
"""Serve with uvicorn's autoreloader. Unlike _serve, this passes an import
STRING (uvicorn re-imports in a fresh subprocess on every change), so the
module's directory must be importable there — hence PYTHONPATH."""
import os
import uvicorn
path_str, _, attr = target.partition(":")
attr = attr or "app"
path = Path(path_str).resolve()
if not path.exists():
sys.exit(f"modulearn: no such file: {path_str}")
os.environ["PYTHONPATH"] = (
str(path.parent) + os.pathsep + os.environ.get("PYTHONPATH", ""))
url = f"http://{'localhost' if host in ('0.0.0.0', '') else host}:{port}"
print(f"ModuLearn (reload) → {url} watching {path.parent} (Ctrl-C to stop)")
uvicorn.run(f"{path.stem}:{attr}", host=host, port=port,
reload=True, reload_dirs=[str(path.parent)])
run subparser p_run.add_argument("--reload", action="store_true",
help="restart the server when the app file changes (dev)")
run arm of main() elif args.command == "run":
if args.reload:
_serve_reload(args.target, args.host, args.port)
else:
_serve(_load_app(args.target), args.host, args.port)
modulearn run app.py --reload # serves, prints "watching <dir>"
# in the app, change title="..." and save
# terminal logs: StatReload detected changes in 'app.py'. Reloading...
# refresh the browser — the new title is live
reload_dirs is the
file's directory, so edits to sibling modules your app imports also trigger a restart — which
is what you want once an app grows past one file.Add --reload to the usage lines in the cli.py module docstring, then:
git add modulearn/cli.py
git commit -m "Add --reload to modulearn run"
git push
gh run list --branch main --limit 1 # expect: success
Add done:true, to the
{area:"dx", … title:"--reload for live development"} item in
docs/roadmap.html.
modulearn run (no flag) as the default so nobody ships
with it on. For faster change detection, pip install watchfiles and uvicorn uses it
automatically instead of stat-polling.