Repository: spyder-ide/spyder

Issue:
KeyError when adding and removing language servers
## Description

### What steps will reproduce the problem?

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

I added the go language Server (gopls). And then this error Message showed up. By the way i using MacOS Ventura on an M2 Mac

### Traceback
```python-traceback
Traceback (most recent call last):
  File "/Applications/Spyder.app/Contents/Resources/lib/python3.9/spyder/plugins/preferences/widgets/configdialog.py", line 133, in accept
    configpage.apply_changes()
  File "/Applications/Spyder.app/Contents/Resources/lib/python3.9/spyder/plugins/preferences/api.py", line 118, in apply_changes
    self.apply_callback()
  File "/Applications/Spyder.app/Contents/Resources/lib/python3.9/spyder/plugins/preferences/api.py", line 150, in <lambda>
    self._apply_settings_tabs(self.changed_options))
  File "/Applications/Spyder.app/Contents/Resources/lib/python3.9/spyder/plugins/preferences/api.py", line 177, in _apply_settings_tabs
    options |= widget.apply_settings()
  File "/Applications/Spyder.app/Contents/Resources/lib/python3.9/spyder/plugins/completion/plugin.py", line 714, in wrapper
    for opt in prev_method(self):
  File "/Applications/Spyder.app/Contents/Resources/lib/python3.9/spyder/plugins/completion/providers/languageserver/conftabs/otherlanguages.py", line 104, in apply_settings
    return self.table.save_servers()
  File "/Applications/Spyder.app/Contents/Resources/lib/python3.9/spyder/plugins/completion/providers/languageserver/widgets/serversconfig.py", line 652, in save_servers
    server.delete()
  File "/Applications/Spyder.app/Contents/Resources/lib/python3.9/spyder/plugins/completion/providers/languageserver/widgets/serversconfig.py", line 107, in delete
    self.remove_option(language)
  File "/Applications/Spyder.app/Contents/Resources/lib/python3.9/spyder/plugins/completion/plugin.py", line 671, in wrapper
    return plugin.remove_conf(option, section)
  File "/Applications/Spyder.app/Contents/Resources/lib/python3.9/spyder/api/plugins/new_api.py", line 555, in remove_conf
    self._conf.remove_option(section, option)
  File "/Applications/Spyder.app/Contents/Resources/lib/python3.9/spyder/config/manager.py", line 571, in remove_option
    conf_ptr.pop(last_option)
KeyError: 'css/less/sass'
```

## Versions

* Spyder version: 5.4.3 b6abc3d30 (standalone)
* Python version: 3.9.14 64-bit
* Qt version: 5.15.2
* PyQt5 version: 5.15.9
* Operating System: Darwin 22.5.0

### Dependencies

```
# Mandatory:
atomicwrites >=1.2.0                             :  1.4.1 (OK)
chardet >=2.0.0                                  :  5.1.0 (OK)
cloudpickle >=0.5.0                              :  2.2.1 (OK)
cookiecutter >=1.6.0                             :  2.1.1 (OK)
diff_match_patch >=20181111                      :  20200713 (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.12.0 (OK)
jedi >=0.17.2,<0.19.0                            :  0.18.2 (OK)
jellyfish >=0.7                                  :  0.11.2 (OK)
jsonschema >=3.2.0                               :  4.17.3 (OK)
keyring >=17.0.0                                 :  23.13.1 (OK)
nbconvert >=4.0                                  :  7.3.0 (OK)
numpydoc >=0.6.0                                 :  1.5.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.17.2 (OK)
pylint_venv >=2.1.1                              :  None (OK)
pyls_spyder >=0.4.0                              :  0.4.0 (OK)
pylsp >=1.7.2,<1.8.0                             :  1.7.2 (OK)
pylsp_black >=1.2.0                              :  1.2.1 (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.2 (OK)
qtpy >=2.1.0                                     :  2.3.1 (OK)
rtree >=0.9.7                                    :  1.0.1 (OK)
setuptools >=49.6.0                              :  67.6.1 (OK)
sphinx >=0.6.6                                   :  5.1.1 (OK)
spyder_kernels >=2.4.3,<2.5.0                    :  2.4.3 (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.0.2 (OK)

# Optional:
cython >=0.21                                    :  0.29.34 (OK)
matplotlib >=3.0.0                               :  3.7.1 (OK)
numpy >=1.7                                      :  1.24.2 (OK)
pandas >=1.1.1                                   :  2.0.0 (OK)
scipy >=0.17.0                                   :  1.10.1 (OK)
sympy >=0.7.3                                    :  1.11.1 (OK)

# Spyder plugins:
spyder_terminal.terminalplugin 1.2.2             :  1.2.2 (OK)
```



Discussion:
Hey @jpx40, thanks for reporting. You said:

> I added the go language Server (gopls).

Did you add it and then remove it? That's not clear to me from the error you posted above.
> Hey @jpx40, thanks for reporting. You said:
> 
> > I added the go language Server (gopls).
> 
> Did you add it and then remove it? That's not clear to me from the error you posted above.

I added it, to use language completion for go.
> Hey @jpx40, thanks for reporting. You said:
> 
> > I added the go language Server (gopls).
> 
> Did you add it and then remove it? That's not clear to me from the error you posted above.

I removed a few language servers before i added go. Because the path was wrong. One of the removed language servers was for css.
Ok, that makes sense because that's what the error is reporting. We'll investigate this more carefully and try to solve it in our next version (5.5.0), to be released in a couple of months.
Just in case, I was able to reproduce this while checking PR #21215:

```python-traceback
Traceback (most recent call last):
  File "e:\acer\documentos\spyder\spyder otros\carlos\spyder\spyder\plugins\preferences\widgets\configdialog.py", line 142, in button_clicked
    configpage.apply_changes()
  File "e:\acer\documentos\spyder\spyder otros\carlos\spyder\spyder\plugins\preferences\api.py", line 119, in apply_changes
    self.apply_callback()
  File "e:\acer\documentos\spyder\spyder otros\carlos\spyder\spyder\plugins\preferences\api.py", line 151, in <lambda>
    self._apply_settings_tabs(self.changed_options))
  File "e:\acer\documentos\spyder\spyder otros\carlos\spyder\spyder\plugins\preferences\api.py", line 178, in _apply_settings_tabs
    options |= widget.apply_settings()
  File "e:\acer\documentos\spyder\spyder otros\carlos\spyder\spyder\plugins\completion\plugin.py", line 716, in wrapper
    for opt in prev_method(self):
  File "e:\acer\documentos\spyder\spyder otros\carlos\spyder\spyder\plugins\completion\providers\languageserver\conftabs\otherlanguages.py", line 104, in apply_settings
    return self.table.save_servers()
  File "e:\acer\documentos\spyder\spyder otros\carlos\spyder\spyder\plugins\completion\providers\languageserver\widgets\serversconfig.py", line 643, in save_servers
    server.delete()
  File "e:\acer\documentos\spyder\spyder otros\carlos\spyder\spyder\plugins\completion\providers\languageserver\widgets\serversconfig.py", line 108, in delete
    self.remove_option(language)
  File "e:\acer\documentos\spyder\spyder otros\carlos\spyder\spyder\plugins\completion\plugin.py", line 673, in wrapper
    return plugin.remove_conf(option, section)
  File "e:\acer\documentos\spyder\spyder otros\carlos\spyder\spyder\api\plugins\new_api.py", line 555, in remove_conf
    self._conf.remove_option(section, option)
  File "e:\acer\documentos\spyder\spyder otros\carlos\spyder\spyder\config\manager.py", line 572, in remove_option
    conf_ptr.pop(last_option)
KeyError: 'bash'
```

Adding a language server and then removing it before clicking `Apply` triggers the error 
@dalthviz, please take a look at this one since you were able to reproduce it.

Resolving patch:
diff --git a/spyder/config/manager.py b/spyder/config/manager.py
--- a/spyder/config/manager.py
+++ b/spyder/config/manager.py
@@ -560,17 +560,32 @@ def remove_option(self, section, option):
         """Remove `option` from `section`."""
         config = self.get_active_conf(section)
         if isinstance(option, tuple):
+            # The actual option saved in the config
             base_option = option[0]
+
+            # Keys of the nested dicts where the option to remove is contained
             intermediate_options = option[1:-1]
+
+            # Key of the option to remove
             last_option = option[-1]
 
+            # Get config value (which is a dictionary)
             base_conf = self.get(section, base_option)
+
+            # Get reference to the actual dictionary containing the option
+            # that needs to be removed
             conf_ptr = base_conf
             for opt in intermediate_options:
                 conf_ptr = conf_ptr[opt]
-            conf_ptr.pop(last_option)
-            self.set(section, base_option)
-            self.notify_observers(section, base_option)
+
+            # Remove option and set updated config values for the actual option
+            # while checking that the option to be removed is actually a value
+            # available in the config.
+            # See spyder-ide/spyder#21161
+            if last_option in conf_ptr:
+                conf_ptr.pop(last_option)
+                self.set(section, base_option,  base_conf)
+                self.notify_observers(section, base_option)
         else:
             config.remove_option(section, option)
 


Test patch: