Repository: spyder-ide/spyder

Issue:
`TypeError: 'dict' object is not reversible` in Python 3.7
## Description

### What steps will reproduce the problem?

<!--- You can use Markdown here --->

I had to reset my laptop, then installed pythion 3.7.9 and spyder. The first time I ran spyder from command prompt, I am stuck with this error. 

### Traceback
```python-traceback
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
Traceback (most recent call last):
  File "c:\users\indranil ojha\appdata\local\programs\python\python37\lib\site-packages\spyder\plugins\editor\panels\scrollflag.py", line 218, in paintEvent
    for flag_type in reversed(dict_flag_lists):
TypeError: 'dict' object is not reversible
```

## Versions

* Spyder version: 5.4.4  (pip)
* Python version: 3.7.9 64-bit
* Qt version: 5.15.2
* PyQt5 version: 5.15.9
* Operating System: Windows-10-10.0.22000-SP0

### Dependencies

```
# Mandatory:
atomicwrites >=1.2.0                                                        :  1.4.1 (OK)
chardet >=2.0.0                                                             :  5.2.0 (OK)
cloudpickle >=0.5.0                                                         :  2.2.1 (OK)
cookiecutter >=1.6.0                                                        :  2.3.0 (OK)
diff_match_patch >=20181111                                                 :  20230430 (OK)
intervaltree >=3.0.2                                                        :  3.1.0 (OK)
IPython >=7.31.1,<9.0.0,!=8.8.0,!=8.9.0,!=8.10.0,!=8.11.0,!=8.12.0,!=8.12.1 :  7.34.0 (OK)
jedi >=0.17.2,<0.19.0                                                       :  0.18.2 (OK)
jellyfish >=0.7                                                             :  1.0.0 (OK)
jsonschema >=3.2.0                                                          :  4.17.3 (OK)
keyring >=17.0.0                                                            :  24.1.1 (OK)
nbconvert >=4.0                                                             :  7.6.0 (OK)
numpydoc >=0.6.0                                                            :  1.5.0 (OK)
paramiko >=2.4.0                                                            :  3.3.1 (OK)
parso >=0.7.0,<0.9.0                                                        :  0.8.3 (OK)
pexpect >=4.4.0                                                             :  4.8.0 (OK)
pickleshare >=0.4                                                           :  0.7.5 (OK)
psutil >=5.3                                                                :  5.9.5 (OK)
pygments >=2.0                                                              :  2.16.1 (OK)
pylint >=2.5.0,<3.0                                                         :  2.17.5 (OK)
pylint_venv >=3.0.2                                                         :  3.0.2 (OK)
pyls_spyder >=0.4.0                                                         :  0.4.0 (OK)
pylsp >=1.7.4,<1.8.0                                                        :  1.7.4 (OK)
pylsp_black >=1.2.0,<3.0.0                                                  :  1.3.0 (OK)
qdarkstyle >=3.0.2,<3.2.0                                                   :  3.1 (OK)
qstylizer >=0.2.2                                                           :  0.2.2 (OK)
qtawesome >=1.2.1                                                           :  1.2.3 (OK)
qtconsole >=5.4.2,<5.5.0                                                    :  5.4.3 (OK)
qtpy >=2.1.0                                                                :  2.3.1 (OK)
rtree >=0.9.7                                                               :  1.0.1 (OK)
setuptools >=49.6.0                                                         :  68.0.0 (OK)
sphinx >=0.6.6                                                              :  5.3.0 (OK)
spyder_kernels >=2.4.4,<2.5.0                                               :  2.4.4 (OK)
textdistance >=4.2.0                                                        :  4.5.0 (OK)
three_merge >=0.1.1                                                         :  0.1.1 (OK)
watchdog >=0.10.3                                                           :  3.0.0 (OK)
zmq >=22.1.0                                                                :  25.1.1 (OK)

# Optional:
cython >=0.21                                                               :  None (NOK)
matplotlib >=3.0.0                                                          :  3.5.3 (OK)
numpy >=1.7                                                                 :  1.21.6 (OK)
pandas >=1.1.1                                                              :  1.3.5 (OK)
scipy >=0.17.0                                                              :  1.7.3 (OK)
sympy >=0.7.3                                                               :  None (NOK)
```



Discussion:
Hey @indranilo, thanks a lot for reporting. It seems we broke compatibility with Python 3.7 in our latest version (5.4.4) because the ability to reverse dictionaries (which is causing the error you reported) was added in Python 3.8 (see [here](https://stackoverflow.com/questions/58413076/why-are-python-dictionaries-not-reversible-for-python3-7)).

We'll fix this in a new, emergency version (5.4.5), to be released in the next couple of days. In the meantime, please downgrade to 5.4.3, which shouldn't have this problem.

Resolving patch:
diff --git a/spyder/app/mainwindow.py b/spyder/app/mainwindow.py
--- a/spyder/app/mainwindow.py
+++ b/spyder/app/mainwindow.py
@@ -391,7 +391,7 @@ def show_plugin_compatibility_message(self, plugin_name, message):
         # Set attributes
         messageBox.setWindowModality(Qt.NonModal)
         messageBox.setAttribute(Qt.WA_DeleteOnClose)
-        messageBox.setWindowTitle(_('Spyder compatibility check'))
+        messageBox.setWindowTitle(_('Plugin compatibility check'))
         messageBox.setText(
             _("It was not possible to load the {} plugin. The problem "
               "was:<br><br>{}").format(plugin_name, message)
diff --git a/spyder/plugins/editor/panels/scrollflag.py b/spyder/plugins/editor/panels/scrollflag.py
--- a/spyder/plugins/editor/panels/scrollflag.py
+++ b/spyder/plugins/editor/panels/scrollflag.py
@@ -215,7 +215,17 @@ def paintEvent(self, event):
         }
         dict_flag_lists.update(self._dict_flag_list)
 
-        for flag_type in reversed(dict_flag_lists):
+        # The ability to reverse dictionaries was added in Python 3.8.
+        # Fixes spyder-ide/spyder#21286
+        if sys.version_info[:2] > (3, 7):
+            # This is necessary to paint find matches above errors and
+            # warnings.
+            # See spyder-ide/spyder#20970
+            dict_flag_lists_iter = reversed(dict_flag_lists)
+        else:
+            dict_flag_lists_iter = dict_flag_lists
+
+        for flag_type in dict_flag_lists_iter:
             painter.setBrush(self._facecolors[flag_type])
             painter.setPen(self._edgecolors[flag_type])
             if editor.verticalScrollBar().maximum() == 0:


Test patch: