comparison lib/python3.8/site-packages/pip/_vendor/requests/sessions.py @ 0:9e54283cc701 draft

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