Interrupt main-thread as soon as a changed module file is detected, the lockfile gets deleted or gets too old.
| 4134 | |
| 4135 | |
| 4136 | class FileCheckerThread(threading.Thread): |
| 4137 | """ Interrupt main-thread as soon as a changed module file is detected, |
| 4138 | the lockfile gets deleted or gets too old. """ |
| 4139 | |
| 4140 | def __init__(self, lockfile, interval): |
| 4141 | threading.Thread.__init__(self) |
| 4142 | self.daemon = True |
| 4143 | self.lockfile, self.interval = lockfile, interval |
| 4144 | #: Is one of 'reload', 'error' or 'exit' |
| 4145 | self.status = None |
| 4146 | |
| 4147 | def run(self): |
| 4148 | exists = os.path.exists |
| 4149 | mtime = lambda p: os.stat(p).st_mtime |
| 4150 | files = dict() |
| 4151 | |
| 4152 | for module in list(sys.modules.values()): |
| 4153 | path = getattr(module, '__file__', '') or '' |
| 4154 | if path[-4:] in ('.pyo', '.pyc'): path = path[:-1] |
| 4155 | if path and exists(path): files[path] = mtime(path) |
| 4156 | |
| 4157 | while not self.status: |
| 4158 | if not exists(self.lockfile)\ |
| 4159 | or mtime(self.lockfile) < time.time() - self.interval - 5: |
| 4160 | self.status = 'error' |
| 4161 | thread.interrupt_main() |
| 4162 | for path, lmtime in list(files.items()): |
| 4163 | if not exists(path) or mtime(path) > lmtime: |
| 4164 | self.status = 'reload' |
| 4165 | thread.interrupt_main() |
| 4166 | break |
| 4167 | time.sleep(self.interval) |
| 4168 | |
| 4169 | def __enter__(self): |
| 4170 | self.start() |
| 4171 | |
| 4172 | def __exit__(self, exc_type, *_): |
| 4173 | if not self.status: self.status = 'exit' # silent exit |
| 4174 | self.join() |
| 4175 | return exc_type is not None and issubclass(exc_type, KeyboardInterrupt) |
| 4176 | |
| 4177 | ############################################################################### |
| 4178 | # Template Adapters ############################################################ |
no outgoing calls
no test coverage detected
searching dependent graphs…