def watch_file(directory, filename): observer = PollingObserver() observer.schedule(MyHandler(observer), path=directory) observer.start() print('\nwatching for changes to {}'.format(directory)) while observer.isAlive() == True: time.sleep(1) observer.join()
class AiidaLabAppWatch: """Watch to monitor the app installation status. Create a watch instance to monitor the installation status of an AiiDAlab app. This is achieved by monitoring the app repository for existance and changes. Arguments: app (AiidaLabApp): The AiidaLab app to monitor. """ class AppPathFileSystemEventHandler(FileSystemEventHandler): """Internal event handeler for app path file system events.""" def __init__(self, app): self.app = app def on_any_event(self, event): """Refresh app for any event.""" self.app.refresh_async() def __init__(self, app): self.app = app self._started = False self._monitor_thread = None self._observer = None def __repr__(self): return f"<{type(self).__name__}(app={self.app!r})>" def _start_observer(self): """Start the directory observer thread. The ._observer thread is controlled by the ._monitor_thread. """ assert os.path.isdir(self.app.path) assert self._observer is None or not self._observer.isAlive() event_handler = self.AppPathFileSystemEventHandler(self.app) self._observer = Observer() self._observer.schedule(event_handler, self.app.path, recursive=True) try: self._observer.start() except OSError as error: if error.errno in (errno.ENOSPC, errno.EMFILE) and 'inotify' in str(error): # We reached the inotify watch limit, using polling-based fallback observer. self._observer = PollingObserver() self._observer.schedule(event_handler, self.app.path, recursive=True) self._observer.start() else: # reraise unrelated error raise error def _stop_observer(self): """Stop the directory observer thread. The ._observer thread is controlled by the ._monitor_thread. """ assert self._observer is not None self._observer.stop() def start(self): """Watch the app repository for file system events. The app state is refreshed automatically for all events. """ if self._started: raise RuntimeError( f"Instances of {type(self).__name__} can only be started once." ) if self._monitor_thread is None: def check_path_exists_changed(): is_dir = os.path.isdir(self.app.path) while not self._monitor_thread.stop_flag: switched = is_dir != os.path.isdir(self.app.path) if switched: is_dir = not is_dir self.app.refresh() if is_dir: if self._observer is None or not self._observer.isAlive( ): self._start_observer() elif self._observer and self._observer.isAlive(): self._stop_observer() sleep(1) # stop-flag set, stopping observer... if self._observer: self._observer.stop() self._monitor_thread = Thread(target=check_path_exists_changed) self._monitor_thread.stop_flag = False self._monitor_thread.start() self._started = True def stop(self): """Stop watching the app repository for file system events.""" if self._monitor_thread is not None: self._monitor_thread.stop_flag = True def is_alive(self): """Return True if this watch is still alive.""" return self._monitor_thread and self._monitor_thread.is_alive() def join(self, timeout=None): """Join the watch after stopping. This function will timeout if a timeout argument is provided. Use the is_alive() function to determien whether the watch was stopped within the given timout. """ if self._monitor_thread is not None: self._monitor_thread.join(timeout=timeout)