diff --git a/src/lib.rs b/src/lib.rs index febaa3b..295046a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,7 +122,12 @@ impl RustNotify { CHANGE_MODIFIED } } - EventKind::Modify(ModifyKind::Name(RenameMode::Both)) => CHANGE_MOVED, + EventKind::Modify(ModifyKind::Name(RenameMode::From)) => CHANGE_DELETED, + EventKind::Modify(ModifyKind::Name(RenameMode::Both)) => { + let mut changes = changes_clone.lock().unwrap(); + changes.remove(&(CHANGE_DELETED, path.clone(), EMPTY_STRING)); + CHANGE_MOVED + } EventKind::Remove(_) => CHANGE_DELETED, _ => return, }; diff --git a/tests/test_docs.py b/tests/test_docs.py index 1c0b141..ba38fba 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -81,7 +81,7 @@ def generate_code_chunks(*directories: str): @pytest.mark.filterwarnings('ignore:The loop argument is deprecated:DeprecationWarning') @pytest.mark.parametrize('module_name,source_code', generate_code_chunks('watchfiles', 'docs')) def test_docs_examples(module_name, source_code, import_execute, mocker, mock_rust_notify: 'MockRustType'): - mock_rust_notify([{(1, 'foo.txt'), (2, 'bar.py')}]) + mock_rust_notify([{(1, 'foo.txt', ''), (2, 'bar.py', '')}]) mocker.patch('watchfiles.run.spawn_context.Process') mocker.patch('watchfiles.run.os.kill') diff --git a/tests/test_filters.py b/tests/test_filters.py index 98427b8..249ad44 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -13,29 +13,29 @@ def test_ignore_file(mock_rust_notify: 'MockRustType'): - mock = mock_rust_notify([{(1, 'spam.pyc'), (1, 'spam.swp'), (1, 'foo.txt')}]) + mock = mock_rust_notify([{(1, 'spam.pyc', ''), (1, 'spam.swp', ''), (1, 'foo.txt', '')}]) - assert next(watch('.')) == {(Change.added, 'foo.txt')} + assert next(watch('.')) == {(Change.added, 'foo.txt', '')} assert mock.watch_count == 1 def test_ignore_dir(mock_rust_notify: 'MockRustType'): - mock_rust_notify([{(1, '.git'), (1, str(Path('.git') / 'spam')), (1, 'foo.txt')}]) + mock_rust_notify([{(1, '.git', ''), (1, str(Path('.git') / 'spam'), ''), (1, 'foo.txt', '')}]) - assert next(watch('.')) == {(Change.added, 'foo.txt')} + assert next(watch('.')) == {(Change.added, 'foo.txt', '')} def test_python(mock_rust_notify: 'MockRustType'): - mock_rust_notify([{(2, 'spam.txt'), (2, 'spam.md'), (2, 'foo.py')}]) + mock_rust_notify([{(2, 'spam.txt', ''), (2, 'spam.md', ''), (2, 'foo.py', '')}]) - assert next(watch('.', watch_filter=PythonFilter())) == {(Change.modified, 'foo.py')} + assert next(watch('.', watch_filter=PythonFilter())) == {(Change.modified, 'foo.py', '')} def test_python_extensions(mock_rust_notify: 'MockRustType'): - mock_rust_notify([{(1, 'spam.txt'), (1, 'spam.md'), (1, 'foo.py')}]) + mock_rust_notify([{(1, 'spam.txt', ''), (1, 'spam.md', ''), (1, 'foo.py', '')}]) f = PythonFilter(extra_extensions=('.md',)) - assert next(watch('.', watch_filter=f)) == {(Change.added, 'foo.py'), (Change.added, 'spam.md')} + assert next(watch('.', watch_filter=f)) == {(Change.added, 'foo.py', ''), (Change.added, 'spam.md', '')} def test_web_filter(mock_rust_notify: 'MockRustType'): @@ -47,18 +47,18 @@ class WebFilter(DefaultFilter): def __call__(self, change: Change, path: str) -> bool: return super().__call__(change, path) and path.endswith(self.allowed_extensions) - mock_rust_notify([{(1, 'foo.txt'), (2, 'bar.html'), (3, 'spam.xlsx'), (1, '.other.js')}]) + mock_rust_notify([{(1, 'foo.txt', ''), (2, 'bar.html', ''), (3, 'spam.xlsx', ''), (1, '.other.js', '')}]) - assert next(watch('.', watch_filter=WebFilter())) == {(Change.modified, 'bar.html'), (Change.added, '.other.js')} + assert next(watch('.', watch_filter=WebFilter())) == {(Change.modified, 'bar.html', ''), (Change.added, '.other.js', '')} def test_simple_function(mock_rust_notify: 'MockRustType'): - mock_rust_notify([{(1, 'added.txt'), (2, 'mod.txt'), (3, 'del.txt')}]) + mock_rust_notify([{(1, 'added.txt', ''), (2, 'mod.txt', ''), (3, 'del.txt', '')}]) def only_added(change: Change, path: str) -> bool: return change == Change.added - assert next(watch('.', watch_filter=only_added)) == {(Change.added, 'added.txt')} + assert next(watch('.', watch_filter=only_added)) == {(Change.added, 'added.txt', '')} @pytest.mark.parametrize( diff --git a/tests/test_run_process.py b/tests/test_run_process.py index 889f18b..9e0d1c4 100644 --- a/tests/test_run_process.py +++ b/tests/test_run_process.py @@ -45,7 +45,7 @@ def test_alive_terminates(mocker, mock_rust_notify: 'MockRustType', caplog): mock_spawn_process = mocker.patch('watchfiles.run.spawn_context.Process', return_value=FakeProcess()) mock_popen = mocker.patch('watchfiles.run.subprocess.Popen', return_value=FakePopen()) mock_kill = mocker.patch('watchfiles.run.os.kill') - mock_rust_notify([{(1, '/path/to/foobar.py')}]) + mock_rust_notify([{(1, '/path/to/foobar.py', '')}]) assert run_process('/x/y/z', target=os.getcwd, debounce=5, step=1) == 1 assert mock_spawn_process.call_count == 2 @@ -57,7 +57,7 @@ def test_alive_terminates(mocker, mock_rust_notify: 'MockRustType', caplog): def test_dead_callback(mocker, mock_rust_notify: 'MockRustType'): mock_spawn_process = mocker.patch('watchfiles.run.spawn_context.Process', return_value=FakeProcess(is_alive=False)) mock_kill = mocker.patch('watchfiles.run.os.kill') - mock_rust_notify([{(1, '/path/to/foobar.py')}, {(1, '/path/to/foobar.py')}]) + mock_rust_notify([{(1, '/path/to/foobar.py', '')}, {(1, '/path/to/foobar.py', '')}]) c = mocker.MagicMock() @@ -65,7 +65,7 @@ def test_dead_callback(mocker, mock_rust_notify: 'MockRustType'): assert mock_spawn_process.call_count == 3 assert mock_kill.call_count == 0 assert c.call_count == 2 - c.assert_called_with({(Change.added, '/path/to/foobar.py')}) + c.assert_called_with({(Change.added, '/path/to/foobar.py', '')}) @pytest.mark.skipif(sys.platform != 'win32', reason='no need to test this except on windows') @@ -85,7 +85,7 @@ def test_split_cmd_posix(): def test_alive_doesnt_terminate(mocker, mock_rust_notify: 'MockRustType'): mock_spawn_process = mocker.patch('watchfiles.run.spawn_context.Process', return_value=FakeProcess(exitcode=None)) mock_kill = mocker.patch('watchfiles.run.os.kill') - mock_rust_notify([{(1, '/path/to/foobar.py')}]) + mock_rust_notify([{(1, '/path/to/foobar.py', '')}]) assert run_process('/x/y/z', target=object(), debounce=5, step=1) == 1 assert mock_spawn_process.call_count == 2 @@ -104,7 +104,7 @@ def test_sigint_timeout(mocker, mock_rust_notify: 'MockRustType', caplog): mock_spawn_process = mocker.patch('watchfiles.run.spawn_context.Process', return_value=FakeProcessTimeout()) mock_kill = mocker.patch('watchfiles.run.os.kill') - mock_rust_notify([{(1, '/path/to/foobar.py')}]) + mock_rust_notify([{(1, '/path/to/foobar.py', '')}]) assert run_process('/x/y/z', target=object(), debounce=5, step=1, sigint_timeout='sigint_timeout') == 1 assert mock_spawn_process.call_count == 2 @@ -124,18 +124,18 @@ def test_start_process(mocker): def test_start_process_env(mocker): mock_process = mocker.patch('watchfiles.run.spawn_context.Process') v = object() - changes = [(Change.added, 'a.py'), (Change.modified, 'b.py'), (Change.deleted, 'c.py')] # use a list to keep order + changes = [(Change.added, 'a.py', ''), (Change.modified, 'b.py', ''), (Change.deleted, 'c.py', '')] # use a list to keep order start_process(v, 'function', (1, 2, 3), {}, changes) assert mock_process.call_count == 1 mock_process.assert_called_with(target=v, args=(1, 2, 3), kwargs={}) - assert os.getenv('WATCHFILES_CHANGES') == '[["added", "a.py"], ["modified", "b.py"], ["deleted", "c.py"]]' + assert os.getenv('WATCHFILES_CHANGES') == '[["added", "a.py", ""], ["modified", "b.py", ""], ["deleted", "c.py", ""]]' def test_function_string_not_win(mocker, mock_rust_notify: 'MockRustType', caplog): caplog.set_level('DEBUG', 'watchfiles') mock_spawn_process = mocker.patch('watchfiles.run.spawn_context.Process', return_value=FakeProcess()) mocker.patch('watchfiles.run.os.kill') - mock_rust_notify([{(1, '/path/to/foobar.py')}]) + mock_rust_notify([{(1, '/path/to/foobar.py', '')}]) assert run_process('/x/y/z', target='os.getcwd', debounce=5, step=1) == 1 assert mock_spawn_process.call_count == 2 @@ -150,7 +150,7 @@ def test_function_string_not_win(mocker, mock_rust_notify: 'MockRustType', caplo def test_function_list(mocker, mock_rust_notify: 'MockRustType'): mock_spawn_process = mocker.patch('watchfiles.run.spawn_context.Process', return_value=FakeProcess()) mock_kill = mocker.patch('watchfiles.run.os.kill') - mock_rust_notify([{(1, '/path/to/foobar.py')}]) + mock_rust_notify([{(1, '/path/to/foobar.py', '')}]) assert run_process('/x/y/z', target=['os.getcwd'], debounce=5, step=1) == 1 assert mock_spawn_process.call_count == 2 @@ -160,7 +160,7 @@ def test_function_list(mocker, mock_rust_notify: 'MockRustType'): async def test_async_alive_terminates(mocker, mock_rust_notify: 'MockRustType'): mock_spawn_process = mocker.patch('watchfiles.run.spawn_context.Process', return_value=FakeProcess()) mock_kill = mocker.patch('watchfiles.run.os.kill') - mock_rust_notify([{(1, '/path/to/foobar.py')}]) + mock_rust_notify([{(1, '/path/to/foobar.py', '')}]) callback_calls = [] @@ -170,13 +170,13 @@ async def c(changes): assert await arun_process('/x/y/async', target=object(), callback=c, debounce=5, step=1) == 1 assert mock_spawn_process.call_count == 2 assert mock_kill.call_count == 2 # kill in loop + final kill - assert callback_calls == [{(Change.added, '/path/to/foobar.py')}] + assert callback_calls == [{(Change.added, '/path/to/foobar.py', '')}] async def test_async_sync_callback(mocker, mock_rust_notify: 'MockRustType'): mock_spawn_process = mocker.patch('watchfiles.run.spawn_context.Process', return_value=FakeProcess()) mock_kill = mocker.patch('watchfiles.run.os.kill') - mock_rust_notify([{(1, '/path/to/foo.py')}, {(2, '/path/to/bar.py')}]) + mock_rust_notify([{(1, '/path/to/foo.py', '')}, {(2, '/path/to/bar.py', '')}]) callback_calls = [] @@ -188,7 +188,7 @@ async def test_async_sync_callback(mocker, mock_rust_notify: 'MockRustType'): ) assert mock_spawn_process.call_count == 3 assert mock_kill.call_count == 3 - assert callback_calls == [{(Change.added, '/path/to/foo.py')}, {(Change.modified, '/path/to/bar.py')}] + assert callback_calls == [{(Change.added, '/path/to/foo.py', '')}, {(Change.modified, '/path/to/bar.py', '')}] def test_run_function(tmp_work_path: Path, create_test_function): @@ -227,7 +227,7 @@ def test_command(mocker, mock_rust_notify: 'MockRustType', caplog): mock_spawn_process = mocker.patch('watchfiles.run.spawn_context.Process', return_value=FakeProcess()) mock_popen = mocker.patch('watchfiles.run.subprocess.Popen', return_value=FakePopen()) mock_kill = mocker.patch('watchfiles.run.os.kill') - mock_rust_notify([{(1, '/path/to/foobar.py')}]) + mock_rust_notify([{(1, '/path/to/foobar.py', '')}]) assert run_process('/x/y/z', target='echo foobar', debounce=5, step=1) == 1 assert mock_spawn_process.call_count == 0 @@ -242,7 +242,7 @@ def test_command_with_args(mocker, mock_rust_notify: 'MockRustType', caplog): mock_spawn_process = mocker.patch('watchfiles.run.spawn_context.Process', return_value=FakeProcess()) mock_popen = mocker.patch('watchfiles.run.subprocess.Popen', return_value=FakePopen()) mock_kill = mocker.patch('watchfiles.run.os.kill') - mock_rust_notify([{(1, '/path/to/foobar.py')}]) + mock_rust_notify([{(1, '/path/to/foobar.py', '')}]) assert run_process('/x/y/z', target='echo foobar', args=(1, 2), target_type='command', debounce=5, step=1) == 1 assert mock_spawn_process.call_count == 0 diff --git a/tests/test_rust_notify.py b/tests/test_rust_notify.py index dbd0668..9e2bf8a 100644 --- a/tests/test_rust_notify.py +++ b/tests/test_rust_notify.py @@ -13,7 +13,7 @@ def test_add(test_dir: Path): watcher = RustNotify([str(test_dir)], True, False, 0, True) (test_dir / 'new_file.txt').write_text('foobar') - assert watcher.watch(200, 50, 500, None) == {(1, str(test_dir / 'new_file.txt'))} + assert watcher.watch(200, 50, 500, None) == {(1, str(test_dir / 'new_file.txt'), '')} def test_add_non_recursive(test_dir: Path): @@ -22,7 +22,7 @@ def test_add_non_recursive(test_dir: Path): (test_dir / 'new_file_non_recursive.txt').write_text('foobar') (test_dir / 'dir_a' / 'new_file_non_recursive.txt').write_text('foobar') - assert watcher.watch(200, 50, 500, None) == {(1, str(test_dir / 'new_file_non_recursive.txt'))} + assert watcher.watch(200, 50, 500, None) == {(1, str(test_dir / 'new_file_non_recursive.txt'), '')} def test_close(test_dir: Path): @@ -41,7 +41,7 @@ def test_modify_write(test_dir: Path): (test_dir / 'a.txt').write_text('this is new') - assert watcher.watch(200, 50, 500, None) == {(2, str(test_dir / 'a.txt'))} + assert watcher.watch(200, 50, 500, None) == {(2, str(test_dir / 'a.txt'), '')} def test_modify_write_non_recursive(test_dir: Path): @@ -51,7 +51,7 @@ def test_modify_write_non_recursive(test_dir: Path): (test_dir / 'dir_a' / 'a_non_recursive.txt').write_text('this is new') assert watcher.watch(200, 50, 500, None) == { - (2, str(test_dir / 'a_non_recursive.txt')), + (2, str(test_dir / 'a_non_recursive.txt'), ''), } @@ -61,7 +61,7 @@ def test_modify_chmod(test_dir: Path): (test_dir / 'b.txt').chmod(0o444) - assert watcher.watch(200, 50, 500, None) == {(2, str(test_dir / 'b.txt'))} + assert watcher.watch(200, 50, 500, None) == {(2, str(test_dir / 'b.txt'), '')} def test_delete(test_dir: Path): @@ -70,7 +70,7 @@ def test_delete(test_dir: Path): (test_dir / 'c.txt').unlink() assert watcher.watch(200, 50, 500, None) == { - (3, str(test_dir / 'c.txt')), + (3, str(test_dir / 'c.txt'), ''), } @@ -81,7 +81,7 @@ def test_delete_non_recursive(test_dir: Path): (test_dir / 'dir_a' / 'c_non_recursive.txt').unlink() assert watcher.watch(200, 50, 500, None) == { - (3, str(test_dir / 'c_non_recursive.txt')), + (3, str(test_dir / 'c_non_recursive.txt'), ''), } @@ -99,8 +99,8 @@ def test_move_in(test_dir: Path): (src / f).rename(dst / f) assert watcher.watch(200, 50, 500, None) == { - (1, str(dst / 'a.txt')), - (1, str(dst / 'b.txt')), + (1, str(dst / 'a.txt'), ''), + (1, str(dst / 'b.txt'), ''), } @@ -116,8 +116,8 @@ def test_move_out(test_dir: Path): (src / f).rename(dst / f) assert watcher.watch(200, 50, 500, None) == { - (3, str(src / 'c.txt')), - (3, str(src / 'd.txt')), + (3, str(src / 'c.txt'), ''), + (3, str(src / 'd.txt'), ''), } @@ -133,14 +133,12 @@ def test_move_internal(test_dir: Path): (src / f).rename(dst / f) expected_changes = { - (3, str(src / 'e.txt')), - (3, str(src / 'f.txt')), - (1, str(dst / 'e.txt')), - (1, str(dst / 'f.txt')), + (4, str(src / 'e.txt'), str(dst / 'e.txt')), + (4, str(src / 'f.txt'), str(dst / 'f.txt')), } if sys.platform == 'win32': # Windows adds a "modified" event for the dst directory - expected_changes.add((2, str(dst))) + expected_changes.add((2, str(dst), '')) assert watcher.watch(200, 50, 500, None) == expected_changes @@ -158,8 +156,7 @@ def test_rename(test_dir: Path): f.rename(f.with_suffix('.new')) assert watcher.watch(200, 50, 500, None) == { - (3, str(f)), - (1, str(test_dir / 'a.new')), + (4, str(f), str(test_dir / 'a.new')), } @@ -176,9 +173,9 @@ def test_watch_multiple(tmp_path: Path): changes = watcher.watch(200, 50, 500, None) # can compare directly since on macos creating the foo and bar directories is included in changes - assert (1, str(foo / 'foo.txt')) in changes - assert (1, str(bar / 'foo.txt')) in changes - assert not any('not_included.txt' in p for c, p in changes) + assert (1, str(foo / 'foo.txt'), '') in changes + assert (1, str(bar / 'foo.txt'), '') in changes + assert not any('not_included.txt' in p for c, p, p2 in changes) def test_wrong_type_event(test_dir: Path, time_taken): @@ -235,7 +232,7 @@ def test_return_debounce_no_timeout(test_dir: Path, time_taken): (test_dir / 'debounce.txt').write_text('foobar') with time_taken(50, 130): - assert watcher.watch(100, 50, 20, None) == {(1, str(test_dir / 'debounce.txt'))} + assert watcher.watch(100, 50, 20, None) == {(1, str(test_dir / 'debounce.txt'), '')} @skip_unless_linux @@ -260,12 +257,9 @@ def test_rename_multiple_inside(tmp_path: Path): f3.rename(d2 / '3.txt') assert watcher_all.watch(200, 50, 500, None) == { - (3, str(f1)), - (3, str(f2)), - (3, str(f3)), - (1, str(d2 / '1.txt')), - (1, str(d2 / '2.txt')), - (1, str(d2 / '3.txt')), + (4, str(f1), str(d2 / '1.txt')), + (4, str(f2), str(d2 / '2.txt')), + (4, str(f3), str(d2 / '3.txt')), } @@ -275,7 +269,7 @@ def test_polling(test_dir: Path): (test_dir / 'test_polling.txt').write_text('foobar') changes = watcher.watch(200, 50, 500, None) - assert (1, str(test_dir / 'test_polling.txt')) in changes # sometimes has an event modify too + assert (1, str(test_dir / 'test_polling.txt'), '') in changes # sometimes has an event modify too def test_not_polling_repr(test_dir: Path): diff --git a/tests/test_watch.py b/tests/test_watch.py index 2fdbc20..cdfd98e 100644 --- a/tests/test_watch.py +++ b/tests/test_watch.py @@ -22,7 +22,7 @@ def test_watch(tmp_path: Path, write_soon): for changes in watch(tmp_path, debounce=50, step=10, watch_filter=None): break - assert changes == {(Change.added, str((tmp_path / 'foo.txt')))} + assert changes == {(Change.added, str((tmp_path / 'foo.txt')), '')} def test_wait_stop_event(tmp_path: Path, write_soon): @@ -31,7 +31,7 @@ def test_wait_stop_event(tmp_path: Path, write_soon): stop_event = threading.Event() for changes in watch(tmp_path, debounce=50, step=10, watch_filter=None, stop_event=stop_event): - assert changes == {(Change.added, str((tmp_path / 'foo.txt')))} + assert changes == {(Change.added, str((tmp_path / 'foo.txt')), '')} stop_event.set() @@ -39,7 +39,7 @@ async def test_awatch(tmp_path: Path, write_soon): sleep(0.05) write_soon(tmp_path / 'foo.txt') async for changes in awatch(tmp_path, debounce=50, step=10, watch_filter=None): - assert changes == {(Change.added, str((tmp_path / 'foo.txt')))} + assert changes == {(Change.added, str((tmp_path / 'foo.txt')), '')} break @@ -49,25 +49,25 @@ async def test_await_stop_event(tmp_path: Path, write_soon): write_soon(tmp_path / 'foo.txt') stop_event = anyio.Event() async for changes in awatch(tmp_path, debounce=50, step=10, watch_filter=None, stop_event=stop_event): - assert changes == {(Change.added, str((tmp_path / 'foo.txt')))} + assert changes == {(Change.added, str((tmp_path / 'foo.txt')), '')} stop_event.set() def test_watch_raise_interrupt(mock_rust_notify: 'MockRustType'): - mock_rust_notify([{(1, 'foo.txt')}], exit_code='signal') + mock_rust_notify([{(1, 'foo.txt', '')}], exit_code='signal') w = watch('.', raise_interrupt=True) - assert next(w) == {(Change.added, 'foo.txt')} + assert next(w) == {(Change.added, 'foo.txt', '')} with pytest.raises(KeyboardInterrupt): next(w) def test_watch_dont_raise_interrupt(mock_rust_notify: 'MockRustType', caplog): caplog.set_level('WARNING', 'watchfiles') - mock_rust_notify([{(1, 'foo.txt')}], exit_code='signal') + mock_rust_notify([{(1, 'foo.txt', '')}], exit_code='signal') w = watch('.', raise_interrupt=False) - assert next(w) == {(Change.added, 'foo.txt')} + assert next(w) == {(Change.added, 'foo.txt', '')} with pytest.raises(StopIteration): next(w) @@ -83,7 +83,7 @@ async def signals(): async def test_awatch_unexpected_signal(mock_rust_notify: 'MockRustType'): - mock_rust_notify([{(1, 'foo.txt')}], exit_code='signal') + mock_rust_notify([{(1, 'foo.txt', '')}], exit_code='signal') count = 0 with pytest.raises(RuntimeError, match='watch thread unexpectedly received a signal'): @@ -94,7 +94,7 @@ async def test_awatch_unexpected_signal(mock_rust_notify: 'MockRustType'): async def test_awatch_interrupt_warning(mock_rust_notify: 'MockRustType', caplog): - mock_rust_notify([{(1, 'foo.txt')}]) + mock_rust_notify([{(1, 'foo.txt', '')}]) count = 0 with pytest.warns(DeprecationWarning, match='raise_interrupt is deprecated, KeyboardInterrupt will cause this'): @@ -105,78 +105,78 @@ async def test_awatch_interrupt_warning(mock_rust_notify: 'MockRustType', caplog def test_watch_no_yield(mock_rust_notify: 'MockRustType', caplog): - mock = mock_rust_notify([{(1, 'spam.pyc')}, {(1, 'spam.py'), (2, 'ham.txt')}]) + mock = mock_rust_notify([{(1, 'spam.pyc', '')}, {(1, 'spam.py', ''), (2, 'ham.txt', '')}]) caplog.set_level('INFO', 'watchfiles') - assert next(watch('.')) == {(Change.added, 'spam.py'), (Change.modified, 'ham.txt')} + assert next(watch('.')) == {(Change.added, 'spam.py', ''), (Change.modified, 'ham.txt', '')} assert mock.watch_count == 2 assert caplog.text == 'watchfiles.main INFO: 2 changes detected\n' async def test_awatch_no_yield(mock_rust_notify: 'MockRustType', caplog): - mock = mock_rust_notify([{(1, 'spam.pyc')}, {(1, 'spam.py')}]) + mock = mock_rust_notify([{(1, 'spam.pyc', '')}, {(1, 'spam.py', '')}]) caplog.set_level('DEBUG', 'watchfiles') changes = None async for changes in awatch('.'): pass - assert changes == {(Change.added, 'spam.py')} + assert changes == {(Change.added, 'spam.py', '')} assert mock.watch_count == 2 - assert caplog.text == "watchfiles.main DEBUG: 1 change detected: {(, 'spam.py')}\n" + assert caplog.text == "watchfiles.main DEBUG: 1 change detected: {(, 'spam.py', '')}\n" def test_watch_timeout(mock_rust_notify: 'MockRustType', caplog): - mock = mock_rust_notify(['timeout', {(1, 'spam.py')}]) + mock = mock_rust_notify(['timeout', {(1, 'spam.py', '')}]) caplog.set_level('DEBUG', 'watchfiles') change_list = [] for changes in watch('.'): change_list.append(changes) - assert change_list == [{(Change.added, 'spam.py')}] + assert change_list == [{(Change.added, 'spam.py', '')}] assert mock.watch_count == 2 assert caplog.text == ( "watchfiles.main DEBUG: rust notify timeout, continuing\n" # noqa: Q000 - "watchfiles.main DEBUG: 1 change detected: {(, 'spam.py')}\n" + "watchfiles.main DEBUG: 1 change detected: {(, 'spam.py', '')}\n" ) def test_watch_yield_on_timeout(mock_rust_notify: 'MockRustType'): - mock = mock_rust_notify(['timeout', {(1, 'spam.py')}]) + mock = mock_rust_notify(['timeout', {(1, 'spam.py', '')}]) change_list = [] for changes in watch('.', yield_on_timeout=True): change_list.append(changes) - assert change_list == [set(), {(Change.added, 'spam.py')}] + assert change_list == [set(), {(Change.added, 'spam.py', '')}] assert mock.watch_count == 2 async def test_awatch_timeout(mock_rust_notify: 'MockRustType', caplog): - mock = mock_rust_notify(['timeout', {(1, 'spam.py')}]) + mock = mock_rust_notify(['timeout', {(1, 'spam.py', '')}]) caplog.set_level('DEBUG', 'watchfiles') change_list = [] async for changes in awatch('.'): change_list.append(changes) - assert change_list == [{(Change.added, 'spam.py')}] + assert change_list == [{(Change.added, 'spam.py', '')}] assert mock.watch_count == 2 assert caplog.text == ( "watchfiles.main DEBUG: rust notify timeout, continuing\n" # noqa: Q000 - "watchfiles.main DEBUG: 1 change detected: {(, 'spam.py')}\n" + "watchfiles.main DEBUG: 1 change detected: {(, 'spam.py', '')}\n" ) async def test_awatch_yield_on_timeout(mock_rust_notify: 'MockRustType'): - mock = mock_rust_notify(['timeout', {(1, 'spam.py')}]) + mock = mock_rust_notify(['timeout', {(1, 'spam.py', '')}]) change_list = [] async for changes in awatch('.', yield_on_timeout=True): change_list.append(changes) - assert change_list == [set(), {(Change.added, 'spam.py')}] + assert change_list == [set(), {(Change.added, 'spam.py', '')}] assert mock.watch_count == 2 @@ -200,7 +200,7 @@ def watch(self, *args): if self.i == 1: raise KeyboardInterrupt('test error') self.i += 1 - return {(Change.added, 'spam.py')} + return {(Change.added, 'spam.py', '')} def __enter__(self): return self diff --git a/watchfiles/run.py b/watchfiles/run.py index 22bd4f0..34fb6e5 100644 --- a/watchfiles/run.py +++ b/watchfiles/run.py @@ -236,7 +236,7 @@ def start_process( if changes is None: changes_env_var = '[]' else: - changes_env_var = json.dumps([[c.raw_str(), p] for c, p in changes]) + changes_env_var = json.dumps([[c.raw_str(), p, p2] for c, p, p2 in changes]) os.environ['WATCHFILES_CHANGES'] = changes_env_var