diff --git a/src/hatch/index/core.py b/src/hatch/index/core.py index c5a231bae..4fff1f99e 100644 --- a/src/hatch/index/core.py +++ b/src/hatch/index/core.py @@ -90,7 +90,19 @@ def upload_artifact(self, artifact: Path, data: dict): files={'content': (artifact.name, f, 'application/octet-stream')}, auth=(self.user, self.auth), ) - response.raise_for_status() + if response.is_error: + import re + + import httpx + + # strip all html tags + post_res = re.sub(r'<[^>]+>', '', response.text) + exc_text = f'{response.status_code} {response.reason_phrase}\n{post_res}' + raise httpx.HTTPStatusError( + message=exc_text, + request=response.request, + response=response, + ) def get_simple_api(self, project: str) -> httpx.Response: return self.client.get( diff --git a/tests/index/test_core.py b/tests/index/test_core.py index 9f6b32c1a..8ba8005f9 100644 --- a/tests/index/test_core.py +++ b/tests/index/test_core.py @@ -1,3 +1,7 @@ +from pathlib import Path +from unittest.mock import MagicMock + +import httpx import pytest from hatch.index.core import PackageIndex @@ -66,3 +70,35 @@ def test_client_cert_with_key(self, mocker): _ = index.client mock.assert_called_once_with(verify=True, cert=('foo', 'bar'), trust_env=True) + + +def test_upload_artifact_http_error(): + package_index = PackageIndex(repo='') + mock_response = MagicMock() + mock_response.is_error = True + mock_response.status_code = 400 + mock_response.reason_phrase = 'Bad Request' + # test real response content from pypi + mock_response.text = """ + + + 400 This filename has already been used, use a different version. See https://test.pypi.org/help/#file-name-reuse for more information. + + +

400 This filename has already been used, use a different version. See https://test.pypi.org/help/#file-name-reuse for more information.

+ The server could not comply with the request since it is either malformed or otherwise incorrect.

+This filename has already been used, use a different version. See https://test.pypi.org/help/#file-name-reuse for more information. + + +""" + package_index.client.post = MagicMock(return_value=mock_response) + artifact = Path('dummy_artifact.txt') + artifact.write_text('dummy content') + data = {} + with pytest.raises(httpx.HTTPStatusError) as exc_info: + package_index.upload_artifact(artifact, data) + artifact.unlink() + assert ( + '400 This filename has already been used, use a different version. See https://test.pypi.org/help/#file-name-reuse for more information.' + in str(exc_info.value) + )