Index: swarm_client/third_party/requests/sessions.py |
=================================================================== |
--- swarm_client/third_party/requests/sessions.py (revision 235167) |
+++ swarm_client/third_party/requests/sessions.py (working copy) |
@@ -1,527 +0,0 @@ |
-# -*- coding: utf-8 -*- |
- |
-""" |
-requests.session |
-~~~~~~~~~~~~~~~~ |
- |
-This module provides a Session object to manage and persist settings across |
-requests (cookies, auth, proxies). |
- |
-""" |
-import os |
-from collections import Mapping |
-from datetime import datetime |
- |
-from .compat import cookielib, OrderedDict, urljoin, urlparse |
-from .cookies import cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar |
-from .models import Request, PreparedRequest |
-from .hooks import default_hooks, dispatch_hook |
-from .utils import to_key_val_list, default_headers |
-from .exceptions import TooManyRedirects, InvalidSchema |
-from .structures import CaseInsensitiveDict |
- |
-from .adapters import HTTPAdapter |
- |
-from .utils import requote_uri, get_environ_proxies, get_netrc_auth |
- |
-from .status_codes import codes |
-REDIRECT_STATI = ( |
- codes.moved, # 301 |
- codes.found, # 302 |
- codes.other, # 303 |
- codes.temporary_moved, # 307 |
-) |
-DEFAULT_REDIRECT_LIMIT = 30 |
- |
- |
-def merge_setting(request_setting, session_setting, dict_class=OrderedDict): |
- """ |
- Determines appropriate setting for a given request, taking into account the |
- explicit setting on that request, and the setting in the session. If a |
- setting is a dictionary, they will be merged together using `dict_class` |
- """ |
- |
- if session_setting is None: |
- return request_setting |
- |
- if request_setting is None: |
- return session_setting |
- |
- # Bypass if not a dictionary (e.g. verify) |
- if not ( |
- isinstance(session_setting, Mapping) and |
- isinstance(request_setting, Mapping) |
- ): |
- return request_setting |
- |
- merged_setting = dict_class(to_key_val_list(session_setting)) |
- merged_setting.update(to_key_val_list(request_setting)) |
- |
- # Remove keys that are set to None. |
- for (k, v) in request_setting.items(): |
- if v is None: |
- del merged_setting[k] |
- |
- return merged_setting |
- |
- |
-class SessionRedirectMixin(object): |
- def resolve_redirects(self, resp, req, stream=False, timeout=None, |
- verify=True, cert=None, proxies=None): |
- """Receives a Response. Returns a generator of Responses.""" |
- |
- i = 0 |
- |
- # ((resp.status_code is codes.see_other)) |
- while (('location' in resp.headers and resp.status_code in REDIRECT_STATI)): |
- prepared_request = req.copy() |
- |
- resp.content # Consume socket so it can be released |
- |
- if i >= self.max_redirects: |
- raise TooManyRedirects('Exceeded %s redirects.' % self.max_redirects) |
- |
- # Release the connection back into the pool. |
- resp.close() |
- |
- url = resp.headers['location'] |
- method = req.method |
- |
- # Handle redirection without scheme (see: RFC 1808 Section 4) |
- if url.startswith('//'): |
- parsed_rurl = urlparse(resp.url) |
- url = '%s:%s' % (parsed_rurl.scheme, url) |
- |
- # The scheme should be lower case... |
- if '://' in url: |
- scheme, uri = url.split('://', 1) |
- url = '%s://%s' % (scheme.lower(), uri) |
- |
- # Facilitate non-RFC2616-compliant 'location' headers |
- # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource') |
- # Compliant with RFC3986, we percent encode the url. |
- if not urlparse(url).netloc: |
- url = urljoin(resp.url, requote_uri(url)) |
- else: |
- url = requote_uri(url) |
- |
- prepared_request.url = url |
- |
- # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4 |
- if (resp.status_code == codes.see_other and |
- method != 'HEAD'): |
- method = 'GET' |
- |
- # Do what the browsers do, despite standards... |
- if (resp.status_code in (codes.moved, codes.found) and |
- method not in ('GET', 'HEAD')): |
- method = 'GET' |
- |
- prepared_request.method = method |
- |
- # https://github.com/kennethreitz/requests/issues/1084 |
- if resp.status_code not in (codes.temporary, codes.resume): |
- if 'Content-Length' in prepared_request.headers: |
- del prepared_request.headers['Content-Length'] |
- |
- prepared_request.body = None |
- |
- headers = prepared_request.headers |
- try: |
- del headers['Cookie'] |
- except KeyError: |
- pass |
- |
- prepared_request.prepare_cookies(self.cookies) |
- |
- resp = self.send( |
- prepared_request, |
- stream=stream, |
- timeout=timeout, |
- verify=verify, |
- cert=cert, |
- proxies=proxies, |
- allow_redirects=False, |
- ) |
- |
- extract_cookies_to_jar(self.cookies, prepared_request, resp.raw) |
- |
- i += 1 |
- yield resp |
- |
- |
-class Session(SessionRedirectMixin): |
- """A Requests session. |
- |
- Provides cookie persistence, connection-pooling, and configuration. |
- |
- Basic Usage:: |
- |
- >>> import requests |
- >>> s = requests.Session() |
- >>> s.get('http://httpbin.org/get') |
- 200 |
- """ |
- |
- __attrs__ = [ |
- 'headers', 'cookies', 'auth', 'timeout', 'proxies', 'hooks', |
- 'params', 'verify', 'cert', 'prefetch', 'adapters', 'stream', |
- 'trust_env', 'max_redirects'] |
- |
- def __init__(self): |
- |
- #: A case-insensitive dictionary of headers to be sent on each |
- #: :class:`Request <Request>` sent from this |
- #: :class:`Session <Session>`. |
- self.headers = default_headers() |
- |
- #: Default Authentication tuple or object to attach to |
- #: :class:`Request <Request>`. |
- self.auth = None |
- |
- #: Dictionary mapping protocol to the URL of the proxy (e.g. |
- #: {'http': 'foo.bar:3128'}) to be used on each |
- #: :class:`Request <Request>`. |
- self.proxies = {} |
- |
- #: Event-handling hooks. |
- self.hooks = default_hooks() |
- |
- #: Dictionary of querystring data to attach to each |
- #: :class:`Request <Request>`. The dictionary values may be lists for |
- #: representing multivalued query parameters. |
- self.params = {} |
- |
- #: Stream response content default. |
- self.stream = False |
- |
- #: SSL Verification default. |
- self.verify = True |
- |
- #: SSL certificate default. |
- self.cert = None |
- |
- #: Maximum number of redirects allowed. If the request exceeds this |
- #: limit, a :class:`TooManyRedirects` exception is raised. |
- self.max_redirects = DEFAULT_REDIRECT_LIMIT |
- |
- #: Should we trust the environment? |
- self.trust_env = True |
- |
- #: A CookieJar containing all currently outstanding cookies set on this |
- #: session. By default it is a |
- #: :class:`RequestsCookieJar <requests.cookies.RequestsCookieJar>`, but |
- #: may be any other ``cookielib.CookieJar`` compatible object. |
- self.cookies = cookiejar_from_dict({}) |
- |
- # Default connection adapters. |
- self.adapters = OrderedDict() |
- self.mount('https://', HTTPAdapter()) |
- self.mount('http://', HTTPAdapter()) |
- |
- def __enter__(self): |
- return self |
- |
- def __exit__(self, *args): |
- self.close() |
- |
- def prepare_request(self, request): |
- """Constructs a :class:`PreparedRequest <PreparedRequest>` for |
- transmission and returns it. The :class:`PreparedRequest` has settings |
- merged from the :class:`Request <Request>` instance and those of the |
- :class:`Session`. |
- |
- :param request: :class:`Request` instance to prepare with this |
- session's settings. |
- """ |
- cookies = request.cookies or {} |
- |
- # Bootstrap CookieJar. |
- if not isinstance(cookies, cookielib.CookieJar): |
- cookies = cookiejar_from_dict(cookies) |
- |
- # Merge with session cookies |
- merged_cookies = RequestsCookieJar() |
- merged_cookies.update(self.cookies) |
- merged_cookies.update(cookies) |
- |
- |
- # Set environment's basic authentication if not explicitly set. |
- auth = request.auth |
- if self.trust_env and not auth and not self.auth: |
- auth = get_netrc_auth(request.url) |
- |
- p = PreparedRequest() |
- p.prepare( |
- method=request.method.upper(), |
- url=request.url, |
- files=request.files, |
- data=request.data, |
- headers=merge_setting(request.headers, self.headers, dict_class=CaseInsensitiveDict), |
- params=merge_setting(request.params, self.params), |
- auth=merge_setting(auth, self.auth), |
- cookies=merged_cookies, |
- hooks=merge_setting(request.hooks, self.hooks), |
- ) |
- return p |
- |
- def request(self, method, url, |
- params=None, |
- data=None, |
- headers=None, |
- cookies=None, |
- files=None, |
- auth=None, |
- timeout=None, |
- allow_redirects=True, |
- proxies=None, |
- hooks=None, |
- stream=None, |
- verify=None, |
- cert=None): |
- """Constructs a :class:`Request <Request>`, prepares it and sends it. |
- Returns :class:`Response <Response>` object. |
- |
- :param method: method for the new :class:`Request` object. |
- :param url: URL for the new :class:`Request` object. |
- :param params: (optional) Dictionary or bytes to be sent in the query |
- string for the :class:`Request`. |
- :param data: (optional) Dictionary or bytes to send in the body of the |
- :class:`Request`. |
- :param headers: (optional) Dictionary of HTTP Headers to send with the |
- :class:`Request`. |
- :param cookies: (optional) Dict or CookieJar object to send with the |
- :class:`Request`. |
- :param files: (optional) Dictionary of 'filename': file-like-objects |
- for multipart encoding upload. |
- :param auth: (optional) Auth tuple or callable to enable |
- Basic/Digest/Custom HTTP Auth. |
- :param timeout: (optional) Float describing the timeout of the |
- request. |
- :param allow_redirects: (optional) Boolean. Set to True by default. |
- :param proxies: (optional) Dictionary mapping protocol to the URL of |
- the proxy. |
- :param stream: (optional) whether to immediately download the response |
- content. Defaults to ``False``. |
- :param verify: (optional) if ``True``, the SSL cert will be verified. |
- A CA_BUNDLE path can also be provided. |
- :param cert: (optional) if String, path to ssl client cert file (.pem). |
- If Tuple, ('cert', 'key') pair. |
- """ |
- # Create the Request. |
- req = Request( |
- method = method.upper(), |
- url = url, |
- headers = headers, |
- files = files, |
- data = data or {}, |
- params = params or {}, |
- auth = auth, |
- cookies = cookies, |
- hooks = hooks, |
- ) |
- prep = self.prepare_request(req) |
- |
- proxies = proxies or {} |
- |
- # Gather clues from the surrounding environment. |
- if self.trust_env: |
- # Set environment's proxies. |
- env_proxies = get_environ_proxies(url) or {} |
- for (k, v) in env_proxies.items(): |
- proxies.setdefault(k, v) |
- |
- # Look for configuration. |
- if not verify and verify is not False: |
- verify = os.environ.get('REQUESTS_CA_BUNDLE') |
- |
- # Curl compatibility. |
- if not verify and verify is not False: |
- verify = os.environ.get('CURL_CA_BUNDLE') |
- |
- # Merge all the kwargs. |
- proxies = merge_setting(proxies, self.proxies) |
- stream = merge_setting(stream, self.stream) |
- verify = merge_setting(verify, self.verify) |
- cert = merge_setting(cert, self.cert) |
- |
- # Send the request. |
- send_kwargs = { |
- 'stream': stream, |
- 'timeout': timeout, |
- 'verify': verify, |
- 'cert': cert, |
- 'proxies': proxies, |
- 'allow_redirects': allow_redirects, |
- } |
- resp = self.send(prep, **send_kwargs) |
- |
- return resp |
- |
- def get(self, url, **kwargs): |
- """Sends a GET request. Returns :class:`Response` object. |
- |
- :param url: URL for the new :class:`Request` object. |
- :param \*\*kwargs: Optional arguments that ``request`` takes. |
- """ |
- |
- kwargs.setdefault('allow_redirects', True) |
- return self.request('GET', url, **kwargs) |
- |
- def options(self, url, **kwargs): |
- """Sends a OPTIONS request. Returns :class:`Response` object. |
- |
- :param url: URL for the new :class:`Request` object. |
- :param \*\*kwargs: Optional arguments that ``request`` takes. |
- """ |
- |
- kwargs.setdefault('allow_redirects', True) |
- return self.request('OPTIONS', url, **kwargs) |
- |
- def head(self, url, **kwargs): |
- """Sends a HEAD request. Returns :class:`Response` object. |
- |
- :param url: URL for the new :class:`Request` object. |
- :param \*\*kwargs: Optional arguments that ``request`` takes. |
- """ |
- |
- kwargs.setdefault('allow_redirects', False) |
- return self.request('HEAD', url, **kwargs) |
- |
- def post(self, url, data=None, **kwargs): |
- """Sends a POST request. Returns :class:`Response` object. |
- |
- :param url: URL for the new :class:`Request` object. |
- :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`. |
- :param \*\*kwargs: Optional arguments that ``request`` takes. |
- """ |
- |
- return self.request('POST', url, data=data, **kwargs) |
- |
- def put(self, url, data=None, **kwargs): |
- """Sends a PUT request. Returns :class:`Response` object. |
- |
- :param url: URL for the new :class:`Request` object. |
- :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`. |
- :param \*\*kwargs: Optional arguments that ``request`` takes. |
- """ |
- |
- return self.request('PUT', url, data=data, **kwargs) |
- |
- def patch(self, url, data=None, **kwargs): |
- """Sends a PATCH request. Returns :class:`Response` object. |
- |
- :param url: URL for the new :class:`Request` object. |
- :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`. |
- :param \*\*kwargs: Optional arguments that ``request`` takes. |
- """ |
- |
- return self.request('PATCH', url, data=data, **kwargs) |
- |
- def delete(self, url, **kwargs): |
- """Sends a DELETE request. Returns :class:`Response` object. |
- |
- :param url: URL for the new :class:`Request` object. |
- :param \*\*kwargs: Optional arguments that ``request`` takes. |
- """ |
- |
- return self.request('DELETE', url, **kwargs) |
- |
- def send(self, request, **kwargs): |
- """Send a given PreparedRequest.""" |
- # Set defaults that the hooks can utilize to ensure they always have |
- # the correct parameters to reproduce the previous request. |
- kwargs.setdefault('stream', self.stream) |
- kwargs.setdefault('verify', self.verify) |
- kwargs.setdefault('cert', self.cert) |
- kwargs.setdefault('proxies', self.proxies) |
- |
- # It's possible that users might accidentally send a Request object. |
- # Guard against that specific failure case. |
- if not isinstance(request, PreparedRequest): |
- raise ValueError('You can only send PreparedRequests.') |
- |
- # Set up variables needed for resolve_redirects and dispatching of |
- # hooks |
- allow_redirects = kwargs.pop('allow_redirects', True) |
- stream = kwargs.get('stream') |
- timeout = kwargs.get('timeout') |
- verify = kwargs.get('verify') |
- cert = kwargs.get('cert') |
- proxies = kwargs.get('proxies') |
- hooks = request.hooks |
- |
- # Get the appropriate adapter to use |
- adapter = self.get_adapter(url=request.url) |
- |
- # Start time (approximately) of the request |
- start = datetime.utcnow() |
- # Send the request |
- r = adapter.send(request, **kwargs) |
- # Total elapsed time of the request (approximately) |
- r.elapsed = datetime.utcnow() - start |
- |
- # Response manipulation hooks |
- r = dispatch_hook('response', hooks, r, **kwargs) |
- |
- # Persist cookies |
- if r.history: |
- # If the hooks create history then we want those cookies too |
- for resp in r.history: |
- extract_cookies_to_jar(self.cookies, resp.request, resp.raw) |
- extract_cookies_to_jar(self.cookies, request, r.raw) |
- |
- # Redirect resolving generator. |
- gen = self.resolve_redirects(r, request, stream=stream, |
- timeout=timeout, verify=verify, cert=cert, |
- proxies=proxies) |
- |
- # Resolve redirects if allowed. |
- history = [resp for resp in gen] if allow_redirects else [] |
- |
- # Shuffle things around if there's history. |
- if history: |
- # Insert the first (original) request at the start |
- history.insert(0, r) |
- # Get the last request made |
- r = history.pop() |
- r.history = tuple(history) |
- |
- return r |
- |
- def get_adapter(self, url): |
- """Returns the appropriate connnection adapter for the given URL.""" |
- for (prefix, adapter) in self.adapters.items(): |
- |
- if url.lower().startswith(prefix): |
- return adapter |
- |
- # Nothing matches :-/ |
- raise InvalidSchema("No connection adapters were found for '%s'" % url) |
- |
- def close(self): |
- """Closes all adapters and as such the session""" |
- for v in self.adapters.values(): |
- v.close() |
- |
- def mount(self, prefix, adapter): |
- """Registers a connection adapter to a prefix. |
- |
- Adapters are sorted in descending order by key length.""" |
- self.adapters[prefix] = adapter |
- keys_to_move = [k for k in self.adapters if len(k) < len(prefix)] |
- for key in keys_to_move: |
- self.adapters[key] = self.adapters.pop(key) |
- |
- def __getstate__(self): |
- return dict((attr, getattr(self, attr, None)) for attr in self.__attrs__) |
- |
- def __setstate__(self, state): |
- for attr, value in state.items(): |
- setattr(self, attr, value) |
- |
- |
-def session(): |
- """Returns a :class:`Session` for context-management.""" |
- |
- return Session() |