statreload.py 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. from __future__ import annotations
  2. import logging
  3. from collections.abc import Callable, Iterator
  4. from pathlib import Path
  5. from socket import socket
  6. from uvicorn.config import Config
  7. from uvicorn.supervisors.basereload import BaseReload
  8. logger = logging.getLogger("uvicorn.error")
  9. class StatReload(BaseReload):
  10. def __init__(
  11. self,
  12. config: Config,
  13. target: Callable[[list[socket] | None], None],
  14. sockets: list[socket],
  15. ) -> None:
  16. super().__init__(config, target, sockets)
  17. self.reloader_name = "StatReload"
  18. self.mtimes: dict[Path, float] = {}
  19. if config.reload_excludes or config.reload_includes:
  20. logger.warning("--reload-include and --reload-exclude have no effect unless watchfiles is installed.")
  21. def should_restart(self) -> list[Path] | None:
  22. self.pause()
  23. for file in self.iter_py_files():
  24. try:
  25. mtime = file.stat().st_mtime
  26. except OSError: # pragma: nocover
  27. continue
  28. old_time = self.mtimes.get(file)
  29. if old_time is None:
  30. self.mtimes[file] = mtime
  31. continue
  32. elif mtime > old_time:
  33. return [file]
  34. return None
  35. def restart(self) -> None:
  36. self.mtimes = {}
  37. return super().restart()
  38. def iter_py_files(self) -> Iterator[Path]:
  39. for reload_dir in self.config.reload_dirs:
  40. for path in list(reload_dir.rglob("*.py")):
  41. yield path.resolve()