Coverage for human_requests / abstraction / response.py: 91%
45 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-25 10:02 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-25 10:02 +0000
1import json
2from dataclasses import dataclass
3from time import time
4from typing import TYPE_CHECKING, Literal, Optional
6from .http import URL
7from .request import FetchRequest
9if TYPE_CHECKING:
10 from ..human_page import HumanPage
13@dataclass(frozen=True)
14class FetchResponse:
15 """Represents the response of a request."""
17 request: FetchRequest
18 """The request that was made."""
20 page: "HumanPage"
21 """The page that made the request."""
23 url: URL
24 """The URL of the response. Due to redirects, it can differ from `request.url`."""
26 headers: dict
27 """The headers of the response."""
29 raw: bytes
30 """The raw body of the response."""
32 status_code: int
33 """The status code of the response."""
35 status_text: str
36 """Человеко-читаемое представление status_code"""
38 redirected: bool
39 """Был ли ответ сформировапн в следствии редиректа"""
41 type: Literal["basic", "cors", "error", "opaque", "opaqueredirect"]
43 duration: float
44 """The duration of the request in seconds."""
46 end_time: float
47 """Current time in seconds since the Epoch."""
49 @property
50 def text(self) -> str:
51 """The body of the response."""
52 defchar = "utf-8"
53 ct = self.headers.get("content-type", "")
54 charset = ct.split("charset=")[-1] if "charset=" in ct else defchar
55 return self.raw.decode(charset, errors="replace")
57 def json(self) -> dict | list:
58 to_return = json.loads(self.text)
59 assert isinstance(to_return, list) or isinstance(
60 to_return, dict
61 ), f"Response body is not JSON: {type(self.text).__name__}"
62 return to_return
64 def seconds_ago(self) -> float:
65 """How long ago was the request?"""
66 return time() - self.end_time
68 async def render(
69 self,
70 retry: int = 2,
71 timeout: Optional[float] = None,
72 wait_until: Literal["commit", "load", "domcontentloaded", "networkidle"] = "commit",
73 referer: Optional[str] = None,
74 ) -> "HumanPage":
75 """Renders the response content in the current browser.
76 It will look like we requested it through the browser from the beginning.
78 Recommended to use in cases when the server returns a JS challenge instead of a response."""
79 page = await self.page.context.new_page()
80 await page.goto_render(
81 self, wait_until=wait_until, referer=referer, timeout=timeout, retry=retry
82 )
83 return page