jaraco / keyring

MIT License
1.23k stars 152 forks source link

Python 3.12.2 can't find brew installed keyring on Mac Sonoma 14.4 #669

Closed RichardDooling closed 5 months ago

RichardDooling commented 5 months ago

I upgraded Python via brew and access to keyring broke. I tried installing keyring via Homebrew. Still doesn't work. How can I tell Python how to find the Homebrew Keyring?

Python 3.12.2 (main, Feb  6 2024, 20:19:44) [Clang 15.0.0 (clang-1500.1.0.2.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import keyring
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'keyring'

To Reproduce Upgrade python and keyring on Mac. Try to import keyring.

Expected behavior

I expected python to import keyring, as usual.

Environment

macOS Sonoma 14.4

$ pip list | grep keyring

keyring            23.13.1
...
$ keyring --list-backends

keyring            23.13.1
~ ᐅ keyring --list-backends
keyring.backends.fail.Keyring (priority: 0)
keyring.backends.macOS.Keyring (priority: 5)
keyring.backends.chainer.ChainerBackend (priority: -1)
...

If I try to install via pip, I get an error message:

error: externally-managed-environment

Thanks. I am a writer, not a programmer, so I apologize for any mistake I made.

jaraco commented 5 months ago

Probably the issue is with how homebrew installs keyring. To replicate, I've installed keyring using:

 ~ @ brew install keyring
==> Downloading https://ghcr.io/v2/homebrew/core/keyring/manifests/24.3.1
########################################################################################################################################### 100.0%
==> Fetching keyring
==> Downloading https://ghcr.io/v2/homebrew/core/keyring/blobs/sha256:23c9073a230f05c2c1aab7e42f4d756dbc2ff8e89ef8401fe5e199a6e4a920c6
########################################################################################################################################### 100.0%
==> Pouring keyring--24.3.1.arm64_sonoma.bottle.tar.gz
==> Caveats
Bash completion has been installed to:
  /opt/homebrew/etc/bash_completion.d

zsh completions have been installed to:
  /opt/homebrew/share/zsh/site-functions
==> Summary
🍺  /opt/homebrew/Cellar/keyring/24.3.1: 95 files, 457.6KB
==> Running `brew cleanup keyring`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).

Now I'm able to use keyring from the command-line:

 ~ @ /opt/homebrew/bin/keyring --list-backends
keyring.backends.fail.Keyring (priority: 0)
keyring.backends.chainer.ChainerBackend (priority: -1)
keyring.backends.macOS.Keyring (priority: 5)

And like you, when I run Python, I'm still unable to import keyring:

 ~ @ python3.12 -c 'import keyring'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'keyring'

Listing the files that brew installed:

 ~ @ brew list keyring
/opt/homebrew/Cellar/keyring/24.3.1/bin/keyring
/opt/homebrew/Cellar/keyring/24.3.1/etc/bash_completion.d/keyring
/opt/homebrew/Cellar/keyring/24.3.1/libexec/bin/ (5 files)
/opt/homebrew/Cellar/keyring/24.3.1/libexec/lib/ (105 files)
/opt/homebrew/Cellar/keyring/24.3.1/libexec/pyvenv.cfg
/opt/homebrew/Cellar/keyring/24.3.1/share/zsh/site-functions/_keyring

I can see that keyring appears to be installed into a virtualenv and not alongside the python 3.12 installation. If I use Python from that directory, however, I am able to import keyring:

 ~ @ bash -c '$(brew --prefix keyring)/libexec/bin/python -c "import keyring"; echo done'
done

So my guess is that homebrew has re-engineered how it installs keyring (and likely other Python applications) in order to maintain isolation between packages.

If you want to have the keyring library installed, you'll have to decide where you want it installed. I personally have it installed in a couple of places. I use pipx install keyring to make the command line available (equivalent to brew install keyring now), but I also have keyring injected into my xonsh install, so that the library is available alongside my shell.

If you want keyring available in your default Python 3 environment (and this mode is recommended against by the Python packaging community, but has been known to work), you have a couple of choices:

You'll notice that in both cases, you're forced to pass the --break-system-packages. That's because the Python environment installed by homebrew is managed by homebrew and pip requires an override to install anything into that environment (even --user, which isn't managed by homebrew).

Your other option might be to reach out to the homebrew project and ask them what they recommend. It's possible they don't realize that there are users who wish to import the library in their Python install or maybe there's an option to link the libraries into the environment so that they're available for import.

Question for you - if you're a writer and not a programmer, why are you using "import keyring" instead of simply using the keyring executable?

RichardDooling commented 5 months ago

Thank you! I'll play with your one-liner and learn about Python virtualenv. I definitely don't want to break system packages, so I'll learn the other ways. I'm not a programmer, as in, I just know enough to make a Python script now and then as I need one to do something. For years I imported keyring in a script to get the password so I could FTP files to my site. Suddenly it broke. I'll figure it out. Thank you so much for the helpful tips.

jaraco commented 5 months ago

Here's what I'd recommend:

  1. brew install pipx (great for installing Python-based applications).
  2. Run pipx ensurepath (unless homebrew does that).
  3. pipx install pip-run (pip-run) (great for running scripts with their dependencies).
  4. In your script, put #!/usr/bin/env pip-run in the header.
  5. In the script, define any dependencies; e.g. __requires__ = ['keyring']
  6. Make sure your script is executable (chmod u+x myscript).

Now you can run your script (and any one like it) by simply executing it.

Hope that helps.