Repository: spyder-ide/spyder

Issue:
AttributeError after closing all files in a new editor window
## Description

### What steps will reproduce the problem?

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

Edit two python files in a single window.
Right click the tab for one of them and select New window.
Now there are two windows, both showing both files.
In the new window, close one file.  It disappears from both.
In the new window, close the second file.  The error which led me this dialog occurs.
Now both windows have an untitled[n] file which wasn't there before.

What I really wanted was one file in each window, but even if I did that incorrectly, this should not happen.


### Traceback
```python-traceback
Traceback (most recent call last):
  File "C:\Program Files\Spyder\pkgs\spyder\plugins\editor\plugin.py", line 2679, in current_file_changed
    cursor = self.get_current_editor().textCursor()
AttributeError: 'NoneType' object has no attribute 'textCursor'
Traceback (most recent call last):
  File "C:\Program Files\Spyder\pkgs\spyder\plugins\editor\plugin.py", line 2679, in current_file_changed
    cursor = self.get_current_editor().textCursor()
AttributeError: 'NoneType' object has no attribute 'textCursor'
Traceback (most recent call last):
  File "C:\Program Files\Spyder\pkgs\spyder\plugins\editor\plugin.py", line 2697, in current_editor_cursor_changed
    filename = code_editor.filename
AttributeError: 'NoneType' object has no attribute 'filename'
Traceback (most recent call last):
  File "C:\Program Files\Spyder\pkgs\spyder\plugins\editor\plugin.py", line 2679, in current_file_changed
    cursor = self.get_current_editor().textCursor()
AttributeError: 'NoneType' object has no attribute 'textCursor'
Traceback (most recent call last):
  File "C:\Program Files\Spyder\pkgs\spyder\plugins\editor\plugin.py", line 2679, in current_file_changed
    cursor = self.get_current_editor().textCursor()
AttributeError: 'NoneType' object has no attribute 'textCursor'
Traceback (most recent call last):
  File "C:\Program Files\Spyder\pkgs\spyder\plugins\editor\plugin.py", line 2697, in current_editor_cursor_changed
    filename = code_editor.filename
AttributeError: 'NoneType' object has no attribute 'filename'
```

## Versions

* Spyder version: 5.4.2  (standalone)
* Python version: 3.8.10 64-bit
* Qt version: 5.15.2
* PyQt5 version: 5.15.7
* Operating System: Windows 10

### Dependencies

```
# Mandatory:
atomicwrites >=1.2.0                 :  1.4.1 (OK)
chardet >=2.0.0                      :  5.1.0 (OK)
cloudpickle >=0.5.0                  :  2.2.0 (OK)
cookiecutter >=1.6.0                 :  2.1.1 (OK)
diff_match_patch >=20181111          :  20200713 (OK)
intervaltree                         :  None (OK)
IPython >=7.31.1;<9.0.0              :  8.8.0 (OK)
jedi >=0.17.2;<0.19.0                :  0.18.2 (OK)
jellyfish >=0.7                      :  0.9.0 (OK)
jsonschema >=3.2.0                   :  4.17.3 (OK)
keyring >=17.0.0                     :  23.13.1 (OK)
nbconvert >=4.0                      :  7.2.8 (OK)
numpydoc >=0.6.0                     :  1.5.0 (OK)
paramiko >=2.4.0                     :  2.12.0 (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.4 (OK)
pygments >=2.0                       :  2.14.0 (OK)
pylint >=2.5.0;<3.0                  :  2.15.10 (OK)
pylint_venv >=2.1.1                  :  2.3.0 (OK)
pyls_spyder >=0.4.0                  :  0.4.0 (OK)
pylsp >=1.7.1;<1.8.0                 :  1.7.1 (OK)
pylsp_black >=1.2.0                  :  1.2.1 (OK)
qdarkstyle >=3.0.2;<3.1.0            :  3.0.3 (OK)
qstylizer >=0.2.2                    :  0.2.2 (OK)
qtawesome >=1.2.1                    :  1.2.2 (OK)
qtconsole >=5.4.0;<5.5.0             :  5.4.0 (OK)
qtpy >=2.1.0                         :  2.3.0 (OK)
rtree >=0.9.7                        :  1.0.1 (OK)
setuptools >=49.6.0                  :  66.0.0 (OK)
sphinx >=0.6.6                       :  6.1.3 (OK)
spyder_kernels >=2.4.2;<2.5.0        :  2.4.2 (OK)
textdistance >=4.2.0                 :  4.5.0 (OK)
three_merge >=0.1.1                  :  0.1.1 (OK)
watchdog                             :  2.2.1 (OK)
zmq >=22.1.0                         :  24.0.1 (OK)

# Optional:
cython >=0.21                        :  0.29.33 (OK)
matplotlib >=3.0.0                   :  3.6.3 (OK)
numpy >=1.7                          :  1.24.1 (OK)
pandas >=1.1.1                       :  1.5.2 (OK)
scipy >=0.17.0                       :  1.10.0 (OK)
sympy >=0.7.3                        :  1.11.1 (OK)

# Spyder plugins:
spyder_terminal.terminalplugin 1.2.2 :  1.2.2 (OK)
```



Discussion:
Hi @VeloSteve thank you for the feedback! I was able to reproduce this! We will check a fix for it in a future release :+1:

Resolving patch:
diff --git a/spyder/plugins/editor/plugin.py b/spyder/plugins/editor/plugin.py
--- a/spyder/plugins/editor/plugin.py
+++ b/spyder/plugins/editor/plugin.py
@@ -2676,28 +2676,39 @@ def text_changed_at(self, filename, position):
         self.last_edit_cursor_pos = (to_text_string(filename), position)
 
     def current_file_changed(self, filename, position, line, column):
-        cursor = self.get_current_editor().textCursor()
-        self.add_cursor_to_history(to_text_string(filename), cursor)
+        editor = self.get_current_editor()
 
-        # Hide any open tooltips
-        current_stack = self.get_current_editorstack()
-        if current_stack is not None:
-            current_stack.hide_tooltip()
+        # Needed to validate if an editor exists.
+        # See spyder-ide/spyder#20643
+        if editor:
+            cursor = editor.textCursor()
+            self.add_cursor_to_history(to_text_string(filename), cursor)
 
-        # Update debugging state
-        ipyconsole = self.main.get_plugin(Plugins.IPythonConsole, error=False)
-        if ipyconsole is not None:
-            pdb_state = ipyconsole.get_pdb_state()
-            pdb_last_step = ipyconsole.get_pdb_last_step()
-            self.update_pdb_state(pdb_state, pdb_last_step)
+            # Hide any open tooltips
+            current_stack = self.get_current_editorstack()
+            if current_stack is not None:
+                current_stack.hide_tooltip()
+
+            # Update debugging state
+            ipyconsole = self.main.get_plugin(Plugins.IPythonConsole,
+                                              error=False)
+            if ipyconsole is not None:
+                pdb_state = ipyconsole.get_pdb_state()
+                pdb_last_step = ipyconsole.get_pdb_last_step()
+                self.update_pdb_state(pdb_state, pdb_last_step)
 
     def current_editor_cursor_changed(self, line, column):
         """Handles the change of the cursor inside the current editor."""
-        code_editor = self.get_current_editor()
-        filename = code_editor.filename
-        cursor = code_editor.textCursor()
-        self.add_cursor_to_history(
-            to_text_string(filename), cursor)
+        editor = self.get_current_editor()
+
+        # Needed to validate if an editor exists.
+        # See spyder-ide/spyder#20643
+        if editor:
+            code_editor = self.get_current_editor()
+            filename = code_editor.filename
+            cursor = code_editor.textCursor()
+            self.add_cursor_to_history(
+                to_text_string(filename), cursor)
 
     def remove_file_cursor_history(self, id, filename):
         """Remove the cursor history of a file if the file is closed."""


Test patch: