Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
_compat.py303 linesDownload Raw Back to requests_toolbelt
1"""Private module full of compatibility hacks.2 3Primarily this is for downstream redistributions of requests that unvendor4urllib3 without providing a shim.5 6.. warning::7 8    This module is private. If you use it, and something breaks, you were9    warned10"""11import sys12 13import requests14 15try:16    from requests.packages.urllib3 import fields17    from requests.packages.urllib3 import filepost18    from requests.packages.urllib3 import poolmanager19except ImportError:20    from urllib3 import fields21    from urllib3 import filepost22    from urllib3 import poolmanager23 24try:25    from requests.packages.urllib3.connection import HTTPConnection26    from requests.packages.urllib3 import connection27except ImportError:28    try:29        from urllib3.connection import HTTPConnection30        from urllib3 import connection31    except ImportError:32        HTTPConnection = None33        connection = None34 35 36if requests.__build__ < 0x020300:37    timeout = None38else:39    try:40        from requests.packages.urllib3.util import timeout41    except ImportError:42        from urllib3.util import timeout43 44PY3 = sys.version_info > (3, 0)45 46if PY3:47    from collections.abc import Mapping, MutableMapping48    import queue49    from urllib.parse import urlencode, urljoin50else:51    from collections import Mapping, MutableMapping52    import Queue as queue53    from urllib import urlencode54    from urlparse import urljoin55 56try:57    basestring = basestring58except NameError:59    basestring = (str, bytes)60 61 62class HTTPHeaderDict(MutableMapping):63    """64    :param headers:65        An iterable of field-value pairs. Must not contain multiple field names66        when compared case-insensitively.67 68    :param kwargs:69        Additional field-value pairs to pass in to ``dict.update``.70 71    A ``dict`` like container for storing HTTP Headers.72 73    Field names are stored and compared case-insensitively in compliance with74    RFC 7230. Iteration provides the first case-sensitive key seen for each75    case-insensitive pair.76 77    Using ``__setitem__`` syntax overwrites fields that compare equal78    case-insensitively in order to maintain ``dict``'s api. For fields that79    compare equal, instead create a new ``HTTPHeaderDict`` and use ``.add``80    in a loop.81 82    If multiple fields that are equal case-insensitively are passed to the83    constructor or ``.update``, the behavior is undefined and some will be84    lost.85 86    >>> headers = HTTPHeaderDict()87    >>> headers.add('Set-Cookie', 'foo=bar')88    >>> headers.add('set-cookie', 'baz=quxx')89    >>> headers['content-length'] = '7'90    >>> headers['SET-cookie']91    'foo=bar, baz=quxx'92    >>> headers['Content-Length']93    '7'94    """95 96    def __init__(self, headers=None, **kwargs):97        super(HTTPHeaderDict, self).__init__()98        self._container = {}99        if headers is not None:100            if isinstance(headers, HTTPHeaderDict):101                self._copy_from(headers)102            else:103                self.extend(headers)104        if kwargs:105            self.extend(kwargs)106 107    def __setitem__(self, key, val):108        self._container[key.lower()] = (key, val)109        return self._container[key.lower()]110 111    def __getitem__(self, key):112        val = self._container[key.lower()]113        return ', '.join(val[1:])114 115    def __delitem__(self, key):116        del self._container[key.lower()]117 118    def __contains__(self, key):119        return key.lower() in self._container120 121    def __eq__(self, other):122        if not isinstance(other, Mapping) and not hasattr(other, 'keys'):123            return False124        if not isinstance(other, type(self)):125            other = type(self)(other)126        return ({k.lower(): v for k, v in self.itermerged()} ==127                {k.lower(): v for k, v in other.itermerged()})128 129    def __ne__(self, other):130        return not self.__eq__(other)131 132    if not PY3:  # Python 2133        iterkeys = MutableMapping.iterkeys134        itervalues = MutableMapping.itervalues135 136    __marker = object()137 138    def __len__(self):139        return len(self._container)140 141    def __iter__(self):142        # Only provide the originally cased names143        for vals in self._container.values():144            yield vals[0]145 146    def pop(self, key, default=__marker):147        """D.pop(k[,d]) -> v, remove specified key and return its value.148 149        If key is not found, d is returned if given, otherwise KeyError is150        raised.151        """152        # Using the MutableMapping function directly fails due to the private153        # marker.154        # Using ordinary dict.pop would expose the internal structures.155        # So let's reinvent the wheel.156        try:157            value = self[key]158        except KeyError:159            if default is self.__marker:160                raise161            return default162        else:163            del self[key]164            return value165 166    def discard(self, key):167        try:168            del self[key]169        except KeyError:170            pass171 172    def add(self, key, val):173        """Adds a (name, value) pair, doesn't overwrite the value if it already174        exists.175 176        >>> headers = HTTPHeaderDict(foo='bar')177        >>> headers.add('Foo', 'baz')178        >>> headers['foo']179        'bar, baz'180        """181        key_lower = key.lower()182        new_vals = key, val183        # Keep the common case aka no item present as fast as possible184        vals = self._container.setdefault(key_lower, new_vals)185        if new_vals is not vals:186            # new_vals was not inserted, as there was a previous one187            if isinstance(vals, list):188                # If already several items got inserted, we have a list189                vals.append(val)190            else:191                # vals should be a tuple then, i.e. only one item so far192                # Need to convert the tuple to list for further extension193                self._container[key_lower] = [vals[0], vals[1], val]194 195    def extend(self, *args, **kwargs):196        """Generic import function for any type of header-like object.197        Adapted version of MutableMapping.update in order to insert items198        with self.add instead of self.__setitem__199        """200        if len(args) > 1:201            raise TypeError("extend() takes at most 1 positional "202                            "arguments ({} given)".format(len(args)))203        other = args[0] if len(args) >= 1 else ()204 205        if isinstance(other, HTTPHeaderDict):206            for key, val in other.iteritems():207                self.add(key, val)208        elif isinstance(other, Mapping):209            for key in other:210                self.add(key, other[key])211        elif hasattr(other, "keys"):212            for key in other.keys():213                self.add(key, other[key])214        else:215            for key, value in other:216                self.add(key, value)217 218        for key, value in kwargs.items():219            self.add(key, value)220 221    def getlist(self, key):222        """Returns a list of all the values for the named field. Returns an223        empty list if the key doesn't exist."""224        try:225            vals = self._container[key.lower()]226        except KeyError:227            return []228        else:229            if isinstance(vals, tuple):230                return [vals[1]]231            else:232                return vals[1:]233 234    # Backwards compatibility for httplib235    getheaders = getlist236    getallmatchingheaders = getlist237    iget = getlist238 239    def __repr__(self):240        return "%s(%s)" % (type(self).__name__, dict(self.itermerged()))241 242    def _copy_from(self, other):243        for key in other:244            val = other.getlist(key)245            if isinstance(val, list):246                # Don't need to convert tuples247                val = list(val)248            self._container[key.lower()] = [key] + val249 250    def copy(self):251        clone = type(self)()252        clone._copy_from(self)253        return clone254 255    def iteritems(self):256        """Iterate over all header lines, including duplicate ones."""257        for key in self:258            vals = self._container[key.lower()]259            for val in vals[1:]:260                yield vals[0], val261 262    def itermerged(self):263        """Iterate over all headers, merging duplicate ones together."""264        for key in self:265            val = self._container[key.lower()]266            yield val[0], ', '.join(val[1:])267 268    def items(self):269        return list(self.iteritems())270 271    @classmethod272    def from_httplib(cls, message):  # Python 2273        """Read headers from a Python 2 httplib message object."""274        # python2.7 does not expose a proper API for exporting multiheaders275        # efficiently. This function re-reads raw lines from the message276        # object and extracts the multiheaders properly.277        headers = []278 279        for line in message.headers:280            if line.startswith((' ', '\t')):281                key, value = headers[-1]282                headers[-1] = (key, value + '\r\n' + line.rstrip())283                continue284 285            key, value = line.split(':', 1)286            headers.append((key, value.strip()))287 288        return cls(headers)289 290 291__all__ = (292    'basestring',293    'connection',294    'fields',295    'filepost',296    'poolmanager',297    'timeout',298    'HTTPHeaderDict',299    'queue',300    'urlencode',301    'urljoin',302)303 
codekingpro/portable-devtools · Team Ai