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

ENH Add raise_for_status to FetchResponse #4053

Merged
merged 3 commits into from
Aug 9, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 7 additions & 6 deletions docs/project/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,6 @@ myst:
present also on `Task`s as well as `Future`s.
{pr}`3748`

- {{ Enhancement }} Added `headers` property to `pyodide.http.FetchResponse`.
{pr}`2078`

- {{ Enhancement }} Added methods to a `PyProxy` of a `list` to make these work
as drop-in replacements for JavaScript Arrays.
{pr}`3853`
Expand All @@ -70,9 +67,13 @@ myst:
`pyodide-lock.json`
{pr}`3824`

- {{ Breaking }} Changed the FetchResponse body getter methods to no longer
throw an OSError exception for 400 and above response status codes
{pr}`3986`
- {{ Enhancement }} Added `headers` property to `pyodide.http.FetchResponse`.
{pr}`2078`

- {{ Breaking }} Changed the `FetchResponse` body getter methods to no longer
throw an `OSError` exception for 400 and above response status codes. Added
`FetchResponse.raise_for_status` to raise an `OSError` for error status codes.
{pr}`3986` {pr}`4053`

### Packages

Expand Down
16 changes: 16 additions & 0 deletions src/py/pyodide/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,22 @@
if self.js_response.bodyUsed:
raise OSError("Response body is already used")

def raise_for_status(self) -> None:
"""Raise an :py:exc:`OSError` if the status of the response is an error (4xx or 5xx)"""
http_error_msg = ""
if 400 <= self.status < 500:
http_error_msg = (

Check warning on line 148 in src/py/pyodide/http.py

View check run for this annotation

Codecov / codecov/patch

src/py/pyodide/http.py#L146-L148

Added lines #L146 - L148 were not covered by tests
f"{self.status} Client Error: {self.status_text} for url: {self.url}"
)

if 500 <= self.status < 600:
http_error_msg = (

Check warning on line 153 in src/py/pyodide/http.py

View check run for this annotation

Codecov / codecov/patch

src/py/pyodide/http.py#L152-L153

Added lines #L152 - L153 were not covered by tests
f"{self.status} Server Error: {self.status_text} for url: {self.url}"
)

if http_error_msg:
raise OSError(http_error_msg)

Check warning on line 158 in src/py/pyodide/http.py

View check run for this annotation

Codecov / codecov/patch

src/py/pyodide/http.py#L157-L158

Added lines #L157 - L158 were not covered by tests

def clone(self) -> "FetchResponse":
"""Return an identical copy of the :py:class:`FetchResponse`.

Expand Down
44 changes: 44 additions & 0 deletions src/tests/test_pyodide_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,50 @@ async def test_pyfetch_return_400_status_body(selenium, url_notfound):
assert body == "404 Not Found"


@pytest.fixture
def raise_for_status_fixture(httpserver):
httpserver.expect_request("/200").respond_with_data(
b"Some data here!",
content_type="text/text",
headers={"Access-Control-Allow-Origin": "*"},
status=200,
)
httpserver.expect_request("/404").respond_with_data(
b"Not Found",
content_type="text/text",
headers={"Access-Control-Allow-Origin": "*"},
status=404,
)
httpserver.expect_request("/504").respond_with_data(
b"Gateway timeout",
content_type="text/text",
headers={"Access-Control-Allow-Origin": "*"},
status=504,
)
return {p: httpserver.url_for(p) for p in ["/200", "/404", "/504"]}


@run_in_pyodide
async def test_pyfetch_raise_for_status(selenium, raise_for_status_fixture):
import pytest

from pyodide.http import pyfetch

resp = await pyfetch(raise_for_status_fixture["/200"])
resp.raise_for_status()
assert await resp.string() == "Some data here!"

resp = await pyfetch(raise_for_status_fixture["/404"])
with pytest.raises(OSError, match="404 Client Error: NOT FOUND for url: .*/404"):
resp.raise_for_status()

resp = await pyfetch(raise_for_status_fixture["/504"])
with pytest.raises(
OSError, match="504 Server Error: GATEWAY TIMEOUT for url: .*/504"
):
resp.raise_for_status()


@run_in_pyodide
async def test_pyfetch_unpack_archive(selenium):
import pathlib
Expand Down