comparison env/lib/python3.7/site-packages/requests/sessions.py @ 0:26e78fe6e8c4 draft

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