Skip to content

Commit

Permalink
Projects: Switch to use a polling observer in its watcher
Browse files Browse the repository at this point in the history
That's because it's more performant on Linux and behaves better on
Windows. It seems there are no issues with the current observer on Mac,
but I think it's better to have a single solution for all OSes.
  • Loading branch information
ccordoba12 committed Feb 1, 2024
1 parent 78a1554 commit a1d5625
Showing 1 changed file with 21 additions and 39 deletions.
60 changes: 21 additions & 39 deletions spyder/plugins/projects/utils/watcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@
"""Watcher to detect filesystem changes in the project's directory."""

# Standard lib imports
import os
import logging

# Third-party imports
from qtpy.QtCore import QObject, Signal
from qtpy.QtWidgets import QMessageBox
from superqt.utils import qthrottled
import watchdog
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler, PatternMatchingEventHandler
from watchdog.observers.polling import PollingObserverVFS

# Local imports
from spyder.config.base import _
from spyder.py3compat import to_text_string
from spyder.config.utils import get_edit_extensions


Expand Down Expand Up @@ -142,42 +140,26 @@ def connect_signals(self, project):
self.sig_file_modified.connect(project.file_modified)

def start(self, workspace_folder):
# Needed to handle an error caused by the inotify limit reached.
# See spyder-ide/spyder#10478
# We use a polling observer because:
# * It doesn't introduce long freezes on Linux when switching git
# branches that have many changes between them. That's because the
# OS-based observer (i.e. inotify) generates way too many events.
# * The OS-based observer on Windows has many shortcomings (see
# openmsi/openmsistream#56).
# * There doesn't seem to be issues on Mac, but it's simpler to use a
# single observer for all OSes.
self.observer = PollingObserverVFS(stat=os.stat, listdir=os.scandir)

self.observer.schedule(
self.event_handler, workspace_folder, recursive=True
)

try:
self.observer = Observer()
self.observer.schedule(
self.event_handler, workspace_folder, recursive=True)
try:
self.observer.start()
except OSError:
# This error happens frequently on Linux
logger.debug("Watcher could not be started.")
except OSError as e:
self.observer = None
if u'inotify' in to_text_string(e):
QMessageBox.warning(
self.parent(),
"Spyder",
_("File system changes for this project can't be tracked "
"because it contains too many files. To fix this you "
"need to increase the inotify limit in your system, "
"with the following command:"
"<br><br>"
"<code>"
"sudo sysctl -n -w fs.inotify.max_user_watches=524288"
"</code>"
"<br><br>For a permanent solution you need to add to"
"<code>/etc/sysctl.conf</code>"
"the following line:<br><br>"
"<code>"
"fs.inotify.max_user_watches=524288"
"</code>"
"<br><br>"
"After doing that, you need to close and start Spyder "
"again so those changes can take effect."))
else:
raise e
self.observer.start()
except Exception:
logger.debug(
f"Observer could not be started for: {workspace_folder}."
)

def stop(self):
if self.observer is not None:
Expand Down

0 comments on commit a1d5625

Please sign in to comment.