(
sleep: Callable[[float], Awaitable[Any]], shutdown_event: Event
)
| 103 | |
| 104 | |
| 105 | async def observe_changes( |
| 106 | sleep: Callable[[float], Awaitable[Any]], shutdown_event: Event |
| 107 | ) -> None: |
| 108 | last_updates: dict[Path, float] = {} |
| 109 | for module in list(sys.modules.values()): |
| 110 | filename = getattr(module, "__file__", None) |
| 111 | if filename is None: |
| 112 | continue |
| 113 | path = Path(filename) |
| 114 | try: |
| 115 | last_updates[Path(filename)] = path.stat().st_mtime |
| 116 | except (FileNotFoundError, NotADirectoryError): |
| 117 | pass |
| 118 | |
| 119 | while not shutdown_event.is_set(): |
| 120 | await sleep(1) |
| 121 | |
| 122 | for index, (path, last_mtime) in enumerate(last_updates.items()): |
| 123 | if index % 10 == 0: |
| 124 | # Yield to the event loop |
| 125 | await sleep(0) |
| 126 | |
| 127 | try: |
| 128 | mtime = path.stat().st_mtime |
| 129 | except FileNotFoundError as e: |
| 130 | # File deleted |
| 131 | raise MustReloadError() from e |
| 132 | else: |
| 133 | if mtime > last_mtime: |
| 134 | raise MustReloadError() |
| 135 | else: |
| 136 | last_updates[path] = mtime |
| 137 | |
| 138 | |
| 139 | def restart() -> None: |
no test coverage detected
searching dependent graphs…