Repository: spyder-ide/spyder
Pull request: PR: Fix `UnboundLocalError` when removing and adding paths to Pythonpath Manager
<!--- Make sure to read the Contributing Guidelines:                   --->
<!--- https://github.com/spyder-ide/spyder/blob/master/CONTRIBUTING.md --->
<!--- and follow PEP 8, PEP 257 and Spyder's code style:               --->
<!--- https://github.com/spyder-ide/spyder/wiki/Dev:-Coding-Style      --->

## Description of Changes

<!--- Explain what you've done and why --->

Fix issue where `user_widget` was not defined if `self.user_header` was defined but not visible in the PYTHONPATH Manager widget.
Reject PYTHONPATH paths that match conda base environment `/pkgs` directory.

### Issue(s) Resolved

<!--- List the issue(s) below, in the form "Fixes #1234"; one per line --->

Fixes #22827



Problem statement:
Attempt to add path in `Anaconda3/pkgs` to Pythonpath manager leads to an error
## Description

### What steps will reproduce the problem?

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

An attempt to overcome the problem:
run zsni -in testosterone.smi
Traceback (most recent call last):

  File D:\ICDD_PDF\TOOLS_2020\LexiChemTK\Struct_Name\SmiNamImg\zsni.py:17
    from openeye import oechem

ModuleNotFoundError: No module named 'openeye'
where 'openeye' is a component of  Anaconda3>pkgs>openeye-toolkits-2022.2.2-py310_0

### Traceback
```python-traceback
Traceback (most recent call last):
  File "C:\Users\Garve\anaconda3\envs\spyder\Lib\site-packages\spyder\plugins\pythonpath\widgets\pathmanager.py", line 182, in <lambda>
    triggered=lambda x: self.add_path())
                        ^^^^^^^^^^^^^^^
  File "C:\Users\Garve\anaconda3\envs\spyder\Lib\site-packages\spyder\plugins\pythonpath\widgets\pathmanager.py", line 525, in add_path
    self.user_header, user_widget
                      ^^^^^^^^^^^
UnboundLocalError: cannot access local variable 'user_widget' where it is not associated with a value
```

## Versions

* Spyder version: 6.0.1  (conda)
* Python version: 3.12.7 64-bit
* Qt version: 5.15.2
* PyQt5 version: 5.15.10
* Operating System: Windows-11-10.0.22631-SP0

### Dependencies

```
# Mandatory:
aiohttp >=3.9.3                  :  3.10.5 (OK)
asyncssh >=2.14.0,<3.0.0         :  2.17.0 (OK)
atomicwrites >=1.2.0             :  1.4.0 (OK)
chardet >=2.0.0                  :  4.0.0 (OK)
cloudpickle >=0.5.0              :  3.0.0 (OK)
cookiecutter >=1.6.0             :  2.6.0 (OK)
diff_match_patch >=20181111      :  20200713 (OK)
github >=2.3.0                   :  2.4.0 (OK)
importlib_metadata >=4.6.0       :  7.0.1 (OK)
intervaltree >=3.0.2             :  3.1.0 (OK)
IPython >=8.13.0,<9.0.0,!=8.17.1 :  8.27.0 (OK)
jedi >=0.17.2,<0.20.0            :  0.19.1 (OK)
jellyfish >=0.7                  :  1.0.1 (OK)
jsonschema >=3.2.0               :  4.23.0 (OK)
keyring >=17.0.0                 :  24.3.1 (OK)
nbconvert >=4.0                  :  7.16.4 (OK)
numpydoc >=0.6.0                 :  1.7.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.0 (OK)
pygments >=2.0                   :  2.15.1 (OK)
pylint >=3.1,<4                  :  3.2.7 (OK)
pylint_venv >=3.0.2              :  3.0.3 (OK)
pyls_spyder >=0.4.0              :  0.4.0 (OK)
pylsp >=1.12.0,<1.13.0           :  1.12.0 (OK)
pylsp_black >=2.0.0,<3.0.0       :  2.0.0 (OK)
pyuca >=1.2                      :  1.2 (OK)
qdarkstyle >=3.2.0,<3.3.0        :  3.2.3 (OK)
qstylizer >=0.2.2                :  0.2.2 (OK)
qtawesome >=1.3.1,<1.4.0         :  1.3.1 (OK)
qtconsole >=5.6.0,<5.7.0         :  5.6.0 (OK)
qtpy >=2.4.0                     :  2.4.1 (OK)
rtree >=0.9.7                    :  1.0.1 (OK)
setuptools >=49.6.0              :  75.1.0 (OK)
sphinx >=0.6.6                   :  7.3.7 (OK)
spyder_kernels >=3.0.0,<3.1.0    :  3.0.0 (OK)
superqt >=0.6.2,<1.0.0           :  0.6.7 (OK)
textdistance >=4.2.0             :  4.2.1 (OK)
three_merge >=0.1.1              :  0.1.1 (OK)
watchdog >=0.10.3                :  4.0.1 (OK)
yarl >=1.9.4                     :  1.11.0 (OK)
zmq >=24.0.0                     :  25.1.2 (OK)

# Optional:
cython >=0.21                    :  None (NOK)
matplotlib >=3.0.0               :  None (NOK)
numpy >=1.7                      :  None (NOK)
pandas >=1.1.1                   :  None (NOK)
scipy >=0.17.0                   :  None (NOK)
sympy >=0.7.3                    :  None (NOK)
```

### Environment

<details><summary>Environment</summary>

```
# packages in environment at C:\Users\Garve\anaconda3\envs\spyder:
#
# Name                    Version                   Build  Channel
aiohappyeyeballs          2.4.0           py312haa95532_0  
aiohttp                   3.10.5          py312h827c3e9_0  
aiosignal                 1.2.0              pyhd3eb1b0_0  
alabaster                 0.7.16          py312haa95532_0  
archspec                  0.2.3              pyhd3eb1b0_0  
arrow                     1.3.0           py312haa95532_0  
astroid                   3.2.4           py312haa95532_0  
asttokens                 2.0.5              pyhd3eb1b0_0  
asyncssh                  2.17.0          py312haa95532_0  
atomicwrites              1.4.0                      py_0  
attrs                     24.2.0          py312haa95532_0  
autopep8                  2.0.4              pyhd3eb1b0_0  
babel                     2.11.0          py312haa95532_0  
beautifulsoup4            4.12.3          py312haa95532_0  
binaryornot               0.4.4              pyhd3eb1b0_1  
black                     24.8.0          py312haa95532_0  
bleach                    4.1.0              pyhd3eb1b0_0  
boltons                   23.0.0          py312haa95532_0  
brotli-python             1.0.9           py312hd77b12b_8  
bzip2                     1.0.8                h2bbff1b_6  
ca-certificates           2024.9.24            haa95532_0  
certifi                   2024.8.30       py312haa95532_0  
cffi                      1.17.1          py312h827c3e9_0  
chardet                   4.0.0           py312haa95532_1003  
charset-normalizer        3.3.2              pyhd3eb1b0_0  
click                     8.1.7           py312haa95532_0  
cloudpickle               3.0.0           py312haa95532_0  
colorama                  0.4.6           py312haa95532_0  
comm                      0.2.1           py312haa95532_0  
conda                     24.9.2          py312haa95532_0  
conda-libmamba-solver     24.9.0             pyhd3eb1b0_0  
conda-package-handling    2.3.0           py312haa95532_0  
conda-package-streaming   0.10.0          py312haa95532_0  
console_shortcut          0.1.1                haa95532_6  
cookiecutter              2.6.0           py312haa95532_0  
cryptography              43.0.0          py312h89fc84f_0  
debugpy                   1.6.7           py312hd77b12b_0  
decorator                 5.1.1              pyhd3eb1b0_0  
defusedxml                0.7.1              pyhd3eb1b0_0  
deprecated                1.2.13          py312haa95532_0  
diff-match-patch          20200713           pyhd3eb1b0_0  
dill                      0.3.8           py312haa95532_0  
distro                    1.9.0           py312haa95532_0  
docstring-to-markdown     0.11            py312haa95532_0  
docutils                  0.18.1          py312haa95532_3  
executing                 0.8.3              pyhd3eb1b0_0  
expat                     2.6.3                h5da7b33_0  
flake8                    7.1.1           py312haa95532_0  
fmt                       9.1.0                h6d14046_1  
frozendict                2.4.2           py312haa95532_0  
frozenlist                1.4.0           py312h2bbff1b_0  
icu                       73.1                 h6c2663c_0  
idna                      3.7             py312haa95532_0  
imagesize                 1.4.1           py312haa95532_0  
importlib-metadata        7.0.1           py312haa95532_0  
inflection                0.5.1           py312haa95532_1  
intervaltree              3.1.0              pyhd3eb1b0_0  
ipykernel                 6.29.5          py312haa95532_0  
ipython                   8.27.0          py312haa95532_0  
isort                     5.13.2          py312haa95532_0  
jaraco.classes            3.2.1              pyhd3eb1b0_0  
jedi                      0.19.1          py312haa95532_0  
jellyfish                 1.0.1           py312h36a85e1_0  
jinja2                    3.1.4           py312haa95532_0  
jpeg                      9e                   h827c3e9_3  
jsonpatch                 1.33            py312haa95532_1  
jsonpointer               2.1                pyhd3eb1b0_0  
jsonschema                4.23.0          py312haa95532_0  
jsonschema-specifications 2023.7.1        py312haa95532_0  
jupyter_client            8.6.0           py312haa95532_0  
jupyter_core              5.7.2           py312haa95532_0  
jupyterlab_pygments       0.2.2           py312haa95532_0  
keyring                   24.3.1          py312haa95532_0  
krb5                      1.20.1               h5b6d351_0  
libarchive                3.7.4                h9243413_0  
libclang                  14.0.6          default_hb5a9fac_1  
libclang13                14.0.6          default_h8e68704_1  
libcurl                   8.9.1                h0416ee5_0  
libffi                    3.4.4                hd77b12b_1  
libiconv                  1.16                 h2bbff1b_3  
libmamba                  1.5.8                h99b1521_3  
libmambapy                1.5.8           py312h77c03ed_3  
libpng                    1.6.39               h8cc25b3_0  
libpq                     12.17                h906ac69_0  
libsodium                 1.0.18               h62dcd97_0  
libsolv                   0.7.24               h23ce68f_1  
libspatialindex           1.9.3                h6c2663c_0  
libssh2                   1.11.0               h291bd65_0  
libxml2                   2.13.1               h24da03e_2  
lz4-c                     1.9.4                h2bbff1b_1  
markdown-it-py            2.2.0           py312haa95532_1  
markupsafe                2.1.3           py312h2bbff1b_0  
matplotlib-inline         0.1.6           py312haa95532_0  
mccabe                    0.7.0              pyhd3eb1b0_0  
mdurl                     0.1.0           py312haa95532_0  
menuinst                  2.1.2           py312h5da7b33_0  
mistune                   2.0.4           py312haa95532_0  
more-itertools            10.3.0          py312haa95532_0  
multidict                 6.0.4           py312h2bbff1b_0  
mypy_extensions           1.0.0           py312haa95532_0  
nbclient                  0.8.0           py312haa95532_0  
nbconvert                 7.16.4          py312haa95532_0  
nbformat                  5.10.4          py312haa95532_0  
nest-asyncio              1.6.0           py312haa95532_0  
numpydoc                  1.7.0           py312haa95532_0  
openssl                   3.0.15               h827c3e9_0  
packaging                 24.1            py312haa95532_0  
pandocfilters             1.5.0              pyhd3eb1b0_0  
parso                     0.8.3              pyhd3eb1b0_0  
pathspec                  0.10.3          py312haa95532_0  
pcre2                     10.42                h0ff8eda_1  
pexpect                   4.8.0              pyhd3eb1b0_3  
pickleshare               0.7.5           pyhd3eb1b0_1003  
pip                       24.2            py312haa95532_0  
platformdirs              3.10.0          py312haa95532_0  
pluggy                    1.0.0           py312haa95532_1  
ply                       3.11            py312haa95532_1  
prompt-toolkit            3.0.43          py312haa95532_0  
prompt_toolkit            3.0.43               hd3eb1b0_0  
psutil                    5.9.0           py312h2bbff1b_0  
ptyprocess                0.7.0              pyhd3eb1b0_2  
pure_eval                 0.2.2              pyhd3eb1b0_0  
pybind11-abi              5                    hd3eb1b0_0  
pycodestyle               2.12.1          py312haa95532_0  
pycosat                   0.6.6           py312h2bbff1b_1  
pycparser                 2.21               pyhd3eb1b0_0  
pydocstyle                6.3.0           py312haa95532_0  
pyflakes                  3.2.0           py312haa95532_0  
pygithub                  2.4.0           py312haa95532_0  
pygments                  2.15.1          py312haa95532_1  
pyjwt                     2.8.0           py312haa95532_0  
pylint                    3.2.7           py312haa95532_0  
pylint-venv               3.0.3           py312haa95532_0  
pyls-spyder               0.4.0              pyhd3eb1b0_0  
pynacl                    1.5.0           py312h8cc25b3_0  
pyqt                      5.15.10         py312hd77b12b_0  
pyqt5-sip                 12.13.0         py312h2bbff1b_0  
pyqtwebengine             5.15.10         py312hd77b12b_0  
pysocks                   1.7.1           py312haa95532_0  
python                    3.12.7               h14ffc60_0  
python-dateutil           2.9.0post0      py312haa95532_2  
python-fastjsonschema     2.16.2          py312haa95532_0  
python-lsp-black          2.0.0           py312haa95532_0  
python-lsp-jsonrpc        1.1.2              pyhd3eb1b0_0  
python-lsp-server         1.12.0          py312hfc267ef_0  
python-slugify            5.0.2              pyhd3eb1b0_0  
pytoolconfig              1.2.6           py312haa95532_0  
pytz                      2024.1          py312haa95532_0  
pyuca                     1.2             py312haa95532_1  
pywin32                   305             py312h2bbff1b_0  
pywin32-ctypes            0.2.2           py312haa95532_0  
pyyaml                    6.0.2           py312h827c3e9_0  
pyzmq                     25.1.2          py312hd77b12b_0  
qdarkstyle                3.2.3              pyhd3eb1b0_0  
qstylizer                 0.2.2           py312haa95532_0  
qt-main                   5.15.2              h19c9488_10  
qt-webengine              5.15.9               h5bd16bc_7  
qtawesome                 1.3.1           py312haa95532_0  
qtconsole                 5.6.0           py312haa95532_0  
qtpy                      2.4.1           py312haa95532_0  
referencing               0.30.2          py312haa95532_0  
reproc                    14.2.4               hd77b12b_2  
reproc-cpp                14.2.4               hd77b12b_2  
requests                  2.32.3          py312haa95532_0  
rich                      13.7.1          py312haa95532_0  
rope                      1.12.0          py312haa95532_0  
rpds-py                   0.10.6          py312h062c2fa_0  
rtree                     1.0.1           py312h2eaa2aa_0  
ruamel.yaml               0.18.6          py312h827c3e9_0  
ruamel.yaml.clib          0.2.8           py312h827c3e9_0  
setuptools                75.1.0          py312haa95532_0  
sip                       6.7.12          py312hd77b12b_0  
six                       1.16.0             pyhd3eb1b0_1  
snowballstemmer           2.2.0              pyhd3eb1b0_0  
sortedcontainers          2.4.0              pyhd3eb1b0_0  
soupsieve                 2.5             py312haa95532_0  
sphinx                    7.3.7           py312h827c3e9_0  
sphinxcontrib-applehelp   1.0.2              pyhd3eb1b0_0  
sphinxcontrib-devhelp     1.0.2              pyhd3eb1b0_0  
sphinxcontrib-htmlhelp    2.0.0              pyhd3eb1b0_0  
sphinxcontrib-jsmath      1.0.1              pyhd3eb1b0_0  
sphinxcontrib-qthelp      1.0.3              pyhd3eb1b0_0  
sphinxcontrib-serializinghtml 1.1.10          py312haa95532_0  
spyder                    6.0.1           py312haa95532_0  
spyder-kernels            3.0.0           py312hfc267ef_0  
sqlite                    3.45.3               h2bbff1b_0  
stack_data                0.2.0              pyhd3eb1b0_0  
superqt                   0.6.7           py312hfc267ef_0  
tabulate                  0.9.0           py312haa95532_0  
text-unidecode            1.3                pyhd3eb1b0_0  
textdistance              4.2.1              pyhd3eb1b0_0  
three-merge               0.1.1              pyhd3eb1b0_0  
tinycss2                  1.2.1           py312haa95532_0  
tk                        8.6.14               h0416ee5_0  
tomli                     2.0.1           py312haa95532_1  
tomlkit                   0.13.2          py312haa95532_0  
tornado                   6.4.1           py312h827c3e9_0  
tqdm                      4.66.5          py312hfc267ef_0  
traitlets                 5.14.3          py312haa95532_0  
truststore                0.8.0           py312haa95532_0  
typing-extensions         4.11.0          py312haa95532_0  
typing_extensions         4.11.0          py312haa95532_0  
tzdata                    2024b                h04d1e81_0  
ujson                     5.10.0          py312h5da7b33_0  
unidecode                 1.3.8           py312haa95532_0  
urllib3                   2.2.3           py312haa95532_0  
vc                        14.40                h2eaa2aa_1  
vs2015_runtime            14.40.33807          h98bb1dd_1  
watchdog                  4.0.1           py312haa95532_0  
wcwidth                   0.2.5              pyhd3eb1b0_0  
webencodings              0.5.1           py312haa95532_2  
whatthepatch              1.0.2           py312haa95532_0  
wheel                     0.44.0          py312haa95532_0  
win_inet_pton             1.1.0           py312haa95532_0  
wrapt                     1.14.1          py312h2bbff1b_0  
xz                        5.4.6                h8cc25b3_1  
yaml                      0.2.5                he774522_0  
yaml-cpp                  0.8.0                hd77b12b_1  
yapf                      0.40.2          py312haa95532_0  
yarl                      1.11.0          py312h827c3e9_0  
zeromq                    4.3.5                hd77b12b_0  
zipp                      3.20.2          py312haa95532_0  
zlib                      1.2.13               h8cc25b3_1  
zstandard                 0.23.0          py312h4fc1ca9_0  
zstd                      1.5.6                h8880b57_0  

```
</details>

Hints from issue discussion:
Hey @Rg111Ga31, thanks for reporting. You said:

> An attempt to overcome the problem:
run zsni -in testosterone.smi
Traceback (most recent call last):
>
>File D:\ICDD_PDF\TOOLS_2020\LexiChemTK\Struct_Name\SmiNamImg\zsni.py:17
from openeye import oechem
>
> ModuleNotFoundError: No module named 'openeye'

The way to solve this problem is not to add the path where conda downloaded `openeye` to your environment through our Pythonpath manager (and fortunately there's a bug in it which prevented you to do that).

The reason is that mixing Python packages from different installations like that causes odd errors or segfaults.

Instead, you need to select the environment where you installed `openeye` and start a console for it. There are two options to do it:

* Go to the menu `Consoles > New console in environment` and select your environment from the listed shown there.
* Go to the menu `Tools > Preferences` and then `Python Interpreter > Use the following interpreter` and select there the path to the Python executable from your environment.

----

To address this issue we'll add a new rule to prevent users from adding packages located in `Anaconda3\pkgs` or similar directories, and take a look at the unassigned variable bug in your traceback above.
@mrclary, could you take a look at this one?
Regarding the traceback, this is an issue I discovered and is fixed in #21769. This issue occurs because `user_widget` is not defined but `self.user_header` is defined but not visible. This results when all paths are removed and then a new path is added.

@Rg111Ga31, if you close and reopen PYTHONPATH Manager, then try to add your path first, before removing any paths, then you should succeed. However, as @ccordoba12 recommends, you should not add paths that belong to other environments as this may cause other issues.

@ccordoba12, I can add `Anaconda3/pkgs` to the current path filtering in #21769. Although there could be many variants to accommodate.
Thanks Carlos for the suggestions.  However I am concerned that when I use
Navigator to update From Spyder 5.5.1 to Spyder 6.0.1 the path information
within Anaconda3 is NOT automatically made available to the latter version
as it was for Spyder 5.  Your suggestions seem to more properly apply to
the Spyder installer version not the Anaconda3 update version where a
compatibility issue seems to exist.

On Mon, Nov 4, 2024 at 10:48 AM Carlos Cordoba ***@***.***>
wrote:

> Hey @Rg111Ga31 <https://github.com/Rg111Ga31>, thanks for reporting. You
> said:
>
> An attempt to overcome the problem:
> run zsni -in testosterone.smi
> Traceback (most recent call last):
>
> File D:\ICDD_PDF\TOOLS_2020\LexiChemTK\Struct_Name\SmiNamImg\zsni.py:17
> from openeye import oechem
>
> ModuleNotFoundError: No module named 'openeye'
>
> The way to solve this problem is not to add the path where conda
> downloaded openeye to your environment through our Pythonpath manager
> (and fortunately there's a bug in it which prevented you to do that).
>
> The reason is that mixing Python packages from different installations
> like that causes odd errors or segfaults.
>
> Instead, you need to select the environment where you installed openeye
> and start a console for it. There are two options to do it:
>
>    - Go to the menu Consoles > New console in environment and select your
>    environment from the listed shown there.
>    - Go to the menu Tools > Preferences and then Python Interpreter > Use
>    the following interpreter and select there the path to the Python
>    executable from your environment.
>
> ------------------------------
>
> To address this issue we'll add a new rule to prevent users from adding
> packages located in Anaconda3\pkgs or similar directories, and take a
> look at the unassigned variable bug in your traceback above.
>
> —
> Reply to this email directly, view it on GitHub
> <https://github.com/spyder-ide/spyder/issues/22827#issuecomment-2455209860>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AKI6PCMVFUB5BLOAZLPGHCDZ66QPBAVCNFSM6AAAAABRC5EKGKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDINJVGIYDSOBWGA>
> .
> You are receiving this because you were mentioned.Message ID:
> ***@***.***>
>


-- 
r O Y

To @mrclary:

> Regarding the traceback, this is an issue I discovered and is fixed in https://github.com/spyder-ide/spyder/pull/21769.

Since this is a bug that seriously affects how the Pythonpath manager works, I'd prefer to have a fix for it in our stable branch. So, could you cherry-pick the commit you did to fix that and add it to another branch?

> I can add Anaconda3/pkgs to the current path filtering in https://github.com/spyder-ide/spyder/pull/21769. Although there could be many variants to accommodate.

That's even more important to include in our next version to avoid people using our Pythonpath manager in a way that was not designed for. You could add those changes to the same branch I mentioned above.

To @Rg111Ga31:

> However I am concerned that when I use Navigator to update From Spyder 5.5.1 to Spyder 6.0.1 the path information within Anaconda3 is NOT automatically made available to the latter version as it was for Spyder 5.

You're right, it won't be because adding directories placed in `Anaconda3/pkgs` to our PythonPath manager is not a valid use case (we were not aware that people were doing that). So, we're going to prevent it.

>  Your suggestions seem to more properly apply to the Spyder installer version not the Anaconda3 update version where a compatibility issue seems to exist.

That's not correct. As I said above:

>> mixing Python packages from different installations [or environments] ... causes odd errors or segfaults.

It seems in your case you have several environments, install packages in one or more of them, are unable to find them in Spyder and resort to add their directories in `Anaconda3/pkgs` to our PythonPath manager.

That's a horrible practice because environments have to be activated for their packages to work properly. Furthermore, packages from different Python versions (e.g. 3.9 and 3.12) can't be mixed and used in the same environment (the exception is that they are pure Python packages, but not many of them are in the scientific space).

So, this is something we must do.
Thanks for the feedback!

On Mon, Nov 4, 2024 at 4:28 PM Carlos Cordoba ***@***.***>
wrote:

> To @mrclary <https://github.com/mrclary>:
>
> Regarding the traceback, this is an issue I discovered and is fixed in
> #21769 <https://github.com/spyder-ide/spyder/pull/21769>.
>
> Since this is an bug that seriously affects how the Pythonpath manager
> works, I'd prefer to have a fix for it in our stable branch. So, could you
> cherry-pick the commit you did to fix that and add it to another branch?
>
> I can add Anaconda3/pkgs to the current path filtering in #21769
> <https://github.com/spyder-ide/spyder/pull/21769>. Although there could
> be many variants to accommodate.
>
> That's even more important to include in our next version to avoid people
> using our Pythonpath manager in a way that was not designed for. You could
> add those changes to the same branch I mentioned above.
>
> To @Rg111Ga31 <https://github.com/Rg111Ga31>:
>
> However I am concerned that when I use Navigator to update From Spyder
> 5.5.1 to Spyder 6.0.1 the path information within Anaconda3 is NOT
> automatically made available to the latter version as it was for Spyder 5.
>
> You're right, it won't be because adding directories placed in
> Anaconda3/pkgs to our PythonPath manager is not a valid use case (we were
> not aware that people were doing that). So, we're going to prevent it.
>
> Your suggestions seem to more properly apply to the Spyder installer
> version not the Anaconda3 update version where a compatibility issue seems
> to exist.
>
> That's not correct. As I said above:
>
> mixing Python packages from different installations [or environments] ...
> causes odd errors or segfaults.
>
> It seems in your case you have several environments, install packages in
> one or more of them, are unable to find them in Spyder and resort to add
> their directories in Anaconda3/pkgs to our PythonPath manager.
>
> That's a horrible practice because environments have to be activated for
> their packages to work properly. Furthermore, packages from different
> Python versions (e.g. 3.9 and 3.12) can't be mixed and used in the same
> environment (the exception is that they are pure Python packages, but not
> many of them are in the scientific space).
>
> So, this is something we must do.
>
> —
> Reply to this email directly, view it on GitHub
> <https://github.com/spyder-ide/spyder/issues/22827#issuecomment-2455831541>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AKI6PCLUMVRKXYHKGXZENQLZ67YIXAVCNFSM6AAAAABRC5EKGKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDINJVHAZTCNJUGE>
> .
> You are receiving this because you were mentioned.Message ID:
> ***@***.***>
>


-- 
r O Y

Commit message: Update tests

Patch to review:
diff --git a/spyder/plugins/pythonpath/tests/test_utils.py b/spyder/plugins/pythonpath/tests/test_utils.py
index 2a6c63b133a..f4c1bdecc82 100644
--- a/spyder/plugins/pythonpath/tests/test_utils.py
+++ b/spyder/plugins/pythonpath/tests/test_utils.py
@@ -27,6 +27,7 @@ def test_check_path(tmp_path):
         assert not check_path('lib\\site-packages')
         assert not check_path('lib\\dist-packages')
         assert not check_path('Lib/site-packages')
+        assert not check_path('Anaconda3/pkgs')
     else:
         # One digit Python versions
         assert not check_path('lib/python3.9/site-packages')
@@ -45,3 +46,9 @@ def test_check_path(tmp_path):
 
         # Paths that don't have digits must pass
         assert check_path('lib/pythonX.Y/site-packages')
+
+        # Distribution packages
+        assert not check_path('anaconda3/pkgs')
+        assert not check_path('miniconda3/pkgs')
+        assert not check_path('miniforge/base/pkgs')  # macOS Homebrew
+        assert not check_path('micromamba/pkgs')
diff --git a/spyder/plugins/pythonpath/utils.py b/spyder/plugins/pythonpath/utils.py
index 7fef6ae1220..66654ca0e4f 100644
--- a/spyder/plugins/pythonpath/utils.py
+++ b/spyder/plugins/pythonpath/utils.py
@@ -17,14 +17,20 @@
 
 def check_path(path):
     """Check that `path` is not a [site|dist]-packages folder."""
+    pattern_string = r'(ana|Ana|mini|micro)(conda|mamba|forge)\d*(/base)*/pkgs'
     if os.name == 'nt':
-        pattern = re.compile(r'.*(l|L)ib/(site|dist)-packages.*')
+        pattern_string = (
+            f'.*({pattern_string}'
+            r'|(l|L)ib/(site|dist)-packages).*'
+        )
     else:
-        pattern = re.compile(
-            r'.*(lib|lib64)/'
+        pattern_string = (
+            f'.*({pattern_string}'
+            r'|(lib|lib64)/'
             r'(python|python\d+|python\d+\.\d+)/'
-            r'(site|dist)-packages.*'
+            r'(site|dist)-packages).*'
         )
+    pattern = re.compile(pattern_string)
 
     path_norm = path.replace('\\', '/')
     return pattern.match(path_norm) is None
diff --git a/spyder/plugins/pythonpath/widgets/pathmanager.py b/spyder/plugins/pythonpath/widgets/pathmanager.py
index c54032449d5..c04994d7657 100644
--- a/spyder/plugins/pythonpath/widgets/pathmanager.py
+++ b/spyder/plugins/pythonpath/widgets/pathmanager.py
@@ -514,8 +514,6 @@ def add_path(self, directory=None):
                     )
                     self.headers.append(self.user_header)
 
-                # Add header if not visible
-                if self.listwidget.row(self.user_header) < 0:
                     if self.editable_top_row > 0:
                         header_row = self.editable_top_row - 1
                     else:
@@ -577,7 +575,10 @@ def remove_path(self, force=False):
                 # Remove user header if there are no more user paths
                 if len(self.user_path) == 0:
                     self.listwidget.takeItem(
-                        self.listwidget.row(self.user_header))
+                        self.listwidget.row(self.user_header)
+                    )
+                    self.headers.remove(self.user_header)
+                    self.user_header = None
 
                 # Refresh widget
                 self.refresh()


Code review comments:
diff_hunk: @@ -17,14 +17,20 @@
 
 def check_path(path):
     """Check that `path` is not a [site|dist]-packages folder."""
+    pattern_string = r'(ana|Ana|mini|micro)(conda|mamba|forge)\d*(/base)*/pkgs'
path: spyder/plugins/pythonpath/utils.py
text: @user1:
Does this pattern take into account capitalized Conda distribution names such as `Miniconda` or `Mambaforge`? I think those names are the default on Windows, so we need to cover them too.

diff_hunk: @@ -17,14 +17,20 @@
 
 def check_path(path):
     """Check that `path` is not a [site|dist]-packages folder."""
path: spyder/plugins/pythonpath/utils.py
text: @user1:
```suggestion
    """
    Check that `path` is not a [site|dist]-packages folder or a Conda
    distribution `pkgs` directory.
    """
```