From e9fd12ca949f32b3ce720ddc2c185479de47d04b Mon Sep 17 00:00:00 2001 From: Larivact Date: Tue, 21 Mar 2017 16:41:40 +0100 Subject: [PATCH 01/10] add ignored_dirs param to InotifyTree(s) --- inotify/adapters.py | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/inotify/adapters.py b/inotify/adapters.py index d136698..a097a77 100644 --- a/inotify/adapters.py +++ b/inotify/adapters.py @@ -227,53 +227,55 @@ def event_gen(self): class InotifyTree(BaseTree): def __init__(self, path, mask=inotify.constants.IN_ALL_EVENTS, - block_duration_s=_DEFAULT_EPOLL_BLOCK_DURATION_S): + block_duration_s=_DEFAULT_EPOLL_BLOCK_DURATION_S, ignored_dirs=[]): super(InotifyTree, self).__init__(mask=mask, block_duration_s=block_duration_s) self.__root_path = path - self.__load_tree(path) + self.__load_tree(path, ignored_dirs) - def __load_tree(self, path): + def __load_tree(self, path, ignored_dirs): _LOGGER.debug("Adding initial watches on tree: [%s]", path) q = [path] while q: current_path = q[0] del q[0] + + if current_path not in ignored_dirs: + self._i.add_watch(current_path, self._mask) - self._i.add_watch(current_path, self._mask) - - for filename in os.listdir(current_path): - entry_filepath = os.path.join(current_path, filename) - if os.path.isdir(entry_filepath) is False: - continue + for filename in os.listdir(current_path): + entry_filepath = os.path.join(current_path, filename) + if os.path.isdir(entry_filepath) is False: + continue - q.append(entry_filepath) + q.append(entry_filepath) class InotifyTrees(BaseTree): def __init__(self, paths, mask=inotify.constants.IN_ALL_EVENTS, - block_duration_s=_DEFAULT_EPOLL_BLOCK_DURATION_S): + block_duration_s=_DEFAULT_EPOLL_BLOCK_DURATION_S, ignored_dirs=[]): super(InotifyTrees, self).__init__(mask=mask, block_duration_s=block_duration_s) - self.__load_trees(paths) + self.__load_trees(paths, ignored_dirs) - def __load_trees(self, paths): + def __load_trees(self, paths, ignored_dirs): _LOGGER.debug("Adding initial watches on trees: [%s]", ",".join(map(str, paths))) q = paths while q: current_path = q[0] del q[0] + + if current_path not in ignored_dirs: + self._i.add_watch(current_path, self._mask) - self._i.add_watch(current_path, self._mask) - - for filename in os.listdir(current_path): - entry_filepath = os.path.join(current_path, filename) - if os.path.isdir(entry_filepath) is False: - continue + for filename in os.listdir(current_path): + entry_filepath = os.path.join(current_path, filename) + if os.path.isdir(entry_filepath) is False: + continue - q.append(entry_filepath) + q.append(entry_filepath) From a4e1d5b15dc938575b0f11aad1e313746d26c80d Mon Sep 17 00:00:00 2001 From: Larivact Date: Tue, 21 Mar 2017 16:47:57 +0100 Subject: [PATCH 02/10] document ignored_dirs in readme --- inotify/resources/README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/inotify/resources/README.rst b/inotify/resources/README.rst index b6e9193..178fc40 100644 --- a/inotify/resources/README.rst +++ b/inotify/resources/README.rst @@ -105,6 +105,7 @@ This will immediately recurse through the directory tree and add watches on all The other differences from the standard functionality: +- You can ignore specific directories with the *ignored_dirs* parameter. - You can't remove a watch since watches are automatically managed. - Even if you provide a very restrictive mask that doesn't allow for directory create/delete events, the *IN_ISDIR*, *IN_CREATE*, and *IN_DELETE* flags will still be added. From ea6bb32fc3d7f8639e52e4002253d527ff4e9097 Mon Sep 17 00:00:00 2001 From: Xie Yinglin Date: Fri, 24 Mar 2017 14:25:03 +0800 Subject: [PATCH 03/10] Fixed bug: mkdir -p foo/bar,InotifyTree(s) not add watch bar --- inotify/adapters.py | 56 +++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/inotify/adapters.py b/inotify/adapters.py index d136698..7ee7a88 100644 --- a/inotify/adapters.py +++ b/inotify/adapters.py @@ -71,8 +71,8 @@ def add_watch(self, path, mask=inotify.constants.IN_ALL_EVENTS): self.__watches_r[wd] = path def remove_watch(self, path, superficial=False): - """Remove our tracking information and call inotify to stop watching - the given path. When a directory is removed, we'll just have to remove + """Remove our tracking information and call inotify to stop watching + the given path. When a directory is removed, we'll just have to remove our tracking since inotify already cleans-up the watch. """ @@ -149,8 +149,8 @@ def __handle_inotify_event(self, wd, event_type): yield (header, type_names, path, filename) # TODO(dustin): !! For renames, we should drop the entry and re-add with the new name. -# TODO(dustin): !! The add_watch() call should return the handle. We should be -# able to remove the watches using the handle (not just with +# TODO(dustin): !! The add_watch() call should return the handle. We should be +# able to remove the watches using the handle (not just with # the path). buffer_length = len(self.__buffer) @@ -197,7 +197,7 @@ def __init__(self, mask=inotify.constants.IN_ALL_EVENTS, self._i = Inotify(block_duration_s=block_duration_s) def event_gen(self): - """This is a secondary generator that wraps the principal one, and + """This is a secondary generator that wraps the principal one, and adds/removes watches as directories are added/removed. """ @@ -213,7 +213,7 @@ def event_gen(self): "adding a watch on it (because we're " "being recursive): [%s]", full_path) - self._i.add_watch(full_path, self._mask) + self._load_tree(full_path) elif header.mask & inotify.constants.IN_DELETE: _LOGGER.debug("A directory has been removed. We're " "being recursive, but it would have " @@ -225,18 +225,7 @@ def event_gen(self): yield event -class InotifyTree(BaseTree): - def __init__(self, path, mask=inotify.constants.IN_ALL_EVENTS, - block_duration_s=_DEFAULT_EPOLL_BLOCK_DURATION_S): - super(InotifyTree, self).__init__(mask=mask, block_duration_s=block_duration_s) - - self.__root_path = path - - self.__load_tree(path) - - def __load_tree(self, path): - _LOGGER.debug("Adding initial watches on tree: [%s]", path) - + def _load_tree(self, path): q = [path] while q: current_path = q[0] @@ -252,6 +241,20 @@ def __load_tree(self, path): q.append(entry_filepath) +class InotifyTree(BaseTree): + def __init__(self, path, mask=inotify.constants.IN_ALL_EVENTS, + block_duration_s=_DEFAULT_EPOLL_BLOCK_DURATION_S): + super(InotifyTree, self).__init__(mask=mask, block_duration_s=block_duration_s) + + self.__root_path = path + + self.__load_tree(path) + + def __load_tree(self, path): + _LOGGER.debug("Adding initial watches on tree: [%s]", path) + self._load_tree(path) + + class InotifyTrees(BaseTree): def __init__(self, paths, mask=inotify.constants.IN_ALL_EVENTS, @@ -262,18 +265,5 @@ def __init__(self, paths, mask=inotify.constants.IN_ALL_EVENTS, def __load_trees(self, paths): _LOGGER.debug("Adding initial watches on trees: [%s]", ",".join(map(str, paths))) - - q = paths - while q: - current_path = q[0] - del q[0] - - self._i.add_watch(current_path, self._mask) - - for filename in os.listdir(current_path): - entry_filepath = os.path.join(current_path, filename) - if os.path.isdir(entry_filepath) is False: - continue - - q.append(entry_filepath) - + for path in paths: + self._load_tree(path) From d512a2c33e8dc4c70d541752a5185e5990077f2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionu=C8=9B=20Cioc=C3=AErlan?= Date: Wed, 7 Mar 2018 18:40:11 +0200 Subject: [PATCH 04/10] use os.walk for recursing --- inotify/adapters.py | 44 ++++-------------------------- inotify/test_support.py | 3 --- tests/test_inotify.py | 60 +++++++++++++++++++++++++++++------------ 3 files changed, 48 insertions(+), 59 deletions(-) diff --git a/inotify/adapters.py b/inotify/adapters.py index ee96d0b..0aa888d 100644 --- a/inotify/adapters.py +++ b/inotify/adapters.py @@ -320,31 +320,13 @@ def __init__(self, path, mask=inotify.constants.IN_ALL_EVENTS, block_duration_s=_DEFAULT_EPOLL_BLOCK_DURATION_S): super(InotifyTree, self).__init__(mask=mask, block_duration_s=block_duration_s) - self.__root_path = path - self.__load_tree(path) def __load_tree(self, path): _LOGGER.debug("Adding initial watches on tree: [%s]", path) - paths = [] - - q = [path] - while q: - current_path = q[0] - del q[0] - - paths.append(current_path) - - for filename in os.listdir(current_path): - entry_filepath = os.path.join(current_path, filename) - if os.path.isdir(entry_filepath) is False: - continue - - q.append(entry_filepath) - - for path in paths: - self._i.add_watch(path, self._mask) + for dirpath, _d, _f in os.walk(path): + self._i.add_watch(dirpath, self._mask) class InotifyTrees(_BaseTree): @@ -359,22 +341,6 @@ def __init__(self, paths, mask=inotify.constants.IN_ALL_EVENTS, def __load_trees(self, paths): _LOGGER.debug("Adding initial watches on trees: [%s]", ",".join(map(str, paths))) - found = [] - - q = paths - while q: - current_path = q[0] - del q[0] - - found.append(current_path) - - for filename in os.listdir(current_path): - entry_filepath = os.path.join(current_path, filename) - if os.path.isdir(entry_filepath) is False: - continue - - q.append(entry_filepath) - - - for path in found: - self._i.add_watch(path, self._mask) + for path in paths: + for dirpath, _d, _f in os.walk(path): + self._i.add_watch(dirpath, self._mask) diff --git a/inotify/test_support.py b/inotify/test_support.py index ed8b88f..c986787 100644 --- a/inotify/test_support.py +++ b/inotify/test_support.py @@ -11,12 +11,9 @@ def temp_path(): path = tempfile.mkdtemp() original_wd = os.getcwd() - os.chdir(path) try: yield path finally: - os.chdir(original_wd) - if os.path.exists(path) is True: shutil.rmtree(path) diff --git a/tests/test_inotify.py b/tests/test_inotify.py index 0f87524..27e48f2 100644 --- a/tests/test_inotify.py +++ b/tests/test_inotify.py @@ -166,7 +166,10 @@ def test__cycle(self): i = inotify.adapters.InotifyTree(path) - with open('seen_new_file1', 'w'): + watches = i._i._Inotify__watches + w2, w3 = watches[path1], watches[path2] + + with open(os.path.join(path, 'seen_new_file1'), 'w'): pass with open(os.path.join(path1, 'seen_new_file2'), 'w'): @@ -184,29 +187,45 @@ def test__cycle(self): events = self.__read_all_events(i) - expected = [ + _access_dir_a = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'aa'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'aa'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'aa'), + ] + + _access_dir_b = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'bb'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'bb'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'bb'), + ] + + # we can't be sure about the order the watches were registered + expected = (_access_dir_a + _access_dir_b if w2 < w3 + else _access_dir_b + _access_dir_a) + + expected += [ (inotify.adapters._INOTIFY_EVENT(wd=1, mask=256, cookie=0, len=16), ['IN_CREATE'], path, 'seen_new_file1'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=32, cookie=0, len=16), ['IN_OPEN'], path, 'seen_new_file1'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=8, cookie=0, len=16), ['IN_CLOSE_WRITE'], path, 'seen_new_file1'), - (inotify.adapters._INOTIFY_EVENT(wd=2, mask=256, cookie=0, len=16), ['IN_CREATE'], path1, 'seen_new_file2'), - (inotify.adapters._INOTIFY_EVENT(wd=2, mask=32, cookie=0, len=16), ['IN_OPEN'], path1, 'seen_new_file2'), - (inotify.adapters._INOTIFY_EVENT(wd=2, mask=8, cookie=0, len=16), ['IN_CLOSE_WRITE'], path1, 'seen_new_file2'), + (inotify.adapters._INOTIFY_EVENT(wd=w2, mask=256, cookie=0, len=16), ['IN_CREATE'], path1, 'seen_new_file2'), + (inotify.adapters._INOTIFY_EVENT(wd=w2, mask=32, cookie=0, len=16), ['IN_OPEN'], path1, 'seen_new_file2'), + (inotify.adapters._INOTIFY_EVENT(wd=w2, mask=8, cookie=0, len=16), ['IN_CLOSE_WRITE'], path1, 'seen_new_file2'), - (inotify.adapters._INOTIFY_EVENT(wd=3, mask=256, cookie=0, len=16), ['IN_CREATE'], path2, 'seen_new_file3'), - (inotify.adapters._INOTIFY_EVENT(wd=3, mask=32, cookie=0, len=16), ['IN_OPEN'], path2, 'seen_new_file3'), - (inotify.adapters._INOTIFY_EVENT(wd=3, mask=8, cookie=0, len=16), ['IN_CLOSE_WRITE'], path2, 'seen_new_file3'), + (inotify.adapters._INOTIFY_EVENT(wd=w3, mask=256, cookie=0, len=16), ['IN_CREATE'], path2, 'seen_new_file3'), + (inotify.adapters._INOTIFY_EVENT(wd=w3, mask=32, cookie=0, len=16), ['IN_OPEN'], path2, 'seen_new_file3'), + (inotify.adapters._INOTIFY_EVENT(wd=w3, mask=8, cookie=0, len=16), ['IN_CLOSE_WRITE'], path2, 'seen_new_file3'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=512, cookie=0, len=16), ['IN_DELETE'], path, 'seen_new_file1'), - (inotify.adapters._INOTIFY_EVENT(wd=2, mask=512, cookie=0, len=16), ['IN_DELETE'], path1, 'seen_new_file2'), - (inotify.adapters._INOTIFY_EVENT(wd=3, mask=512, cookie=0, len=16), ['IN_DELETE'], path2, 'seen_new_file3'), + (inotify.adapters._INOTIFY_EVENT(wd=w2, mask=512, cookie=0, len=16), ['IN_DELETE'], path1, 'seen_new_file2'), + (inotify.adapters._INOTIFY_EVENT(wd=w3, mask=512, cookie=0, len=16), ['IN_DELETE'], path2, 'seen_new_file3'), - (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1024, cookie=0, len=0), ['IN_DELETE_SELF'], path1, ''), - (inotify.adapters._INOTIFY_EVENT(wd=2, mask=32768, cookie=0, len=0), ['IN_IGNORED'], path1, ''), + (inotify.adapters._INOTIFY_EVENT(wd=w2, mask=1024, cookie=0, len=0), ['IN_DELETE_SELF'], path1, ''), + (inotify.adapters._INOTIFY_EVENT(wd=w2, mask=32768, cookie=0, len=0), ['IN_IGNORED'], path1, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073742336, cookie=0, len=16), ['IN_ISDIR', 'IN_DELETE'], path, 'aa'), - (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1024, cookie=0, len=0), ['IN_DELETE_SELF'], path2, ''), - (inotify.adapters._INOTIFY_EVENT(wd=3, mask=32768, cookie=0, len=0), ['IN_IGNORED'], path2, ''), + (inotify.adapters._INOTIFY_EVENT(wd=w3, mask=1024, cookie=0, len=0), ['IN_DELETE_SELF'], path2, ''), + (inotify.adapters._INOTIFY_EVENT(wd=w3, mask=32768, cookie=0, len=0), ['IN_IGNORED'], path2, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073742336, cookie=0, len=16), ['IN_ISDIR', 'IN_DELETE'], path, 'bb'), ] @@ -254,8 +273,8 @@ def test__renames(self): os.path.join(new_path, 'old_filename'), os.path.join(new_path, 'new_filename')) - os.remove(os.path.join('new_folder', 'new_filename')) - os.rmdir('new_folder') + os.remove(os.path.join(path, 'new_folder', 'new_filename')) + os.rmdir(os.path.join(path, 'new_folder')) events3 = self.__read_all_events(i) @@ -297,7 +316,6 @@ def test__automatic_new_watches_on_new_paths(self): self.assertEquals(events, expected) - os.mkdir(path2) events = self.__read_all_events(i) @@ -342,6 +360,14 @@ def test__automatic_new_watches_on_existing_paths(self): events = self.__read_all_events(i) expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'folder1'), + + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=256, cookie=0, len=16), ['IN_CREATE'], path2, 'filename'), (inotify.adapters._INOTIFY_EVENT(wd=3, mask=32, cookie=0, len=16), ['IN_OPEN'], path2, 'filename'), (inotify.adapters._INOTIFY_EVENT(wd=3, mask=8, cookie=0, len=16), ['IN_CLOSE_WRITE'], path2, 'filename'), From 67ee2423a10c4c5a44c11430c89a3fd7e44fd213 Mon Sep 17 00:00:00 2001 From: Elias Ohm Date: Thu, 20 Sep 2018 02:00:01 +0200 Subject: [PATCH 05/10] fix merge (removed additional line) --- inotify/adapters.py | 1 - 1 file changed, 1 deletion(-) diff --git a/inotify/adapters.py b/inotify/adapters.py index b458745..7318989 100644 --- a/inotify/adapters.py +++ b/inotify/adapters.py @@ -350,7 +350,6 @@ def __load_tree(self, path, ignored_dirs): del q[0] if current_path not in ignored_dirs: - self._i.add_watch(current_path, self._mask) paths.append(current_path) for filename in os.listdir(current_path): entry_filepath = os.path.join(current_path, filename) From adecb07c4321e76d01db43920bc88af71824632d Mon Sep 17 00:00:00 2001 From: Elias Ohm Date: Thu, 20 Sep 2018 06:43:02 +0200 Subject: [PATCH 06/10] first shot try to make tests compatible to different versions/setups regarding directory access events.. --- .coverage | 2 +- tests/test_inotify.py | 130 +++++++++++++++++++++++++++++++++--------- 2 files changed, 103 insertions(+), 29 deletions(-) diff --git a/.coverage b/.coverage index f0181e4..8089ede 100644 --- a/.coverage +++ b/.coverage @@ -1 +1 @@ -!coverage.py: This is a private format, don't read it directly!{"lines":{"/home/eohm/github/Elias481/PyInotify/inotify/__init__.py":[1],"/home/eohm/github/Elias481/PyInotify/inotify/adapters.py":[1,2,3,4,5,6,8,10,11,15,16,20,25,27,28,30,31,32,33,36,37,40,41,44,45,50,51,52,53,54,55,57,58,60,61,63,65,68,71,72,73,75,77,78,79,81,82,89,90,91,93,95,96,98,99,101,103,109,110,113,114,116,118,120,121,123,124,126,128,129,130,131,132,133,135,136,138,141,143,146,147,150,152,153,155,161,163,164,165,167,168,169,171,172,175,178,180,182,183,184,185,187,188,189,192,193,201,203,204,205,209,210,223,224,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,243,244,245,246,247,248,249,250,251,252,253,254,255,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,314,315,316,317,318,319,320,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,391,392,393],"/home/dustin/development/python/pyinotify/inotify/adapters.py":[1,2,3,4,5,6,8,10,11,15,16,20,22,23,25,26,27,28,31,32,35,36,39,40,41,42,43,44,46,47,49,51,53,56,59,60,61,63,65,66,67,69,70,72,73,75,76,78,84,85,88,89,91,92,93,95,97,98,99,100,101,102,104,105,107,110,112,115,117,118,121,123,124,126,132,134,135,136,138,139,141,142,145,148,150,152,153,154,161,162,163,165,170,171,172,176,177,191,194,195,196,197,199,200,201,202,204,208,209,210,216,217,219,221,230,231,232,234,235,238,239,242,245,247,250,252,253,256,259,261,264,265,267,268,269,271,273,275,276,278,280,281,282,283,285,287,288,289,292,294,295,298,299,301,302,303,305,307,308,310,312,313,314,315,317,319,327,328],"/home/dustin/development/python/pyinotify/inotify/constants.py":[3,4,8,9,10,11,12,13,14,15,16,17,18,19,23,24,30,34,35,36,40,41,42,43,44,46,47,48,52,53,54,55,56,57,58,59,60,61,62,63,67,68,69,73,74,75,76,77],"/home/eohm/github/Elias481/PyInotify/inotify/constants.py":[3,4,8,9,10,11,12,13,14,15,16,17,18,19,23,24,30,34,35,36,40,41,42,43,44,46,47,48,52,53,54,55,56,57,58,59,60,61,62,63,67,68,69,73,74,75,76,77],"/home/eohm/github/Elias481/PyInotify/inotify/calls.py":[1,2,4,6,8,11,12,18,25,32,33,37,39,40,41,43,45,46,47,49,51,52,53,55,56],"/home/eohm/github/Elias481/PyInotify/inotify/library.py":[1,2,4,5,8],"/home/dustin/development/python/pyinotify/inotify/__init__.py":[1],"/home/dustin/development/python/pyinotify/inotify/library.py":[8,1,2,4,5],"/home/eohm/github/Elias481/PyInotify/inotify/test_support.py":[1,2,3,4,5,7,9,11,13,14,16,17,19,21,22],"/home/dustin/development/python/pyinotify/inotify/test_support.py":[1,2,3,4,5,7,9,11,13,14,16,17,19,21,22],"/home/dustin/development/python/pyinotify/inotify/calls.py":[1,2,4,6,8,11,12,18,25,32,33,37,39,40,41,43,45,46,47,49,51,52,53,55,56]}} \ No newline at end of file +!coverage.py: This is a private format, don't read it directly!{"lines":{"/home/eohm/github/Elias481/PyInotify/inotify/constants.py":[3,4,8,9,10,11,12,13,14,15,16,17,18,19,23,24,30,34,35,36,40,41,42,43,44,46,47,48,52,53,54,55,56,57,58,59,60,61,62,63,67,68,69,73,74,75,76,77],"/home/dustin/development/python/pyinotify/inotify/constants.py":[3,4,8,9,10,11,12,13,14,15,16,17,18,19,23,24,30,34,35,36,40,41,42,43,44,46,47,48,52,53,54,55,56,57,58,59,60,61,62,63,67,68,69,73,74,75,76,77],"/home/dustin/development/python/pyinotify/inotify/library.py":[8,1,2,4,5],"/home/dustin/development/python/pyinotify/inotify/__init__.py":[1],"/home/eohm/github/Elias481/PyInotify/inotify/library.py":[1,2,4,5,8],"/home/eohm/github/Elias481/PyInotify/inotify/calls.py":[1,2,4,6,8,11,12,18,25,32,33,37,39,40,41,43,45,46,47,49,51,52,53,55,56],"/home/eohm/github/Elias481/PyInotify/inotify/test_support.py":[1,2,3,4,5,7,9,11,13,14,16,17,19,21,22],"/home/eohm/github/Elias481/PyInotify/inotify/__init__.py":[1],"/home/dustin/development/python/pyinotify/inotify/adapters.py":[1,2,3,4,5,6,8,10,11,15,16,20,22,23,25,26,27,28,31,32,35,36,39,40,41,42,43,44,46,47,49,51,53,56,59,60,61,63,65,66,67,69,70,72,73,75,76,78,84,85,88,89,91,92,93,95,97,98,99,100,101,102,104,105,107,110,112,115,117,118,121,123,124,126,132,134,135,136,138,139,141,142,145,148,150,152,153,154,161,162,163,165,170,171,172,176,177,191,194,195,196,197,199,200,201,202,204,208,209,210,216,217,219,221,230,231,232,234,235,238,239,242,245,247,250,252,253,256,259,261,264,265,267,268,269,271,273,275,276,278,280,281,282,283,285,287,288,289,292,294,295,298,299,301,302,303,305,307,308,310,312,313,314,315,317,319,327,328],"/home/dustin/development/python/pyinotify/inotify/test_support.py":[1,2,3,4,5,7,9,11,13,14,16,17,19,21,22],"/home/eohm/github/Elias481/PyInotify/inotify/adapters.py":[1,2,3,4,5,6,8,10,11,15,16,20,25,27,28,30,31,32,33,36,37,40,41,44,45,50,51,52,53,54,55,57,58,60,61,63,65,68,71,72,73,75,77,78,79,81,82,89,90,91,93,95,96,98,99,101,103,109,110,113,114,116,118,120,121,123,124,126,128,129,130,131,132,133,135,136,138,141,143,146,147,150,152,153,155,161,163,164,165,167,168,169,171,172,175,178,180,182,183,184,185,187,188,189,192,193,201,203,204,205,209,210,223,224,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,243,244,245,246,247,248,249,250,251,252,253,254,255,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,314,315,316,317,318,319,320,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,391,392,393],"/home/dustin/development/python/pyinotify/inotify/calls.py":[1,2,4,6,8,11,12,18,25,32,33,37,39,40,41,43,45,46,47,49,51,52,53,55,56]}} \ No newline at end of file diff --git a/tests/test_inotify.py b/tests/test_inotify.py index 99cceab..7e0f73c 100644 --- a/tests/test_inotify.py +++ b/tests/test_inotify.py @@ -14,6 +14,38 @@ else: _HAS_PYTHON2_UNICODE_SUPPORT = True +_HAS_DIRECTORY_ACCESS_EVENTS = None + +def setUpModule(): + with inotify.test_support.temp_path() as path: + subdirname = 'dir_acc_evt_tst' + inner_path = os.path.join(path, subdirname) + os.mkdir(inner_path) + + i = inotify.adapters.Inotify() + i.add_watch(path) + + dircontent = os.listdir(inner_path) + + events = list(i.event_gen(timeout_s=1, yield_nones=False)) + + expected_na = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, subdirname), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, subdirname), + ] + expected_wa = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, subdirname), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, subdirname), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, subdirname), + ] + if events == expected_na: + _HAS_DIRECTORY_ACCESS_EVENTS = False + elif events == expected_wa: + _HAS_DIRECTORY_ACCESS_EVENTS = True + else: + print('Got unknown list directory pattern:\n%r' %(events,)) + raise AssertionError('Found neighter expected list-directory pattern') + class TestInotify(unittest.TestCase): def __init__(self, *args, **kwargs): @@ -228,11 +260,19 @@ def test__renames(self): events1 = self.__read_all_events(i) - expected = [ - (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path, 'old_folder'), - (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'old_folder'), - (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'old_folder'), - ] + if _HAS_DIRECTORY_ACCESS_EVENTS: + expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path, 'old_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'old_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'old_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'old_folder'), + ] + else: + expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path, 'old_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'old_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'old_folder'), + ] self.assertEquals(events1, expected) @@ -241,19 +281,37 @@ def test__renames(self): events2 = self.__read_all_events(i) - expected = [ - (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741888, cookie=events2[1][0].cookie, len=16), ['IN_MOVED_FROM', 'IN_ISDIR'], path, 'old_folder'), - (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741952, cookie=events2[0][0].cookie, len=16), ['IN_MOVED_TO', 'IN_ISDIR'], path, 'new_folder'), - (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'new_folder'), - (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'new_folder'), - ####!!!!! This is not correct - only commited for intermediate testing without - #### applying commit fb4feb3 / see pull-request 61 on dsoprea/PyInotify:master - (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'new_folder'), - (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], new_path, ''), - (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'new_folder'), - (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], new_path, '') - ####!!!!! Preceding 4 would normally not happen in this version - to be removed - ] + if _HAS_DIRECTORY_ACCESS_EVENTS: + expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741888, cookie=events2[1][0].cookie, len=16), ['IN_MOVED_FROM', 'IN_ISDIR'], path, 'old_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741952, cookie=events2[0][0].cookie, len=16), ['IN_MOVED_TO', 'IN_ISDIR'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'new_folder'), + ####!!!!! This is not correct - only commited for intermediate testing without + #### applying commit fb4feb3 / see pull-request 61 on dsoprea/PyInotify:master + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], new_path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], new_path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], new_path, '') + ####!!!!! Preceding 4 would normally not happen in this version - to be removed + ] + else: + expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741888, cookie=events2[1][0].cookie, len=16), ['IN_MOVED_FROM', 'IN_ISDIR'], path, 'old_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741952, cookie=events2[0][0].cookie, len=16), ['IN_MOVED_TO', 'IN_ISDIR'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'new_folder'), + ####!!!!! This is not correct - only commited for intermediate testing without + #### applying commit fb4feb3 / see pull-request 61 on dsoprea/PyInotify:master + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], new_path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], new_path, '') + ####!!!!! Preceding 4 would normally not happen in this version - to be removed + ] self.assertEquals(events2, expected) @@ -302,11 +360,19 @@ def test__automatic_new_watches_on_new_paths(self): events = self.__read_all_events(i) - expected = [ - (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path, 'folder1'), - (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'folder1'), - (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'folder1'), - ] + if _HAS_DIRECTORY_ACCESS_EVENTS: + expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'folder1'), + ] + else: + expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'folder1'), + ] self.assertEquals(events, expected) @@ -315,11 +381,19 @@ def test__automatic_new_watches_on_new_paths(self): events = self.__read_all_events(i) - expected = [ - (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path1, 'folder2'), - (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path1, 'folder2'), - (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, 'folder2'), - ] + if _HAS_DIRECTORY_ACCESS_EVENTS: + expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, 'folder2'), + ] + else: + expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, 'folder2'), + ] self.assertEquals(events, expected) From 18949a795407d748877dab4bcb22c1a7510d93fc Mon Sep 17 00:00:00 2001 From: Elias Ohm Date: Thu, 20 Sep 2018 13:06:46 +0200 Subject: [PATCH 07/10] fix problem with tet module setup --- .coverage | 2 +- tests/test_inotify.py | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.coverage b/.coverage index 8089ede..532b73a 100644 --- a/.coverage +++ b/.coverage @@ -1 +1 @@ -!coverage.py: This is a private format, don't read it directly!{"lines":{"/home/eohm/github/Elias481/PyInotify/inotify/constants.py":[3,4,8,9,10,11,12,13,14,15,16,17,18,19,23,24,30,34,35,36,40,41,42,43,44,46,47,48,52,53,54,55,56,57,58,59,60,61,62,63,67,68,69,73,74,75,76,77],"/home/dustin/development/python/pyinotify/inotify/constants.py":[3,4,8,9,10,11,12,13,14,15,16,17,18,19,23,24,30,34,35,36,40,41,42,43,44,46,47,48,52,53,54,55,56,57,58,59,60,61,62,63,67,68,69,73,74,75,76,77],"/home/dustin/development/python/pyinotify/inotify/library.py":[8,1,2,4,5],"/home/dustin/development/python/pyinotify/inotify/__init__.py":[1],"/home/eohm/github/Elias481/PyInotify/inotify/library.py":[1,2,4,5,8],"/home/eohm/github/Elias481/PyInotify/inotify/calls.py":[1,2,4,6,8,11,12,18,25,32,33,37,39,40,41,43,45,46,47,49,51,52,53,55,56],"/home/eohm/github/Elias481/PyInotify/inotify/test_support.py":[1,2,3,4,5,7,9,11,13,14,16,17,19,21,22],"/home/eohm/github/Elias481/PyInotify/inotify/__init__.py":[1],"/home/dustin/development/python/pyinotify/inotify/adapters.py":[1,2,3,4,5,6,8,10,11,15,16,20,22,23,25,26,27,28,31,32,35,36,39,40,41,42,43,44,46,47,49,51,53,56,59,60,61,63,65,66,67,69,70,72,73,75,76,78,84,85,88,89,91,92,93,95,97,98,99,100,101,102,104,105,107,110,112,115,117,118,121,123,124,126,132,134,135,136,138,139,141,142,145,148,150,152,153,154,161,162,163,165,170,171,172,176,177,191,194,195,196,197,199,200,201,202,204,208,209,210,216,217,219,221,230,231,232,234,235,238,239,242,245,247,250,252,253,256,259,261,264,265,267,268,269,271,273,275,276,278,280,281,282,283,285,287,288,289,292,294,295,298,299,301,302,303,305,307,308,310,312,313,314,315,317,319,327,328],"/home/dustin/development/python/pyinotify/inotify/test_support.py":[1,2,3,4,5,7,9,11,13,14,16,17,19,21,22],"/home/eohm/github/Elias481/PyInotify/inotify/adapters.py":[1,2,3,4,5,6,8,10,11,15,16,20,25,27,28,30,31,32,33,36,37,40,41,44,45,50,51,52,53,54,55,57,58,60,61,63,65,68,71,72,73,75,77,78,79,81,82,89,90,91,93,95,96,98,99,101,103,109,110,113,114,116,118,120,121,123,124,126,128,129,130,131,132,133,135,136,138,141,143,146,147,150,152,153,155,161,163,164,165,167,168,169,171,172,175,178,180,182,183,184,185,187,188,189,192,193,201,203,204,205,209,210,223,224,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,243,244,245,246,247,248,249,250,251,252,253,254,255,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,314,315,316,317,318,319,320,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,391,392,393],"/home/dustin/development/python/pyinotify/inotify/calls.py":[1,2,4,6,8,11,12,18,25,32,33,37,39,40,41,43,45,46,47,49,51,52,53,55,56]}} \ No newline at end of file +!coverage.py: This is a private format, don't read it directly!{"lines":{"/home/eohm/github/Elias481/PyInotify/inotify/calls.py":[1,2,4,6,8,11,12,18,25,32,33,37,39,40,41,43,45,46,47,49,51,52,53,55,56],"/home/dustin/development/python/pyinotify/inotify/adapters.py":[1,2,3,4,5,6,8,10,11,15,16,20,22,23,25,26,27,28,31,32,35,36,39,40,41,42,43,44,46,47,49,51,53,56,59,60,61,63,65,66,67,69,70,72,73,75,76,78,84,85,88,89,91,92,93,95,97,98,99,100,101,102,104,105,107,110,112,115,117,118,121,123,124,126,132,134,135,136,138,139,141,142,145,148,150,152,153,154,161,162,163,165,170,171,172,176,177,191,194,195,196,197,199,200,201,202,204,208,209,210,216,217,219,221,230,231,232,234,235,238,239,242,245,247,250,252,253,256,259,261,264,265,267,268,269,271,273,275,276,278,280,281,282,283,285,287,288,289,292,294,295,298,299,301,302,303,305,307,308,310,312,313,314,315,317,319,327,328],"/home/dustin/development/python/pyinotify/inotify/test_support.py":[1,2,3,4,5,7,9,11,13,14,16,17,19,21,22],"/home/eohm/github/Elias481/PyInotify/inotify/test_support.py":[1,2,3,4,5,7,9,11,13,14,16,17,19,21,22],"/home/eohm/github/Elias481/PyInotify/inotify/library.py":[1,2,4,5,8],"/home/dustin/development/python/pyinotify/inotify/constants.py":[3,4,8,9,10,11,12,13,14,15,16,17,18,19,23,24,30,34,35,36,40,41,42,43,44,46,47,48,52,53,54,55,56,57,58,59,60,61,62,63,67,68,69,73,74,75,76,77],"/home/eohm/github/Elias481/PyInotify/inotify/__init__.py":[1],"/home/eohm/github/Elias481/PyInotify/inotify/constants.py":[3,4,8,9,10,11,12,13,14,15,16,17,18,19,23,24,30,34,35,36,40,41,42,43,44,46,47,48,52,53,54,55,56,57,58,59,60,61,62,63,67,68,69,73,74,75,76,77],"/home/dustin/development/python/pyinotify/inotify/calls.py":[1,2,4,6,8,11,12,18,25,32,33,37,39,40,41,43,45,46,47,49,51,52,53,55,56],"/home/dustin/development/python/pyinotify/inotify/__init__.py":[1],"/home/dustin/development/python/pyinotify/inotify/library.py":[8,1,2,4,5],"/home/eohm/github/Elias481/PyInotify/inotify/adapters.py":[1,2,3,4,5,6,8,10,11,15,16,20,25,27,28,30,31,32,33,36,37,40,41,44,45,50,51,52,53,54,55,57,58,60,61,63,65,68,71,72,73,75,77,78,79,81,82,89,90,91,93,95,96,98,99,101,103,109,110,113,114,116,118,120,121,123,124,126,128,129,130,131,132,133,135,136,138,141,143,146,147,150,152,153,155,161,163,164,165,167,168,169,171,172,175,178,180,182,183,184,185,187,188,189,192,193,201,203,204,205,209,210,223,224,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,243,244,245,246,247,248,249,250,251,252,253,254,255,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,314,315,316,317,318,319,320,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,391,392,393]}} \ No newline at end of file diff --git a/tests/test_inotify.py b/tests/test_inotify.py index 7e0f73c..d6a4b19 100644 --- a/tests/test_inotify.py +++ b/tests/test_inotify.py @@ -38,6 +38,7 @@ def setUpModule(): (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, subdirname), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, subdirname), ] + global _HAS_DIRECTORY_ACCESS_EVENTS if events == expected_na: _HAS_DIRECTORY_ACCESS_EVENTS = False elif events == expected_wa: @@ -53,6 +54,11 @@ def __init__(self, *args, **kwargs): super(TestInotify, self).__init__(*args, **kwargs) + @classmethod + def setUpClass(cls): + global _HAS_DIRECTORY_ACCESS_EVENTS + cls._HAS_DIRECTORY_ACCESS_EVENTS = _HAS_DIRECTORY_ACCESS_EVENTS + def __read_all_events(self, i): events = list(i.event_gen(timeout_s=1, yield_nones=False)) return events @@ -184,6 +190,11 @@ def __init__(self, *args, **kwargs): super(TestInotifyTree, self).__init__(*args, **kwargs) + @classmethod + def setUpClass(cls): + global _HAS_DIRECTORY_ACCESS_EVENTS + cls._HAS_DIRECTORY_ACCESS_EVENTS = _HAS_DIRECTORY_ACCESS_EVENTS + def __read_all_events(self, i): events = list(i.event_gen(timeout_s=1, yield_nones=False)) return events @@ -260,7 +271,7 @@ def test__renames(self): events1 = self.__read_all_events(i) - if _HAS_DIRECTORY_ACCESS_EVENTS: + if self._HAS_DIRECTORY_ACCESS_EVENTS: expected = [ (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path, 'old_folder'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'old_folder'), @@ -281,7 +292,7 @@ def test__renames(self): events2 = self.__read_all_events(i) - if _HAS_DIRECTORY_ACCESS_EVENTS: + if self._HAS_DIRECTORY_ACCESS_EVENTS: expected = [ (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741888, cookie=events2[1][0].cookie, len=16), ['IN_MOVED_FROM', 'IN_ISDIR'], path, 'old_folder'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741952, cookie=events2[0][0].cookie, len=16), ['IN_MOVED_TO', 'IN_ISDIR'], path, 'new_folder'), @@ -360,7 +371,7 @@ def test__automatic_new_watches_on_new_paths(self): events = self.__read_all_events(i) - if _HAS_DIRECTORY_ACCESS_EVENTS: + if self._HAS_DIRECTORY_ACCESS_EVENTS: expected = [ (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path, 'folder1'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'folder1'), @@ -381,7 +392,7 @@ def test__automatic_new_watches_on_new_paths(self): events = self.__read_all_events(i) - if _HAS_DIRECTORY_ACCESS_EVENTS: + if self._HAS_DIRECTORY_ACCESS_EVENTS: expected = [ (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path1, 'folder2'), (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path1, 'folder2'), From 5dcd8158c6c6482ed6343fab3a3c7e2ad5fa39cd Mon Sep 17 00:00:00 2001 From: Elias Ohm Date: Thu, 20 Sep 2018 14:18:48 +0200 Subject: [PATCH 08/10] fix error in tests + work around inotify bug for duplicate directory access events? --- .coverage | 2 +- tests/test_inotify.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.coverage b/.coverage index 532b73a..a9d615e 100644 --- a/.coverage +++ b/.coverage @@ -1 +1 @@ -!coverage.py: This is a private format, don't read it directly!{"lines":{"/home/eohm/github/Elias481/PyInotify/inotify/calls.py":[1,2,4,6,8,11,12,18,25,32,33,37,39,40,41,43,45,46,47,49,51,52,53,55,56],"/home/dustin/development/python/pyinotify/inotify/adapters.py":[1,2,3,4,5,6,8,10,11,15,16,20,22,23,25,26,27,28,31,32,35,36,39,40,41,42,43,44,46,47,49,51,53,56,59,60,61,63,65,66,67,69,70,72,73,75,76,78,84,85,88,89,91,92,93,95,97,98,99,100,101,102,104,105,107,110,112,115,117,118,121,123,124,126,132,134,135,136,138,139,141,142,145,148,150,152,153,154,161,162,163,165,170,171,172,176,177,191,194,195,196,197,199,200,201,202,204,208,209,210,216,217,219,221,230,231,232,234,235,238,239,242,245,247,250,252,253,256,259,261,264,265,267,268,269,271,273,275,276,278,280,281,282,283,285,287,288,289,292,294,295,298,299,301,302,303,305,307,308,310,312,313,314,315,317,319,327,328],"/home/dustin/development/python/pyinotify/inotify/test_support.py":[1,2,3,4,5,7,9,11,13,14,16,17,19,21,22],"/home/eohm/github/Elias481/PyInotify/inotify/test_support.py":[1,2,3,4,5,7,9,11,13,14,16,17,19,21,22],"/home/eohm/github/Elias481/PyInotify/inotify/library.py":[1,2,4,5,8],"/home/dustin/development/python/pyinotify/inotify/constants.py":[3,4,8,9,10,11,12,13,14,15,16,17,18,19,23,24,30,34,35,36,40,41,42,43,44,46,47,48,52,53,54,55,56,57,58,59,60,61,62,63,67,68,69,73,74,75,76,77],"/home/eohm/github/Elias481/PyInotify/inotify/__init__.py":[1],"/home/eohm/github/Elias481/PyInotify/inotify/constants.py":[3,4,8,9,10,11,12,13,14,15,16,17,18,19,23,24,30,34,35,36,40,41,42,43,44,46,47,48,52,53,54,55,56,57,58,59,60,61,62,63,67,68,69,73,74,75,76,77],"/home/dustin/development/python/pyinotify/inotify/calls.py":[1,2,4,6,8,11,12,18,25,32,33,37,39,40,41,43,45,46,47,49,51,52,53,55,56],"/home/dustin/development/python/pyinotify/inotify/__init__.py":[1],"/home/dustin/development/python/pyinotify/inotify/library.py":[8,1,2,4,5],"/home/eohm/github/Elias481/PyInotify/inotify/adapters.py":[1,2,3,4,5,6,8,10,11,15,16,20,25,27,28,30,31,32,33,36,37,40,41,44,45,50,51,52,53,54,55,57,58,60,61,63,65,68,71,72,73,75,77,78,79,81,82,89,90,91,93,95,96,98,99,101,103,109,110,113,114,116,118,120,121,123,124,126,128,129,130,131,132,133,135,136,138,141,143,146,147,150,152,153,155,161,163,164,165,167,168,169,171,172,175,178,180,182,183,184,185,187,188,189,192,193,201,203,204,205,209,210,223,224,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,243,244,245,246,247,248,249,250,251,252,253,254,255,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,314,315,316,317,318,319,320,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,391,392,393]}} \ No newline at end of file +!coverage.py: This is a private format, don't read it directly!{"lines":{"/home/eohm/github/Elias481/PyInotify/inotify/calls.py":[1,2,4,6,8,11,12,18,25,32,33,37,39,40,41,43,45,46,47,49,51,52,53,55,56],"/home/dustin/development/python/pyinotify/inotify/test_support.py":[1,2,3,4,5,7,9,11,13,14,16,17,19,21,22],"/home/eohm/github/Elias481/PyInotify/inotify/test_support.py":[1,2,3,4,5,7,9,11,13,14,16,17,19,21,22],"/home/dustin/development/python/pyinotify/inotify/adapters.py":[1,2,3,4,5,6,8,10,11,15,16,20,22,23,25,26,27,28,31,32,35,36,39,40,41,42,43,44,46,47,49,51,53,56,59,60,61,63,65,66,67,69,70,72,73,75,76,78,84,85,88,89,91,92,93,95,97,98,99,100,101,102,104,105,107,110,112,115,117,118,121,123,124,126,132,134,135,136,138,139,141,142,145,148,150,152,153,154,161,162,163,165,170,171,172,176,177,191,194,195,196,197,199,200,201,202,204,208,209,210,216,217,219,221,230,231,232,234,235,238,239,242,245,247,250,252,253,256,259,261,264,265,267,268,269,271,273,275,276,278,280,281,282,283,285,287,288,289,292,294,295,298,299,301,302,303,305,307,308,310,312,313,314,315,317,319,327,328],"/home/dustin/development/python/pyinotify/inotify/library.py":[8,1,2,4,5],"/home/eohm/github/Elias481/PyInotify/inotify/__init__.py":[1],"/home/eohm/github/Elias481/PyInotify/inotify/library.py":[1,2,4,5,8],"/home/dustin/development/python/pyinotify/inotify/calls.py":[1,2,4,6,8,11,12,18,25,32,33,37,39,40,41,43,45,46,47,49,51,52,53,55,56],"/home/dustin/development/python/pyinotify/inotify/__init__.py":[1],"/home/eohm/github/Elias481/PyInotify/inotify/constants.py":[3,4,8,9,10,11,12,13,14,15,16,17,18,19,23,24,30,34,35,36,40,41,42,43,44,46,47,48,52,53,54,55,56,57,58,59,60,61,62,63,67,68,69,73,74,75,76,77],"/home/dustin/development/python/pyinotify/inotify/constants.py":[3,4,8,9,10,11,12,13,14,15,16,17,18,19,23,24,30,34,35,36,40,41,42,43,44,46,47,48,52,53,54,55,56,57,58,59,60,61,62,63,67,68,69,73,74,75,76,77],"/home/eohm/github/Elias481/PyInotify/inotify/adapters.py":[1,2,3,4,5,6,8,10,11,15,16,20,25,27,28,30,31,32,33,36,37,40,41,44,45,50,51,52,53,54,55,57,58,60,61,63,65,68,71,72,73,75,77,78,79,81,82,89,90,91,93,95,96,98,99,101,103,109,110,113,114,116,118,120,121,123,124,126,128,129,130,131,132,133,135,136,138,141,143,146,147,150,152,153,155,161,163,164,165,167,168,169,171,172,175,178,180,182,183,184,185,187,188,189,192,193,201,203,204,205,209,210,223,224,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,243,244,245,246,247,248,249,250,251,252,253,254,255,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,314,315,316,317,318,319,320,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393]}} \ No newline at end of file diff --git a/tests/test_inotify.py b/tests/test_inotify.py index d6a4b19..af16135 100644 --- a/tests/test_inotify.py +++ b/tests/test_inotify.py @@ -305,6 +305,10 @@ def test__renames(self): (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], new_path, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'new_folder'), (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], new_path, ''), + ####????? No explanation for these duplicate directory access events + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], new_path, ''), + ####????? listdir is only called once - is it a bug in inotify? -> not test system (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'new_folder'), (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], new_path, '') ####!!!!! Preceding 4 would normally not happen in this version - to be removed @@ -396,7 +400,7 @@ def test__automatic_new_watches_on_new_paths(self): expected = [ (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path1, 'folder2'), (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path1, 'folder2'), - (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path1, 'folder2'), (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, 'folder2'), ] else: From 026c74d5cf87233802a6f2e7a12c2c1a3165a930 Mon Sep 17 00:00:00 2001 From: Elias Ohm Date: Sat, 22 Sep 2018 03:02:30 +0200 Subject: [PATCH 09/10] - completed merge/implementation of use os.walk for recursing * fixed order of add-watch/scandir to ensure not missing any directory created between scanning directory and adding watch * try to import walk from scandir module if python's version os module is missing scandir functionality * adjusted README accordingly * adjusted tests accordingly - fixed merge/implementation of ignored_dirs parameter for the tree-watchers * added testcase - did a small fix I have commited in another branch (remove duplicate IN_MOVED_TO handling) to have clean testcases (- maybe some other minor adjustments btw... check history...) --- .coverage | 2 +- inotify/adapters.py | 39 +++++-- inotify/resources/README.rst | 4 +- tests/test_inotify.py | 192 ++++++++++++++++++++++++++++++++++- 4 files changed, 224 insertions(+), 13 deletions(-) diff --git a/.coverage b/.coverage index 54f1741..ee77b7c 100644 --- a/.coverage +++ b/.coverage @@ -1 +1 @@ -!coverage.py: This is a private format, don't read it directly!{"lines":{"/home/dustin/development/python/pyinotify/inotify/library.py":[8,1,2,4,5],"/home/eohm/github/Elias481/PyInotify/inotify/adapters.py":[1,2,3,4,5,6,8,10,11,15,16,20,25,27,28,30,31,32,33,36,37,40,41,44,45,50,51,52,53,54,55,57,58,60,61,63,65,68,71,72,73,75,77,78,79,81,82,89,90,91,93,95,96,98,99,101,103,109,110,113,114,116,118,120,121,123,124,126,128,129,130,131,132,133,135,136,138,141,143,146,147,150,152,153,155,161,163,164,165,167,168,169,171,172,175,178,180,182,183,184,185,187,188,189,192,193,201,203,204,205,209,210,223,224,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,243,244,245,246,247,248,249,250,251,252,253,254,255,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393],"/home/eohm/github/Elias481/PyInotify/inotify/constants.py":[3,4,8,9,10,11,12,13,14,15,16,17,18,19,23,24,30,34,35,36,40,41,42,43,44,46,47,48,52,53,54,55,56,57,58,59,60,61,62,63,67,68,69,73,74,75,76,77],"/home/eohm/github/Elias481/PyInotify/inotify/calls.py":[1,2,4,6,8,11,12,18,25,32,33,37,39,40,41,43,45,46,47,49,51,52,53,55,56],"/home/dustin/development/python/pyinotify/inotify/calls.py":[1,2,4,6,8,11,12,18,25,32,33,37,39,40,41,43,45,46,47,49,51,52,53,55,56],"/home/eohm/github/Elias481/PyInotify/inotify/library.py":[1,2,4,5,8],"/home/eohm/github/Elias481/PyInotify/inotify/test_support.py":[1,2,3,4,5,7,9,11,13,14,16,17,19,21,22],"/home/dustin/development/python/pyinotify/inotify/constants.py":[3,4,8,9,10,11,12,13,14,15,16,17,18,19,23,24,30,34,35,36,40,41,42,43,44,46,47,48,52,53,54,55,56,57,58,59,60,61,62,63,67,68,69,73,74,75,76,77],"/home/eohm/github/Elias481/PyInotify/inotify/__init__.py":[1],"/home/dustin/development/python/pyinotify/inotify/test_support.py":[1,2,3,4,5,7,9,11,13,14,16,17,19,21,22],"/home/dustin/development/python/pyinotify/inotify/adapters.py":[1,2,3,4,5,6,8,10,11,15,16,20,22,23,25,26,27,28,31,32,35,36,39,40,41,42,43,44,46,47,49,51,53,56,59,60,61,63,65,66,67,69,70,72,73,75,76,78,84,85,88,89,91,92,93,95,97,98,99,100,101,102,104,105,107,110,112,115,117,118,121,123,124,126,132,134,135,136,138,139,141,142,145,148,150,152,153,154,161,162,163,165,170,171,172,176,177,191,194,195,196,197,199,200,201,202,204,208,209,210,216,217,219,221,230,231,232,234,235,238,239,242,245,247,250,252,253,256,259,261,264,265,267,268,269,271,273,275,276,278,280,281,282,283,285,287,288,289,292,294,295,298,299,301,302,303,305,307,308,310,312,313,314,315,317,319,327,328],"/home/dustin/development/python/pyinotify/inotify/__init__.py":[1]}} \ No newline at end of file +!coverage.py: This is a private format, don't read it directly!{"lines":{"/home/eohm/github/Elias481/PyInotify/inotify/calls.py":[1,2,4,6,8,11,12,13,14,16,18,25,32,33,34,35,37,39,40,41,43,45,46,47,49,51,52,53,55,56],"/home/dustin/development/python/pyinotify/inotify/adapters.py":[1,2,3,4,5,6,8,10,11,15,16,20,22,23,25,26,27,28,31,32,35,36,39,40,41,42,43,44,46,47,49,51,53,56,59,60,61,63,65,66,67,69,70,72,73,75,76,78,84,85,88,89,91,92,93,95,97,98,99,100,101,102,104,105,107,110,112,115,117,118,121,123,124,126,132,134,135,136,138,139,141,142,145,148,150,152,153,154,161,162,163,165,170,171,172,176,177,191,194,195,196,197,199,200,201,202,204,208,209,210,216,217,219,221,230,231,232,234,235,238,239,242,245,247,250,252,253,256,259,261,264,265,267,268,269,271,273,275,276,278,280,281,282,283,285,287,288,289,292,294,295,298,299,301,302,303,305,307,308,310,312,313,314,315,317,319,327,328],"/home/dustin/development/python/pyinotify/inotify/test_support.py":[1,2,3,4,5,7,9,11,13,14,16,17,19,21,22],"/home/eohm/github/Elias481/PyInotify/inotify/test_support.py":[1,2,3,4,5,7,9,11,13,14,16,17,19,21,22],"/home/eohm/github/Elias481/PyInotify/inotify/constants.py":[3,4,8,9,10,11,12,13,14,15,16,17,18,19,23,24,30,34,35,36,40,41,42,43,44,46,47,48,52,53,54,55,56,57,58,59,60,61,62,63,67,68,69,73,74,75,76,77],"/home/dustin/development/python/pyinotify/inotify/constants.py":[3,4,8,9,10,11,12,13,14,15,16,17,18,19,23,24,30,34,35,36,40,41,42,43,44,46,47,48,52,53,54,55,56,57,58,59,60,61,62,63,67,68,69,73,74,75,76,77],"/home/eohm/github/Elias481/PyInotify/inotify/__init__.py":[1],"/home/eohm/github/Elias481/PyInotify/inotify/library.py":[1,2,4,5,8],"/home/dustin/development/python/pyinotify/inotify/calls.py":[1,2,4,6,8,11,12,18,25,32,33,37,39,40,41,43,45,46,47,49,51,52,53,55,56],"/home/dustin/development/python/pyinotify/inotify/__init__.py":[1],"/home/dustin/development/python/pyinotify/inotify/library.py":[8,1,2,4,5],"/home/eohm/github/Elias481/PyInotify/inotify/adapters.py":[1,2,3,4,5,6,8,10,11,12,13,14,15,16,18,19,20,23,24,25,27,28,30,31,32,33,35,36,37,38,39,40,41,44,45,48,49,50,51,52,53,54,55,57,58,59,60,61,62,63,65,66,68,69,71,72,73,75,76,77,78,79,80,81,82,83,85,86,87,89,90,91,93,95,96,97,98,99,101,103,104,106,107,109,110,111,113,114,116,117,118,120,121,122,123,124,126,128,129,130,131,132,133,134,135,136,137,138,139,140,141,143,144,146,147,149,150,151,152,153,154,155,158,160,161,163,164,165,167,168,169,171,172,173,175,176,177,178,179,180,182,183,184,185,186,187,188,189,190,191,192,193,195,196,197,200,201,203,204,205,209,210,211,212,213,217,218,223,224,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,396,397,398,399]}} \ No newline at end of file diff --git a/inotify/adapters.py b/inotify/adapters.py index 2967cd6..222c7c4 100644 --- a/inotify/adapters.py +++ b/inotify/adapters.py @@ -5,6 +5,14 @@ import collections import time +if hasattr(os, 'scandir'): + from os import walk +else: + try: + from scandir import walk + except ImportError: + from os import walk + from errno import EINTR import inotify.constants @@ -340,21 +348,33 @@ def inotify(self): return self._i def _load_tree(self, path): + def filter_dirs_add_watches_gen(inotify, mask, dirpath, subdirs, ignored_subdirs): + for subdir in subdirs: + if subdir in ignored_subdirs: + continue + inotify.add_watch(os.path.join(dirpath, subdir), mask) + yield subdir + + inotify = self._i + mask = self._mask + inotify.add_watch(path, mask) ignored_dirs = self._ignored_dirs - for dirpath, subdirs, _f in os.walk(path): - self._i.add_watch(dirpath, self._mask) - ignored = ignored_dirs.get(dirpath) - if ignored: - subdirs[:] = (subdir for subdir in subdirs if subdir not in ignored) + + for dirpath, subdirs, _f in walk(path): + ignored_subdirs = ignored_dirs.get(dirpath) + if ignored_subdirs: + subdirs[:] = filter_dirs_add_watches_gen(inotify, mask, dirpath, subdirs, ignored_subdirs) + continue + for subdir in subdirs: + inotify.add_watch(os.path.join(dirpath, subdir), mask) class InotifyTree(_BaseTree): """Recursively watch a path.""" def __init__(self, path, mask=inotify.constants.IN_ALL_EVENTS, block_duration_s=_DEFAULT_EPOLL_BLOCK_DURATION_S, ignored_dirs=[]): - super(InotifyTree, self).__init__(mask=mask, block_duration_s=block_duration_s) - - self.__root_path = path + super(InotifyTree, self).__init__(mask=mask, block_duration_s=block_duration_s, + ignored_dirs=ignored_dirs) self.__load_tree(path) @@ -368,7 +388,8 @@ class InotifyTrees(_BaseTree): def __init__(self, paths, mask=inotify.constants.IN_ALL_EVENTS, block_duration_s=_DEFAULT_EPOLL_BLOCK_DURATION_S, ignored_dirs=[]): - super(InotifyTrees, self).__init__(mask=mask, block_duration_s=block_duration_s) + super(InotifyTrees, self).__init__(mask=mask, block_duration_s=block_duration_s, + ignored_dirs=ignored_dirs) self.__load_trees(paths) diff --git a/inotify/resources/README.rst b/inotify/resources/README.rst index 0ea801f..d636662 100644 --- a/inotify/resources/README.rst +++ b/inotify/resources/README.rst @@ -119,7 +119,9 @@ The other differences from the standard functionality: Notes ===== -- **IMPORTANT:** Recursively monitoring paths is **not** a functionality provided by the kernel. Rather, we artificially implement it. As directory-created events are received, we create watches for the child directories on-the-fly. This means that there is potential for a race condition: if a directory is created and a file or directory is created inside before you (using the `event_gen()` loop) have a chance to observe it, then you are going to have a problem: If it is a file, then you will miss the events related to its creation, but, if it is a directory, then not only will you miss those creation events but this library will also miss them and not be able to add a watch for them. If you are dealing with a **large number of hierarchical directory creations** and have the ability to be aware new directories via a secondary channel with some lead time before any files are populated *into* them, you can take advantage of this and call `add_watch()` manually. In this case there is limited value in using `InotifyTree()`/`InotifyTree()` instead of just `Inotify()` but this choice is left to you. +- **IMPORTANT:** Recursively monitoring paths is **not** a functionality provided by the kernel. Rather, we artificially implement it. As directory-created events are received, we create watches for the child directories on-the-fly. This means that there is potential for a race condition: if a directory is created and files or directorie are created inside before you (using the `event_gen()` loop) have a chance to observe it, then you are going to miss the events related to them up to the point in time the directory is registered by `event_gen()` loop. If you are dealing with a **large number of hierarchical directory creations** and have the ability to be aware new directories via a secondary channel with some lead time before any files are populated *into* them, you can take advantage of this and call `add_watch()` manually. In this case there would be limited value in using `InotifyTree()`/`InotifyTree()` instead of just `Inotify()` so `add_watch()` is not provided by `InotifyTree()`/`InotifyTree()`. + +- For best performance on recursive paths monitoring it is recommended to install *scandir* module if You are using a pre 3.5 Python. - *epoll* is used to audit for *inotify* kernel events. diff --git a/tests/test_inotify.py b/tests/test_inotify.py index 2d12192..1839741 100644 --- a/tests/test_inotify.py +++ b/tests/test_inotify.py @@ -231,28 +231,51 @@ def test__cycle(self): events = self.__read_all_events(i) if self._HAS_DIRECTORY_ACCESS_EVENTS: + expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, ''), + ] _access_dir_a = [ (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'aa'), + (inotify.adapters._INOTIFY_EVENT(wd=w2, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path1, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'aa'), + (inotify.adapters._INOTIFY_EVENT(wd=w2, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path1, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'aa'), + (inotify.adapters._INOTIFY_EVENT(wd=w2, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path1, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'aa'), + (inotify.adapters._INOTIFY_EVENT(wd=w2, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, ''), ] _access_dir_b = [ (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'bb'), + (inotify.adapters._INOTIFY_EVENT(wd=w3, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path2, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'bb'), + (inotify.adapters._INOTIFY_EVENT(wd=w3, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path2, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'bb'), + (inotify.adapters._INOTIFY_EVENT(wd=w3, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path2, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'bb'), + (inotify.adapters._INOTIFY_EVENT(wd=w3, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path2, ''), ] else: + expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, ''), + ] _access_dir_a = [ (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'aa'), + (inotify.adapters._INOTIFY_EVENT(wd=w2, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path1, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'aa'), + (inotify.adapters._INOTIFY_EVENT(wd=w2, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, ''), ] _access_dir_b = [ (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'bb'), + (inotify.adapters._INOTIFY_EVENT(wd=w3, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path2, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'bb'), + (inotify.adapters._INOTIFY_EVENT(wd=w3, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path2, ''), ] # we can't be sure about the order the watches were registered - expected = (_access_dir_a + _access_dir_b if w2 < w3 + expected += (_access_dir_a + _access_dir_b if w2 < w3 else _access_dir_b + _access_dir_a) expected += [ @@ -301,16 +324,28 @@ def test__renames(self): if self._HAS_DIRECTORY_ACCESS_EVENTS: expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path, 'old_folder'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'old_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], old_path, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'old_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], old_path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'old_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], old_path, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'old_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], old_path, ''), ] else: expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path, 'old_folder'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'old_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], old_path, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'old_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], old_path, ''), ] self.assertEquals(events1, expected) @@ -325,15 +360,22 @@ def test__renames(self): (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741888, cookie=events2[1][0].cookie, len=16), ['IN_MOVED_FROM', 'IN_ISDIR'], path, 'old_folder'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741952, cookie=events2[0][0].cookie, len=16), ['IN_MOVED_TO', 'IN_ISDIR'], path, 'new_folder'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], new_path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], new_path, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], new_path, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], new_path, ''), ] else: expected = [ (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741888, cookie=events2[1][0].cookie, len=16), ['IN_MOVED_FROM', 'IN_ISDIR'], path, 'old_folder'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741952, cookie=events2[0][0].cookie, len=16), ['IN_MOVED_TO', 'IN_ISDIR'], path, 'new_folder'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], new_path, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'new_folder'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], new_path, ''), ] self.assertEquals(events2, expected) @@ -385,16 +427,28 @@ def test__automatic_new_watches_on_new_paths(self): if self._HAS_DIRECTORY_ACCESS_EVENTS: expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path, 'folder1'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path1, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path1, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path1, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, ''), ] else: expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path, 'folder1'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path1, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, ''), ] self.assertEquals(events, expected) @@ -408,14 +462,21 @@ def test__automatic_new_watches_on_new_paths(self): expected = [ (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path1, 'folder2'), (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path2, ''), (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path2, ''), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path2, ''), (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path2, ''), ] else: expected = [ (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], path1, 'folder2'), (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path2, ''), (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path2, ''), ] self.assertEquals(events, expected) @@ -455,22 +516,41 @@ def test__automatic_new_watches_on_existing_paths(self): if self._HAS_DIRECTORY_ACCESS_EVENTS: expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path1, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path1, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path1, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, ''), (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path2, ''), (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path2, ''), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path2, ''), (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path2, ''), (inotify.adapters._INOTIFY_EVENT(wd=3, mask=256, cookie=0, len=16), ['IN_CREATE'], path2, 'filename'), (inotify.adapters._INOTIFY_EVENT(wd=3, mask=32, cookie=0, len=16), ['IN_OPEN'], path2, 'filename'), (inotify.adapters._INOTIFY_EVENT(wd=3, mask=8, cookie=0, len=16), ['IN_CLOSE_WRITE'], path2, 'filename'), ] else: expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path1, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'folder1'), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, ''), (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path2, ''), (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, 'folder2'), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path2, ''), (inotify.adapters._INOTIFY_EVENT(wd=3, mask=256, cookie=0, len=16), ['IN_CREATE'], path2, 'filename'), (inotify.adapters._INOTIFY_EVENT(wd=3, mask=32, cookie=0, len=16), ['IN_OPEN'], path2, 'filename'), (inotify.adapters._INOTIFY_EVENT(wd=3, mask=8, cookie=0, len=16), ['IN_CLOSE_WRITE'], path2, 'filename'), @@ -478,6 +558,92 @@ def test__automatic_new_watches_on_existing_paths(self): self.assertEquals(events, expected) + def test__exclude_subdirectories(self): + + # Tests whether the skip_dires parameter works as expected + + with inotify.test_support.temp_path() as path: + for foldernum1 in range(1,5): + path1 = os.path.join(path, 'folder%d' % foldernum1) + os.mkdir(path1) + for foldernum2 in range(1,5): + path2 = os.path.join(path1, 'subfolder%d' % foldernum2) + os.mkdir(path2) + for foldernum3 in range(1,3): + path3 = os.path.join(path2, 'subsubfolder%d' % foldernum3) + os.mkdir(path3) + + ignored_dirs = (os.path.join(path, 'folder1'), + os.path.join(path, 'folder2', 'subfolder2'), + os.path.join(path, 'folder2', 'subfolder3'), + os.path.join(path, 'folder2', 'subfolder4', 'subsubfolder2'), + os.path.join(path, 'folder3'), + os.path.join(path, 'folder4'), + ) + + expected_watches = (path, os.path.join(path, 'folder2'), + os.path.join(path, 'folder2', 'subfolder1'), + os.path.join(path, 'folder2', 'subfolder1', 'subsubfolder1'), + os.path.join(path, 'folder2', 'subfolder1', 'subsubfolder2'), + os.path.join(path, 'folder2', 'subfolder4'), + os.path.join(path, 'folder2', 'subfolder4', 'subsubfolder1'), + ) + + i = inotify.adapters.InotifyTree(path, ignored_dirs=ignored_dirs) + events = self.__read_all_events(i) + + watches = i._i._Inotify__watches + self.assertEquals(sorted(watches.keys()), sorted(expected_watches)) + + discovered_subdirs_expects = { path: [] } + + if self._HAS_DIRECTORY_ACCESS_EVENTS: + expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, ''), + ] + for dirpath, dirwd in sorted(watches.items(), key=lambda tup: tup[1])[1:]: + parentpath, dirname = os.path.split(dirpath) + parentwd = watches[parentpath] + expects = [ + (inotify.adapters._INOTIFY_EVENT(wd=parentwd, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], parentpath, dirname), + (inotify.adapters._INOTIFY_EVENT(wd=dirwd, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], dirpath, ''), + (inotify.adapters._INOTIFY_EVENT(wd=parentwd, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], parentpath, dirname), + (inotify.adapters._INOTIFY_EVENT(wd=dirwd, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], dirpath, ''), + (inotify.adapters._INOTIFY_EVENT(wd=parentwd, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], parentpath, dirname), + (inotify.adapters._INOTIFY_EVENT(wd=dirwd, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], dirpath, ''), + (inotify.adapters._INOTIFY_EVENT(wd=parentwd, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], parentpath, dirname), + (inotify.adapters._INOTIFY_EVENT(wd=dirwd, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], dirpath, ''), + ] + discovered_subdirs_expects[parentpath].append((dirpath, expects)) + discovered_subdirs_expects[dirpath] = [] + else: + expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, ''), + ] + for dirpath, dirwd in sorted(watches.items(), key=lambda tup: tup[1])[1:]: + parentpath, dirname = os.path.split(dirpath) + parentwd = watches[parentpath] + expects = [ + (inotify.adapters._INOTIFY_EVENT(wd=parentwd, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], parentpath, dirname), + (inotify.adapters._INOTIFY_EVENT(wd=dirwd, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], dirpath, ''), + (inotify.adapters._INOTIFY_EVENT(wd=parentwd, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], parentpath, dirname), + (inotify.adapters._INOTIFY_EVENT(wd=dirwd, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], dirpath, ''), + ] + discovered_subdirs_expects[parentpath].append((dirpath, expects)) + discovered_subdirs_expects[dirpath] = [] + + for dirpath, expects in discovered_subdirs_expects[path]: + expected += expects + for dirpath, expects in discovered_subdirs_expects[dirpath]: + expected += expects + for dirpath, expects in discovered_subdirs_expects[dirpath]: + expected += expects + + self.assertEquals(events, expected) + class TestInotifyTrees(unittest.TestCase): def __init__(self, *args, **kwargs): @@ -485,6 +651,11 @@ def __init__(self, *args, **kwargs): super(TestInotifyTrees, self).__init__(*args, **kwargs) + @classmethod + def setUpClass(cls): + global _HAS_DIRECTORY_ACCESS_EVENTS + cls._HAS_DIRECTORY_ACCESS_EVENTS = _HAS_DIRECTORY_ACCESS_EVENTS + def __read_all_events(self, i): events = list(i.event_gen(timeout_s=1, yield_nones=False)) return events @@ -507,7 +678,24 @@ def test__cycle(self): events = self.__read_all_events(i) - expected = [ + if self._HAS_DIRECTORY_ACCESS_EVENTS: + expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path1, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path1, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, ''), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path2, ''), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], path2, ''), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path2, ''), + ] + else: + expected = [ + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path1, ''), + (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path1, ''), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], path2, ''), + (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path2, ''), + ] + + expected += [ (inotify.adapters._INOTIFY_EVENT(wd=1, mask=256, cookie=0, len=16), ['IN_CREATE'], path1, 'seen_new_file1'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=32, cookie=0, len=16), ['IN_OPEN'], path1, 'seen_new_file1'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=8, cookie=0, len=16), ['IN_CLOSE_WRITE'], path1, 'seen_new_file1'), From 2fe0df69af7531ba4440a25785be772827ebcdb3 Mon Sep 17 00:00:00 2001 From: Elias Ohm Date: Sat, 22 Sep 2018 03:12:21 +0200 Subject: [PATCH 10/10] fixed test... (sadly there is currently some duplication of code "needed" and missed to fix the "trusty" (v4 kernel?) version) --- tests/test_inotify.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_inotify.py b/tests/test_inotify.py index 1839741..028cb74 100644 --- a/tests/test_inotify.py +++ b/tests/test_inotify.py @@ -360,13 +360,13 @@ def test__renames(self): (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741888, cookie=events2[1][0].cookie, len=16), ['IN_MOVED_FROM', 'IN_ISDIR'], path, 'old_folder'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741952, cookie=events2[0][0].cookie, len=16), ['IN_MOVED_TO', 'IN_ISDIR'], path, 'new_folder'), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], path, 'new_folder'), - (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], new_path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741856, cookie=0, len=0), ['IN_ISDIR', 'IN_OPEN'], new_path, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'new_folder'), - (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], new_path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], new_path, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741825, cookie=0, len=16), ['IN_ACCESS', 'IN_ISDIR'], path, 'new_folder'), - (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], new_path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741825, cookie=0, len=0), ['IN_ACCESS', 'IN_ISDIR'], new_path, ''), (inotify.adapters._INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], path, 'new_folder'), - (inotify.adapters._INOTIFY_EVENT(wd=2, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], new_path, ''), + (inotify.adapters._INOTIFY_EVENT(wd=3, mask=1073741840, cookie=0, len=0), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], new_path, ''), ] else: expected = [