Repository: napari/napari

Issue:
Bug: conda install of plugin via Plugin Manager doesn't work when run from terminal (macOS only?)
## 🐛 Bug

I originally noted this in #5198 
Using the `conda` source to install a plugin (pure conda env, everything from conda-forge) doesn't work and shows an error in the Status:
```
Starting '/Users/piotrsobolewski/Dev/miniforge3/bin/mamba' with args ['install', '-y', '--prefix', '/Users/piotrsobolewski/Dev/miniforge3/envs/napari-main', '--override-channels', '-c', 'conda-forge', 'napari-animation==0.0.5']
Traceback (most recent call last):
  File "/Users/piotrsobolewski/Dev/miniforge3/bin/mamba", line 7, in <module>

    from mamba.mamba import main
ModuleNotFoundError: No module named 'mamba'

Task finished with exit code 1 with status 0.
```
Note: I have mamba installed (mamba 1.3.0, conda 22.9.0).
 
## To Reproduce

Steps to reproduce the behavior:

1. Make a conda env with the latest main nightly: `mamba create -n napari-main -c "napari/label/nightly" -c conda-forge napari python=3.10`
2. run napari from the terminal
3. Open the Plugin Manager, scroll down to `napari-animation`
4. Open the Installation Info menu and change source from PyPi to conda
5. Click install, open Show Status

Note: this issue only occurs when running napari direct from the terminal and is almost certainly macOS-only.

## Expected behavior

The plugin should install, if the option to change to `conda` is available.

## Environment

```
napari: 0.5.0a2.dev42+g9e911040
Platform: macOS-13.2.1-arm64-arm-64bit
System: MacOS 13.2.1
Python: 3.10.9 | packaged by conda-forge | (main, Feb 2 2023, 20:26:08) [Clang 14.0.6 ]
Qt: 5.15.6
PyQt5: 5.15.7
NumPy: 1.24.2
SciPy: 1.10.1
Dask: 2023.3.1
VisPy: 0.12.1
magicgui: 0.7.2
superqt: unknown
in-n-out: 0.1.7
app-model: 0.1.2
npe2: 0.6.2

OpenGL:
- GL version: 2.1 Metal - 83
- MAX_TEXTURE_SIZE: 16384

Screens:
- screen 1: resolution 1680x1050, scale 2.0

Settings path:
- /Users/piotrsobolewski/Library/Application Support/napari/napari-main_e240b8daeed1098c91bdc4f2a9ad585200c6d954/settings.yaml
```

## Additional context

`mamba` is installed in `base`. if I open python REPL, in base, then `from mamba.mamba import main` works. In my napari env, it doesn't, with the same error as above.
Also, a simple test of QProcess works:
```
from qtpy.QtCore import QProcess

def test_mamba_qprocess():
    process = QProcess()
    process.start('mamba', ['--version'])
    process.waitForFinished()

    if process.exitStatus() == QProcess.NormalExit:
        output = process.readAllStandardOutput().data().decode().strip()
        if output.startswith('mamba '):
            return output.split()[1]
    return None
```


Discussion:
The plot thickens:
If I use ipython and run:
```
from qtpy.QtCore import QProcess

def test_mamba_qprocess():
    process = QProcess()
    process.start('mamba', ['install', 'napari-animation', '--dry-run'])
    process.waitForFinished()

    if process.exitStatus() == QProcess.NormalExit:
        output = process.readAllStandardOutput().data().decode().strip()
        
        return output
    return None
```    
And then:
`test_mamba_qprocess()`

I get the expected output listing stuff to install.
But if I run the same in the napari-console, i get:
```
Out[2]: ''
```
If I then modify the output to get the StandardError:
`output = process.readAllStandardError().data().decode().strip()`
```
Out[4]: 'Traceback (most recent call last):\n  File "/Users/piotrsobolewski/Dev/miniforge3/condabin/mamba", line 7, in <module>\n    from mamba.mamba import main\nModuleNotFoundError: No module named \'mamba\''
```
Bam. So it seems related to something that napari sets or to being run from inside another Qt loop?
Note: using the above code in `jupyter qtconsole` returns the proper mamba output, just like ipython.
OK, I figured it out, I think.
I think it's the same issue as: https://github.com/spyder-ide/spyder/issues/20599
So napari sets `PYTHONEXECUTABLE` to `sys.executable`, which is python in the env that napari was run from. But that env doesn't have conda/mamba, only base does.
So if we do env.remove('PYTHONEXECUTABLE') then it works, because mamba (or conda, it doesn't matter) is available in the path, but uses a different python executable.

Try:
```
from qtpy.QtCore import QProcess, QProcessEnvironment

def test_mamba_qprocess():
    env = QProcessEnvironment.systemEnvironment()
    env.remove('PYTHONEXECUTABLE')   # toggle this line
    process = QProcess()
    process.setProcessEnvironment(env)
    process.start('mamba install napari-animation --dry-run')
    process.waitForFinished()
    if process.exitStatus() == QProcess.NormalExit:
        output = process.readAllStandardOutput().data().decode().strip()
        
        return output
    return None
```
I can toggle the PYTHONEXECUTABLE line to see it work or fail.

What I don't get is why the shebang at the top of `/Users/piotrsobolewski/Dev/miniforge3/condabin/mamba` :
```
#!/Users/piotrsobolewski/Dev/miniforge3/bin/python
```
doesn't prevent this.

I think it's also related to: https://github.com/napari/napari/issues/5454
so it's probably a macOS issue only

I can make a PR to fix, but before I do, @jaimergp @aganders3 do you have any thoughts?

Whoa - sorry you ended up on this journey, but nice troubleshooting! I can test this later but what you found makes sense to me and removing PYTHONEXECUTABLE seems okay as long as we test for other side effects of that.

Out of curiosity, does it work if you install mamba (+conda?) explicitly into the env?
So if 
I do:
```
mamba create -n napari-main -c "napari/label/nightly" -c conda-forge napari python=3.10
mamba activate napari-main
mamba install mamba
napari
```
And then use the Plugin Manager, as described in the OP to install `napari-animation` from conda, it works!
```
Starting '/Users/piotrsobolewski/Dev/miniforge3/bin/mamba' with args ['install', '-y', '--prefix', '/Users/piotrsobolewski/Dev/miniforge3/envs/napari-main', '--override-channels', '-c', 'conda-forge', 'napari-animation==0.0.5']
Transaction

  Prefix: /Users/piotrsobolewski/Dev/miniforge3/envs/napari-main

  Updating specs:

   - napari-animation==0.0.5
   - ca-certificates
   - certifi
   - openssl



  Package                Version  Build             Channel                    Size
─────────────────────────────────────────────────────────────────────────────────────
  Install:
─────────────────────────────────────────────────────────────────────────────────────

  + ffmpeg                 5.1.2  gpl_hf318d42_106  conda-forge/osx-arm64       8MB
  + gmp                    6.2.1  h9f76cd9_0        conda-forge/osx-arm64     571kB
  + gnutls                 3.7.8  h9f1a10d_0        conda-forge/osx-arm64       2MB
  + imageio-ffmpeg         0.4.8  pyhd8ed1ab_0      conda-forge/noarch         20kB
  + lame                   3.100  h1a8c8d9_1003     conda-forge/osx-arm64     529kB
  + libidn2                2.3.4  h1a8c8d9_0        conda-forge/osx-arm64     173kB
  + libtasn1              4.19.0  h1a8c8d9_0        conda-forge/osx-arm64     117kB
  + libunistring          0.9.10  h3422bc3_0        conda-forge/osx-arm64       2MB
  + libvpx                1.11.0  hc470f4d_3        conda-forge/osx-arm64       1MB
  + napari-animation       0.0.5  pyhd8ed1ab_0      conda-forge/noarch         28kB
  + nettle                 3.8.1  h63371fa_1        conda-forge/osx-arm64     537kB
  + openh264               2.3.1  hb7217d7_2        conda-forge/osx-arm64     588kB
  + p11-kit               0.24.1  h29577a5_0        conda-forge/osx-arm64     891kB
  + svt-av1                1.4.1  h7ea286d_0        conda-forge/osx-arm64       1MB
  + x264              1!164.3095  h57fd34a_2        conda-forge/osx-arm64     717kB
  + x265                     3.5  hbc6ce65_3        conda-forge/osx-arm64       2MB

  Summary:

  Install: 16 packages

  Total download: 21MB

─────────────────────────────────────────────────────────────────────────────────────




Looking for: ['napari-animation==0.0.5']


Pinned packages:
  - python 3.10.*
  - napari 0.5.*



Downloading and Extracting Packages

Preparing transaction: ...working... 
done
Verifying transaction: ...working... 
done

Executing transaction: ...working... 
done

Task finished with exit code 0 with status 0.
```

Side note: after a restart, **uninstalling** it used `pip`:
```Starting '/Users/piotrsobolewski/Dev/miniforge3/envs/napari-main/bin/python3.10' with args ['-m', 'pip', 'uninstall', '-y', 'napari-animation']
Found existing installation: napari-animation 0.0.5

Uninstalling napari-animation-0.0.5:

  Successfully uninstalled napari-animation-0.0.5

Task finished with exit code 0 with status 0.
```
Probably less than ideal? It was showing as source: conda in the installed list, so napari was aware of that...


Anyhow, I don't want to revert the PR that added PYTHONEXECUTABLE, just remove it from the `env` QProcessEnvironment. Since it was added for venv/pyenv issues, then probably those folks wouldn't be using conda, so it should be mostly harmless? I'll make a PR and we can do more testing.

Resolving patch:
diff --git a/napari/_qt/dialogs/qt_package_installer.py b/napari/_qt/dialogs/qt_package_installer.py
--- a/napari/_qt/dialogs/qt_package_installer.py
+++ b/napari/_qt/dialogs/qt_package_installer.py
@@ -212,6 +212,10 @@ def environment(
             if not env.contains("USERPROFILE"):
                 env.insert("HOME", os.path.expanduser("~"))
                 env.insert("USERPROFILE", os.path.expanduser("~"))
+        if sys.platform == 'darwin' and env.contains('PYTHONEXECUTABLE'):
+            # Fix for macOS when napari launched from terminal
+            # related to https://github.com/napari/napari/pull/5531
+            env.remove("PYTHONEXECUTABLE")
         return env
 
     @staticmethod


Test patch: