Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
models.py1035 linesDownload Raw Back to requests
1"""2requests.models3~~~~~~~~~~~~~~~4 5This module contains the primary objects that power Requests.6"""7 8import datetime9 10# Import encoding now, to avoid implicit import later.11# Implicit import within threads may cause LookupError when standard library is in a ZIP,12# such as in Embedded Python. See https://github.com/psf/requests/issues/3578.13import encodings.idna  # noqa: F40114from io import UnsupportedOperation15 16from urllib3.exceptions import (17    DecodeError,18    LocationParseError,19    ProtocolError,20    ReadTimeoutError,21    SSLError,22)23from urllib3.fields import RequestField24from urllib3.filepost import encode_multipart_formdata25from urllib3.util import parse_url26 27from ._internal_utils import to_native_string, unicode_is_ascii28from .auth import HTTPBasicAuth29from .compat import (30    Callable,31    JSONDecodeError,32    Mapping,33    basestring,34    builtin_str,35    chardet,36    cookielib,37)38from .compat import json as complexjson39from .compat import urlencode, urlsplit, urlunparse40from .cookies import _copy_cookie_jar, cookiejar_from_dict, get_cookie_header41from .exceptions import (42    ChunkedEncodingError,43    ConnectionError,44    ContentDecodingError,45    HTTPError,46    InvalidJSONError,47    InvalidURL,48)49from .exceptions import JSONDecodeError as RequestsJSONDecodeError50from .exceptions import MissingSchema51from .exceptions import SSLError as RequestsSSLError52from .exceptions import StreamConsumedError53from .hooks import default_hooks54from .status_codes import codes55from .structures import CaseInsensitiveDict56from .utils import (57    check_header_validity,58    get_auth_from_url,59    guess_filename,60    guess_json_utf,61    iter_slices,62    parse_header_links,63    requote_uri,64    stream_decode_response_unicode,65    super_len,66    to_key_val_list,67)68 69#: The set of HTTP status codes that indicate an automatically70#: processable redirect.71REDIRECT_STATI = (72    codes.moved,  # 30173    codes.found,  # 30274    codes.other,  # 30375    codes.temporary_redirect,  # 30776    codes.permanent_redirect,  # 30877)78 79DEFAULT_REDIRECT_LIMIT = 3080CONTENT_CHUNK_SIZE = 10 * 102481ITER_CHUNK_SIZE = 51282 83 84class RequestEncodingMixin:85    @property86    def path_url(self):87        """Build the path URL to use."""88 89        url = []90 91        p = urlsplit(self.url)92 93        path = p.path94        if not path:95            path = "/"96 97        url.append(path)98 99        query = p.query100        if query:101            url.append("?")102            url.append(query)103 104        return "".join(url)105 106    @staticmethod107    def _encode_params(data):108        """Encode parameters in a piece of data.109 110        Will successfully encode parameters when passed as a dict or a list of111        2-tuples. Order is retained if data is a list of 2-tuples but arbitrary112        if parameters are supplied as a dict.113        """114 115        if isinstance(data, (str, bytes)):116            return data117        elif hasattr(data, "read"):118            return data119        elif hasattr(data, "__iter__"):120            result = []121            for k, vs in to_key_val_list(data):122                if isinstance(vs, basestring) or not hasattr(vs, "__iter__"):123                    vs = [vs]124                for v in vs:125                    if v is not None:126                        result.append(127                            (128                                k.encode("utf-8") if isinstance(k, str) else k,129                                v.encode("utf-8") if isinstance(v, str) else v,130                            )131                        )132            return urlencode(result, doseq=True)133        else:134            return data135 136    @staticmethod137    def _encode_files(files, data):138        """Build the body for a multipart/form-data request.139 140        Will successfully encode files when passed as a dict or a list of141        tuples. Order is retained if data is a list of tuples but arbitrary142        if parameters are supplied as a dict.143        The tuples may be 2-tuples (filename, fileobj), 3-tuples (filename, fileobj, contentype)144        or 4-tuples (filename, fileobj, contentype, custom_headers).145        """146        if not files:147            raise ValueError("Files must be provided.")148        elif isinstance(data, basestring):149            raise ValueError("Data must not be a string.")150 151        new_fields = []152        fields = to_key_val_list(data or {})153        files = to_key_val_list(files or {})154 155        for field, val in fields:156            if isinstance(val, basestring) or not hasattr(val, "__iter__"):157                val = [val]158            for v in val:159                if v is not None:160                    # Don't call str() on bytestrings: in Py3 it all goes wrong.161                    if not isinstance(v, bytes):162                        v = str(v)163 164                    new_fields.append(165                        (166                            field.decode("utf-8")167                            if isinstance(field, bytes)168                            else field,169                            v.encode("utf-8") if isinstance(v, str) else v,170                        )171                    )172 173        for (k, v) in files:174            # support for explicit filename175            ft = None176            fh = None177            if isinstance(v, (tuple, list)):178                if len(v) == 2:179                    fn, fp = v180                elif len(v) == 3:181                    fn, fp, ft = v182                else:183                    fn, fp, ft, fh = v184            else:185                fn = guess_filename(v) or k186                fp = v187 188            if isinstance(fp, (str, bytes, bytearray)):189                fdata = fp190            elif hasattr(fp, "read"):191                fdata = fp.read()192            elif fp is None:193                continue194            else:195                fdata = fp196 197            rf = RequestField(name=k, data=fdata, filename=fn, headers=fh)198            rf.make_multipart(content_type=ft)199            new_fields.append(rf)200 201        body, content_type = encode_multipart_formdata(new_fields)202 203        return body, content_type204 205 206class RequestHooksMixin:207    def register_hook(self, event, hook):208        """Properly register a hook."""209 210        if event not in self.hooks:211            raise ValueError(f'Unsupported event specified, with event name "{event}"')212 213        if isinstance(hook, Callable):214            self.hooks[event].append(hook)215        elif hasattr(hook, "__iter__"):216            self.hooks[event].extend(h for h in hook if isinstance(h, Callable))217 218    def deregister_hook(self, event, hook):219        """Deregister a previously registered hook.220        Returns True if the hook existed, False if not.221        """222 223        try:224            self.hooks[event].remove(hook)225            return True226        except ValueError:227            return False228 229 230class Request(RequestHooksMixin):231    """A user-created :class:`Request <Request>` object.232 233    Used to prepare a :class:`PreparedRequest <PreparedRequest>`, which is sent to the server.234 235    :param method: HTTP method to use.236    :param url: URL to send.237    :param headers: dictionary of headers to send.238    :param files: dictionary of {filename: fileobject} files to multipart upload.239    :param data: the body to attach to the request. If a dictionary or240        list of tuples ``[(key, value)]`` is provided, form-encoding will241        take place.242    :param json: json for the body to attach to the request (if files or data is not specified).243    :param params: URL parameters to append to the URL. If a dictionary or244        list of tuples ``[(key, value)]`` is provided, form-encoding will245        take place.246    :param auth: Auth handler or (user, pass) tuple.247    :param cookies: dictionary or CookieJar of cookies to attach to this request.248    :param hooks: dictionary of callback hooks, for internal usage.249 250    Usage::251 252      >>> import requests253      >>> req = requests.Request('GET', 'https://httpbin.org/get')254      >>> req.prepare()255      <PreparedRequest [GET]>256    """257 258    def __init__(259        self,260        method=None,261        url=None,262        headers=None,263        files=None,264        data=None,265        params=None,266        auth=None,267        cookies=None,268        hooks=None,269        json=None,270    ):271 272        # Default empty dicts for dict params.273        data = [] if data is None else data274        files = [] if files is None else files275        headers = {} if headers is None else headers276        params = {} if params is None else params277        hooks = {} if hooks is None else hooks278 279        self.hooks = default_hooks()280        for (k, v) in list(hooks.items()):281            self.register_hook(event=k, hook=v)282 283        self.method = method284        self.url = url285        self.headers = headers286        self.files = files287        self.data = data288        self.json = json289        self.params = params290        self.auth = auth291        self.cookies = cookies292 293    def __repr__(self):294        return f"<Request [{self.method}]>"295 296    def prepare(self):297        """Constructs a :class:`PreparedRequest <PreparedRequest>` for transmission and returns it."""298        p = PreparedRequest()299        p.prepare(300            method=self.method,301            url=self.url,302            headers=self.headers,303            files=self.files,304            data=self.data,305            json=self.json,306            params=self.params,307            auth=self.auth,308            cookies=self.cookies,309            hooks=self.hooks,310        )311        return p312 313 314class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):315    """The fully mutable :class:`PreparedRequest <PreparedRequest>` object,316    containing the exact bytes that will be sent to the server.317 318    Instances are generated from a :class:`Request <Request>` object, and319    should not be instantiated manually; doing so may produce undesirable320    effects.321 322    Usage::323 324      >>> import requests325      >>> req = requests.Request('GET', 'https://httpbin.org/get')326      >>> r = req.prepare()327      >>> r328      <PreparedRequest [GET]>329 330      >>> s = requests.Session()331      >>> s.send(r)332      <Response [200]>333    """334 335    def __init__(self):336        #: HTTP verb to send to the server.337        self.method = None338        #: HTTP URL to send the request to.339        self.url = None340        #: dictionary of HTTP headers.341        self.headers = None342        # The `CookieJar` used to create the Cookie header will be stored here343        # after prepare_cookies is called344        self._cookies = None345        #: request body to send to the server.346        self.body = None347        #: dictionary of callback hooks, for internal usage.348        self.hooks = default_hooks()349        #: integer denoting starting position of a readable file-like body.350        self._body_position = None351 352    def prepare(353        self,354        method=None,355        url=None,356        headers=None,357        files=None,358        data=None,359        params=None,360        auth=None,361        cookies=None,362        hooks=None,363        json=None,364    ):365        """Prepares the entire request with the given parameters."""366 367        self.prepare_method(method)368        self.prepare_url(url, params)369        self.prepare_headers(headers)370        self.prepare_cookies(cookies)371        self.prepare_body(data, files, json)372        self.prepare_auth(auth, url)373 374        # Note that prepare_auth must be last to enable authentication schemes375        # such as OAuth to work on a fully prepared request.376 377        # This MUST go after prepare_auth. Authenticators could add a hook378        self.prepare_hooks(hooks)379 380    def __repr__(self):381        return f"<PreparedRequest [{self.method}]>"382 383    def copy(self):384        p = PreparedRequest()385        p.method = self.method386        p.url = self.url387        p.headers = self.headers.copy() if self.headers is not None else None388        p._cookies = _copy_cookie_jar(self._cookies)389        p.body = self.body390        p.hooks = self.hooks391        p._body_position = self._body_position392        return p393 394    def prepare_method(self, method):395        """Prepares the given HTTP method."""396        self.method = method397        if self.method is not None:398            self.method = to_native_string(self.method.upper())399 400    @staticmethod401    def _get_idna_encoded_host(host):402        import idna403 404        try:405            host = idna.encode(host, uts46=True).decode("utf-8")406        except idna.IDNAError:407            raise UnicodeError408        return host409 410    def prepare_url(self, url, params):411        """Prepares the given HTTP URL."""412        #: Accept objects that have string representations.413        #: We're unable to blindly call unicode/str functions414        #: as this will include the bytestring indicator (b'')415        #: on python 3.x.416        #: https://github.com/psf/requests/pull/2238417        if isinstance(url, bytes):418            url = url.decode("utf8")419        else:420            url = str(url)421 422        # Remove leading whitespaces from url423        url = url.lstrip()424 425        # Don't do any URL preparation for non-HTTP schemes like `mailto`,426        # `data` etc to work around exceptions from `url_parse`, which427        # handles RFC 3986 only.428        if ":" in url and not url.lower().startswith("http"):429            self.url = url430            return431 432        # Support for unicode domain names and paths.433        try:434            scheme, auth, host, port, path, query, fragment = parse_url(url)435        except LocationParseError as e:436            raise InvalidURL(*e.args)437 438        if not scheme:439            raise MissingSchema(440                f"Invalid URL {url!r}: No scheme supplied. "441                f"Perhaps you meant https://{url}?"442            )443 444        if not host:445            raise InvalidURL(f"Invalid URL {url!r}: No host supplied")446 447        # In general, we want to try IDNA encoding the hostname if the string contains448        # non-ASCII characters. This allows users to automatically get the correct IDNA449        # behaviour. For strings containing only ASCII characters, we need to also verify450        # it doesn't start with a wildcard (*), before allowing the unencoded hostname.451        if not unicode_is_ascii(host):452            try:453                host = self._get_idna_encoded_host(host)454            except UnicodeError:455                raise InvalidURL("URL has an invalid label.")456        elif host.startswith(("*", ".")):457            raise InvalidURL("URL has an invalid label.")458 459        # Carefully reconstruct the network location460        netloc = auth or ""461        if netloc:462            netloc += "@"463        netloc += host464        if port:465            netloc += f":{port}"466 467        # Bare domains aren't valid URLs.468        if not path:469            path = "/"470 471        if isinstance(params, (str, bytes)):472            params = to_native_string(params)473 474        enc_params = self._encode_params(params)475        if enc_params:476            if query:477                query = f"{query}&{enc_params}"478            else:479                query = enc_params480 481        url = requote_uri(urlunparse([scheme, netloc, path, None, query, fragment]))482        self.url = url483 484    def prepare_headers(self, headers):485        """Prepares the given HTTP headers."""486 487        self.headers = CaseInsensitiveDict()488        if headers:489            for header in headers.items():490                # Raise exception on invalid header value.491                check_header_validity(header)492                name, value = header493                self.headers[to_native_string(name)] = value494 495    def prepare_body(self, data, files, json=None):496        """Prepares the given HTTP body data."""497 498        # Check if file, fo, generator, iterator.499        # If not, run through normal process.500 501        # Nottin' on you.502        body = None503        content_type = None504 505        if not data and json is not None:506            # urllib3 requires a bytes-like body. Python 2's json.dumps507            # provides this natively, but Python 3 gives a Unicode string.508            content_type = "application/json"509 510            try:511                body = complexjson.dumps(json, allow_nan=False)512            except ValueError as ve:513                raise InvalidJSONError(ve, request=self)514 515            if not isinstance(body, bytes):516                body = body.encode("utf-8")517 518        is_stream = all(519            [520                hasattr(data, "__iter__"),521                not isinstance(data, (basestring, list, tuple, Mapping)),522            ]523        )524 525        if is_stream:526            try:527                length = super_len(data)528            except (TypeError, AttributeError, UnsupportedOperation):529                length = None530 531            body = data532 533            if getattr(body, "tell", None) is not None:534                # Record the current file position before reading.535                # This will allow us to rewind a file in the event536                # of a redirect.537                try:538                    self._body_position = body.tell()539                except OSError:540                    # This differentiates from None, allowing us to catch541                    # a failed `tell()` later when trying to rewind the body542                    self._body_position = object()543 544            if files:545                raise NotImplementedError(546                    "Streamed bodies and files are mutually exclusive."547                )548 549            if length:550                self.headers["Content-Length"] = builtin_str(length)551            else:552                self.headers["Transfer-Encoding"] = "chunked"553        else:554            # Multi-part file uploads.555            if files:556                (body, content_type) = self._encode_files(files, data)557            else:558                if data:559                    body = self._encode_params(data)560                    if isinstance(data, basestring) or hasattr(data, "read"):561                        content_type = None562                    else:563                        content_type = "application/x-www-form-urlencoded"564 565            self.prepare_content_length(body)566 567            # Add content-type if it wasn't explicitly provided.568            if content_type and ("content-type" not in self.headers):569                self.headers["Content-Type"] = content_type570 571        self.body = body572 573    def prepare_content_length(self, body):574        """Prepare Content-Length header based on request method and body"""575        if body is not None:576            length = super_len(body)577            if length:578                # If length exists, set it. Otherwise, we fallback579                # to Transfer-Encoding: chunked.580                self.headers["Content-Length"] = builtin_str(length)581        elif (582            self.method not in ("GET", "HEAD")583            and self.headers.get("Content-Length") is None584        ):585            # Set Content-Length to 0 for methods that can have a body586            # but don't provide one. (i.e. not GET or HEAD)587            self.headers["Content-Length"] = "0"588 589    def prepare_auth(self, auth, url=""):590        """Prepares the given HTTP auth data."""591 592        # If no Auth is explicitly provided, extract it from the URL first.593        if auth is None:594            url_auth = get_auth_from_url(self.url)595            auth = url_auth if any(url_auth) else None596 597        if auth:598            if isinstance(auth, tuple) and len(auth) == 2:599                # special-case basic HTTP auth600                auth = HTTPBasicAuth(*auth)601 602            # Allow auth to make its changes.603            r = auth(self)604 605            # Update self to reflect the auth changes.606            self.__dict__.update(r.__dict__)607 608            # Recompute Content-Length609            self.prepare_content_length(self.body)610 611    def prepare_cookies(self, cookies):612        """Prepares the given HTTP cookie data.613 614        This function eventually generates a ``Cookie`` header from the615        given cookies using cookielib. Due to cookielib's design, the header616        will not be regenerated if it already exists, meaning this function617        can only be called once for the life of the618        :class:`PreparedRequest <PreparedRequest>` object. Any subsequent calls619        to ``prepare_cookies`` will have no actual effect, unless the "Cookie"620        header is removed beforehand.621        """622        if isinstance(cookies, cookielib.CookieJar):623            self._cookies = cookies624        else:625            self._cookies = cookiejar_from_dict(cookies)626 627        cookie_header = get_cookie_header(self._cookies, self)628        if cookie_header is not None:629            self.headers["Cookie"] = cookie_header630 631    def prepare_hooks(self, hooks):632        """Prepares the given hooks."""633        # hooks can be passed as None to the prepare method and to this634        # method. To prevent iterating over None, simply use an empty list635        # if hooks is False-y636        hooks = hooks or []637        for event in hooks:638            self.register_hook(event, hooks[event])639 640 641class Response:642    """The :class:`Response <Response>` object, which contains a643    server's response to an HTTP request.644    """645 646    __attrs__ = [647        "_content",648        "status_code",649        "headers",650        "url",651        "history",652        "encoding",653        "reason",654        "cookies",655        "elapsed",656        "request",657    ]658 659    def __init__(self):660        self._content = False661        self._content_consumed = False662        self._next = None663 664        #: Integer Code of responded HTTP Status, e.g. 404 or 200.665        self.status_code = None666 667        #: Case-insensitive Dictionary of Response Headers.668        #: For example, ``headers['content-encoding']`` will return the669        #: value of a ``'Content-Encoding'`` response header.670        self.headers = CaseInsensitiveDict()671 672        #: File-like object representation of response (for advanced usage).673        #: Use of ``raw`` requires that ``stream=True`` be set on the request.674        #: This requirement does not apply for use internally to Requests.675        self.raw = None676 677        #: Final URL location of Response.678        self.url = None679 680        #: Encoding to decode with when accessing r.text.681        self.encoding = None682 683        #: A list of :class:`Response <Response>` objects from684        #: the history of the Request. Any redirect responses will end685        #: up here. The list is sorted from the oldest to the most recent request.686        self.history = []687 688        #: Textual reason of responded HTTP Status, e.g. "Not Found" or "OK".689        self.reason = None690 691        #: A CookieJar of Cookies the server sent back.692        self.cookies = cookiejar_from_dict({})693 694        #: The amount of time elapsed between sending the request695        #: and the arrival of the response (as a timedelta).696        #: This property specifically measures the time taken between sending697        #: the first byte of the request and finishing parsing the headers. It698        #: is therefore unaffected by consuming the response content or the699        #: value of the ``stream`` keyword argument.700        self.elapsed = datetime.timedelta(0)701 702        #: The :class:`PreparedRequest <PreparedRequest>` object to which this703        #: is a response.704        self.request = None705 706    def __enter__(self):707        return self708 709    def __exit__(self, *args):710        self.close()711 712    def __getstate__(self):713        # Consume everything; accessing the content attribute makes714        # sure the content has been fully read.715        if not self._content_consumed:716            self.content717 718        return {attr: getattr(self, attr, None) for attr in self.__attrs__}719 720    def __setstate__(self, state):721        for name, value in state.items():722            setattr(self, name, value)723 724        # pickled objects do not have .raw725        setattr(self, "_content_consumed", True)726        setattr(self, "raw", None)727 728    def __repr__(self):729        return f"<Response [{self.status_code}]>"730 731    def __bool__(self):732        """Returns True if :attr:`status_code` is less than 400.733 734        This attribute checks if the status code of the response is between735        400 and 600 to see if there was a client error or a server error. If736        the status code, is between 200 and 400, this will return True. This737        is **not** a check to see if the response code is ``200 OK``.738        """739        return self.ok740 741    def __nonzero__(self):742        """Returns True if :attr:`status_code` is less than 400.743 744        This attribute checks if the status code of the response is between745        400 and 600 to see if there was a client error or a server error. If746        the status code, is between 200 and 400, this will return True. This747        is **not** a check to see if the response code is ``200 OK``.748        """749        return self.ok750 751    def __iter__(self):752        """Allows you to use a response as an iterator."""753        return self.iter_content(128)754 755    @property756    def ok(self):757        """Returns True if :attr:`status_code` is less than 400, False if not.758 759        This attribute checks if the status code of the response is between760        400 and 600 to see if there was a client error or a server error. If761        the status code is between 200 and 400, this will return True. This762        is **not** a check to see if the response code is ``200 OK``.763        """764        try:765            self.raise_for_status()766        except HTTPError:767            return False768        return True769 770    @property771    def is_redirect(self):772        """True if this Response is a well-formed HTTP redirect that could have773        been processed automatically (by :meth:`Session.resolve_redirects`).774        """775        return "location" in self.headers and self.status_code in REDIRECT_STATI776 777    @property778    def is_permanent_redirect(self):779        """True if this Response one of the permanent versions of redirect."""780        return "location" in self.headers and self.status_code in (781            codes.moved_permanently,782            codes.permanent_redirect,783        )784 785    @property786    def next(self):787        """Returns a PreparedRequest for the next request in a redirect chain, if there is one."""788        return self._next789 790    @property791    def apparent_encoding(self):792        """The apparent encoding, provided by the charset_normalizer or chardet libraries."""793        return chardet.detect(self.content)["encoding"]794 795    def iter_content(self, chunk_size=1, decode_unicode=False):796        """Iterates over the response data.  When stream=True is set on the797        request, this avoids reading the content at once into memory for798        large responses.  The chunk size is the number of bytes it should799        read into memory.  This is not necessarily the length of each item800        returned as decoding can take place.801 802        chunk_size must be of type int or None. A value of None will803        function differently depending on the value of `stream`.804        stream=True will read data as it arrives in whatever size the805        chunks are received. If stream=False, data is returned as806        a single chunk.807 808        If decode_unicode is True, content will be decoded using the best809        available encoding based on the response.810        """811 812        def generate():813            # Special case for urllib3.814            if hasattr(self.raw, "stream"):815                try:816                    yield from self.raw.stream(chunk_size, decode_content=True)817                except ProtocolError as e:818                    raise ChunkedEncodingError(e)819                except DecodeError as e:820                    raise ContentDecodingError(e)821                except ReadTimeoutError as e:822                    raise ConnectionError(e)823                except SSLError as e:824                    raise RequestsSSLError(e)825            else:826                # Standard file-like object.827                while True:828                    chunk = self.raw.read(chunk_size)829                    if not chunk:830                        break831                    yield chunk832 833            self._content_consumed = True834 835        if self._content_consumed and isinstance(self._content, bool):836            raise StreamConsumedError()837        elif chunk_size is not None and not isinstance(chunk_size, int):838            raise TypeError(839                f"chunk_size must be an int, it is instead a {type(chunk_size)}."840            )841        # simulate reading small chunks of the content842        reused_chunks = iter_slices(self._content, chunk_size)843 844        stream_chunks = generate()845 846        chunks = reused_chunks if self._content_consumed else stream_chunks847 848        if decode_unicode:849            chunks = stream_decode_response_unicode(chunks, self)850 851        return chunks852 853    def iter_lines(854        self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=False, delimiter=None855    ):856        """Iterates over the response data, one line at a time.  When857        stream=True is set on the request, this avoids reading the858        content at once into memory for large responses.859 860        .. note:: This method is not reentrant safe.861        """862 863        pending = None864 865        for chunk in self.iter_content(866            chunk_size=chunk_size, decode_unicode=decode_unicode867        ):868 869            if pending is not None:870                chunk = pending + chunk871 872            if delimiter:873                lines = chunk.split(delimiter)874            else:875                lines = chunk.splitlines()876 877            if lines and lines[-1] and chunk and lines[-1][-1] == chunk[-1]:878                pending = lines.pop()879            else:880                pending = None881 882            yield from lines883 884        if pending is not None:885            yield pending886 887    @property888    def content(self):889        """Content of the response, in bytes."""890 891        if self._content is False:892            # Read the contents.893            if self._content_consumed:894                raise RuntimeError("The content for this response was already consumed")895 896            if self.status_code == 0 or self.raw is None:897                self._content = None898            else:899                self._content = b"".join(self.iter_content(CONTENT_CHUNK_SIZE)) or b""900 901        self._content_consumed = True902        # don't need to release the connection; that's been handled by urllib3903        # since we exhausted the data.904        return self._content905 906    @property907    def text(self):908        """Content of the response, in unicode.909 910        If Response.encoding is None, encoding will be guessed using911        ``charset_normalizer`` or ``chardet``.912 913        The encoding of the response content is determined based solely on HTTP914        headers, following RFC 2616 to the letter. If you can take advantage of915        non-HTTP knowledge to make a better guess at the encoding, you should916        set ``r.encoding`` appropriately before accessing this property.917        """918 919        # Try charset from content-type920        content = None921        encoding = self.encoding922 923        if not self.content:924            return ""925 926        # Fallback to auto-detected encoding.927        if self.encoding is None:928            encoding = self.apparent_encoding929 930        # Decode unicode from given encoding.931        try:932            content = str(self.content, encoding, errors="replace")933        except (LookupError, TypeError):934            # A LookupError is raised if the encoding was not found which could935            # indicate a misspelling or similar mistake.936            #937            # A TypeError can be raised if encoding is None938            #939            # So we try blindly encoding.940            content = str(self.content, errors="replace")941 942        return content943 944    def json(self, **kwargs):945        r"""Returns the json-encoded content of a response, if any.946 947        :param \*\*kwargs: Optional arguments that ``json.loads`` takes.948        :raises requests.exceptions.JSONDecodeError: If the response body does not949            contain valid json.950        """951 952        if not self.encoding and self.content and len(self.content) > 3:953            # No encoding set. JSON RFC 4627 section 3 states we should expect954            # UTF-8, -16 or -32. Detect which one to use; If the detection or955            # decoding fails, fall back to `self.text` (using charset_normalizer to make956            # a best guess).957            encoding = guess_json_utf(self.content)958            if encoding is not None:959                try:960                    return complexjson.loads(self.content.decode(encoding), **kwargs)961                except UnicodeDecodeError:962                    # Wrong UTF codec detected; usually because it's not UTF-8963                    # but some other 8-bit codec.  This is an RFC violation,964                    # and the server didn't bother to tell us what codec *was*965                    # used.966                    pass967                except JSONDecodeError as e:968                    raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)969 970        try:971            return complexjson.loads(self.text, **kwargs)972        except JSONDecodeError as e:973            # Catch JSON-related errors and raise as requests.JSONDecodeError974            # This aliases json.JSONDecodeError and simplejson.JSONDecodeError975            raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)976 977    @property978    def links(self):979        """Returns the parsed header links of the response, if any."""980 981        header = self.headers.get("link")982 983        resolved_links = {}984 985        if header:986            links = parse_header_links(header)987 988            for link in links:989                key = link.get("rel") or link.get("url")990                resolved_links[key] = link991 992        return resolved_links993 994    def raise_for_status(self):995        """Raises :class:`HTTPError`, if one occurred."""996 997        http_error_msg = ""998        if isinstance(self.reason, bytes):999            # We attempt to decode utf-8 first because some servers1000            # choose to localize their reason strings. If the string1001            # isn't utf-8, we fall back to iso-8859-1 for all other1002            # encodings. (See PR #3538)1003            try:1004                reason = self.reason.decode("utf-8")1005            except UnicodeDecodeError:1006                reason = self.reason.decode("iso-8859-1")1007        else:1008            reason = self.reason1009 1010        if 400 <= self.status_code < 500:1011            http_error_msg = (1012                f"{self.status_code} Client Error: {reason} for url: {self.url}"1013            )1014 1015        elif 500 <= self.status_code < 600:1016            http_error_msg = (1017                f"{self.status_code} Server Error: {reason} for url: {self.url}"1018            )1019 1020        if http_error_msg:1021            raise HTTPError(http_error_msg, response=self)1022 1023    def close(self):1024        """Releases the connection back to the pool. Once this method has been1025        called the underlying ``raw`` object must not be accessed again.1026 1027        *Note: Should not normally need to be called explicitly.*1028        """1029        if not self._content_consumed:1030            self.raw.close()1031 1032        release_conn = getattr(self.raw, "release_conn", None)1033        if release_conn is not None:1034            release_conn()1035 
codekingpro/portable-devtools · Team Ai