Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
_client.py2020 linesDownload Raw Back to httpx
1from __future__ import annotations2 3import datetime4import enum5import logging6import time7import typing8import warnings9from contextlib import asynccontextmanager, contextmanager10from types import TracebackType11 12from .__version__ import __version__13from ._auth import Auth, BasicAuth, FunctionAuth14from ._config import (15    DEFAULT_LIMITS,16    DEFAULT_MAX_REDIRECTS,17    DEFAULT_TIMEOUT_CONFIG,18    Limits,19    Proxy,20    Timeout,21)22from ._decoders import SUPPORTED_DECODERS23from ._exceptions import (24    InvalidURL,25    RemoteProtocolError,26    TooManyRedirects,27    request_context,28)29from ._models import Cookies, Headers, Request, Response30from ._status_codes import codes31from ._transports.base import AsyncBaseTransport, BaseTransport32from ._transports.default import AsyncHTTPTransport, HTTPTransport33from ._types import (34    AsyncByteStream,35    AuthTypes,36    CertTypes,37    CookieTypes,38    HeaderTypes,39    ProxyTypes,40    QueryParamTypes,41    RequestContent,42    RequestData,43    RequestExtensions,44    RequestFiles,45    SyncByteStream,46    TimeoutTypes,47)48from ._urls import URL, QueryParams49from ._utils import URLPattern, get_environment_proxies50 51if typing.TYPE_CHECKING:52    import ssl  # pragma: no cover53 54__all__ = ["USE_CLIENT_DEFAULT", "AsyncClient", "Client"]55 56# The type annotation for @classmethod and context managers here follows PEP 48457# https://www.python.org/dev/peps/pep-0484/#annotating-instance-and-class-methods58T = typing.TypeVar("T", bound="Client")59U = typing.TypeVar("U", bound="AsyncClient")60 61 62def _is_https_redirect(url: URL, location: URL) -> bool:63    """64    Return 'True' if 'location' is a HTTPS upgrade of 'url'65    """66    if url.host != location.host:67        return False68 69    return (70        url.scheme == "http"71        and _port_or_default(url) == 8072        and location.scheme == "https"73        and _port_or_default(location) == 44374    )75 76 77def _port_or_default(url: URL) -> int | None:78    if url.port is not None:79        return url.port80    return {"http": 80, "https": 443}.get(url.scheme)81 82 83def _same_origin(url: URL, other: URL) -> bool:84    """85    Return 'True' if the given URLs share the same origin.86    """87    return (88        url.scheme == other.scheme89        and url.host == other.host90        and _port_or_default(url) == _port_or_default(other)91    )92 93 94class UseClientDefault:95    """96    For some parameters such as `auth=...` and `timeout=...` we need to be able97    to indicate the default "unset" state, in a way that is distinctly different98    to using `None`.99 100    The default "unset" state indicates that whatever default is set on the101    client should be used. This is different to setting `None`, which102    explicitly disables the parameter, possibly overriding a client default.103 104    For example we use `timeout=USE_CLIENT_DEFAULT` in the `request()` signature.105    Omitting the `timeout` parameter will send a request using whatever default106    timeout has been configured on the client. Including `timeout=None` will107    ensure no timeout is used.108 109    Note that user code shouldn't need to use the `USE_CLIENT_DEFAULT` constant,110    but it is used internally when a parameter is not included.111    """112 113 114USE_CLIENT_DEFAULT = UseClientDefault()115 116 117logger = logging.getLogger("httpx")118 119USER_AGENT = f"python-httpx/{__version__}"120ACCEPT_ENCODING = ", ".join(121    [key for key in SUPPORTED_DECODERS.keys() if key != "identity"]122)123 124 125class ClientState(enum.Enum):126    # UNOPENED:127    #   The client has been instantiated, but has not been used to send a request,128    #   or been opened by entering the context of a `with` block.129    UNOPENED = 1130    # OPENED:131    #   The client has either sent a request, or is within a `with` block.132    OPENED = 2133    # CLOSED:134    #   The client has either exited the `with` block, or `close()` has135    #   been called explicitly.136    CLOSED = 3137 138 139class BoundSyncStream(SyncByteStream):140    """141    A byte stream that is bound to a given response instance, and that142    ensures the `response.elapsed` is set once the response is closed.143    """144 145    def __init__(146        self, stream: SyncByteStream, response: Response, start: float147    ) -> None:148        self._stream = stream149        self._response = response150        self._start = start151 152    def __iter__(self) -> typing.Iterator[bytes]:153        for chunk in self._stream:154            yield chunk155 156    def close(self) -> None:157        elapsed = time.perf_counter() - self._start158        self._response.elapsed = datetime.timedelta(seconds=elapsed)159        self._stream.close()160 161 162class BoundAsyncStream(AsyncByteStream):163    """164    An async byte stream that is bound to a given response instance, and that165    ensures the `response.elapsed` is set once the response is closed.166    """167 168    def __init__(169        self, stream: AsyncByteStream, response: Response, start: float170    ) -> None:171        self._stream = stream172        self._response = response173        self._start = start174 175    async def __aiter__(self) -> typing.AsyncIterator[bytes]:176        async for chunk in self._stream:177            yield chunk178 179    async def aclose(self) -> None:180        elapsed = time.perf_counter() - self._start181        self._response.elapsed = datetime.timedelta(seconds=elapsed)182        await self._stream.aclose()183 184 185EventHook = typing.Callable[..., typing.Any]186 187 188class BaseClient:189    def __init__(190        self,191        *,192        auth: AuthTypes | None = None,193        params: QueryParamTypes | None = None,194        headers: HeaderTypes | None = None,195        cookies: CookieTypes | None = None,196        timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,197        follow_redirects: bool = False,198        max_redirects: int = DEFAULT_MAX_REDIRECTS,199        event_hooks: None | (typing.Mapping[str, list[EventHook]]) = None,200        base_url: URL | str = "",201        trust_env: bool = True,202        default_encoding: str | typing.Callable[[bytes], str] = "utf-8",203    ) -> None:204        event_hooks = {} if event_hooks is None else event_hooks205 206        self._base_url = self._enforce_trailing_slash(URL(base_url))207 208        self._auth = self._build_auth(auth)209        self._params = QueryParams(params)210        self.headers = Headers(headers)211        self._cookies = Cookies(cookies)212        self._timeout = Timeout(timeout)213        self.follow_redirects = follow_redirects214        self.max_redirects = max_redirects215        self._event_hooks = {216            "request": list(event_hooks.get("request", [])),217            "response": list(event_hooks.get("response", [])),218        }219        self._trust_env = trust_env220        self._default_encoding = default_encoding221        self._state = ClientState.UNOPENED222 223    @property224    def is_closed(self) -> bool:225        """226        Check if the client being closed227        """228        return self._state == ClientState.CLOSED229 230    @property231    def trust_env(self) -> bool:232        return self._trust_env233 234    def _enforce_trailing_slash(self, url: URL) -> URL:235        if url.raw_path.endswith(b"/"):236            return url237        return url.copy_with(raw_path=url.raw_path + b"/")238 239    def _get_proxy_map(240        self, proxy: ProxyTypes | None, allow_env_proxies: bool241    ) -> dict[str, Proxy | None]:242        if proxy is None:243            if allow_env_proxies:244                return {245                    key: None if url is None else Proxy(url=url)246                    for key, url in get_environment_proxies().items()247                }248            return {}249        else:250            proxy = Proxy(url=proxy) if isinstance(proxy, (str, URL)) else proxy251            return {"all://": proxy}252 253    @property254    def timeout(self) -> Timeout:255        return self._timeout256 257    @timeout.setter258    def timeout(self, timeout: TimeoutTypes) -> None:259        self._timeout = Timeout(timeout)260 261    @property262    def event_hooks(self) -> dict[str, list[EventHook]]:263        return self._event_hooks264 265    @event_hooks.setter266    def event_hooks(self, event_hooks: dict[str, list[EventHook]]) -> None:267        self._event_hooks = {268            "request": list(event_hooks.get("request", [])),269            "response": list(event_hooks.get("response", [])),270        }271 272    @property273    def auth(self) -> Auth | None:274        """275        Authentication class used when none is passed at the request-level.276 277        See also [Authentication][0].278 279        [0]: /quickstart/#authentication280        """281        return self._auth282 283    @auth.setter284    def auth(self, auth: AuthTypes) -> None:285        self._auth = self._build_auth(auth)286 287    @property288    def base_url(self) -> URL:289        """290        Base URL to use when sending requests with relative URLs.291        """292        return self._base_url293 294    @base_url.setter295    def base_url(self, url: URL | str) -> None:296        self._base_url = self._enforce_trailing_slash(URL(url))297 298    @property299    def headers(self) -> Headers:300        """301        HTTP headers to include when sending requests.302        """303        return self._headers304 305    @headers.setter306    def headers(self, headers: HeaderTypes) -> None:307        client_headers = Headers(308            {309                b"Accept": b"*/*",310                b"Accept-Encoding": ACCEPT_ENCODING.encode("ascii"),311                b"Connection": b"keep-alive",312                b"User-Agent": USER_AGENT.encode("ascii"),313            }314        )315        client_headers.update(headers)316        self._headers = client_headers317 318    @property319    def cookies(self) -> Cookies:320        """321        Cookie values to include when sending requests.322        """323        return self._cookies324 325    @cookies.setter326    def cookies(self, cookies: CookieTypes) -> None:327        self._cookies = Cookies(cookies)328 329    @property330    def params(self) -> QueryParams:331        """332        Query parameters to include in the URL when sending requests.333        """334        return self._params335 336    @params.setter337    def params(self, params: QueryParamTypes) -> None:338        self._params = QueryParams(params)339 340    def build_request(341        self,342        method: str,343        url: URL | str,344        *,345        content: RequestContent | None = None,346        data: RequestData | None = None,347        files: RequestFiles | None = None,348        json: typing.Any | None = None,349        params: QueryParamTypes | None = None,350        headers: HeaderTypes | None = None,351        cookies: CookieTypes | None = None,352        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,353        extensions: RequestExtensions | None = None,354    ) -> Request:355        """356        Build and return a request instance.357 358        * The `params`, `headers` and `cookies` arguments359        are merged with any values set on the client.360        * The `url` argument is merged with any `base_url` set on the client.361 362        See also: [Request instances][0]363 364        [0]: /advanced/clients/#request-instances365        """366        url = self._merge_url(url)367        headers = self._merge_headers(headers)368        cookies = self._merge_cookies(cookies)369        params = self._merge_queryparams(params)370        extensions = {} if extensions is None else extensions371        if "timeout" not in extensions:372            timeout = (373                self.timeout374                if isinstance(timeout, UseClientDefault)375                else Timeout(timeout)376            )377            extensions = dict(**extensions, timeout=timeout.as_dict())378        return Request(379            method,380            url,381            content=content,382            data=data,383            files=files,384            json=json,385            params=params,386            headers=headers,387            cookies=cookies,388            extensions=extensions,389        )390 391    def _merge_url(self, url: URL | str) -> URL:392        """393        Merge a URL argument together with any 'base_url' on the client,394        to create the URL used for the outgoing request.395        """396        merge_url = URL(url)397        if merge_url.is_relative_url:398            # To merge URLs we always append to the base URL. To get this399            # behaviour correct we always ensure the base URL ends in a '/'400            # separator, and strip any leading '/' from the merge URL.401            #402            # So, eg...403            #404            # >>> client = Client(base_url="https://www.example.com/subpath")405            # >>> client.base_url406            # URL('https://www.example.com/subpath/')407            # >>> client.build_request("GET", "/path").url408            # URL('https://www.example.com/subpath/path')409            merge_raw_path = self.base_url.raw_path + merge_url.raw_path.lstrip(b"/")410            return self.base_url.copy_with(raw_path=merge_raw_path)411        return merge_url412 413    def _merge_cookies(self, cookies: CookieTypes | None = None) -> CookieTypes | None:414        """415        Merge a cookies argument together with any cookies on the client,416        to create the cookies used for the outgoing request.417        """418        if cookies or self.cookies:419            merged_cookies = Cookies(self.cookies)420            merged_cookies.update(cookies)421            return merged_cookies422        return cookies423 424    def _merge_headers(self, headers: HeaderTypes | None = None) -> HeaderTypes | None:425        """426        Merge a headers argument together with any headers on the client,427        to create the headers used for the outgoing request.428        """429        merged_headers = Headers(self.headers)430        merged_headers.update(headers)431        return merged_headers432 433    def _merge_queryparams(434        self, params: QueryParamTypes | None = None435    ) -> QueryParamTypes | None:436        """437        Merge a queryparams argument together with any queryparams on the client,438        to create the queryparams used for the outgoing request.439        """440        if params or self.params:441            merged_queryparams = QueryParams(self.params)442            return merged_queryparams.merge(params)443        return params444 445    def _build_auth(self, auth: AuthTypes | None) -> Auth | None:446        if auth is None:447            return None448        elif isinstance(auth, tuple):449            return BasicAuth(username=auth[0], password=auth[1])450        elif isinstance(auth, Auth):451            return auth452        elif callable(auth):453            return FunctionAuth(func=auth)454        else:455            raise TypeError(f'Invalid "auth" argument: {auth!r}')456 457    def _build_request_auth(458        self,459        request: Request,460        auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,461    ) -> Auth:462        auth = (463            self._auth if isinstance(auth, UseClientDefault) else self._build_auth(auth)464        )465 466        if auth is not None:467            return auth468 469        username, password = request.url.username, request.url.password470        if username or password:471            return BasicAuth(username=username, password=password)472 473        return Auth()474 475    def _build_redirect_request(self, request: Request, response: Response) -> Request:476        """477        Given a request and a redirect response, return a new request that478        should be used to effect the redirect.479        """480        method = self._redirect_method(request, response)481        url = self._redirect_url(request, response)482        headers = self._redirect_headers(request, url, method)483        stream = self._redirect_stream(request, method)484        cookies = Cookies(self.cookies)485        return Request(486            method=method,487            url=url,488            headers=headers,489            cookies=cookies,490            stream=stream,491            extensions=request.extensions,492        )493 494    def _redirect_method(self, request: Request, response: Response) -> str:495        """496        When being redirected we may want to change the method of the request497        based on certain specs or browser behavior.498        """499        method = request.method500 501        # https://tools.ietf.org/html/rfc7231#section-6.4.4502        if response.status_code == codes.SEE_OTHER and method != "HEAD":503            method = "GET"504 505        # Do what the browsers do, despite standards...506        # Turn 302s into GETs.507        if response.status_code == codes.FOUND and method != "HEAD":508            method = "GET"509 510        # If a POST is responded to with a 301, turn it into a GET.511        # This bizarre behaviour is explained in 'requests' issue 1704.512        if response.status_code == codes.MOVED_PERMANENTLY and method == "POST":513            method = "GET"514 515        return method516 517    def _redirect_url(self, request: Request, response: Response) -> URL:518        """519        Return the URL for the redirect to follow.520        """521        location = response.headers["Location"]522 523        try:524            url = URL(location)525        except InvalidURL as exc:526            raise RemoteProtocolError(527                f"Invalid URL in location header: {exc}.", request=request528            ) from None529 530        # Handle malformed 'Location' headers that are "absolute" form, have no host.531        # See: https://github.com/encode/httpx/issues/771532        if url.scheme and not url.host:533            url = url.copy_with(host=request.url.host)534 535        # Facilitate relative 'Location' headers, as allowed by RFC 7231.536        # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource')537        if url.is_relative_url:538            url = request.url.join(url)539 540        # Attach previous fragment if needed (RFC 7231 7.1.2)541        if request.url.fragment and not url.fragment:542            url = url.copy_with(fragment=request.url.fragment)543 544        return url545 546    def _redirect_headers(self, request: Request, url: URL, method: str) -> Headers:547        """548        Return the headers that should be used for the redirect request.549        """550        headers = Headers(request.headers)551 552        if not _same_origin(url, request.url):553            if not _is_https_redirect(request.url, url):554                # Strip Authorization headers when responses are redirected555                # away from the origin. (Except for direct HTTP to HTTPS redirects.)556                headers.pop("Authorization", None)557 558            # Update the Host header.559            headers["Host"] = url.netloc.decode("ascii")560 561        if method != request.method and method == "GET":562            # If we've switch to a 'GET' request, then strip any headers which563            # are only relevant to the request body.564            headers.pop("Content-Length", None)565            headers.pop("Transfer-Encoding", None)566 567        # We should use the client cookie store to determine any cookie header,568        # rather than whatever was on the original outgoing request.569        headers.pop("Cookie", None)570 571        return headers572 573    def _redirect_stream(574        self, request: Request, method: str575    ) -> SyncByteStream | AsyncByteStream | None:576        """577        Return the body that should be used for the redirect request.578        """579        if method != request.method and method == "GET":580            return None581 582        return request.stream583 584    def _set_timeout(self, request: Request) -> None:585        if "timeout" not in request.extensions:586            timeout = (587                self.timeout588                if isinstance(self.timeout, UseClientDefault)589                else Timeout(self.timeout)590            )591            request.extensions = dict(**request.extensions, timeout=timeout.as_dict())592 593 594class Client(BaseClient):595    """596    An HTTP client, with connection pooling, HTTP/2, redirects, cookie persistence, etc.597 598    It can be shared between threads.599 600    Usage:601 602    ```python603    >>> client = httpx.Client()604    >>> response = client.get('https://example.org')605    ```606 607    **Parameters:**608 609    * **auth** - *(optional)* An authentication class to use when sending610    requests.611    * **params** - *(optional)* Query parameters to include in request URLs, as612    a string, dictionary, or sequence of two-tuples.613    * **headers** - *(optional)* Dictionary of HTTP headers to include when614    sending requests.615    * **cookies** - *(optional)* Dictionary of Cookie items to include when616    sending requests.617    * **verify** - *(optional)* Either `True` to use an SSL context with the618    default CA bundle, `False` to disable verification, or an instance of619    `ssl.SSLContext` to use a custom context.620    * **http2** - *(optional)* A boolean indicating if HTTP/2 support should be621    enabled. Defaults to `False`.622    * **proxy** - *(optional)* A proxy URL where all the traffic should be routed.623    * **timeout** - *(optional)* The timeout configuration to use when sending624    requests.625    * **limits** - *(optional)* The limits configuration to use.626    * **max_redirects** - *(optional)* The maximum number of redirect responses627    that should be followed.628    * **base_url** - *(optional)* A URL to use as the base when building629    request URLs.630    * **transport** - *(optional)* A transport class to use for sending requests631    over the network.632    * **trust_env** - *(optional)* Enables or disables usage of environment633    variables for configuration.634    * **default_encoding** - *(optional)* The default encoding to use for decoding635    response text, if no charset information is included in a response Content-Type636    header. Set to a callable for automatic character set detection. Default: "utf-8".637    """638 639    def __init__(640        self,641        *,642        auth: AuthTypes | None = None,643        params: QueryParamTypes | None = None,644        headers: HeaderTypes | None = None,645        cookies: CookieTypes | None = None,646        verify: ssl.SSLContext | str | bool = True,647        cert: CertTypes | None = None,648        trust_env: bool = True,649        http1: bool = True,650        http2: bool = False,651        proxy: ProxyTypes | None = None,652        mounts: None | (typing.Mapping[str, BaseTransport | None]) = None,653        timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,654        follow_redirects: bool = False,655        limits: Limits = DEFAULT_LIMITS,656        max_redirects: int = DEFAULT_MAX_REDIRECTS,657        event_hooks: None | (typing.Mapping[str, list[EventHook]]) = None,658        base_url: URL | str = "",659        transport: BaseTransport | None = None,660        default_encoding: str | typing.Callable[[bytes], str] = "utf-8",661    ) -> None:662        super().__init__(663            auth=auth,664            params=params,665            headers=headers,666            cookies=cookies,667            timeout=timeout,668            follow_redirects=follow_redirects,669            max_redirects=max_redirects,670            event_hooks=event_hooks,671            base_url=base_url,672            trust_env=trust_env,673            default_encoding=default_encoding,674        )675 676        if http2:677            try:678                import h2  # noqa679            except ImportError:  # pragma: no cover680                raise ImportError(681                    "Using http2=True, but the 'h2' package is not installed. "682                    "Make sure to install httpx using `pip install httpx[http2]`."683                ) from None684 685        allow_env_proxies = trust_env and transport is None686        proxy_map = self._get_proxy_map(proxy, allow_env_proxies)687 688        self._transport = self._init_transport(689            verify=verify,690            cert=cert,691            trust_env=trust_env,692            http1=http1,693            http2=http2,694            limits=limits,695            transport=transport,696        )697        self._mounts: dict[URLPattern, BaseTransport | None] = {698            URLPattern(key): None699            if proxy is None700            else self._init_proxy_transport(701                proxy,702                verify=verify,703                cert=cert,704                trust_env=trust_env,705                http1=http1,706                http2=http2,707                limits=limits,708            )709            for key, proxy in proxy_map.items()710        }711        if mounts is not None:712            self._mounts.update(713                {URLPattern(key): transport for key, transport in mounts.items()}714            )715 716        self._mounts = dict(sorted(self._mounts.items()))717 718    def _init_transport(719        self,720        verify: ssl.SSLContext | str | bool = True,721        cert: CertTypes | None = None,722        trust_env: bool = True,723        http1: bool = True,724        http2: bool = False,725        limits: Limits = DEFAULT_LIMITS,726        transport: BaseTransport | None = None,727    ) -> BaseTransport:728        if transport is not None:729            return transport730 731        return HTTPTransport(732            verify=verify,733            cert=cert,734            trust_env=trust_env,735            http1=http1,736            http2=http2,737            limits=limits,738        )739 740    def _init_proxy_transport(741        self,742        proxy: Proxy,743        verify: ssl.SSLContext | str | bool = True,744        cert: CertTypes | None = None,745        trust_env: bool = True,746        http1: bool = True,747        http2: bool = False,748        limits: Limits = DEFAULT_LIMITS,749    ) -> BaseTransport:750        return HTTPTransport(751            verify=verify,752            cert=cert,753            trust_env=trust_env,754            http1=http1,755            http2=http2,756            limits=limits,757            proxy=proxy,758        )759 760    def _transport_for_url(self, url: URL) -> BaseTransport:761        """762        Returns the transport instance that should be used for a given URL.763        This will either be the standard connection pool, or a proxy.764        """765        for pattern, transport in self._mounts.items():766            if pattern.matches(url):767                return self._transport if transport is None else transport768 769        return self._transport770 771    def request(772        self,773        method: str,774        url: URL | str,775        *,776        content: RequestContent | None = None,777        data: RequestData | None = None,778        files: RequestFiles | None = None,779        json: typing.Any | None = None,780        params: QueryParamTypes | None = None,781        headers: HeaderTypes | None = None,782        cookies: CookieTypes | None = None,783        auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,784        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,785        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,786        extensions: RequestExtensions | None = None,787    ) -> Response:788        """789        Build and send a request.790 791        Equivalent to:792 793        ```python794        request = client.build_request(...)795        response = client.send(request, ...)796        ```797 798        See `Client.build_request()`, `Client.send()` and799        [Merging of configuration][0] for how the various parameters800        are merged with client-level configuration.801 802        [0]: /advanced/clients/#merging-of-configuration803        """804        if cookies is not None:805            message = (806                "Setting per-request cookies=<...> is being deprecated, because "807                "the expected behaviour on cookie persistence is ambiguous. Set "808                "cookies directly on the client instance instead."809            )810            warnings.warn(message, DeprecationWarning, stacklevel=2)811 812        request = self.build_request(813            method=method,814            url=url,815            content=content,816            data=data,817            files=files,818            json=json,819            params=params,820            headers=headers,821            cookies=cookies,822            timeout=timeout,823            extensions=extensions,824        )825        return self.send(request, auth=auth, follow_redirects=follow_redirects)826 827    @contextmanager828    def stream(829        self,830        method: str,831        url: URL | str,832        *,833        content: RequestContent | None = None,834        data: RequestData | None = None,835        files: RequestFiles | None = None,836        json: typing.Any | None = None,837        params: QueryParamTypes | None = None,838        headers: HeaderTypes | None = None,839        cookies: CookieTypes | None = None,840        auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,841        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,842        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,843        extensions: RequestExtensions | None = None,844    ) -> typing.Iterator[Response]:845        """846        Alternative to `httpx.request()` that streams the response body847        instead of loading it into memory at once.848 849        **Parameters**: See `httpx.request`.850 851        See also: [Streaming Responses][0]852 853        [0]: /quickstart#streaming-responses854        """855        request = self.build_request(856            method=method,857            url=url,858            content=content,859            data=data,860            files=files,861            json=json,862            params=params,863            headers=headers,864            cookies=cookies,865            timeout=timeout,866            extensions=extensions,867        )868        response = self.send(869            request=request,870            auth=auth,871            follow_redirects=follow_redirects,872            stream=True,873        )874        try:875            yield response876        finally:877            response.close()878 879    def send(880        self,881        request: Request,882        *,883        stream: bool = False,884        auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,885        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,886    ) -> Response:887        """888        Send a request.889 890        The request is sent as-is, unmodified.891 892        Typically you'll want to build one with `Client.build_request()`893        so that any client-level configuration is merged into the request,894        but passing an explicit `httpx.Request()` is supported as well.895 896        See also: [Request instances][0]897 898        [0]: /advanced/clients/#request-instances899        """900        if self._state == ClientState.CLOSED:901            raise RuntimeError("Cannot send a request, as the client has been closed.")902 903        self._state = ClientState.OPENED904        follow_redirects = (905            self.follow_redirects906            if isinstance(follow_redirects, UseClientDefault)907            else follow_redirects908        )909 910        self._set_timeout(request)911 912        auth = self._build_request_auth(request, auth)913 914        response = self._send_handling_auth(915            request,916            auth=auth,917            follow_redirects=follow_redirects,918            history=[],919        )920        try:921            if not stream:922                response.read()923 924            return response925 926        except BaseException as exc:927            response.close()928            raise exc929 930    def _send_handling_auth(931        self,932        request: Request,933        auth: Auth,934        follow_redirects: bool,935        history: list[Response],936    ) -> Response:937        auth_flow = auth.sync_auth_flow(request)938        try:939            request = next(auth_flow)940 941            while True:942                response = self._send_handling_redirects(943                    request,944                    follow_redirects=follow_redirects,945                    history=history,946                )947                try:948                    try:949                        next_request = auth_flow.send(response)950                    except StopIteration:951                        return response952 953                    response.history = list(history)954                    response.read()955                    request = next_request956                    history.append(response)957 958                except BaseException as exc:959                    response.close()960                    raise exc961        finally:962            auth_flow.close()963 964    def _send_handling_redirects(965        self,966        request: Request,967        follow_redirects: bool,968        history: list[Response],969    ) -> Response:970        while True:971            if len(history) > self.max_redirects:972                raise TooManyRedirects(973                    "Exceeded maximum allowed redirects.", request=request974                )975 976            for hook in self._event_hooks["request"]:977                hook(request)978 979            response = self._send_single_request(request)980            try:981                for hook in self._event_hooks["response"]:982                    hook(response)983                response.history = list(history)984 985                if not response.has_redirect_location:986                    return response987 988                request = self._build_redirect_request(request, response)989                history = history + [response]990 991                if follow_redirects:992                    response.read()993                else:994                    response.next_request = request995                    return response996 997            except BaseException as exc:998                response.close()999                raise exc1000 1001    def _send_single_request(self, request: Request) -> Response:1002        """1003        Sends a single request, without handling any redirections.1004        """1005        transport = self._transport_for_url(request.url)1006        start = time.perf_counter()1007 1008        if not isinstance(request.stream, SyncByteStream):1009            raise RuntimeError(1010                "Attempted to send an async request with a sync Client instance."1011            )1012 1013        with request_context(request=request):1014            response = transport.handle_request(request)1015 1016        assert isinstance(response.stream, SyncByteStream)1017 1018        response.request = request1019        response.stream = BoundSyncStream(1020            response.stream, response=response, start=start1021        )1022        self.cookies.extract_cookies(response)1023        response.default_encoding = self._default_encoding1024 1025        logger.info(1026            'HTTP Request: %s %s "%s %d %s"',1027            request.method,1028            request.url,1029            response.http_version,1030            response.status_code,1031            response.reason_phrase,1032        )1033 1034        return response1035 1036    def get(1037        self,1038        url: URL | str,1039        *,1040        params: QueryParamTypes | None = None,1041        headers: HeaderTypes | None = None,1042        cookies: CookieTypes | None = None,1043        auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,1044        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,1045        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,1046        extensions: RequestExtensions | None = None,1047    ) -> Response:1048        """1049        Send a `GET` request.1050 1051        **Parameters**: See `httpx.request`.1052        """1053        return self.request(1054            "GET",1055            url,1056            params=params,1057            headers=headers,1058            cookies=cookies,1059            auth=auth,1060            follow_redirects=follow_redirects,1061            timeout=timeout,1062            extensions=extensions,1063        )1064 1065    def options(1066        self,1067        url: URL | str,1068        *,1069        params: QueryParamTypes | None = None,1070        headers: HeaderTypes | None = None,1071        cookies: CookieTypes | None = None,1072        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,1073        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,1074        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,1075        extensions: RequestExtensions | None = None,1076    ) -> Response:1077        """1078        Send an `OPTIONS` request.1079 1080        **Parameters**: See `httpx.request`.1081        """1082        return self.request(1083            "OPTIONS",1084            url,1085            params=params,1086            headers=headers,1087            cookies=cookies,1088            auth=auth,1089            follow_redirects=follow_redirects,1090            timeout=timeout,1091            extensions=extensions,1092        )1093 1094    def head(1095        self,1096        url: URL | str,1097        *,1098        params: QueryParamTypes | None = None,1099        headers: HeaderTypes | None = None,1100        cookies: CookieTypes | None = None,1101        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,1102        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,1103        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,1104        extensions: RequestExtensions | None = None,1105    ) -> Response:1106        """1107        Send a `HEAD` request.1108 1109        **Parameters**: See `httpx.request`.1110        """1111        return self.request(1112            "HEAD",1113            url,1114            params=params,1115            headers=headers,1116            cookies=cookies,1117            auth=auth,1118            follow_redirects=follow_redirects,1119            timeout=timeout,1120            extensions=extensions,1121        )1122 1123    def post(1124        self,1125        url: URL | str,1126        *,1127        content: RequestContent | None = None,1128        data: RequestData | None = None,1129        files: RequestFiles | None = None,1130        json: typing.Any | None = None,1131        params: QueryParamTypes | None = None,1132        headers: HeaderTypes | None = None,1133        cookies: CookieTypes | None = None,1134        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,1135        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,1136        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,1137        extensions: RequestExtensions | None = None,1138    ) -> Response:1139        """1140        Send a `POST` request.1141 1142        **Parameters**: See `httpx.request`.1143        """1144        return self.request(1145            "POST",1146            url,1147            content=content,1148            data=data,1149            files=files,1150            json=json,1151            params=params,1152            headers=headers,1153            cookies=cookies,1154            auth=auth,1155            follow_redirects=follow_redirects,1156            timeout=timeout,1157            extensions=extensions,1158        )1159 1160    def put(1161        self,1162        url: URL | str,1163        *,1164        content: RequestContent | None = None,1165        data: RequestData | None = None,1166        files: RequestFiles | None = None,1167        json: typing.Any | None = None,1168        params: QueryParamTypes | None = None,1169        headers: HeaderTypes | None = None,1170        cookies: CookieTypes | None = None,1171        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,1172        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,1173        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,1174        extensions: RequestExtensions | None = None,1175    ) -> Response:1176        """1177        Send a `PUT` request.1178 1179        **Parameters**: See `httpx.request`.1180        """1181        return self.request(1182            "PUT",1183            url,1184            content=content,1185            data=data,1186            files=files,1187            json=json,1188            params=params,1189            headers=headers,1190            cookies=cookies,1191            auth=auth,1192            follow_redirects=follow_redirects,1193            timeout=timeout,1194            extensions=extensions,1195        )1196 1197    def patch(1198        self,1199        url: URL | str,1200        *,

Showing the first 1,200 of 2020 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai