Skip to content

Commit

Permalink
feat(ux): improve ux for hash not found errors
Browse files Browse the repository at this point in the history
This changes allows better error information propagation to facilitate
improved ux for users encountering errors.

Resolves: #10057
  • Loading branch information
abn committed Jan 23, 2025
1 parent d940f67 commit e78f434
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 7 deletions.
29 changes: 24 additions & 5 deletions src/poetry/installation/chooser.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

from poetry.config.config import Config
from poetry.config.config import PackageFilterPolicy
from poetry.console.exceptions import ConsoleMessage
from poetry.console.exceptions import PoetryRuntimeError
from poetry.repositories.http_repository import HTTPRepository
from poetry.utils.helpers import get_highest_priority_hash_type
from poetry.utils.wheel import Wheel
Expand Down Expand Up @@ -134,11 +136,28 @@ def _get_links(self, package: Package) -> list[Link]:
selected_links.append(link)

if links and not selected_links:
links_str = ", ".join(f"{link}({h})" for link, h in skipped)
raise RuntimeError(
f"Retrieved digests for links {links_str} not in poetry.lock"
f" metadata {locked_hashes}"
)
reason = f"Downloaded distributions for <b>{package.pretty_name} ({package.pretty_version})</> did not match any known checksums in your lock file."
link_hashes = "\n".join(f" - {link}({h})" for link, h in skipped)
known_hashes = "\n".join(f" - {h}" for h in locked_hashes)
messages = [
ConsoleMessage(
"<options=bold>Causes:</>\n"
" - invalid or corrupt cache either during locking or installation\n"
" - network interruptions or errors causing corrupted downloads\n\n"
"<b>Solutions:</>\n"
" 1. Try running your command again using the <c1>--no-cache</> global option enabled.\n"
" 2. Try regenerating your lock file using (<c1>poetry lock --no-cache --regenerate</>).\n\n"
"If any of those solutions worked, you will have to clear your caches using (<c1>poetry cache clear --all CACHE_NAME</>)."
),
ConsoleMessage(
f"Poetry retrieved the following links:\n"
f"{link_hashes}\n\n"
f"The lockfile contained only the following hashes:\n"
f"{known_hashes}",
debug=True,
),
]
raise PoetryRuntimeError(reason, messages)

return selected_links

Expand Down
5 changes: 5 additions & 0 deletions src/poetry/installation/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from poetry.core.packages.utils.link import Link

from poetry.console.exceptions import PoetryRuntimeError
from poetry.installation.chef import Chef
from poetry.installation.chooser import Chooser
from poetry.installation.operations import Install
Expand Down Expand Up @@ -333,6 +334,10 @@ def _execute_operation(self, operation: Operation) -> None:
f" for {pkg.pretty_name}."
"</error>"
)
elif isinstance(e, PoetryRuntimeError):
message = e.get_text(io.is_verbose(), indent=" | ").rstrip()
message = f"<warning>{message}</>"
with_trace = False
else:
message = f"<error>Cannot install {pkg.pretty_name}.</error>"

Expand Down
11 changes: 9 additions & 2 deletions tests/installation/test_chooser.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from packaging.tags import Tag
from poetry.core.packages.package import Package

from poetry.console.exceptions import PoetryRuntimeError
from poetry.installation.chooser import Chooser
from poetry.repositories.legacy_repository import LegacyRepository
from poetry.repositories.pypi_repository import PyPiRepository
Expand Down Expand Up @@ -366,9 +367,15 @@ def test_chooser_throws_an_error_if_package_hashes_do_not_match(

package.files = files

with pytest.raises(RuntimeError) as e:
with pytest.raises(PoetryRuntimeError) as e:
chooser.choose_for(package)
assert files[0]["hash"] in str(e)

reason = f"Downloaded distributions for {package.name} ({package.version}) did not match any known checksums in your lock file."
assert str(e.value) == reason

text = e.value.get_text(debug=True, strip=True)
assert reason in text
assert files[0]["hash"] in text


def test_chooser_md5_remote_fallback_to_sha256_inline_calculation(
Expand Down

0 comments on commit e78f434

Please sign in to comment.