Interrupt main-thread as soon as a changed module file is detected, the lockfile gets deleted or gets to old.
| 3149 | |
| 3150 | |
| 3151 | class FileCheckerThread(threading.Thread): |
| 3152 | ''' Interrupt main-thread as soon as a changed module file is detected, |
| 3153 | the lockfile gets deleted or gets to old. ''' |
| 3154 | |
| 3155 | def __init__(self, lockfile, interval): |
| 3156 | threading.Thread.__init__(self) |
| 3157 | self.lockfile, self.interval = lockfile, interval |
| 3158 | #: Is one of 'reload', 'error' or 'exit' |
| 3159 | self.status = None |
| 3160 | |
| 3161 | def run(self): |
| 3162 | exists = os.path.exists |
| 3163 | mtime = lambda path: os.stat(path).st_mtime |
| 3164 | files = dict() |
| 3165 | |
| 3166 | for module in list(sys.modules.values()): |
| 3167 | path = getattr(module, '__file__', '') or '' |
| 3168 | if path[-4:] in ('.pyo', '.pyc'): path = path[:-1] |
| 3169 | if path and exists(path): files[path] = mtime(path) |
| 3170 | |
| 3171 | while not self.status: |
| 3172 | if not exists(self.lockfile)\ |
| 3173 | or mtime(self.lockfile) < time.time() - self.interval - 5: |
| 3174 | self.status = 'error' |
| 3175 | thread.interrupt_main() |
| 3176 | for path, lmtime in list(files.items()): |
| 3177 | if not exists(path) or mtime(path) > lmtime: |
| 3178 | self.status = 'reload' |
| 3179 | thread.interrupt_main() |
| 3180 | break |
| 3181 | time.sleep(self.interval) |
| 3182 | |
| 3183 | def __enter__(self): |
| 3184 | self.start() |
| 3185 | |
| 3186 | def __exit__(self, exc_type, exc_val, exc_tb): |
| 3187 | if not self.status: self.status = 'exit' # silent exit |
| 3188 | self.join() |
| 3189 | return exc_type is not None and issubclass(exc_type, KeyboardInterrupt) |
| 3190 | |
| 3191 | |
| 3192 |