Repository: napari/napari

Issue:
Mamba on windows is having issues with temp folder when installing plugins
## 🐛 Bug

Installing plugins on windows result in an error. 

```
Traceback (most recent call last):
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\win32com\client\gencache.py", line 60, in __init__
    _LoadDicts()
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\win32com\client\gencache.py", line 116, in _LoadDicts
    f = open(os.path.join(win32com.__gen_path__, "dicts.dat"), "rb")
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Windows\\gen_py\\3.8\\dicts.dat'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\win32com\client\gencache.py", line 151, in GetGeneratePath
    os.stat(fname)
FileNotFoundError: [WinError 3] The system cannot find the path specified: 'C:\\Windows\\gen_py\\3.8\\__init__.py'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\Scripts\mamba-script.py", line 6, in <module>
    from mamba.mamba import main
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\mamba\mamba.py", line 53, in <module>
    from mamba.mamba_shell_init import shell_init
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\mamba\mamba_shell_init.py", line 8, in <module>
    from conda.core.initialize import initialize, initialize_dev, make_initialize_plan
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\conda\core\initialize.py", line 75, in <module>
    from menuinst._legacy.knownfolders import get_folder_path, FOLDERID
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\menuinst\__init__.py", line 4, in <module>
    from .api import *
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\menuinst\api.py", line 10, in <module>
    from .platforms import Menu, MenuItem
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\menuinst\platforms\__init__.py", line 20, in <module>
    Menu, MenuItem = menu_api_for_platform()
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\menuinst\platforms\__init__.py", line 6, in menu_api_for_platform
    from .win import WindowsMenu as Menu, WindowsMenuItem as MenuItem
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\menuinst\platforms\win.py", line 10, in <module>
    from win32com.client import Dispatch
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\win32com\client\__init__.py", line 11, in <module>
    from . import gencache
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\win32com\client\gencache.py", line 761, in <module>
    __init__()
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\win32com\client\gencache.py", line 62, in __init__
    Rebuild()
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\win32com\client\gencache.py", line 746, in Rebuild
    _SaveDicts()
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\win32com\client\gencache.py", line 73, in _SaveDicts
    f = open(os.path.join(GetGeneratePath(), "dicts.dat"), "wb")
  File "C:\ProgramData\napari-0.4.15rc3.dev9\envs\napari-0.4.15rc3.dev9\lib\site-packages\win32com\client\gencache.py", line 153, in GetGeneratePath
    f = open(fname, "w")
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Windows\\gen_py\\3.8\\__init__.py'
```

## To Reproduce

Steps to reproduce the behavior:

1. Open the constructor bundled app 0.4.15rc2 on windows
2. Try to install a plugin


<!-- If you have a code sample, error messages, stack traces, please provide it here as well -->

## Expected behavior

Plugin should install without issues

## Environment

 - Please copy and paste the information at napari info option in help menubar here:

 - Any other relevant information:

## Additional context

<!-- Add any other context about the problem here. -->



Discussion:
I think we can set `TEMP` and `TMP`  env vars to `tempfile.gettempdir()` in the subprocess that calls `mamba`, and that should fix it.

Refs:
* https://github.com/mhammond/pywin32/blob/70ddf693927fa1635f15e9ef41eb1aea37fdf32a/com/win32com/__init__.py#L111
* https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha#remarks

Resolving patch:
diff --git a/napari/_qt/dialogs/qt_plugin_dialog.py b/napari/_qt/dialogs/qt_plugin_dialog.py
--- a/napari/_qt/dialogs/qt_plugin_dialog.py
+++ b/napari/_qt/dialogs/qt_plugin_dialog.py
@@ -3,6 +3,7 @@
 from enum import Enum, auto
 from importlib.metadata import PackageNotFoundError, metadata
 from pathlib import Path
+from tempfile import gettempdir
 from typing import Callable, Dict, List, Optional, Sequence, Tuple
 
 from npe2 import PackageMetadata, PluginManager
@@ -56,7 +57,7 @@
 from ..widgets.qt_message_popup import WarnPopup
 from ..widgets.qt_tooltip import QtToolTipLabel
 
-InstallerTypes = Literal['pip', 'conda', 'mamba']
+InstallerTypes = Literal['pip', 'mamba']
 
 
 # TODO: add error icon and handle pip install errors
@@ -108,6 +109,17 @@ def _create_process(
         env.insert(
             "PATH", QProcessEnvironment.systemEnvironment().value("PATH")
         )
+
+        # workaround https://github.com/napari/napari/issues/4247
+        if (
+            installer == "mamba"
+            and os.name == "nt"
+            and not QProcessEnvironment.systemEnvironment().contains("TEMP")
+        ):
+            temp = gettempdir()
+            env.insert("TMP", temp)
+            env.insert("TEMP", temp)
+
         process.setProcessEnvironment(env)
         self.set_output_widget(self._output_widget)
         process.finished.connect(
@@ -708,9 +720,7 @@ def __init__(self, parent=None):
         self.refresh_state = RefreshState.DONE
         self.already_installed = set()
 
-        installer_type = "pip"
-        if running_as_constructor_app():
-            installer_type = "mamba" if os.name != "nt" else "conda"
+        installer_type = "mamba" if running_as_constructor_app() else "pip"
 
         self.installer = Installer(installer=installer_type)
         self.setup_ui()


Test patch: