pipx icon indicating copy to clipboard operation
pipx copied to clipboard

pipx install fails if PIPX_BIN_DIR contains a recursive symlink

Open piks opened this issue 9 months ago • 1 comments

Describe the bug Not sure if this is worth the bug report as its a super niche case that theoretically should have never happened but,

I'm on Debian, I already had been using ~/.local/bin before using this program, as such it was already populated with symlinks

Past me also somehow managed to make a symlink that linked to itself that was located in that directory (oops?).

When this unique combination exists, any package install using the program will crash under

Traceback (most recent call last):
  File "/usr/lib/python3.11/pathlib.py", line 1004, in resolve
    p.stat()
  File "/usr/lib/python3.11/pathlib.py", line 1014, in stat
    return os.stat(self, follow_symlinks=follow_symlinks)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 40] Too many levels of symbolic links: '/home/USER/.local/bin/recursiveexample'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/bin/pipx", line 8, in <module>
    sys.exit(cli())
             ^^^^^
  File "/usr/lib/python3/dist-packages/pipx/main.py", line 819, in cli
    return run_pipx_command(parsed_pipx_args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/pipx/main.py", line 202, in run_pipx_command
    return commands.install(
           ^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/pipx/commands/install.py", line 69, in install
    run_post_install_actions(
  File "/usr/lib/python3/dist-packages/pipx/commands/common.py", line 400, in run_post_install_actions
    package_summary, _ = get_venv_summary(
                         ^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/pipx/commands/common.py", line 216, in get_venv_summary
    exposed_app_paths = get_exposed_app_paths_for_package(
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/pipx/commands/common.py", line 268, in get_exposed_app_paths_for_package
    is_same_file = b.resolve().parent.samefile(venv_bin_path)
                   ^^^^^^^^^^^
  File "/usr/lib/python3.11/pathlib.py", line 1006, in resolve
    check_eloop(e)
  File "/usr/lib/python3.11/pathlib.py", line 991, in check_eloop
    raise RuntimeError("Symlink loop from %r" % e.filename)
RuntimeError: Symlink loop from '/home/USER/.local/bin/recursiveexample'

How to reproduce

  1. Install pipx however method you like
  2. create a recursive symlink of any kind in PIPX_BIN_DIR (I used ln -s ~/.local/bin/recursiveexample ~/.local/bin/recursiveexample for my testing)
  3. try to install any package via pipx install

Expected behavior

Since the symlink had nothing to do with the package install, in theory the package should install, regardless of the broken symlink as it doesn't matter the link

Granted in my case I could just remove the file and it fixed it (once I found out what was causing it), but it took some troubleshooting to see why a seemingly unrelated symlink was causing the failure.

Potential solutions

  1. Since using ~/.local/ is considered proper standard perhaps for local user information, and ~/.local/bin is considered appropriate for local binaries, changing the default PIPX_BIN_DIR to ~/.local/bin/pipx/ would resolve future conflicts with issues regarding users that had already setup a local bin directory (granted this can be done as well by using PIPX_BIN_DIR)
  2. Ignore failures if the symlink has nothing to do with the install (not sure if this is feasible)

piks avatar Jan 16 '25 19:01 piks