Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ux): improve connection error reporting #10132

Merged
merged 2 commits into from
Feb 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/poetry/console/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,9 @@ def create(
)

return cls(reason, messages)

def append(self, message: str | ConsoleMessage) -> PoetryRuntimeError:
if isinstance(message, str):
message = ConsoleMessage(message)
self._messages.append(message)
return self
27 changes: 25 additions & 2 deletions src/poetry/utils/authenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

from poetry.__version__ import __version__
from poetry.config.config import Config
from poetry.console.exceptions import ConsoleMessage
from poetry.console.exceptions import PoetryRuntimeError
from poetry.exceptions import PoetryError
from poetry.utils.constants import REQUESTS_TIMEOUT
from poetry.utils.constants import RETRY_AFTER_HEADER
Expand Down Expand Up @@ -230,7 +232,28 @@ def request(
resp = session.send(prepared_request, **send_kwargs)
except (requests.exceptions.ConnectionError, OSError) as e:
if is_last_attempt:
raise e
parsed_url = urllib.parse.urlsplit(url)
exc = PoetryRuntimeError.create(
reason=f"<error>All attempts to connect to <c1>{parsed_url.netloc}</> failed.</>",
exception=e,
)
exc.append(
ConsoleMessage(
"the server is not responding to requests at the moment\n"
"the hostname cannot be resolved by your DNS\n"
"your network is not connected to the internet\n"
)
.indent(" - ")
.make_section("Probable Causes")
.wrap("warning")
)
exc.append(
ConsoleMessage(
f"<b>Note:</> The path requested was <c1>{parsed_url.path}</>.",
debug=True,
)
)
raise exc
else:
if resp.status_code not in STATUS_FORCELIST or is_last_attempt:
if raise_for_status:
Expand All @@ -245,7 +268,7 @@ def request(
continue

# this should never really be hit under any sane circumstance
raise PoetryError("Failed HTTP {} request", method.upper())
raise PoetryError(f"Failed HTTP request: {method.upper()} {url}")

def _get_backoff(self, response: requests.Response | None, attempt: int) -> float:
if response is not None:
Expand Down
7 changes: 7 additions & 0 deletions tests/console/test_exections_poetry_runtime_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,10 @@ def test_poetry_runtime_error_create(

actual_texts = [msg.text for msg in error._messages]
assert actual_texts == expected_message_texts


def test_poetry_runtime_error_append() -> None:
"""Test the append method of PoetryRuntimeError."""
error = PoetryRuntimeError.create("Error", info=["Hello"]).append("World")
actual_texts = [msg.text for msg in error._messages]
assert actual_texts == ["Error", "<info>Hello</>", "World"]
4 changes: 3 additions & 1 deletion tests/utils/test_authenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from cleo.io.null_io import NullIO
from keyring.credentials import SimpleCredential

from poetry.console.exceptions import PoetryRuntimeError
from poetry.utils.authenticator import Authenticator
from poetry.utils.authenticator import RepositoryCertificateConfig
from poetry.utils.password_manager import PoetryKeyring
Expand Down Expand Up @@ -279,9 +280,10 @@ def callback(*_: Any, **___: Any) -> None:
http.register_uri(httpretty.GET, sdist_uri, body=callback)
authenticator = Authenticator(config, NullIO())

with pytest.raises(requests.exceptions.ConnectionError):
with pytest.raises(PoetryRuntimeError) as e:
authenticator.request("get", sdist_uri)

assert str(e.value) == "All attempts to connect to foo.bar failed."
assert sleep.call_count == 5


Expand Down