Index: swarm_client/third_party/requests/utils.py |
=================================================================== |
--- swarm_client/third_party/requests/utils.py (revision 235167) |
+++ swarm_client/third_party/requests/utils.py (working copy) |
@@ -1,571 +0,0 @@ |
-# -*- coding: utf-8 -*- |
- |
-""" |
-requests.utils |
-~~~~~~~~~~~~~~ |
- |
-This module provides utility functions that are used within Requests |
-that are also useful for external consumption. |
- |
-""" |
- |
-import cgi |
-import codecs |
-import collections |
-import os |
-import platform |
-import re |
-import sys |
-from netrc import netrc, NetrcParseError |
- |
-from . import __version__ |
-from . import certs |
-from .compat import parse_http_list as _parse_list_header |
-from .compat import (quote, urlparse, bytes, str, OrderedDict, urlunparse, |
- is_py2, is_py3, builtin_str, getproxies, proxy_bypass) |
-from .cookies import RequestsCookieJar, cookiejar_from_dict |
-from .structures import CaseInsensitiveDict |
-from .exceptions import MissingSchema, InvalidURL |
- |
-_hush_pyflakes = (RequestsCookieJar,) |
- |
-NETRC_FILES = ('.netrc', '_netrc') |
- |
-DEFAULT_CA_BUNDLE_PATH = certs.where() |
- |
- |
-def dict_to_sequence(d): |
- """Returns an internal sequence dictionary update.""" |
- |
- if hasattr(d, 'items'): |
- d = d.items() |
- |
- return d |
- |
- |
-def super_len(o): |
- if hasattr(o, '__len__'): |
- return len(o) |
- if hasattr(o, 'len'): |
- return o.len |
- if hasattr(o, 'fileno'): |
- return os.fstat(o.fileno()).st_size |
- |
- |
-def get_netrc_auth(url): |
- """Returns the Requests tuple auth for a given url from netrc.""" |
- |
- try: |
- locations = (os.path.expanduser('~/{0}'.format(f)) for f in NETRC_FILES) |
- netrc_path = None |
- |
- for loc in locations: |
- if os.path.exists(loc) and not netrc_path: |
- netrc_path = loc |
- |
- # Abort early if there isn't one. |
- if netrc_path is None: |
- return netrc_path |
- |
- ri = urlparse(url) |
- |
- # Strip port numbers from netloc |
- host = ri.netloc.split(':')[0] |
- |
- try: |
- _netrc = netrc(netrc_path).authenticators(host) |
- if _netrc: |
- # Return with login / password |
- login_i = (0 if _netrc[0] else 1) |
- return (_netrc[login_i], _netrc[2]) |
- except (NetrcParseError, IOError): |
- # If there was a parsing error or a permissions issue reading the file, |
- # we'll just skip netrc auth |
- pass |
- |
- # AppEngine hackiness. |
- except (ImportError, AttributeError): |
- pass |
- |
- |
-def guess_filename(obj): |
- """Tries to guess the filename of the given object.""" |
- name = getattr(obj, 'name', None) |
- if name and name[0] != '<' and name[-1] != '>': |
- return os.path.basename(name) |
- |
- |
-def from_key_val_list(value): |
- """Take an object and test to see if it can be represented as a |
- dictionary. Unless it can not be represented as such, return an |
- OrderedDict, e.g., |
- |
- :: |
- |
- >>> from_key_val_list([('key', 'val')]) |
- OrderedDict([('key', 'val')]) |
- >>> from_key_val_list('string') |
- ValueError: need more than 1 value to unpack |
- >>> from_key_val_list({'key': 'val'}) |
- OrderedDict([('key', 'val')]) |
- """ |
- if value is None: |
- return None |
- |
- if isinstance(value, (str, bytes, bool, int)): |
- raise ValueError('cannot encode objects that are not 2-tuples') |
- |
- return OrderedDict(value) |
- |
- |
-def to_key_val_list(value): |
- """Take an object and test to see if it can be represented as a |
- dictionary. If it can be, return a list of tuples, e.g., |
- |
- :: |
- |
- >>> to_key_val_list([('key', 'val')]) |
- [('key', 'val')] |
- >>> to_key_val_list({'key': 'val'}) |
- [('key', 'val')] |
- >>> to_key_val_list('string') |
- ValueError: cannot encode objects that are not 2-tuples. |
- """ |
- if value is None: |
- return None |
- |
- if isinstance(value, (str, bytes, bool, int)): |
- raise ValueError('cannot encode objects that are not 2-tuples') |
- |
- if isinstance(value, collections.Mapping): |
- value = value.items() |
- |
- return list(value) |
- |
- |
-# From mitsuhiko/werkzeug (used with permission). |
-def parse_list_header(value): |
- """Parse lists as described by RFC 2068 Section 2. |
- |
- In particular, parse comma-separated lists where the elements of |
- the list may include quoted-strings. A quoted-string could |
- contain a comma. A non-quoted string could have quotes in the |
- middle. Quotes are removed automatically after parsing. |
- |
- It basically works like :func:`parse_set_header` just that items |
- may appear multiple times and case sensitivity is preserved. |
- |
- The return value is a standard :class:`list`: |
- |
- >>> parse_list_header('token, "quoted value"') |
- ['token', 'quoted value'] |
- |
- To create a header from the :class:`list` again, use the |
- :func:`dump_header` function. |
- |
- :param value: a string with a list header. |
- :return: :class:`list` |
- """ |
- result = [] |
- for item in _parse_list_header(value): |
- if item[:1] == item[-1:] == '"': |
- item = unquote_header_value(item[1:-1]) |
- result.append(item) |
- return result |
- |
- |
-# From mitsuhiko/werkzeug (used with permission). |
-def parse_dict_header(value): |
- """Parse lists of key, value pairs as described by RFC 2068 Section 2 and |
- convert them into a python dict: |
- |
- >>> d = parse_dict_header('foo="is a fish", bar="as well"') |
- >>> type(d) is dict |
- True |
- >>> sorted(d.items()) |
- [('bar', 'as well'), ('foo', 'is a fish')] |
- |
- If there is no value for a key it will be `None`: |
- |
- >>> parse_dict_header('key_without_value') |
- {'key_without_value': None} |
- |
- To create a header from the :class:`dict` again, use the |
- :func:`dump_header` function. |
- |
- :param value: a string with a dict header. |
- :return: :class:`dict` |
- """ |
- result = {} |
- for item in _parse_list_header(value): |
- if '=' not in item: |
- result[item] = None |
- continue |
- name, value = item.split('=', 1) |
- if value[:1] == value[-1:] == '"': |
- value = unquote_header_value(value[1:-1]) |
- result[name] = value |
- return result |
- |
- |
-# From mitsuhiko/werkzeug (used with permission). |
-def unquote_header_value(value, is_filename=False): |
- r"""Unquotes a header value. (Reversal of :func:`quote_header_value`). |
- This does not use the real unquoting but what browsers are actually |
- using for quoting. |
- |
- :param value: the header value to unquote. |
- """ |
- if value and value[0] == value[-1] == '"': |
- # this is not the real unquoting, but fixing this so that the |
- # RFC is met will result in bugs with internet explorer and |
- # probably some other browsers as well. IE for example is |
- # uploading files with "C:\foo\bar.txt" as filename |
- value = value[1:-1] |
- |
- # if this is a filename and the starting characters look like |
- # a UNC path, then just return the value without quotes. Using the |
- # replace sequence below on a UNC path has the effect of turning |
- # the leading double slash into a single slash and then |
- # _fix_ie_filename() doesn't work correctly. See #458. |
- if not is_filename or value[:2] != '\\\\': |
- return value.replace('\\\\', '\\').replace('\\"', '"') |
- return value |
- |
- |
-def dict_from_cookiejar(cj): |
- """Returns a key/value dictionary from a CookieJar. |
- |
- :param cj: CookieJar object to extract cookies from. |
- """ |
- |
- cookie_dict = {} |
- |
- for cookie in cj: |
- cookie_dict[cookie.name] = cookie.value |
- |
- return cookie_dict |
- |
- |
-def add_dict_to_cookiejar(cj, cookie_dict): |
- """Returns a CookieJar from a key/value dictionary. |
- |
- :param cj: CookieJar to insert cookies into. |
- :param cookie_dict: Dict of key/values to insert into CookieJar. |
- """ |
- |
- cj2 = cookiejar_from_dict(cookie_dict) |
- cj.update(cj2) |
- return cj |
- |
- |
-def get_encodings_from_content(content): |
- """Returns encodings from given content string. |
- |
- :param content: bytestring to extract encodings from. |
- """ |
- |
- charset_re = re.compile(r'<meta.*?charset=["\']*(.+?)["\'>]', flags=re.I) |
- pragma_re = re.compile(r'<meta.*?content=["\']*;?charset=(.+?)["\'>]', flags=re.I) |
- xml_re = re.compile(r'^<\?xml.*?encoding=["\']*(.+?)["\'>]') |
- |
- return (charset_re.findall(content) + |
- pragma_re.findall(content) + |
- xml_re.findall(content)) |
- |
- |
-def get_encoding_from_headers(headers): |
- """Returns encodings from given HTTP Header Dict. |
- |
- :param headers: dictionary to extract encoding from. |
- """ |
- |
- content_type = headers.get('content-type') |
- |
- if not content_type: |
- return None |
- |
- content_type, params = cgi.parse_header(content_type) |
- |
- if 'charset' in params: |
- return params['charset'].strip("'\"") |
- |
- if 'text' in content_type: |
- return 'ISO-8859-1' |
- |
- |
-def stream_decode_response_unicode(iterator, r): |
- """Stream decodes a iterator.""" |
- |
- if r.encoding is None: |
- for item in iterator: |
- yield item |
- return |
- |
- decoder = codecs.getincrementaldecoder(r.encoding)(errors='replace') |
- for chunk in iterator: |
- rv = decoder.decode(chunk) |
- if rv: |
- yield rv |
- rv = decoder.decode(b'', final=True) |
- if rv: |
- yield rv |
- |
- |
-def iter_slices(string, slice_length): |
- """Iterate over slices of a string.""" |
- pos = 0 |
- while pos < len(string): |
- yield string[pos:pos + slice_length] |
- pos += slice_length |
- |
- |
-def get_unicode_from_response(r): |
- """Returns the requested content back in unicode. |
- |
- :param r: Response object to get unicode content from. |
- |
- Tried: |
- |
- 1. charset from content-type |
- |
- 2. every encodings from ``<meta ... charset=XXX>`` |
- |
- 3. fall back and replace all unicode characters |
- |
- """ |
- |
- tried_encodings = [] |
- |
- # Try charset from content-type |
- encoding = get_encoding_from_headers(r.headers) |
- |
- if encoding: |
- try: |
- return str(r.content, encoding) |
- except UnicodeError: |
- tried_encodings.append(encoding) |
- |
- # Fall back: |
- try: |
- return str(r.content, encoding, errors='replace') |
- except TypeError: |
- return r.content |
- |
- |
-# The unreserved URI characters (RFC 3986) |
-UNRESERVED_SET = frozenset( |
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" |
- + "0123456789-._~") |
- |
- |
-def unquote_unreserved(uri): |
- """Un-escape any percent-escape sequences in a URI that are unreserved |
- characters. This leaves all reserved, illegal and non-ASCII bytes encoded. |
- """ |
- parts = uri.split('%') |
- for i in range(1, len(parts)): |
- h = parts[i][0:2] |
- if len(h) == 2 and h.isalnum(): |
- try: |
- c = chr(int(h, 16)) |
- except ValueError: |
- raise InvalidURL("Invalid percent-escape sequence: '%s'" % h) |
- |
- if c in UNRESERVED_SET: |
- parts[i] = c + parts[i][2:] |
- else: |
- parts[i] = '%' + parts[i] |
- else: |
- parts[i] = '%' + parts[i] |
- return ''.join(parts) |
- |
- |
-def requote_uri(uri): |
- """Re-quote the given URI. |
- |
- This function passes the given URI through an unquote/quote cycle to |
- ensure that it is fully and consistently quoted. |
- """ |
- # Unquote only the unreserved characters |
- # Then quote only illegal characters (do not quote reserved, unreserved, |
- # or '%') |
- return quote(unquote_unreserved(uri), safe="!#$%&'()*+,/:;=?@[]~") |
- |
- |
-def get_environ_proxies(url): |
- """Return a dict of environment proxies.""" |
- |
- get_proxy = lambda k: os.environ.get(k) or os.environ.get(k.upper()) |
- |
- # First check whether no_proxy is defined. If it is, check that the URL |
- # we're getting isn't in the no_proxy list. |
- no_proxy = get_proxy('no_proxy') |
- netloc = urlparse(url).netloc |
- |
- if no_proxy: |
- # We need to check whether we match here. We need to see if we match |
- # the end of the netloc, both with and without the port. |
- no_proxy = no_proxy.replace(' ', '').split(',') |
- |
- for host in no_proxy: |
- if netloc.endswith(host) or netloc.split(':')[0].endswith(host): |
- # The URL does match something in no_proxy, so we don't want |
- # to apply the proxies on this URL. |
- return {} |
- |
- # If the system proxy settings indicate that this URL should be bypassed, |
- # don't proxy. |
- if proxy_bypass(netloc): |
- return {} |
- |
- # If we get here, we either didn't have no_proxy set or we're not going |
- # anywhere that no_proxy applies to, and the system settings don't require |
- # bypassing the proxy for the current URL. |
- return getproxies() |
- |
- |
-def default_user_agent(): |
- """Return a string representing the default user agent.""" |
- _implementation = platform.python_implementation() |
- |
- if _implementation == 'CPython': |
- _implementation_version = platform.python_version() |
- elif _implementation == 'PyPy': |
- _implementation_version = '%s.%s.%s' % (sys.pypy_version_info.major, |
- sys.pypy_version_info.minor, |
- sys.pypy_version_info.micro) |
- if sys.pypy_version_info.releaselevel != 'final': |
- _implementation_version = ''.join([_implementation_version, sys.pypy_version_info.releaselevel]) |
- elif _implementation == 'Jython': |
- _implementation_version = platform.python_version() # Complete Guess |
- elif _implementation == 'IronPython': |
- _implementation_version = platform.python_version() # Complete Guess |
- else: |
- _implementation_version = 'Unknown' |
- |
- try: |
- p_system = platform.system() |
- p_release = platform.release() |
- except IOError: |
- p_system = 'Unknown' |
- p_release = 'Unknown' |
- |
- return " ".join(['python-requests/%s' % __version__, |
- '%s/%s' % (_implementation, _implementation_version), |
- '%s/%s' % (p_system, p_release)]) |
- |
- |
-def default_headers(): |
- return CaseInsensitiveDict({ |
- 'User-Agent': default_user_agent(), |
- 'Accept-Encoding': ', '.join(('gzip', 'deflate', 'compress')), |
- 'Accept': '*/*' |
- }) |
- |
- |
-def parse_header_links(value): |
- """Return a dict of parsed link headers proxies. |
- |
- i.e. Link: <http:/.../front.jpeg>; rel=front; type="image/jpeg",<http://.../back.jpeg>; rel=back;type="image/jpeg" |
- |
- """ |
- |
- links = [] |
- |
- replace_chars = " '\"" |
- |
- for val in value.split(","): |
- try: |
- url, params = val.split(";", 1) |
- except ValueError: |
- url, params = val, '' |
- |
- link = {} |
- |
- link["url"] = url.strip("<> '\"") |
- |
- for param in params.split(";"): |
- try: |
- key, value = param.split("=") |
- except ValueError: |
- break |
- |
- link[key.strip(replace_chars)] = value.strip(replace_chars) |
- |
- links.append(link) |
- |
- return links |
- |
- |
-# Null bytes; no need to recreate these on each call to guess_json_utf |
-_null = '\x00'.encode('ascii') # encoding to ASCII for Python 3 |
-_null2 = _null * 2 |
-_null3 = _null * 3 |
- |
- |
-def guess_json_utf(data): |
- # JSON always starts with two ASCII characters, so detection is as |
- # easy as counting the nulls and from their location and count |
- # determine the encoding. Also detect a BOM, if present. |
- sample = data[:4] |
- if sample in (codecs.BOM_UTF32_LE, codecs.BOM32_BE): |
- return 'utf-32' # BOM included |
- if sample[:3] == codecs.BOM_UTF8: |
- return 'utf-8-sig' # BOM included, MS style (discouraged) |
- if sample[:2] in (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE): |
- return 'utf-16' # BOM included |
- nullcount = sample.count(_null) |
- if nullcount == 0: |
- return 'utf-8' |
- if nullcount == 2: |
- if sample[::2] == _null2: # 1st and 3rd are null |
- return 'utf-16-be' |
- if sample[1::2] == _null2: # 2nd and 4th are null |
- return 'utf-16-le' |
- # Did not detect 2 valid UTF-16 ascii-range characters |
- if nullcount == 3: |
- if sample[:3] == _null3: |
- return 'utf-32-be' |
- if sample[1:] == _null3: |
- return 'utf-32-le' |
- # Did not detect a valid UTF-32 ascii-range character |
- return None |
- |
- |
-def except_on_missing_scheme(url): |
- """Given a URL, raise a MissingSchema exception if the scheme is missing. |
- """ |
- scheme, netloc, path, params, query, fragment = urlparse(url) |
- |
- if not scheme: |
- raise MissingSchema('Proxy URLs must have explicit schemes.') |
- |
- |
-def get_auth_from_url(url): |
- """Given a url with authentication components, extract them into a tuple of |
- username,password.""" |
- if url: |
- parsed = urlparse(url) |
- return (parsed.username, parsed.password) |
- else: |
- return ('', '') |
- |
- |
-def to_native_string(string, encoding='ascii'): |
- """ |
- Given a string object, regardless of type, returns a representation of that |
- string in the native string type, encoding and decoding where necessary. |
- This assumes ASCII unless told otherwise. |
- """ |
- out = None |
- |
- if isinstance(string, builtin_str): |
- out = string |
- else: |
- if is_py2: |
- out = string.encode(encoding) |
- else: |
- out = string.decode(encoding) |
- |
- return out |