Repository: spyder-ide/spyder

Issue:
"OSError: inotify watch limit reached" with many files in a project
spyder4b7 gives this error if there are a lot of files in the project (150000). I use it for machine learning and it is not unusual to have a subdirectory with that number of files in a project. 

`sudo sysctl fs.inotify.max_user_watches=500000 `

makes it work on ubuntu 18.04, but this is not really nice and there is no real help from the crash report:
```
#spyder3
Attribute Qt::AA_ShareOpenGLContexts must be set before QCoreApplication is created.
Attribute Qt::AA_UseSoftwareOpenGL must be set before QCoreApplication is created.
Traceback (most recent call last):
  File "/home/detlef/tf-2-nightly-gpu/lib/python3.6/site-packages/spyder/app/mainwindow.py", line 3646, in main
    mainwindow = run_spyder(app, options, args)
  File "/home/detlef/tf-2-nightly-gpu/lib/python3.6/site-packages/spyder/app/mainwindow.py", line 3498, in run_spyder
    main.post_visible_setup()
  File "/home/detlef/tf-2-nightly-gpu/lib/python3.6/site-packages/spyder/app/mainwindow.py", line 1415, in post_visible_setup
    self.projects.reopen_last_project()
  File "/home/detlef/tf-2-nightly-gpu/lib/python3.6/site-packages/spyder/plugins/projects/plugin.py", line 404, in reopen_last_project
    save_previous_files=False)
  File "/home/detlef/tf-2-nightly-gpu/lib/python3.6/site-packages/spyder/plugins/projects/plugin.py", line 322, in open_project
    self.watcher.start(path)
  File "/home/detlef/tf-2-nightly-gpu/lib/python3.6/site-packages/spyder/plugins/projects/utils/watcher.py", line 93, in start
    self.observer.start()
  File "/home/detlef/tf-2-nightly-gpu/lib/python3.6/site-packages/watchdog/observers/api.py", line 255, in start
    emitter.start()
  File "/home/detlef/tf-2-nightly-gpu/lib/python3.6/site-packages/watchdog/utils/__init__.py", line 110, in start
    self.on_thread_start()
  File "/home/detlef/tf-2-nightly-gpu/lib/python3.6/site-packages/watchdog/observers/inotify.py", line 121, in on_thread_start
    self._inotify = InotifyBuffer(path, self.watch.is_recursive)
  File "/home/detlef/tf-2-nightly-gpu/lib/python3.6/site-packages/watchdog/observers/inotify_buffer.py", line 35, in __init__
    self._inotify = Inotify(path, recursive)
  File "/home/detlef/tf-2-nightly-gpu/lib/python3.6/site-packages/watchdog/observers/inotify_c.py", line 199, in __init__
    self._add_dir_watch(path, recursive, event_mask)
  File "/home/detlef/tf-2-nightly-gpu/lib/python3.6/site-packages/watchdog/observers/inotify_c.py", line 387, in _add_dir_watch
    self._add_watch(full_path, mask)
  File "/home/detlef/tf-2-nightly-gpu/lib/python3.6/site-packages/watchdog/observers/inotify_c.py", line 401, in _add_watch
    Inotify._raise_error()
  File "/home/detlef/tf-2-nightly-gpu/lib/python3.6/site-packages/watchdog/observers/inotify_c.py", line 413, in _raise_error
    raise OSError("inotify watch limit reached")
OSError: inotify watch limit reached
 
```


Discussion:
@dalthviz, please take a look at this one.

The idea is to catch this specific error and explain users how to increase the inotify limit on Linux in a QMessageBox (VSCode does the same, by the way).

Resolving patch:
diff --git a/spyder/plugins/projects/utils/watcher.py b/spyder/plugins/projects/utils/watcher.py
--- a/spyder/plugins/projects/utils/watcher.py
+++ b/spyder/plugins/projects/utils/watcher.py
@@ -11,10 +11,14 @@
 
 # Third-party imports
 from qtpy.QtCore import QObject, Signal
+from qtpy.QtWidgets import QMessageBox
 
 from watchdog.observers import Observer
 from watchdog.events import FileSystemEventHandler
 
+# Local imports
+from spyder.config.base import _
+
 logger = logging.getLogger(__name__)
 
 
@@ -87,12 +91,41 @@ def connect_signals(self, project):
         self.event_handler.sig_file_modified.connect(project.file_modified)
 
     def start(self, workspace_folder):
-        self.observer = Observer()
-        self.observer.schedule(
-            self.event_handler, workspace_folder, recursive=True)
-        self.observer.start()
+        # Needed to handle an error caused by the inotify limit reached.
+        # See spyder-ide/spyder#10478
+        try:
+            self.observer = Observer()
+            self.observer.schedule(
+                self.event_handler, workspace_folder, recursive=True)
+            self.observer.start()
+        except OSError as e:
+            if u'inotify' in 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."))
+                self.observer = None
+            else:
+                raise e
 
     def stop(self):
-        self.observer.stop()
-        self.observer.join()
-        del self.observer
+        if self.observer is not None:
+            self.observer.stop()
+            self.observer.join()
+            del self.observer


Test patch: