-
-
Notifications
You must be signed in to change notification settings - Fork 704
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Modified files trigger more than one event on Python 3 #346
Comments
Same here. |
What's your OS environment? (ex: Ubuntu/Archlinux) |
Mac OS X 10.11.4, Python 3.5.1 |
Windows 8.1, Python 3.5 Windows Vista, Python 3.4 |
Mac OS X 10.10.5, Python 3.5.1 |
CentOS Linux release 7.3.1611 (Core) |
Win 10x64, Python 3.6.5 |
Win 7x64, Python 3.6.4 |
If someone wants to help, we will be very greatful :) |
Does this happen in python 3.7 to anyone? |
I experience this in on_any_event) in a conditional block that checks if the instance is a FileModifiedEvent or a FileCreatedEvent I open up the file I want to edit and type a word. When I hit save on the file it generates 4 events. |
Having this bug as well, I'm on Ubuntu. I found that creating a file in the watched directory generates the following: And copying the same file to the directory while the file already exists generates anywhere from three to four FileModifiedEvents:
|
I experienced the exact same problem where the FileModifiedEvent executed twice. So my walkaround was this:
From the code above,
I hope someone finds this useful. |
I had the same issue, and worked around it in two different ways:
I'm not sure what other people are using it for, but I found the creation event triggering too fast for my needs, it was triggering at the point where the filesystem allocated a dentry, but well before the file contents had been written out, which was a bit counterintuitive.
The rest of Hope this ends up saving someone some time! |
Hi all, Sorry but the two workarounds do not work for me. What I did find is that the The
To answer pmundt about creation event triggering too fast, I use the following code:
|
I am using Python 3.6 on Ubuntu 16.04, and having similar issues. On overwriting a file, two file creation events are registered, both ~ 1/1000 second apart. I have attempted to use both a class property queue and global variables inside the class to append events and read them, as well as counter and dict objects with datetime + src_path keys. While I print out events as they come in, which shows both events registered, when I print out the queue, most of the time it shows only a single item. So far, it has shown two items in this queue a single time out of all attempts; the next run, without modifying the code, it goes back to a single item. I am also running this inside a docker container, Docker version 20.10.6, build 370c289. Docker image is running Ubuntu 16.04 as well. Given the inconsistency, this feels like a low level problem. |
@cdesilv1 , do you have try to do similar test with subfolder? If someone can put me in the right location in the main code. I can try to correct the problem.. |
i think the root cause of a lot of bugs is that you'll get a FileModificationEvent when the access time is updated. |
Thanks @mmattklaus I adapted your solution and it works for me. last_trigger_time = time.time()
class MyFileSystemEventHandler(FileSystemEventHandler):
def on_modified(self, event):
global last_trigger_time
current_time = time.time()
if event.src_path.find('~') == -1 and (current_time - last_trigger_time) > 1:
last_trigger_time = current_time
print('modified') |
The first trigger is perhaps when the file is created, I found I couldn't read the file yet, as it wasn't complete yet. So, perhaps the second trigger is when the file is closed by the writing process, and available. |
Hi, Thanks, |
Hello, are there any news regarding this issue? It even seems if a file gets copied via plain (Ubuntu 20.04, Python 3.8.10, watchdog 2.1.7) |
Here's another adaptation of the above cooldown workarounds for relatively slow directory monitoring (I've hard-coded a minimum cooldown of two seconds), with the boilerplate tucked into a context manager. In this implementation, your So the example usage looks like this... Example usage from pathlib import Path
from watchdog.events import FileSystemEvent
from implementation import DirWatcher # Import from implementation file below
WATCH_DIR = Path("watch")
INTERVAL = 5
def main():
with DirWatcher(WATCH_DIR, on_modified, INTERVAL) as watcher:
watcher.run()
def on_modified(event: FileSystemEvent):
"""Do something with the event, without worrying about the cooldown."""
if __name__ == "__main__":
main() ...which only allows for Note that the implementation uses implementation.py """Context manager for basic directory watching.
Includes a workaround for <https://github.com/gorakhargosh/watchdog/issues/346>.
"""
from datetime import datetime, timedelta
from pathlib import Path
from time import sleep
from typing import Callable, Self
from watchdog.events import FileSystemEvent, FileSystemEventHandler
from watchdog.observers import Observer
class DirWatcher:
"""Run a function when a directory changes."""
min_cooldown = 2
def __init__(
self,
watch_dir: Path,
on_modified: Callable[[FileSystemEvent], None],
interval: int = 5,
cooldown: int = 2,
):
if interval < self.min_cooldown:
raise ValueError(
f"Interval of {interval} seconds is less than the minimum cooldown of"
f" {self.min_cooldown} seconds."
)
if cooldown < self.min_cooldown:
raise ValueError(
f"Cooldown of {cooldown} seconds is less than the minimum cooldown of"
f" {self.min_cooldown} seconds."
)
self.watch_dir = watch_dir
self.on_modified = on_modified
self.interval = interval
self.cooldown = cooldown
def __enter__(self) -> Self:
self.observer = Observer()
self.observer.schedule(
ModifiedFileHandler(self.on_modified, self.cooldown), self.watch_dir
)
self.observer.start()
return self
def __exit__(self, exc_type: Exception | None, *_) -> bool:
if exc_type and exc_type is KeyboardInterrupt:
self.observer.stop()
handled_exception = True
elif exc_type:
handled_exception = False
else:
handled_exception = True
self.observer.join()
return handled_exception
def run(self):
"""Check for changes on an interval."""
while True:
sleep(self.interval)
class ModifiedFileHandler(FileSystemEventHandler):
"""Handle modified files."""
def __init__(self, func: Callable[[FileSystemEvent], None], cooldown: int):
self.func = func
self.cooldown = timedelta(seconds=cooldown)
self.triggered_time = datetime.min
def on_modified(self, event: FileSystemEvent):
if (datetime.now() - self.triggered_time) > self.cooldown:
self.func(event)
self.triggered_time = datetime.now() |
Access time update should be a separate event. |
I've been scratching my head over this issue and after a bit of research I don't believe this is a wtachdog issue. First things first. WATCHDOG_FILE_NOTIFY_FLAGS = reduce(
lambda x, y: x | y,
[
FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_NOTIFY_CHANGE_DIR_NAME,
FILE_NOTIFY_CHANGE_ATTRIBUTES,
FILE_NOTIFY_CHANGE_SIZE,
FILE_NOTIFY_CHANGE_LAST_WRITE,
FILE_NOTIFY_CHANGE_SECURITY,
FILE_NOTIFY_CHANGE_LAST_ACCESS,
FILE_NOTIFY_CHANGE_CREATION,
],
) which means ANY of those modifications over the filesystem entry triggers an event. Now: FS operations are in most cases complex.
In addition on some file types, eg. Images, you might have modification events triggered as last_access is modified due to the fact applications (like file property dialog or the automatic generation of thumbnails) read header metadata (or the entire file) hence opening the file for read and eventually closing it. I am not sure the "cooldown" strategy described above can properly solve the issue as there's no guarantee the flow of triggered events for the same file are contiguos: imagine a massive attribute "A" (archive) lowering in case of backups. Bottom line ... IMO watchdog simply echoes correctly all FS events. |
On Python 3 (3.5), modified file events are showing up more than once.
This does not occur on Python 2.7.11 with the same exact environment.
Please see the following question on SO for an example (not my post, but same symptoms):
https://stackoverflow.com/questions/32861420/watchdog-getting-events-thrice-in-python-3
The text was updated successfully, but these errors were encountered: