diff --git a/inotify/adapters.py b/inotify/adapters.py index e8301da..1cafe57 100644 --- a/inotify/adapters.py +++ b/inotify/adapters.py @@ -125,6 +125,12 @@ def remove_watch_with_id(self, wd, superficial=False): inotify.calls.inotify_rm_watch(self.__inotify_fd, wd) + def remove_watches(self, superficial=False): + for wd in self.__watches.values(): + self.remove_watch_with_id(wd, superficial) + + self.__watches = {} + def _get_event_names(self, event_type): names = [] for bit, name in inotify.constants.MASK_LOOKUP.items(): diff --git a/tests/test_inotify.py b/tests/test_inotify.py index d9f1f84..d166525 100644 --- a/tests/test_inotify.py +++ b/tests/test_inotify.py @@ -133,6 +133,100 @@ def test__cycle(self): events = self.__read_all_events(i) self.assertEquals(events, []) + def test__remove_watches(self): + with inotify.test_support.temp_path() as path: + path1 = os.path.join(path, 'aa') + os.mkdir(path1) + + path2 = os.path.join(path, 'bb') + os.mkdir(path2) + + i = inotify.adapters.Inotify() + i.add_watch(path1) + i.add_watch(path2) + + with open('ignored_new_file', 'w'): + pass + + with open(os.path.join(path1, 'seen_new_file'), 'w'): + pass + + os.remove(os.path.join(path1, 'seen_new_file')) + + + with open(os.path.join(path2, 'seen_new_file'), 'w'): + pass + + os.remove(os.path.join(path2, 'seen_new_file')) + + events = self.__read_all_events(i) + + expected = [ + ( + inotify.adapters._INOTIFY_EVENT(wd=1, mask=256, cookie=0, len=16), + ['IN_CREATE'], + path1, + 'seen_new_file' + ), + ( + inotify.adapters._INOTIFY_EVENT(wd=1, mask=32, cookie=0, len=16), + ['IN_OPEN'], + path1, + 'seen_new_file' + ), + ( + inotify.adapters._INOTIFY_EVENT(wd=1, mask=8, cookie=0, len=16), + ['IN_CLOSE_WRITE'], + path1, + 'seen_new_file' + ), + ( + inotify.adapters._INOTIFY_EVENT(wd=1, mask=512, cookie=0, len=16), + ['IN_DELETE'], + path1, + 'seen_new_file' + ), + ( + inotify.adapters._INOTIFY_EVENT(wd=1, mask=256, cookie=0, len=16), + ['IN_CREATE'], + path2, + 'seen_new_file' + ), + ( + inotify.adapters._INOTIFY_EVENT(wd=1, mask=32, cookie=0, len=16), + ['IN_OPEN'], + path2, + 'seen_new_file' + ), + ( + inotify.adapters._INOTIFY_EVENT(wd=1, mask=8, cookie=0, len=16), + ['IN_CLOSE_WRITE'], + path2, + 'seen_new_file' + ), + ( + inotify.adapters._INOTIFY_EVENT(wd=1, mask=512, cookie=0, len=16), + ['IN_DELETE'], + path2, + 'seen_new_file' + ) + ] + + self.assertEquals(events, expected) + + # This can't be removed until *after* we've read the events because + # they'll be flushed the moment we remove the watch. + i.remove_watches() + + with open(os.path.join(path1, 'ignored_after_removal'), 'w'): + pass + + with open(os.path.join(path2, 'ignored_after_removal'), 'w'): + pass + + events = self.__read_all_events(i) + self.assertEquals(events, []) + @staticmethod def _open_write_close(*args): with open(os.path.join(*args), 'w'):