conda / menuinst

Cross platform menu item installation
https://conda.github.io/menuinst/
BSD 3-Clause "New" or "Revised" License
33 stars 41 forks source link

File types not associated when using file_extensions on Windows #185

Open mrclary opened 5 months ago

mrclary commented 5 months ago

Checklist

What happened?

@jaimergp, I get several errors when using file_extensions. The constructor-based installer successfully installs the environment and shortcuts, however file types don't seem to be associated with Spyder, i.e. Spyder is not an available application to "open with" for expected file types. Additionally, attempting to uninstall or install with menuinst results in the following errors.

Attempt to uninstall shortcut ```cmd [spyder](base) C:\Users\rclary>set bp=%LOCALAPPDATA%\spyder-6 [spyder](base) C:\Users\rclary>set tp=%bp%\envs\spyder-runtime [spyder](base) C:\Users\rclary>set menu=%tp%\Menu\spyder-menu.json [spyder](base) C:\Users\rclary>python -c "from menuinst.api import remove; remove(r'%menu%', target_prefix=r'%tp%', base_prefix=r'%bp%')" Traceback (most recent call last): File "", line 1, in File "C:\Users\rclary\AppData\Local\spyder-6\lib\site-packages\menuinst\utils.py", line 426, in wrapper_elevate return func( File "C:\Users\rclary\AppData\Local\spyder-6\lib\site-packages\menuinst\api.py", line 84, in remove paths += menu_item.remove() File "C:\Users\rclary\AppData\Local\spyder-6\lib\site-packages\menuinst\platforms\win.py", line 173, in remove self._unregister_file_extensions() File "C:\Users\rclary\AppData\Local\spyder-6\lib\site-packages\menuinst\platforms\win.py", line 375, in _unregister_file_extensions unregister_file_extension(ext, identifier, mode=self.menu.mode) File "C:\Users\rclary\AppData\Local\spyder-6\lib\site-packages\menuinst\platforms\win_utils\registry.py", line 88, in unregister_file_extension _reg_exe("delete", fr"{root_str}\Software\Classes\{identifier}") File "C:\Users\rclary\AppData\Local\spyder-6\lib\site-packages\menuinst\platforms\win_utils\registry.py", line 25, in _reg_exe return logged_run(["reg.exe", *args, "/f"], check=True) File "C:\Users\rclary\AppData\Local\spyder-6\lib\site-packages\menuinst\utils.py", line 470, in logged_run process.check_returncode() File "C:\Users\rclary\AppData\Local\spyder-6\lib\subprocess.py", line 457, in check_returncode raise CalledProcessError(self.returncode, self.args, self.stdout, subprocess.CalledProcessError: Command '['reg.exe', 'delete', 'HKCU\\Software\\Classes\\spyder-6.AssocFilec', '/f']' returned non-zero exit status 1. [spyder](base) C:\Users\rclary>reg.exe delete HKLM\Software\Classes\spyder-6.AssocFilec /f ERROR: The system was unable to find the specified registry key or value. ```
Attempt to install shortcut ```cmd [spyder](base) C:\Users\rclary>python -c "from menuinst.api import install; Traceback (most recent call last): File "", line 1, in File "C:\Users\rclary\AppData\Local\spyder-6\lib\site-packages\menuinst\utils.py", line 426, in wrapper_elevate return func( File "C:\Users\rclary\AppData\Local\spyder-6\lib\site-packages\menuinst\api.py", line 62, in install paths += menu_item.create() File "C:\Users\rclary\AppData\Local\spyder-6\lib\site-packages\menuinst\platforms\win.py", line 167, in create self._register_file_extensions() File "C:\Users\rclary\AppData\Local\spyder-6\lib\site-packages\menuinst\platforms\win.py", line 365, in _register_file_extensions register_file_extension(ext, identifier, command, icon=icon, mode=self.menu.mode) File "C:\Users\rclary\AppData\Local\spyder-6\lib\site-packages\menuinst\platforms\win_utils\registry.py", line 75, in register_file_extension winreg.SetValueEx(subkey, "DefaultIcon", 0, winreg.REG_SZ, icon) PermissionError: [WinError 5] Access is denied ```

I get the same errors whether I run the installer as administrator or not, except the traceback file paths are C:\ProgramData\spyder-6... instead. The first error appears to result because the spyder-6.AssocFilec registry key was not created as expected. I'm puzzled why the second error occurs even when run from a cmd window with administrator privileges: why wasn't a PermissionError raised when menuinst was run from the installer?.

Conda Info

```shell mamba version : 1.5.6 active environment : base active env location : C:\Users\rclary\AppData\Local\spyder-6 shell level : 2 user config file : C:\Users\rclary\.condarc populated config files : C:\Users\rclary\AppData\Local\spyder-6\.condarc C:\Users\rclary\.condarc conda version : 23.11.0 conda-build version : not installed python version : 3.10.13.final.0 solver : libmamba (default) virtual packages : __archspec=1=x86_64 __conda=23.11.0=0 __win=0=0 base environment : C:\Users\rclary\AppData\Local\spyder-6 (writable) conda av data dir : C:\Users\rclary\AppData\Local\spyder-6\etc\conda conda av metadata url : None channel URLs : https://conda.anaconda.org/conda-forge/label/spyder_kernels_rc/win-64 https://conda.anaconda.org/conda-forge/label/spyder_kernels_rc/noarch https://conda.anaconda.org/conda-forge/label/spyder_dev/win-64 https://conda.anaconda.org/conda-forge/label/spyder_dev/noarch https://conda.anaconda.org/conda-forge/win-64 https://conda.anaconda.org/conda-forge/noarch package cache : C:\Users\rclary\AppData\Local\spyder-6\pkgs C:\Users\rclary\.conda\pkgs C:\Users\rclary\AppData\Local\conda\conda\pkgs envs directories : C:\Users\rclary\.conda\envs C:\Users\rclary\AppData\Local\spyder-6\envs C:\Users\rclary\AppData\Local\conda\conda\envs platform : win-64 user-agent : conda/23.11.0 requests/2.31.0 CPython/3.10.13 Windows/10 Windows/10.0.19045 solver/libmamba conda-libmamba-solver/23.12.0 libmambapy/1.5.6 administrator : False netrc file : None offline mode : False ```

Conda Config

```shell ==> C:\Users\rclary\AppData\Local\spyder-6\.condarc <== auto_update_conda: False notify_outdated_conda: False env_prompt: [spyder]({default_env}) channel_priority: flexible channels: - conda-forge/label/spyder_kernels_rc - conda-forge/label/spyder_dev - conda-forge repodata_fns: - repodata.json ==> C:\Users\rclary\.condarc <== auto_activate_base: False envs_dirs: - ~/.conda/envs channel_priority: flexible channels: - conda-forge/label/spyder_kernels_rc - conda-forge - defaults show_channel_urls: True conda-build: root-dir: ~/.conda/conda-bld ```

Conda list

```shell # packages in environment at C:\Users\rclary\AppData\Local\spyder-6: # # Name Version Build Channel archspec 0.2.2 pyhd8ed1ab_0 conda-forge boltons 23.1.1 pyhd8ed1ab_0 conda-forge brotli-python 1.1.0 py310h00ffb61_1 conda-forge bzip2 1.0.8 hcfcfb64_5 conda-forge ca-certificates 2023.11.17 h56e8100_0 conda-forge certifi 2023.11.17 pyhd8ed1ab_0 conda-forge cffi 1.16.0 py310h8d17308_0 conda-forge charset-normalizer 3.3.2 pyhd8ed1ab_0 conda-forge colorama 0.4.6 pyhd8ed1ab_0 conda-forge conda 23.11.0 py310h5588dad_1 conda-forge conda-libmamba-solver 23.12.0 pyhd8ed1ab_0 conda-forge conda-package-handling 2.2.0 pyh38be061_0 conda-forge conda-package-streaming 0.9.0 pyhd8ed1ab_0 conda-forge distro 1.9.0 pyhd8ed1ab_0 conda-forge fmt 10.2.1 h181d51b_0 conda-forge idna 3.6 pyhd8ed1ab_0 conda-forge jsonpatch 1.33 pyhd8ed1ab_0 conda-forge jsonpointer 2.4 py310h5588dad_3 conda-forge krb5 1.21.2 heb0366b_0 conda-forge libarchive 3.7.2 h313118b_1 conda-forge libcurl 8.5.0 hd5e4a3a_0 conda-forge libffi 3.4.2 h8ffe710_5 conda-forge libiconv 1.17 hcfcfb64_2 conda-forge libmamba 1.5.6 h3f09ed1_0 conda-forge libmambapy 1.5.6 py310h04f2035_0 conda-forge libsolv 0.7.27 h12be248_0 conda-forge libsqlite 3.44.2 hcfcfb64_0 conda-forge libssh2 1.11.0 h7dfc565_0 conda-forge libxml2 2.12.4 hc3477c8_1 conda-forge libzlib 1.2.13 hcfcfb64_5 conda-forge lz4-c 1.9.4 hcfcfb64_0 conda-forge lzo 2.10 he774522_1000 conda-forge mamba 1.5.6 py310hd9d798f_0 conda-forge menuinst 2.0.2 py310h00ffb61_0 conda-forge openssl 3.2.0 hcfcfb64_1 conda-forge packaging 23.2 pyhd8ed1ab_0 conda-forge pip 23.3.2 pyhd8ed1ab_0 conda-forge platformdirs 4.1.0 pyhd8ed1ab_0 conda-forge pluggy 1.4.0 pyhd8ed1ab_0 conda-forge pybind11-abi 4 hd8ed1ab_3 conda-forge pycosat 0.6.6 py310h8d17308_0 conda-forge pycparser 2.21 pyhd8ed1ab_0 conda-forge pysocks 1.7.1 pyh0701188_6 conda-forge python 3.10.13 h4de0772_1_cpython conda-forge python_abi 3.10 4_cp310 conda-forge reproc 14.2.4.post0 hcfcfb64_1 conda-forge reproc-cpp 14.2.4.post0 h63175ca_1 conda-forge requests 2.31.0 pyhd8ed1ab_0 conda-forge ruamel.yaml 0.18.5 py310h8d17308_0 conda-forge ruamel.yaml.clib 0.2.7 py310h8d17308_2 conda-forge setuptools 69.0.3 pyhd8ed1ab_0 conda-forge tk 8.6.13 h5226925_1 conda-forge tqdm 4.66.1 pyhd8ed1ab_0 conda-forge truststore 0.8.0 pyhd8ed1ab_0 conda-forge tzdata 2023d h0c530f3_0 conda-forge ucrt 10.0.22621.0 h57928b3_0 conda-forge urllib3 2.1.0 pyhd8ed1ab_0 conda-forge vc 14.3 hcf57466_18 conda-forge vc14_runtime 14.38.33130 h82b7239_18 conda-forge vs2015_runtime 14.38.33130 hcb4865c_18 conda-forge wheel 0.42.0 pyhd8ed1ab_0 conda-forge win_inet_pton 1.1.0 pyhd8ed1ab_6 conda-forge xz 5.2.6 h8d14728_0 conda-forge yaml-cpp 0.8.0 h63175ca_0 conda-forge zstandard 0.22.0 py310h0009e47_0 conda-forge zstd 1.5.5 h12be248_0 conda-forge ```

Additional Context

spyder-menu.json ```json { "$schema": "https://json-schema.org/draft-07/schema", "$id": "https://schemas.conda.io/menuinst-1.schema.json", "menu_name": "{{ DISTRIBUTION_NAME }} spyder", "menu_items": [ { "name": "Spyder 6", "description": "Scientific PYthon Development EnviRonment", "icon": "{{ MENU_DIR }}/spyder.{{ ICON_EXT }}", "activate": false, "terminal": false, "command": [""], "platforms": { "win": { "desktop": true, "app_user_model_id": "spyder.Spyder", "command": ["{{ PREFIX }}/pythonw.exe", "{{ PREFIX }}/Scripts/spyder-script.py"], "file_extensions": [ "bat", "c", "cc", "cfg", "cl", "cmd", "cpp", "css", "cxx", "desktop", "diff", "enaml", "f", "f03", "f08", "f2k", "f77", "f90", "f95", "for", "h", "h", "hh", "hpp", "htm", "html", "hxx", "inf", "ini", "ipy", "ipynb", "jl", "js", "json", "m", "md", "nsh", "nsi", "patch", "po", "pot", "pro", "properties", "pxd", "pxi", "py", "pyw", "pyx", "reg", "rej", "rst", "scss", "session", "txt", "xml", "yaml", "yml" ] }, "linux": { "Categories": [ "Development", "Science" ], "command": ["{{ PREFIX }}/bin/spyder", "$@"], "StartupWMClass": "Spyder", "MimeType": [ "text/x-script.python", "text/plain", "text/html", "text/xml", "text/x-c", "text/x-perl" ] }, "osx": { "precommand": "pushd \"$(dirname \"$0\")\" &>/dev/null", "command": ["./python", "{{ PREFIX }}/bin/spyder", "$@"], "link_in_bundle": { "{{ PREFIX }}/bin/python": "{{ MENU_ITEM_LOCATION }}/Contents/MacOS/python" }, "CFBundleName": "Spyder 6", "CFBundleIdentifier": "org.spyder-ide.Spyder", "CFBundleVersion": "6.0.0a4.dev152", "CFBundleDocumentTypes": [ { "CFBundleTypeName": "text document", "CFBundleTypeRole": "Editor", "LSHandlerRank": "Default", "CFBundleTypeIconFile": "spyder.icns", "LSItemContentTypes": [ "com.apple.applescript.text", "com.apple.ascii-property-list", "com.apple.audio-unit-preset", "com.apple.binary-property-list", "com.apple.configprofile", "com.apple.crashreport", "com.apple.dashcode.css", "com.apple.dashcode.javascript", "com.apple.dashcode.json", "com.apple.dashcode.manifest", "com.apple.dt.document.ascii-property-list", "com.apple.dt.document.script-suite-property-list", "com.apple.dt.document.script-terminology-property-list", "com.apple.property-list", "com.apple.rez-source", "com.apple.scripting-definition", "com.apple.structured-text", "com.apple.traditional-mac-plain-text", "com.apple.xcode.ada-source", "com.apple.xcode.apinotes", "com.apple.xcode.bash-script", "com.apple.xcode.configsettings", "com.apple.xcode.csh-script", "com.apple.xcode.entitlements-property-list", "com.apple.xcode.fortran-source", "com.apple.xcode.glsl-source", "com.apple.xcode.ksh-script", "com.apple.xcode.lex-source", "com.apple.xcode.make-script", "com.apple.xcode.mig-source", "com.apple.xcode.pascal-source", "com.apple.xcode.strings-text", "com.apple.xcode.tcsh-script", "com.apple.xcode.yacc-source", "com.apple.xcode.zsh-script", "com.apple.xml-property-list", "com.netscape.javascript-source", "com.scenarist.closed-caption", "com.sun.java-source", "com.sun.java-web-start", "net.daringfireball.markdown", "org.khronos.glsl-source", "org.oasis-open.xliff", "public.ada-source", "public.assembly-source", "public.bash-script", "public.c-header", "public.c-plus-plus-header", "public.c-plus-plus-source", "public.c-source", "public.case-insensitive-text", "public.comma-separated-values-text", "public.csh-script", "public.css", "public.delimited-values-text", "public.dylan-source", "public.filename-extension", "public.fortran-77-source", "public.fortran-90-source", "public.fortran-95-source", "public.fortran-source", "public.html", "public.json", "public.ksh-script", "public.lex-source", "public.log", "public.m3u-playlist", "public.make-source", "public.mig-source", "public.mime-type", "public.module-map", "public.nasm-assembly-source", "public.objective-c-plus-plus-source", "public.objective-c-source", "public.opencl-source", "public.pascal-source", "public.patch-file", "public.perl-script", "public.php-script", "public.plain-text", "public.python-script", "public.rss", "public.ruby-script", "public.script", "public.shell-script", "public.source-code", "public.tcsh-script", "public.text", "public.utf16-external-plain-text", "public.utf16-plain-text", "public.utf8-plain-text", "public.utf8-tab-separated-values-text", "public.xhtml", "public.xml", "public.yacc-source", "public.yaml", "public.zsh-script" ] } ] } } } ] } ```
jaimergp commented 5 months ago

Hm, can you try with a leading period for the extensions? See example.

"It works on CI", but CI runs as administrator by default, so we might need to adjust something. "Open With" has not been added per se, as it requires some extra registry keys.

jaimergp commented 3 months ago

@mrclary did you have a chance to take a look at the workaround?

mrclary commented 3 months ago

@jaimergp, sorry, I have not yet had a chance to look at it.

mrclary commented 3 months ago

The short of it

I suspect that an error occurs on install after the first item in the file extension list is handled resulting in no other extensions being handled, but the shortcut is produced. On uninstall, an error results due to the missing expected AssocFiles.

The long of it

So I tried using menuinst in a standard conda environment.

(base) C:\Users\rclary>mamba create -n spyder6_test -c conda-forge/label/spyder_dev -c conda-forge/label/spyder_kernels_rc spyder=6.0.0a4

This version of Spyder does not have file extensions listed in the spyder-menu.json file and the shortcut is created without issue. I can also uninstall it without issue.

(base) C:\Users\rclary>set bp=C:\Users\AppData\Local\miniforge3
(base) C:\Users\rclary>set tp=%bp%\envs\spyder6_test
(base) C:\Users\rclary>set menu=%tp%\Menu\spyder-menu.json
(base) C:\Users\rclary>python -c "from menuinst.api import remove; remove(r'%menu%', target_prefix=r'%tp%', base_prefix=r'%bp%')"

However, I get the following errors after modifying spyder-menu.json to include two file extensions.

spyder-menu.json ``` { "$schema": "https://json-schema.org/draft-07/schema", "$id": "https://schemas.conda.io/menuinst-1.schema.json", "menu_name": "{{ DISTRIBUTION_NAME }} spyder", "menu_items": [ { "name": "Spyder 6 ({{ ENV_NAME }})", "description": "Scientific PYthon Development EnviRonment", "icon": "{{ MENU_DIR }}/spyder.{{ ICON_EXT }}", "activate": false, "terminal": false, "command": [""], "platforms": { "win": { "desktop": true, "app_user_model_id": "spyder.Spyder", "command": ["{{ PREFIX }}/pythonw.exe", "{{ PREFIX }}/Scripts/spyder-script.py"], "file_extensions": [ ".py", ".pyw" ] }, "linux": { "Categories": [ "Development", "Science" ], "command": ["{{ PREFIX }}/bin/spyder", "$@"], "StartupWMClass": "Spyder" }, "osx": { "precommand": "pushd \"$(dirname \"$0\")\" &>/dev/null", "command": ["./python", "{{ PREFIX }}/bin/spyder", "$@"], "link_in_bundle": { "{{ PREFIX }}/bin/python": "{{ MENU_ITEM_LOCATION }}/Contents/MacOS/python" }, "CFBundleName": "Spyder 6", "CFBundleIdentifier": "org.spyder-ide.Spyder", "CFBundleVersion": "6.0.0a4" } } } ] } ```
(base) C:\Users\rclary>python -c "from menuinst.api import install; install(r'%menu%', target_prefix=r'%tp%', base_prefix=r'%bp%')"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\utils.py", line 426, in wrapper_elevate
    return func(
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\api.py", line 62, in install
    paths += menu_item.create()
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\platforms\win.py", line 167, in create
    self._register_file_extensions()
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\platforms\win.py", line 365, in _register_file_extensions
    register_file_extension(ext, identifier, command, icon=icon, mode=self.menu.mode)
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\platforms\win_utils\registry.py", line 75, in register_file_extension
    winreg.SetValueEx(subkey, "DefaultIcon", 0, winreg.REG_SZ, icon)
PermissionError: [WinError 5] Access is denied

HKCU\Software\Classes\spyder-6-spyder6-test.AssocFile.py appears in the registry, but not HKCU\Software\Classes\spyder-6-spyder6-test.AssocFile.pyw.

And attempting to uninstall:

(base) C:\Users\rclary>python -c "from menuinst.api import remove; remove(r'%menu%', target_prefix=r'%tp%', base_prefix=r'%bp%')"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\utils.py", line 426, in wrapper_elevate
    return func(
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\api.py", line 84, in remove
    paths += menu_item.remove()
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\platforms\win.py", line 173, in remove
    self._unregister_file_extensions()
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\platforms\win.py", line 375, in _unregister_file_extensions
    unregister_file_extension(ext, identifier, mode=self.menu.mode)
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\platforms\win_utils\registry.py", line 88, in unregister_file_extension
    _reg_exe("delete", fr"{root_str}\Software\Classes\{identifier}")
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\platforms\win_utils\registry.py", line 25, in _reg_exe
    return logged_run(["reg.exe", *args, "/f"], check=True)
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\utils.py", line 470, in logged_run
    process.check_returncode()
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\subprocess.py", line 457, in check_returncode
    raise CalledProcessError(self.returncode, self.args, self.stdout,
subprocess.CalledProcessError: Command '['reg.exe', 'delete', 'HKCU\\Software\\Classes\\spyder-6-spyder6-test.AssocFile.pyw', '/f']' returned non-zero exit status 1.

HKCU\Software\Classes\spyder-6-spyder6-test.AssocFile.py is removed from the registry, but there is the error for .pyw.

If I only have one extension in the list, the install produces the same error, although the AssocFile is produced. The uninstall does not produce an error. So, I suspect that the error occurs on install after the first extension in the list is handled resulting in no other extensions being handled, but the shortcut is produced nonetheless. Then, on uninstall, the error is a result of the missing expected AssocFiles.

jaimergp commented 3 months ago

Looks like the problem is at:

https://github.com/conda/menuinst/blob/db528854422d765d9423eb7c705e06b0c7ade905/menuinst/platforms/win_utils/registry.py#L73-L76

So maybe it works if you remove the icon entry from the JSON. I'll check where that permissions issue is coming from and add tests with icons. I see several things to fix the code with:

mrclary commented 4 days ago

@jaimergp, with menuinst=2.1.1 I no longer have the issues I described in my previous comment: https://github.com/conda/menuinst/issues/185#issuecomment-1982536505 👏🏼. I can add/remove the shortcut without errors and the registry entries are added/removed as expected.

The only issue that remains is that the file type association in context menus appears as Python instead of Spyder (both name and icon). Nevertheless, associating with "Python" does, in fact, open the file in Spyder. Perhaps this is a result of the shortcut target using pythonw.exe instead of spyder.exe? I know we've discussed in the past regarding executable targets causing cmd windows to open, which is why I target pythonw.exe instead.

Screenshot 2024-06-28 at 9 25 37 AM Screenshot 2024-06-28 at 9 26 59 AM
mrclary commented 4 days ago

@jaimergp, actually there is still an issue with the registry when removing an environment. For example

(base) C:\Users\rclary>mamba remove -n spy6b3d8 --all

Remove all packages in environment C:\Users\rclary\.conda\envs\spy6b3d8:

Preparing transaction: done
Verifying transaction: done
Executing transaction: | menuinst Exception
Traceback (most recent call last):
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\conda\gateways\disk\create.py", line 261, in make_menu
    menuinst.install(
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\api.py", line 168, in _install_adapter
    _api_remove(metadata, target_prefix=prefix, **kwargs)
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\utils.py", line 426, in wrapper_elevate
    return func(
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\api.py", line 84, in remove
    paths += menu_item.remove()
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\platforms\win.py", line 207, in remove
    self._unregister_file_extensions()
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\platforms\win.py", line 457, in _unregister_file_extensions
    unregister_file_extension(ext, identifier, mode=self.menu.mode)
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\platforms\win_utils\registry.py", line 89, in unregister_file_extension
    _reg_exe("delete", fr"{root_str}\Software\Classes\{identifier}")
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\platforms\win_utils\registry.py", line 26, in _reg_exe
    return logged_run(["reg.exe", *args, "/f"], check=True)
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\site-packages\menuinst\utils.py", line 470, in logged_run
    process.check_returncode()
  File "C:\Users\rclary\AppData\Local\miniforge3\lib\subprocess.py", line 457, in check_returncode
    raise CalledProcessError(self.returncode, self.args, self.stdout,
subprocess.CalledProcessError: Command '['reg.exe', 'delete', 'HKCU\\Software\\Classes\\spyder-6-spy6b3d8.AssocFile.bat', '/f']' returned non-zero exit status done

The registry key is removed, so perhaps it is trying to delete it again and it's no longer there?

mrclary commented 4 days ago

Also, FYI, conda env remove -n spy6b3d8 removes the environment, but not the shortcut or registry keys and there is no error reported. Only conda remove -n spy6b3d8 --all removes the menuinst shortcut, registry keys, and the environment, but with the reported error.

jaimergp commented 1 day ago

Also, FYI, conda env remove -n spy6b3d8 removes the environment, but not the shortcut or registry keys and there is no error reported.

Yes, this is a known issue: https://github.com/conda/conda/issues/11092.

I'll look into the other reports, thanks for giving it a try!

Edit: Found these resources. Writing them down here for future reference:

jaimergp commented 1 day ago

Apparently Windows wants us to use "indirect strings" for those Progids attributes. We can't just put the text directly there.

Instead, we are asked to bundle the custom strings in a resource binary (.rsrc section in a PE file). These files are usually written by passing an XML file to rc.exe (part of the Windows SDK). We can't depend on that or expect it to be installed (too big, compiled, non-redistributable).

Writing a PE file from scratch is technically possible with pefile, pe-tools or lief; the former is preferred because it's lighter, but it will take a lot of experimentation to find out how the strings look like in the final file. lief has some resource handling convenience wrappers that might make it easier but it's heavier as a dependency that will be added to conda...

jaimergp commented 1 day ago

Huh, turns out at least one more person in the world has looked into this and reported that Windows 10 does support raw strings without the PE indirection. That simplifies things drastically. I'll open a PR once I can push to the repo.

jaimergp commented 1 day ago

@mrclary, is there a chance you can try https://github.com/conda/menuinst/pull/225 locally?