uv icon indicating copy to clipboard operation
uv copied to clipboard

Don't break on upgrades of externally-managed Pythons

Open lishaduck opened this issue 1 year ago • 6 comments

I primarily use uv a a pipx replacement. Whenever I run brew upgrade and there's a new version of the [email protected] package, all of the Python CLIs I use break with /Users/username/.local/bin/some-package: bad interpreter: /Users/username/.local/share/uv/tools/some-package/bin/python3: no such file or directory. Upon further inspection, it looks like uv is using aliases instead of symlinks, which the wonderful internet informs me link to a file id, rather than a file path. If I try to repair them using uv tool install --force some-package, it works, but I have to run this manually. uv tool upgrade --all --reinstall fails with error: Failed to upgrade some-package Caused by: `some-package` is not installed; run `uv tool install some-package` to install. Note: this is not a regression, it's been true since August; I just thought there was an existing issue, but there wasn't.

lishaduck avatar Dec 09 '24 15:12 lishaduck

We don't use aliases, afaik. Can you share more details about the contents of /Users/username/.local/bin/some-package and the target of /Users/username/.local/share/uv/tools/some-package/bin/python3?

zanieb avatar Dec 09 '24 15:12 zanieb

We don't use aliases, afaik. Can you share more details about the contents of /Users/username/.local/bin/some-package and the target of /Users/username/.local/share/uv/tools/some-package/bin/python3?

Sure! For ipython, /Users/username/.local/bin/ipython is a symlink pointing to /Users/username/.local/share/uv/tools/ipython/bin/ipython. That's an executable file, if I force-open it in TextEdit (macOS doesn't recognize it as a text file), it's a simple wrapper script:

#!/Users/username/.local/share/uv/tools/ipython/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from IPython import start_ipython
if __name__ == "__main__":
    sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0])
    sys.exit(start_ipython())

/Users/username/.local/share/uv/tools/ipython/bin/python3 is an alias pointing to /opt/homebrew/Cellar/[email protected]/3.13.1/Frameworks/Python.framework/Versions/3.13/bin/python3.13. I know it's an alias because if I rename the python3.13 binary to python6.13, the uv alias remains pointed to the file.

lishaduck avatar Dec 09 '24 15:12 lishaduck

Per a brief Google search

Aliases store two pieces of information about the destination file - both the location and a file identifier. Symbolic links only store the other location. For that reason, if you move a file, Aliases are superior since they can often still point at the correct file when a change happens.

My understanding is that we're using symbolic links everywhere, which matches both the behavior and the above description.

I'm surprised we resolve the Python interpreter to /opt/homebrew/Cellar/[email protected]/3.13.1/Frameworks/Python.framework/Versions/3.13/bin/python3.13 though, I believe we made some changes to try to use their stable directory.

What does uv python list show?

zanieb avatar Dec 10 '24 20:12 zanieb

Per a brief Google search

Aliases store two pieces of information about the destination file - both the location and a file identifier. Symbolic links only store the other location. For that reason, if you move a file, Aliases are superior since they can often still point at the correct file when a change happens.

My understanding is that we're using symbolic links everywhere, which matches both the behavior and the above description.

How do symbolic links match the behavior? If I rename the python3.13 in the Cellar, the alias remains pointed to the "right" file, which is not the behavior of a symlink, which only stores the path. I'm not trying to be a bother, I'm just confused where the statement about behavior came from.

I'm surprised we resolve the Python interpreter to /opt/homebrew/Cellar/[email protected]/3.13.1/Frameworks/Python.framework/Versions/3.13/bin/python3.13 though, I believe we made some changes to try to use their stable directory.

What does uv python list show?

Here you go:

❯ uv python list    
cpython-3.13.1+freethreaded-macos-aarch64-none    <download available>
cpython-3.13.1-macos-aarch64-none                 /opt/homebrew/opt/[email protected]/bin/python3.13 -> ../Frameworks/Python.framework/Versions/3.13/bin/python3.13
cpython-3.13.1-macos-aarch64-none                 <download available>
cpython-3.12.8-macos-aarch64-none                 /opt/homebrew/opt/[email protected]/bin/python3.12 -> ../Frameworks/Python.framework/Versions/3.12/bin/python3.12
cpython-3.12.8-macos-aarch64-none                 <download available>
cpython-3.11.11-macos-aarch64-none                <download available>
cpython-3.10.16-macos-aarch64-none                <download available>
cpython-3.9.21-macos-aarch64-none                 <download available>
cpython-3.9.6-macos-aarch64-none                  /Applications/Xcode.app/Contents/Developer/usr/bin/python3 -> ../../Library/Frameworks/Python3.framework/Versions/3.9/bin/python3
cpython-3.8.20-macos-aarch64-none                 <download available>
pypy-3.10.14-macos-aarch64-none                   <download available>
pypy-3.9.19-macos-aarch64-none                    <download available>
pypy-3.8.16-macos-aarch64-none                    <download available>

~ took 2s 

lishaduck avatar Dec 10 '24 20:12 lishaduck

How do symbolic links match the behavior? If I rename the python3.13 in the Cellar, the alias remains pointed to the "right" file, which is not the behavior of a symlink, which only stores the path.

Ah sorry I misread what you said. I guess I'm a bit confused about the alias vs symlink behaviors. I'll need to just take some time to verify what's happening under the hood — afaik we don't create any aliases explicitly but perhaps the Rust standard library does.

Thanks for providing the uv python list output! That's helpful. I'm surprised we resolve that interpreter to a different path. Can you confirm this occurs on the latest version of uv if you install a new tool?

zanieb avatar Dec 10 '24 22:12 zanieb

Can you confirm this occurs on the latest version of uv if you install a new tool?

Oh, I installed uv via the Homebrew formula as well (it doesn't look they they patch it, but worth noting). I installed black, made a copy of the original python binary, deleted the original python binary, and renamed the copied one to python3.13, and it works fine. I'm unsure what's different (it's gotta something different Brew is doing, I haven't updated uv, python, or Brew since filing the issue (as there aren't new updates)).

lishaduck avatar Dec 10 '24 22:12 lishaduck