summaryrefslogtreecommitdiff
path: root/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/requests/sessions.py
diff options
context:
space:
mode:
Diffstat (limited to 'venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/requests/sessions.py')
-rw-r--r--venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/requests/sessions.py737
1 files changed, 737 insertions, 0 deletions
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/requests/sessions.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/requests/sessions.py
new file mode 100644
index 0000000..d8eafa8
--- /dev/null
+++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/requests/sessions.py
@@ -0,0 +1,737 @@
1# -*- coding: utf-8 -*-
2
3"""
4requests.session
5~~~~~~~~~~~~~~~~
6
7This module provides a Session object to manage and persist settings across
8requests (cookies, auth, proxies).
9"""
10import os
11import platform
12import time
13from collections import Mapping
14from datetime import timedelta
15
16from .auth import _basic_auth_str
17from .compat import cookielib, is_py3, OrderedDict, urljoin, urlparse
18from .cookies import (
19 cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies)
20from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT
21from .hooks import default_hooks, dispatch_hook
22from ._internal_utils import to_native_string
23from .utils import to_key_val_list, default_headers
24from .exceptions import (
25 TooManyRedirects, InvalidSchema, ChunkedEncodingError, ContentDecodingError)
26
27from .structures import CaseInsensitiveDict
28from .adapters import HTTPAdapter
29
30from .utils import (
31 requote_uri, get_environ_proxies, get_netrc_auth, should_bypass_proxies,
32 get_auth_from_url, rewind_body
33)
34
35from .status_codes import codes
36
37# formerly defined here, reexposed here for backward compatibility
38from .models import REDIRECT_STATI
39
40# Preferred clock, based on which one is more accurate on a given system.
41if platform.system() == 'Windows':
42 try: # Python 3.3+
43 preferred_clock = time.perf_counter
44 except AttributeError: # Earlier than Python 3.
45 preferred_clock = time.clock
46else:
47 preferred_clock = time.time
48
49
50def merge_setting(request_setting, session_setting, dict_class=OrderedDict):
51 """Determines appropriate setting for a given request, taking into account
52 the explicit setting on that request, and the setting in the session. If a
53 setting is a dictionary, they will be merged together using `dict_class`
54 """
55
56 if session_setting is None:
57 return request_setting
58
59 if request_setting is None:
60 return session_setting
61
62 # Bypass if not a dictionary (e.g. verify)
63 if not (
64 isinstance(session_setting, Mapping) and
65 isinstance(request_setting, Mapping)
66 ):
67 return request_setting
68
69 merged_setting = dict_class(to_key_val_list(session_setting))
70 merged_setting.update(to_key_val_list(request_setting))
71
72 # Remove keys that are set to None. Extract keys first to avoid altering
73 # the dictionary during iteration.
74 none_keys = [k for (k, v) in merged_setting.items() if v is None]
75 for key in none_keys:
76 del merged_setting[key]
77
78 return merged_setting
79
80
81def merge_hooks(request_hooks, session_hooks, dict_class=OrderedDict):
82 """Properly merges both requests and session hooks.
83
84 This is necessary because when request_hooks == {'response': []}, the
85 merge breaks Session hooks entirely.
86 """
87 if session_hooks is None or session_hooks.get('response') == []:
88 return request_hooks
89
90 if request_hooks is None or request_hooks.get('response') == []:
91 return session_hooks
92
93 return merge_setting(request_hooks, session_hooks, dict_class)
94
95
96class SessionRedirectMixin(object):
97
98 def get_redirect_target(self, resp):
99 """Receives a Response. Returns a redirect URI or ``None``"""
100 # Due to the nature of how requests processes redirects this method will
101 # be called at least once upon the original response and at least twice
102 # on each subsequent redirect response (if any).
103 # If a custom mixin is used to handle this logic, it may be advantageous
104 # to cache the redirect location onto the response object as a private
105 # attribute.
106 if resp.is_redirect:
107 location = resp.headers['location']
108 # Currently the underlying http module on py3 decode headers
109 # in latin1, but empirical evidence suggests that latin1 is very
110 # rarely used with non-ASCII characters in HTTP headers.
111 # It is more likely to get UTF8 header rather than latin1.
112 # This causes incorrect handling of UTF8 encoded location headers.
113 # To solve this, we re-encode the location in latin1.
114 if is_py3:
115 location = location.encode('latin1')
116 return to_native_string(location, 'utf8')
117 return None
118
119 def resolve_redirects(self, resp, req, stream=False, timeout=None,
120 verify=True, cert=None, proxies=None, yield_requests=False, **adapter_kwargs):
121 """Receives a Response. Returns a generator of Responses or Requests."""
122
123 hist = [] # keep track of history
124
125 url = self.get_redirect_target(resp)
126 while url:
127 prepared_request = req.copy()
128
129 # Update history and keep track of redirects.
130 # resp.history must ignore the original request in this loop
131 hist.append(resp)
132 resp.history = hist[1:]
133
134 try:
135 resp.content # Consume socket so it can be released
136 except (ChunkedEncodingError, ContentDecodingError, RuntimeError):
137 resp.raw.read(decode_content=False)
138
139 if len(resp.history) >= self.max_redirects:
140 raise TooManyRedirects('Exceeded %s redirects.' % self.max_redirects, response=resp)
141
142 # Release the connection back into the pool.
143 resp.close()
144
145 # Handle redirection without scheme (see: RFC 1808 Section 4)
146 if url.startswith('//'):
147 parsed_rurl = urlparse(resp.url)
148 url = '%s:%s' % (to_native_string(parsed_rurl.scheme), url)
149
150 # The scheme should be lower case...
151 parsed = urlparse(url)
152 url = parsed.geturl()
153
154 # Facilitate relative 'location' headers, as allowed by RFC 7231.
155 # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource')
156 # Compliant with RFC3986, we percent encode the url.
157 if not parsed.netloc:
158 url = urljoin(resp.url, requote_uri(url))
159 else:
160 url = requote_uri(url)
161
162 prepared_request.url = to_native_string(url)
163
164 self.rebuild_method(prepared_request, resp)
165
166 # https://github.com/requests/requests/issues/1084
167 if resp.status_code not in (codes.temporary_redirect, codes.permanent_redirect):
168 # https://github.com/requests/requests/issues/3490
169 purged_headers = ('Content-Length', 'Content-Type', 'Transfer-Encoding')
170 for header in purged_headers:
171 prepared_request.headers.pop(header, None)
172 prepared_request.body = None
173
174 headers = prepared_request.headers
175 try:
176 del headers['Cookie']
177 except KeyError:
178 pass
179
180 # Extract any cookies sent on the response to the cookiejar
181 # in the new request. Because we've mutated our copied prepared
182 # request, use the old one that we haven't yet touched.
183 extract_cookies_to_jar(prepared_request._cookies, req, resp.raw)
184 merge_cookies(prepared_request._cookies, self.cookies)
185 prepared_request.prepare_cookies(prepared_request._cookies)
186
187 # Rebuild auth and proxy information.
188 proxies = self.rebuild_proxies(prepared_request, proxies)
189 self.rebuild_auth(prepared_request, resp)
190
191 # A failed tell() sets `_body_position` to `object()`. This non-None
192 # value ensures `rewindable` will be True, allowing us to raise an
193 # UnrewindableBodyError, instead of hanging the connection.
194 rewindable = (
195 prepared_request._body_position is not None and
196 ('Content-Length' in headers or 'Transfer-Encoding' in headers)
197 )
198
199 # Attempt to rewind consumed file-like object.
200 if rewindable:
201 rewind_body(prepared_request)
202
203 # Override the original request.
204 req = prepared_request
205
206 if yield_requests:
207 yield req
208 else:
209
210 resp = self.send(
211 req,
212 stream=stream,
213 timeout=timeout,
214 verify=verify,
215 cert=cert,
216 proxies=proxies,
217 allow_redirects=False,
218 **adapter_kwargs
219 )
220
221 extract_cookies_to_jar(self.cookies, prepared_request, resp.raw)
222
223 # extract redirect url, if any, for the next loop
224 url = self.get_redirect_target(resp)
225 yield resp
226
227 def rebuild_auth(self, prepared_request, response):
228 """When being redirected we may want to strip authentication from the
229 request to avoid leaking credentials. This method intelligently removes
230 and reapplies authentication where possible to avoid credential loss.
231 """
232 headers = prepared_request.headers
233 url = prepared_request.url
234
235 if 'Authorization' in headers:
236 # If we get redirected to a new host, we should strip out any
237 # authentication headers.
238 original_parsed = urlparse(response.request.url)
239 redirect_parsed = urlparse(url)
240
241 if (original_parsed.hostname != redirect_parsed.hostname):
242 del headers['Authorization']
243
244 # .netrc might have more auth for us on our new host.
245 new_auth = get_netrc_auth(url) if self.trust_env else None
246 if new_auth is not None:
247 prepared_request.prepare_auth(new_auth)
248
249 return
250
251 def rebuild_proxies(self, prepared_request, proxies):
252 """This method re-evaluates the proxy configuration by considering the
253 environment variables. If we are redirected to a URL covered by
254 NO_PROXY, we strip the proxy configuration. Otherwise, we set missing
255 proxy keys for this URL (in case they were stripped by a previous
256 redirect).
257
258 This method also replaces the Proxy-Authorization header where
259 necessary.
260
261 :rtype: dict
262 """
263 proxies = proxies if proxies is not None else {}
264 headers = prepared_request.headers
265 url = prepared_request.url
266 scheme = urlparse(url).scheme
267 new_proxies = proxies.copy()
268 no_proxy = proxies.get('no_proxy')
269
270 bypass_proxy = should_bypass_proxies(url, no_proxy=no_proxy)
271 if self.trust_env and not bypass_proxy:
272 environ_proxies = get_environ_proxies(url, no_proxy=no_proxy)
273
274 proxy = environ_proxies.get(scheme, environ_proxies.get('all'))
275
276 if proxy:
277 new_proxies.setdefault(scheme, proxy)
278
279 if 'Proxy-Authorization' in headers:
280 del headers['Proxy-Authorization']
281
282 try:
283 username, password = get_auth_from_url(new_proxies[scheme])
284 except KeyError:
285 username, password = None, None
286
287 if username and password:
288 headers['Proxy-Authorization'] = _basic_auth_str(username, password)
289
290 return new_proxies
291
292 def rebuild_method(self, prepared_request, response):
293 """When being redirected we may want to change the method of the request
294 based on certain specs or browser behavior.
295 """
296 method = prepared_request.method
297
298 # http://tools.ietf.org/html/rfc7231#section-6.4.4
299 if response.status_code == codes.see_other and method != 'HEAD':
300 method = 'GET'
301
302 # Do what the browsers do, despite standards...
303 # First, turn 302s into GETs.
304 if response.status_code == codes.found and method != 'HEAD':
305 method = 'GET'
306
307 # Second, if a POST is responded to with a 301, turn it into a GET.
308 # This bizarre behaviour is explained in Issue 1704.
309 if response.status_code == codes.moved and method == 'POST':
310 method = 'GET'
311
312 prepared_request.method = method
313
314
315class Session(SessionRedirectMixin):
316 """A Requests session.
317
318 Provides cookie persistence, connection-pooling, and configuration.
319
320 Basic Usage::
321
322 >>> import requests
323 >>> s = requests.Session()
324 >>> s.get('http://httpbin.org/get')
325 <Response [200]>
326
327 Or as a context manager::
328
329 >>> with requests.Session() as s:
330 >>> s.get('http://httpbin.org/get')
331 <Response [200]>
332 """
333
334 __attrs__ = [
335 'headers', 'cookies', 'auth', 'proxies', 'hooks', 'params', 'verify',
336 'cert', 'prefetch', 'adapters', 'stream', 'trust_env',
337 'max_redirects',
338 ]
339
340 def __init__(self):
341
342 #: A case-insensitive dictionary of headers to be sent on each
343 #: :class:`Request <Request>` sent from this
344 #: :class:`Session <Session>`.
345 self.headers = default_headers()
346
347 #: Default Authentication tuple or object to attach to
348 #: :class:`Request <Request>`.
349 self.auth = None
350
351 #: Dictionary mapping protocol or protocol and host to the URL of the proxy
352 #: (e.g. {'http': 'foo.bar:3128', 'http://host.name': 'foo.bar:4012'}) to
353 #: be used on each :class:`Request <Request>`.
354 self.proxies = {}
355
356 #: Event-handling hooks.
357 self.hooks = default_hooks()
358
359 #: Dictionary of querystring data to attach to each
360 #: :class:`Request <Request>`. The dictionary values may be lists for
361 #: representing multivalued query parameters.
362 self.params = {}
363
364 #: Stream response content default.
365 self.stream = False
366
367 #: SSL Verification default.
368 self.verify = True
369
370 #: SSL client certificate default, if String, path to ssl client
371 #: cert file (.pem). If Tuple, ('cert', 'key') pair.
372 self.cert = None
373
374 #: Maximum number of redirects allowed. If the request exceeds this
375 #: limit, a :class:`TooManyRedirects` exception is raised.
376 #: This defaults to requests.models.DEFAULT_REDIRECT_LIMIT, which is
377 #: 30.
378 self.max_redirects = DEFAULT_REDIRECT_LIMIT
379
380 #: Trust environment settings for proxy configuration, default
381 #: authentication and similar.
382 self.trust_env = True
383
384 #: A CookieJar containing all currently outstanding cookies set on this
385 #: session. By default it is a
386 #: :class:`RequestsCookieJar <requests.cookies.RequestsCookieJar>`, but
387 #: may be any other ``cookielib.CookieJar`` compatible object.
388 self.cookies = cookiejar_from_dict({})
389
390 # Default connection adapters.
391 self.adapters = OrderedDict()
392 self.mount('https://', HTTPAdapter())
393 self.mount('http://', HTTPAdapter())
394
395 def __enter__(self):
396 return self
397
398 def __exit__(self, *args):
399 self.close()
400
401 def prepare_request(self, request):
402 """Constructs a :class:`PreparedRequest <PreparedRequest>` for
403 transmission and returns it. The :class:`PreparedRequest` has settings
404 merged from the :class:`Request <Request>` instance and those of the
405 :class:`Session`.
406
407 :param request: :class:`Request` instance to prepare with this
408 session's settings.
409 :rtype: requests.PreparedRequest
410 """
411 cookies = request.cookies or {}
412
413 # Bootstrap CookieJar.
414 if not isinstance(cookies, cookielib.CookieJar):
415 cookies = cookiejar_from_dict(cookies)
416
417 # Merge with session cookies
418 merged_cookies = merge_cookies(
419 merge_cookies(RequestsCookieJar(), self.cookies), cookies)
420
421 # Set environment's basic authentication if not explicitly set.
422 auth = request.auth
423 if self.trust_env and not auth and not self.auth:
424 auth = get_netrc_auth(request.url)
425
426 p = PreparedRequest()
427 p.prepare(
428 method=request.method.upper(),
429 url=request.url,
430 files=request.files,
431 data=request.data,
432 json=request.json,
433 headers=merge_setting(request.headers, self.headers, dict_class=CaseInsensitiveDict),
434 params=merge_setting(request.params, self.params),
435 auth=merge_setting(auth, self.auth),
436 cookies=merged_cookies,
437 hooks=merge_hooks(request.hooks, self.hooks),
438 )
439 return p
440
441 def request(self, method, url,
442 params=None, data=None, headers=None, cookies=None, files=None,
443 auth=None, timeout=None, allow_redirects=True, proxies=None,
444 hooks=None, stream=None, verify=None, cert=None, json=None):
445 """Constructs a :class:`Request <Request>`, prepares it and sends it.
446 Returns :class:`Response <Response>` object.
447
448 :param method: method for the new :class:`Request` object.
449 :param url: URL for the new :class:`Request` object.
450 :param params: (optional) Dictionary or bytes to be sent in the query
451 string for the :class:`Request`.
452 :param data: (optional) Dictionary, bytes, or file-like object to send
453 in the body of the :class:`Request`.
454 :param json: (optional) json to send in the body of the
455 :class:`Request`.
456 :param headers: (optional) Dictionary of HTTP Headers to send with the
457 :class:`Request`.
458 :param cookies: (optional) Dict or CookieJar object to send with the
459 :class:`Request`.
460 :param files: (optional) Dictionary of ``'filename': file-like-objects``
461 for multipart encoding upload.
462 :param auth: (optional) Auth tuple or callable to enable
463 Basic/Digest/Custom HTTP Auth.
464 :param timeout: (optional) How long to wait for the server to send
465 data before giving up, as a float, or a :ref:`(connect timeout,
466 read timeout) <timeouts>` tuple.
467 :type timeout: float or tuple
468 :param allow_redirects: (optional) Set to True by default.
469 :type allow_redirects: bool
470 :param proxies: (optional) Dictionary mapping protocol or protocol and
471 hostname to the URL of the proxy.
472 :param stream: (optional) whether to immediately download the response
473 content. Defaults to ``False``.
474 :param verify: (optional) Either a boolean, in which case it controls whether we verify
475 the server's TLS certificate, or a string, in which case it must be a path
476 to a CA bundle to use. Defaults to ``True``.
477 :param cert: (optional) if String, path to ssl client cert file (.pem).
478 If Tuple, ('cert', 'key') pair.
479 :rtype: requests.Response
480 """
481 # Create the Request.
482 req = Request(
483 method=method.upper(),
484 url=url,
485 headers=headers,
486 files=files,
487 data=data or {},
488 json=json,
489 params=params or {},
490 auth=auth,
491 cookies=cookies,
492 hooks=hooks,
493 )
494 prep = self.prepare_request(req)
495
496 proxies = proxies or {}
497
498 settings = self.merge_environment_settings(
499 prep.url, proxies, stream, verify, cert
500 )
501
502 # Send the request.
503 send_kwargs = {
504 'timeout': timeout,
505 'allow_redirects': allow_redirects,
506 }
507 send_kwargs.update(settings)
508 resp = self.send(prep, **send_kwargs)
509
510 return resp
511
512 def get(self, url, **kwargs):
513 r"""Sends a GET request. Returns :class:`Response` object.
514
515 :param url: URL for the new :class:`Request` object.
516 :param \*\*kwargs: Optional arguments that ``request`` takes.
517 :rtype: requests.Response
518 """
519
520 kwargs.setdefault('allow_redirects', True)
521 return self.request('GET', url, **kwargs)
522
523 def options(self, url, **kwargs):
524 r"""Sends a OPTIONS request. Returns :class:`Response` object.
525
526 :param url: URL for the new :class:`Request` object.
527 :param \*\*kwargs: Optional arguments that ``request`` takes.
528 :rtype: requests.Response
529 """
530
531 kwargs.setdefault('allow_redirects', True)
532 return self.request('OPTIONS', url, **kwargs)
533
534 def head(self, url, **kwargs):
535 r"""Sends a HEAD request. Returns :class:`Response` object.
536
537 :param url: URL for the new :class:`Request` object.
538 :param \*\*kwargs: Optional arguments that ``request`` takes.
539 :rtype: requests.Response
540 """
541
542 kwargs.setdefault('allow_redirects', False)
543 return self.request('HEAD', url, **kwargs)
544
545 def post(self, url, data=None, json=None, **kwargs):
546 r"""Sends a POST request. Returns :class:`Response` object.
547
548 :param url: URL for the new :class:`Request` object.
549 :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
550 :param json: (optional) json to send in the body of the :class:`Request`.
551 :param \*\*kwargs: Optional arguments that ``request`` takes.
552 :rtype: requests.Response
553 """
554
555 return self.request('POST', url, data=data, json=json, **kwargs)
556
557 def put(self, url, data=None, **kwargs):
558 r"""Sends a PUT request. Returns :class:`Response` object.
559
560 :param url: URL for the new :class:`Request` object.
561 :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
562 :param \*\*kwargs: Optional arguments that ``request`` takes.
563 :rtype: requests.Response
564 """
565
566 return self.request('PUT', url, data=data, **kwargs)
567
568 def patch(self, url, data=None, **kwargs):
569 r"""Sends a PATCH request. Returns :class:`Response` object.
570
571 :param url: URL for the new :class:`Request` object.
572 :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
573 :param \*\*kwargs: Optional arguments that ``request`` takes.
574 :rtype: requests.Response
575 """
576
577 return self.request('PATCH', url, data=data, **kwargs)
578
579 def delete(self, url, **kwargs):
580 r"""Sends a DELETE request. Returns :class:`Response` object.
581
582 :param url: URL for the new :class:`Request` object.
583 :param \*\*kwargs: Optional arguments that ``request`` takes.
584 :rtype: requests.Response
585 """
586
587 return self.request('DELETE', url, **kwargs)
588
589 def send(self, request, **kwargs):
590 """Send a given PreparedRequest.
591
592 :rtype: requests.Response
593 """
594 # Set defaults that the hooks can utilize to ensure they always have
595 # the correct parameters to reproduce the previous request.
596 kwargs.setdefault('stream', self.stream)
597 kwargs.setdefault('verify', self.verify)
598 kwargs.setdefault('cert', self.cert)
599 kwargs.setdefault('proxies', self.proxies)
600
601 # It's possible that users might accidentally send a Request object.
602 # Guard against that specific failure case.
603 if isinstance(request, Request):
604 raise ValueError('You can only send PreparedRequests.')
605
606 # Set up variables needed for resolve_redirects and dispatching of hooks
607 allow_redirects = kwargs.pop('allow_redirects', True)
608 stream = kwargs.get('stream')
609 hooks = request.hooks
610
611 # Get the appropriate adapter to use
612 adapter = self.get_adapter(url=request.url)
613
614 # Start time (approximately) of the request
615 start = preferred_clock()
616
617 # Send the request
618 r = adapter.send(request, **kwargs)
619
620 # Total elapsed time of the request (approximately)
621 elapsed = preferred_clock() - start
622 r.elapsed = timedelta(seconds=elapsed)
623
624 # Response manipulation hooks
625 r = dispatch_hook('response', hooks, r, **kwargs)
626
627 # Persist cookies
628 if r.history:
629
630 # If the hooks create history then we want those cookies too
631 for resp in r.history:
632 extract_cookies_to_jar(self.cookies, resp.request, resp.raw)
633
634 extract_cookies_to_jar(self.cookies, request, r.raw)
635
636 # Redirect resolving generator.
637 gen = self.resolve_redirects(r, request, **kwargs)
638
639 # Resolve redirects if allowed.
640 history = [resp for resp in gen] if allow_redirects else []
641
642 # Shuffle things around if there's history.
643 if history:
644 # Insert the first (original) request at the start
645 history.insert(0, r)
646 # Get the last request made
647 r = history.pop()
648 r.history = history
649
650 # If redirects aren't being followed, store the response on the Request for Response.next().
651 if not allow_redirects:
652 try:
653 r._next = next(self.resolve_redirects(r, request, yield_requests=True, **kwargs))
654 except StopIteration:
655 pass
656
657 if not stream:
658 r.content
659
660 return r
661
662 def merge_environment_settings(self, url, proxies, stream, verify, cert):
663 """
664 Check the environment and merge it with some settings.
665
666 :rtype: dict
667 """
668 # Gather clues from the surrounding environment.
669 if self.trust_env:
670 # Set environment's proxies.
671 no_proxy = proxies.get('no_proxy') if proxies is not None else None
672 env_proxies = get_environ_proxies(url, no_proxy=no_proxy)
673 for (k, v) in env_proxies.items():
674 proxies.setdefault(k, v)
675
676 # Look for requests environment configuration and be compatible
677 # with cURL.
678 if verify is True or verify is None:
679 verify = (os.environ.get('REQUESTS_CA_BUNDLE') or
680 os.environ.get('CURL_CA_BUNDLE'))
681
682 # Merge all the kwargs.
683 proxies = merge_setting(proxies, self.proxies)
684 stream = merge_setting(stream, self.stream)
685 verify = merge_setting(verify, self.verify)
686 cert = merge_setting(cert, self.cert)
687
688 return {'verify': verify, 'proxies': proxies, 'stream': stream,
689 'cert': cert}
690
691 def get_adapter(self, url):
692 """
693 Returns the appropriate connection adapter for the given URL.
694
695 :rtype: requests.adapters.BaseAdapter
696 """
697 for (prefix, adapter) in self.adapters.items():
698
699 if url.lower().startswith(prefix):
700 return adapter
701
702 # Nothing matches :-/
703 raise InvalidSchema("No connection adapters were found for '%s'" % url)
704
705 def close(self):
706 """Closes all adapters and as such the session"""
707 for v in self.adapters.values():
708 v.close()
709
710 def mount(self, prefix, adapter):
711 """Registers a connection adapter to a prefix.
712
713 Adapters are sorted in descending order by prefix length.
714 """
715 self.adapters[prefix] = adapter
716 keys_to_move = [k for k in self.adapters if len(k) < len(prefix)]
717
718 for key in keys_to_move:
719 self.adapters[key] = self.adapters.pop(key)
720
721 def __getstate__(self):
722 state = dict((attr, getattr(self, attr, None)) for attr in self.__attrs__)
723 return state
724
725 def __setstate__(self, state):
726 for attr, value in state.items():
727 setattr(self, attr, value)
728
729
730def session():
731 """
732 Returns a :class:`Session` for context-management.
733
734 :rtype: Session
735 """
736
737 return Session()