Repository: spyder-ide/spyder

Issue:
"Save as" dialog extremely slow
## Description of your problem

**What steps will reproduce the problem?**

1. With any file open, click "Save As"
2. Try to type a file name
3. 

**What is the expected output? What do you see instead?**

Typing a file name should be a flawless, without any delays and without causing measurable CPU load increase.

**Please provide any additional information below**

Every character takes at least 1 second to appear. CPU load goes to 100% in the process.

## Versions and main components

* Spyder Version: 3.0.2
* Python Version: 2.7.12
* Qt Version: 4.8.7 and 5.7.1
* PyQt Version: 4.12
* Operating system: Gentoo Linux


## Dependencies

Please go to the menu entry `Help > Optional Dependencies` (or
`Help > Dependencies`), press the button `Copy to clipboard`
and paste the contents below:

jedi >=0.8.1     :  0.9.0 (OK)
matplotlib >=1.0 :  1.5.3 (OK)
nbconvert >=4.0  :  4.3.0 (OK)
numpy >=1.7      :  1.11.2 (OK)
pandas >=0.13.1  :  0.19.1 (OK)
pep8 >=0.6       :  1.7.0 (OK)
psutil >=0.3     :  5.0.1 (OK)
pyflakes >=0.5.0 :  1.2.3 (OK)
pygments >=2.0   :  2.1.3 (OK)
pylint >=0.25    :  1.6.4 (OK)
qtconsole >=4.2.0:  4.2.1 (OK)
rope >=0.9.4     :  0.10.3 (OK)
sphinx >=0.6.6   :  1.3.5 (OK)
sympy >=0.7.3    :  1.0 (OK)



Discussion:
Some more information: When started from a terminal, spyder outputs the following errors at every character that I type:

kf5.kio.core: Invalid URL: QUrl("f.py")
kf5.kio.core: Invalid URL: QUrl("fi.py")
kf5.kio.core: Invalid URL: QUrl("fil.py")
kf5.kio.core: Invalid URL: QUrl("file.py")
kf5.kio.core: Invalid URL: QUrl("filen.py")
kf5.kio.core: Invalid URL: QUrl("filena.py")
kf5.kio.core: Invalid URL: QUrl("filenam.py")
kf5.kio.core: Invalid URL: QUrl("filename.py")

when I change the existing filename to "filename.py". This only happens if the string ends with ".p" or "py". That is, I have no problem typing anything unless the current string ends with either of those characters.
Yep, I noticed that too. We'll fix this in Spyder 3.1.4.
@rlaverde, please work on this one.
@ccordoba12 I'm not able to reproduce this error, any hints of how to reproduce it?

I tried with python3.5.2 with pyqt 5.6.0 and 4.11.4, and python2.7 with pyqt 5.6.0
I might have a related problem with a regression between 3.1.3 and 3.1.2 on Linux X64, Ananconda 4.3 Python 2.7.13 with updated spyder via conda:
Opening files either from file explorer or menu results in a very very long wait before the new tab in the editor window is activated (the tab is created quick;y, but not brought to the front and given focus for 30 secs to a minute (seems to get worse with more editor tabs open, but perhaps that's just my frustration). There is a similar length of wait after pressing F5 to run the current script and it actually executing.
Reverting back to 3.1.2 (which I had to do as I had some classes to teach!) fixes these problems.
@gb119 I haven't seen this problem (and I also use Linux). Do you have some spare time to help us with a `git bisect` to identify the faulty commit?

We can help you with instructions for that in case you need them :-)
Hi,
Realistically I won't have time until the weekend (too many undergraduate projects to mark :-( ), but happy to give it a go then. I'm never done git bisect before, but the documentation looks straightforward enough - presumably I need to spin a fresh anaconda environment, checkout spyder, mark the tags 3.1.3 as bas and 3.1.2 as good and go from there?
Yep, that's basically it. To start Spyder from its git repo, you need to run

    python bootstrap.py
Ok, so I've had a play and now can't reproduce the problem ! Clearly simply posting on github fixes things..... so if it comes back again I'll know how to give you a more useful bug report - so that's all good then.
I can't reproduce the issue with spyder 3.1.3 on Debian. Perhaps, it would be wise to relax the milestone for this one, since it cannot be reliably triaged at this point.
Can I provide any additional information to assist?
I can reproduce this bug, but I don't have time to fix it right now, sorry.

So I'm going to move it for 3.2, since it's mostly annoying.
Btw @ccordoba12, do you plan to release `3.1.4` soon? Please ping me if / when you do.
Yes, as soon as @dalthviz fixes issue #4191 (hopefully in a couple of days).
Any hints of how to reproduce this issue?

```
kf5.kio.core: Invalid URL: QUrl("f.py")
kf5.kio.core: Invalid URL: QUrl("fi.py")
```
This warning is raised by KDE input/output framework, maybe updating your KDE/Qt installation could fix this error
I'm on Gentoo Linux with all the available updates installed. Specifically, kio is in version 5.37.0 and Qt in version 5.7.1. I believe these are the latest available versions. Please let me know if there is any further information I can provide to track this issue down.
@rlaverde, that's the same warning I'm seeing and what makes to save files slow. I think we should run a `git bisect` between 3.0 and 3.1 to detect the commit that introduced this problem.
>that's the same warning I'm seeing and what makes to save files slow. I think we should run a git bisect between 3.0 and 3.1 to detect the commit that introduced this problem.

Yes, but I can't reproduce it 😞 
I can, so I'll perform the bisect ;-)
Note to self: the source of the problem is PR #3580.

Resolving patch:
diff --git a/spyder/config/utils.py b/spyder/config/utils.py
--- a/spyder/config/utils.py
+++ b/spyder/config/utils.py
@@ -116,9 +116,20 @@ def get_filter(filetypes, ext):
 
 def get_edit_filetypes():
     """Get all file types supported by the Editor"""
-    pygments_exts = _get_pygments_extensions()
-    favorite_exts = ['.py', '.R', '.jl', '.ipynb', '.md', '.pyw', '.pyx', '.C', '.CPP']
-    other_exts = [ext for ext in pygments_exts if ext not in favorite_exts]
+    # The filter details are not hidden on Windows, so we can't use
+    # all Pygments extensions on that platform
+    if os.name == 'nt':
+        supported_exts = []
+    else:
+        supported_exts = _get_pygments_extensions()
+
+    # NOTE: Try to not add too much extensions to this list to not
+    # make the filter look too big on Windows
+    favorite_exts = ['.py', '.R', '.jl', '.ipynb', '.md', '.pyw', '.pyx',
+                     '.c', '.cpp', '.json', '.dat', '.csv', '.tsv', '.txt',
+                     '.ini', '.html', '.js', '.h', '.bat']
+
+    other_exts = [ext for ext in supported_exts if ext not in favorite_exts]
     all_exts = tuple(favorite_exts + other_exts)
     text_filetypes = (_("Supported text files"), all_exts)
     return [text_filetypes] + EDIT_FILETYPES
@@ -171,3 +182,26 @@ def is_gtk_desktop():
             return False
     else:
         return False
+
+
+def is_kde_desktop():
+    "Detect if we are running in a KDE desktop"
+    if sys.platform.startswith('linux'):
+        xdg_desktop = os.environ.get('XDG_CURRENT_DESKTOP', '')
+        if xdg_desktop:
+            if 'KDE' in xdg_desktop:
+                return True
+            else:
+                return False
+        else:
+            return False
+    else:
+        return False
+
+
+def is_anaconda():
+    "Detect if we are running under Anaconda."
+    for var in os.environ:
+        if var.startswith('CONDA'):
+            return True
+    return False
diff --git a/spyder/widgets/editor.py b/spyder/widgets/editor.py
--- a/spyder/widgets/editor.py
+++ b/spyder/widgets/editor.py
@@ -24,15 +24,15 @@
 from qtpy.QtCore import (QByteArray, QFileInfo, QObject, QPoint, QSize, Qt,
                          QThread, QTimer, Signal, Slot)
 from qtpy.QtGui import QFont
-from qtpy.QtWidgets import (QAction, QApplication, QHBoxLayout, QMainWindow,
-                            QMessageBox, QMenu, QSplitter, QVBoxLayout,
-                            QWidget, QListWidget, QListWidgetItem)
+from qtpy.QtWidgets import (QAction, QApplication, QFileDialog, QHBoxLayout,
+                            QMainWindow, QMessageBox, QMenu, QSplitter,
+                            QVBoxLayout, QWidget, QListWidget, QListWidgetItem)
 
 # Local imports
 from spyder.config.base import _, DEBUG, STDERR, STDOUT
 from spyder.config.gui import config_shortcut, get_shortcut
 from spyder.config.utils import (get_edit_filetypes, get_edit_filters,
-                                 get_filter)
+                                 get_filter, is_kde_desktop, is_anaconda)
 from spyder.py3compat import qbytearray_to_str, to_text_string
 from spyder.utils import icon_manager as ima
 from spyder.utils import (codeanalysis, encoding, sourcecode,
@@ -593,6 +593,10 @@ def __init__(self, parent, actions):
         # Reference to save msgbox and avoid memory to be freed.
         self.msgbox = None
 
+        # File types and filters used by the Save As dialog
+        self.edit_filetypes = None
+        self.edit_filters = None
+
     @Slot()
     def show_in_external_file_explorer(self, fnames=None):
         """Show file in external file explorer"""
@@ -1561,12 +1565,29 @@ def file_saved_in_other_editorstack(self, index, filename):
         finfo.lastmodified = QFileInfo(finfo.filename).lastModified()
 
     def select_savename(self, original_filename):
+        """Select a name to save a file."""
+        if self.edit_filetypes is None:
+            self.edit_filetypes = get_edit_filetypes()
+        if self.edit_filters is None:
+            self.edit_filters = get_edit_filters()
+
+        # Don't use filters on KDE to not make the dialog incredible
+        # slow
+        # Fixes issue 4156
+        if is_kde_desktop() and not is_anaconda():
+            filters = ''
+            selectedfilter = ''
+        else:
+            filters = self.edit_filters
+            selectedfilter = get_filter(self.edit_filetypes,
+                                        osp.splitext(original_filename)[1])
+
         self.redirect_stdio.emit(False)
         filename, _selfilter = getsavefilename(self, _("Save file"),
-                                       original_filename,
-                                       get_edit_filters(),
-                                       get_filter(get_edit_filetypes(),
-                                           osp.splitext(original_filename)[1]))
+                                    original_filename,
+                                    filters=filters,
+                                    selectedfilter=selectedfilter,
+                                    options=QFileDialog.HideNameFilterDetails)
         self.redirect_stdio.emit(True)
         if filename:
             return osp.normpath(filename)


Test patch: