python-poetry / poetry

Python packaging and dependency management made easy
https://python-poetry.org
MIT License
31.44k stars 2.27k forks source link

Error: Unable to store the password for poetry-repository-pypi in the key ring: Failed to unlock the collection! #2692

Closed joaqo closed 2 years ago

joaqo commented 4 years ago

Hi, I am getting [KeyRingError] Unable to store the password for poetry-repository-pypi in the key ring: Failed to unlock the collection! when running:

poetry config pypi-token.pypi <MY PYPI TOKEN>

Searched for this error everywhere but couldn't find anything. Running on the last version of Poetry and Ubuntu 18.04 LTS.

Also, if I set the token using an environment variable I get: Unable to retrieve the password for poetry-repository-pypi from the key ring.

abn commented 4 years ago

Can you try unlocking the collection using something like Seahorse?

Usually this happens when your keyring was left locked after login etc. Manual unlocks and/or reboots are known fix this issue. Note that this has nothing to do with poetry or how it interacts with the OS keyring.

earonesty commented 4 years ago

Why does poetry need the keyring? Is it possible to build/deploy in CI/CD without using a keyring?

abn commented 4 years ago

@earonesty poetry uses keyring for storing credentials. It is entirely possible to build/deploy in CI/CD without any issues.

https://github.com/python-poetry/poetry/blob/17b165bf8c8d989d672417fd4610721df59ae1d0/.github/workflows/release.yml#L261-L266

abn commented 4 years ago

@python-poetry/triage we should consider providing a error solution exception via crashtest or implement an option to skip keyring on failure when writing l; and warn in both write and read cases where this fails.

randallpittman commented 3 years ago

I have this problem with keyring working with Seahorse or something if I'm logged into a remote machine over ssh. If I log in with X2Go instead of getting an error it just freezes... 🤷🏼‍♂️ Will return with more info if I get any.

EDIT 1: I get this error "Failed to unlock the collection!" if I try to use keyring in the following manner while logged into a remote machine (Linux Mint 20 XFCE, Seahorse is the password manager):

import keyring
keyring.set_password("poetry-repository-testpypi", "__token__", "<my-testpypi-key>"

So I guess keyring doesn't work over SSH? I'll look into the issues over at jaraco/keyring.

EDIT 2: The README at jaraco/keyring provides instructions for running keyring on a headless system. This seems like quite a bit of hassle and very non-obvious for poetry users.

g8rpal commented 3 years ago

this fixed it for me... https://blog.frank-mich.com/python-poetry-1-0-0-private-repo-issue-fix/

earonesty commented 2 years ago

@earonesty poetry uses keyring for storing credentials. It is entirely possible to build/deploy in CI/CD without any issues.

right, but why bother storing credentials? i don't want it to.

strongbugman commented 2 years ago

well, maybe a permission problem, with "sudo" save me in this case

ypicard commented 2 years ago

Poetry strikes again 💣

KafCoppelia commented 2 years ago

Similar error occured when I was using poetry build then poetry publish to publish my python project to PYPI.🤔 But yesterday before the problem ocurred Poetry did in normal.

KeyRingError

Unable to retrieve the password for poetry-repository-pypi from the key ring

at ~/.local/share/pypoetry/venv/lib/python3.8/site-packages/poetry/utils/password_manager.py:39 in get_password 35│ 36│ try: 37│ return keyring.get_password(name, username) 38│ except (RuntimeError, keyring.errors.KeyringError): → 39│ raise KeyRingError( 40│ "Unable to retrieve the password for {} from the key ring".format(name) 41│ ) 42│ 43│ def set_password(self, name, username, password):

KafCoppelia commented 2 years ago

Oh fixed it today by using poetry config http-basic.pypi username password.

MasterMedo commented 2 years ago

sudo pacman -S gnome-keyring solved it for me.

UltiRequiem commented 2 years ago

sudo pacman -S gnome-keyring

This, but is not cool to have to install something of gnome if you are not using gnome...

Cardu commented 2 years ago

Had the same problem in a container, solved it by setting the null keyring within the underlying lib, it's just an env variable:

PYTHON_KEYRING_BACKEND: keyring.backends.null.Keyring

see https://pypi.org/project/keyring/ disabling keyring

KafCoppelia commented 2 years ago

OK keyringerror again. Then fixed it by keyring --disable in terminal on Ubuntu. Then poetry publish --build as usual OK!

pyalchy1 commented 2 years ago

Why does poetry need the keyring? Is it possible to build/deploy in CI/CD without using a keyring?

I'm quite curious about this as well actually.

https://github.com/python-poetry/poetry/issues/2692#issuecomment-996489094

I can't remember ever having to install any package with root permissions. Infact, If I remember correctly, pip specifically warns against it.

Also, why exactly does poetry modify the error Traceback?

sigh I have other questions, but mainly why does poetry even request access from the keyring in the first place?

sanderland commented 2 years ago

Installing keyrings.alt fixed this for me. The problem was that only keyrings.google-artifactregistry-auth was available, which does not have a set_password

earonesty commented 2 years ago

this works to evade the keyring, and is appropriate for ci/cd

POETRY_HTTP_BASIC_TEST_USERNAME=__token__
POETRY_HTTP_BASIC_TEST_PASSWORD=pypi-secret
pronovic commented 2 years ago

I'm running into a similar error with Poetry v1.2.0 for simple operations like installing a plugin in my Debian development environment. I'm not sure whether this is exactly the same issue as described above or just results in a similar error message.

$ poetry self add poetry-dynamic-versioning-plugin
Failed to unlock the collection!

This seems to have happened because I was SSH'd into my development environment, which has the GNOME Keyring installed. When I RDP'd in so I would have an X session, then the GNOME keyring dialog popped up to unlock the keyring. On the surface, it doesn't seem like there's any need for the keyring in this situation, because I'm installing a public plugin. It seems like maybe there's a code path where Poetry attempts to unlock the keyring even if it's not going to be needed.

I don't get this error on Windows or MacOS, although it's possible that a keyring is just silently being unlocked under the covers on those platforms, and I don't notice because it's not failing.

My workaround is to explicitly set a null keyring as suggested in @Cardu 's comment above, in Poetry issue #6277, and also in pip issue #6773:

$ PYTHON_KEYRING_BACKEND="keyring.backends.null.Keyring" poetry self add poetry-dynamic-versioning-plugin

I also confirmed that keyring --disable works as in @KafCoppelia 's suggestion. However, I don't like that solution for my use case, because it permanently disables the keyring in configuration, and I do need the keyring available for other things.

shyney7 commented 2 years ago

Im also getting this error on my Debian Distro when trying to configure a new project with poetry init. When trying to specify the dependencies it fails with the following errors:

Package to add or search for (leave blank to skip): pydrive
[urllib3.connectionpool] Starting new HTTPS connection (1): pypi.org:443
[urllib3.connectionpool] https://pypi.org:443 "GET /search?q=pydrive HTTP/1.1" 301 215
[urllib3.connectionpool] https://pypi.org:443 "GET /search/?q=pydrive HTTP/1.1" 200 23369
Found 20 packages matching pydrive
Showing the first 10 matches

Enter package # to add, or the complete package name if it is not listed []:
 [ 0] PyDrive
 [ 1] PyDrive3
 [ 2] PyDrive2
 [ 3] pydriver
 [ 4] pydriveziead
 [ 5] pydrivedol
 [ 6] drivelib
 [ 7] GsuiteToMd
 [ 8] yagdrive
 [ 9] free-storage
 [10] 
 > 0
Enter the version constraint to require (or leave blank to use the latest version): 
[keyring.backend] Loading KWallet
[keyring.backend] Loading SecretService
[keyring.backend] Loading Windows
[keyring.backend] Loading chainer
[keyring.backend] Loading libsecret
[keyring.backend] Loading macOS

  Stack trace:

  29  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/cleo/application.py:329 in run
       327│ 
       328│             try:
     → 329│                 exit_code = self._run(io)
       330│             except Exception as e:
       331│                 if not self._catch_exceptions:

  28  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/console/application.py:185 in _run
       183│         self._load_plugins(io)
       184│ 
     → 185│         exit_code: int = super()._run(io)
       186│         return exit_code
       187│ 

  27  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/cleo/application.py:423 in _run
       421│             io.input.set_stream(stream)
       422│ 
     → 423│         exit_code = self._run_command(command, io)
       424│         self._running_command = None
       425│ 

  26  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/cleo/application.py:465 in _run_command
       463│ 
       464│         if error is not None:
     → 465│             raise error
       466│ 
       467│         return event.exit_code

  25  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/cleo/application.py:449 in _run_command
       447│ 
       448│             if event.command_should_run():
     → 449│                 exit_code = command.run(io)
       450│             else:
       451│                 exit_code = ConsoleCommandEvent.RETURN_CODE_DISABLED

  24  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/cleo/commands/base_command.py:119 in run
       117│         io.input.validate()
       118│ 
     → 119│         status_code = self.execute(io)
       120│ 
       121│         if status_code is None:

  23  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/cleo/commands/command.py:83 in execute
        81│ 
        82│         try:
     →  83│             return self.handle()
        84│         except KeyboardInterrupt:
        85│             return 1

  22  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/console/commands/init.py:188 in handle
       186│                 help_displayed = True
       187│             requirements.update(
     → 188│                 self._format_requirements(self._determine_requirements([]))
       189│             )
       190│             if self.io.is_interactive():

  21  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/console/commands/init.py:338 in _determine_requirements
       336│                     if package_constraint is None:
       337│                         _, package_constraint = self._find_best_version_for_package(
     → 338│                             package
       339│                         )
       340│ 

  20  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/console/commands/init.py:399 in _find_best_version_for_package
       397│         selector = VersionSelector(self._get_pool())
       398│         package = selector.find_best_candidate(
     → 399│             name, required_version, allow_prereleases=allow_prereleases, source=source
       400│         )
       401│ 

  19  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/version/version_selector.py:39 in find_best_candidate
        37│             },
        38│         )
     →  39│         candidates = self._pool.find_packages(dependency)
        40│         only_prereleases = all(c.version.is_unstable() for c in candidates)
        41│ 

  18  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/repositories/pool.py:181 in find_packages
       179│         packages = []
       180│         for repo in self._repositories:
     → 181│             packages += repo.find_packages(dependency)
       182│ 
       183│         return packages

  17  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/repositories/repository.py:46 in find_packages
        44│         ignored_pre_release_packages = []
        45│ 
     →  46│         for package in self._find_packages(dependency.name, constraint):
        47│             if package.yanked and not isinstance(constraint, Version):
        48│                 # PEP 592: yanked files are always ignored, unless they are the only

  16  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/repositories/pypi_repository.py:116 in _find_packages
       114│         """
       115│         try:
     → 116│             info = self.get_package_info(name)
       117│         except PackageNotFound:
       118│             self._log(

  15  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/repositories/pypi_repository.py:105 in get_package_info
       103│ 
       104│         package_info: dict[str, Any] = self._cache.store("packages").remember_forever(
     → 105│             name, lambda: self._get_package_info(name)
       106│         )
       107│         return package_info

  14  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/cachy/repository.py:174 in remember_forever
       172│             return val
       173│ 
     → 174│         val = value(callback)
       175│ 
       176│         self.forever(key, val)

  13  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/cachy/helpers.py:6 in value
         4│ def value(val):
         5│     if callable(val):
     →   6│         return val()
         7│ 
         8│     return val

  12  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/repositories/pypi_repository.py:105 in <lambda>
       103│ 
       104│         package_info: dict[str, Any] = self._cache.store("packages").remember_forever(
     → 105│             name, lambda: self._get_package_info(name)
       106│         )
       107│         return package_info

  11  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/repositories/pypi_repository.py:155 in _get_package_info
       153│ 
       154│     def _get_package_info(self, name: NormalizedName) -> dict[str, Any]:
     → 155│         data = self._get(f"pypi/{name}/json")
       156│         if data is None:
       157│             raise PackageNotFound(f"Package [{name}] not found.")

  10  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/repositories/pypi_repository.py:244 in _get
       242│                 self._base_url + endpoint,
       243│                 raise_for_status=False,
     → 244│                 timeout=REQUESTS_TIMEOUT,
       245│             )
       246│         except requests.exceptions.TooManyRedirects:

   9  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/utils/authenticator.py:246 in get
       244│ 
       245│     def get(self, url: str, **kwargs: Any) -> requests.Response:
     → 246│         return self.request("get", url, **kwargs)
       247│ 
       248│     def post(self, url: str, **kwargs: Any) -> requests.Response:

   8  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/utils/authenticator.py:187 in request
       185│     ) -> requests.Response:
       186│         request = requests.Request(method, url)
     → 187│         credential = self.get_credentials_for_url(url)
       188│ 
       189│         if credential.username is not None or credential.password is not None:

   7  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/utils/authenticator.py:310 in get_credentials_for_url
       308│                 # no credentials were provided in the url, try finding the
       309│                 # best repository configuration
     → 310│                 self._credentials[url] = self._get_credentials_for_url(url)
       311│             else:
       312│                 # Split from the right because that's how urllib.parse.urlsplit()

   6  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/utils/authenticator.py:272 in _get_credentials_for_url
       270│         credential = (
       271│             self._get_credentials_for_repository(repository=repository)
     → 272│             if repository is not None
       273│             else HTTPAuthCredential()
       274│         )

   5  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/utils/authenticator.py:260 in _get_credentials_for_repository
       258│         if key not in self._credentials:
       259│             self._credentials[key] = repository.get_http_credentials(
     → 260│                 password_manager=self._password_manager, username=username
       261│             )
       262│ 

   4  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/utils/authenticator.py:91 in get_http_credentials
        89│             # fallback to url and netloc based keyring entries
        90│             credential = password_manager.keyring.get_credential(
     →  91│                 self.url, self.netloc, username=credential.username
        92│             )
        93│ 

   3  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/utils/password_manager.py:51 in get_credential
        49│ 
        50│         for name in names:
     →  51│             credential = keyring.get_credential(name, username)
        52│             if credential:
        53│                 return HTTPAuthCredential(

   2  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/keyring/core.py:72 in get_credential
        70│ ) -> typing.Optional[credentials.Credential]:
        71│     """Get a Credential for the specified service."""
     →  72│     return get_keyring().get_credential(service_name, username)
        73│ 
        74│ 

   1  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/keyring/backends/SecretService.py:112 in get_credential
       110│         scheme = self.schemes[self.scheme]
       111│         query = self._query(service, username)
     → 112│         collection = self.get_preferred_collection()
       113│ 
       114│         with closing(collection.connection):

  KeyringLocked

  Failed to unlock the collection!

  at ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/keyring/backends/SecretService.py:67 in get_preferred_collection
       63│             raise InitError("Failed to create the collection: %s." % e)
       64│         if collection.is_locked():
       65│             collection.unlock()
       66│             if collection.is_locked():  # User dismissed the prompt
    →  67│                 raise KeyringLocked("Failed to unlock the collection!")
       68│         return collection
       69│ 
       70│     def unlock(self, item):
       71│         if hasattr(item, 'unlock'):
maciejskorski commented 2 years ago

Also happens to me when connecting via SSH, and my workaround is to disable keyring within a sufficient scope, as poetry can work without keyring.

My two cents are that this behaviour is not consistent with the docs. The documentation promises a backup in case of keyring failure:

If a system keyring is available and supported, the password is stored to and retrieved from the keyring... 
If access to keyring fails or is unsupported, this will **fall back to writing the password to the auth.toml** file along with the username.

Of course, it may well be an issue on the keyring side (locked, not set up properly...), but would be nice to fall back gracefully. A bit odd, but sometimes poetry depends on keyring even for password-free operations in config:

(.venv) azureuser@sense-mskorski:~/projects/test_project$ poetry config virtualenvs.create false

  KeyRingError

  Unable to retrieve the password for poetry-repository-my_private_repo from the key ring

EDIT: the keyring usage is handled in poetry.utils.password_manager and has improved a bit since in version 1.2, in particular with respect to null backends.

https://github.com/python-poetry/poetry/blob/0686427ce175e14b69c8ffeca4515cce79453047/src/poetry/utils/password_manager.py#L109-L141

neersighted commented 2 years ago

Closing as duplicate of #1917

EKami commented 1 year ago

Had the same problem in a container, solved it by setting the null keyring within the underlying lib, it's just an env variable:

PYTHON_KEYRING_BACKEND: keyring.backends.null.Keyring

see https://pypi.org/project/keyring/ disabling keyring

This, easiest solution and worked perfectly

LuckCky commented 1 year ago

I ran into same issue after updating Poetry from 1.1.xxx to 1.2.2 on Mac BigSur. Before the update it was fine, but after Poetry couldn't read keychain file I advise you not to disable keyring and store password in auth.toml as it is stored plaintext! What helped me was to allow read Poetry's keychain file by any application and then return to ask for access and add python to allowed apps again. Hope this helps you and saves you some time

SheepyBloke-OPO commented 1 year ago

I have a Mac, and I needed to delete an old password in the Keychain in order to get it to work. I went to the Keychain Access app, navigated to the login default keychain and filtered on Passwords. In there was one called poetry-repositor-***, where *** was my private repo. Deleting that and running poetry config http-basic.<PRIVATE-REPO> <USER> <TOKEN> again solved this issue for me.

Slanman3755 commented 1 year ago

Just to add to the macos solutions above: the Issue for me was that the key is added to the keychain with access only allowed by a specific python version. When I switched python versions then the poetry config command started failing. The solution is to allow all apps on the poetry keys or add the additional python versions you need. Ideally poetry would handle this or at least provide a better error message.

niftynei commented 1 year ago

fwiw, i found this really helpful for getting into my keyring on a remote box (jammy/ubuntu) with gnome-keyring installed: https://unix.stackexchange.com/a/602935

note that you have to source the file every time to get it to run correctly.

tlatrace commented 8 months ago

[MacOS] I have the same keyring issue with poetry installed with pip. Un-installing poetry with pip and re-install it with brew this time solved the issue on my side.

srinivaskumarramdas commented 7 months ago

On macOs: python -m keyring --disable and poetry config pypi-token.pypi <MY PYPI TOKEN> worked for me.

github-actions[bot] commented 6 months ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.