Interrupt main-thread as soon as a changed module file is detected, the lockfile gets deleted or gets to old.
| 2392 | |
| 2393 | |
| 2394 | class FileCheckerThread(threading.Thread): |
| 2395 | ''' Interrupt main-thread as soon as a changed module file is detected, |
| 2396 | the lockfile gets deleted or gets to old. ''' |
| 2397 | |
| 2398 | def __init__(self, lockfile, interval): |
| 2399 | threading.Thread.__init__(self) |
| 2400 | self.lockfile, self.interval = lockfile, interval |
| 2401 | #: Is one of 'reload', 'error' or 'exit' |
| 2402 | self.status = None |
| 2403 | |
| 2404 | def run(self): |
| 2405 | exists = os.path.exists |
| 2406 | mtime = lambda path: os.stat(path).st_mtime |
| 2407 | files = dict() |
| 2408 | |
| 2409 | for module in sys.modules.values(): |
| 2410 | path = getattr(module, '__file__', '') |
| 2411 | if path[-4:] in ('.pyo', '.pyc'): path = path[:-1] |
| 2412 | if path and exists(path): files[path] = mtime(path) |
| 2413 | |
| 2414 | while not self.status: |
| 2415 | if not exists(self.lockfile)\ |
| 2416 | or mtime(self.lockfile) < time.time() - self.interval - 5: |
| 2417 | self.status = 'error' |
| 2418 | thread.interrupt_main() |
| 2419 | for path, lmtime in files.iteritems(): |
| 2420 | if not exists(path) or mtime(path) > lmtime: |
| 2421 | self.status = 'reload' |
| 2422 | thread.interrupt_main() |
| 2423 | break |
| 2424 | time.sleep(self.interval) |
| 2425 | |
| 2426 | def __enter__(self): |
| 2427 | self.start() |
| 2428 | |
| 2429 | def __exit__(self, exc_type, exc_val, exc_tb): |
| 2430 | if not self.status: self.status = 'exit' # silent exit |
| 2431 | self.join() |
| 2432 | return issubclass(exc_type, KeyboardInterrupt) |
| 2433 | |
| 2434 | |
| 2435 |