Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hhhrrrttt222111
GitHub Repository: hhhrrrttt222111/Dorkify
Path: blob/master/venv/Lib/site-packages/requests/sessions.py
811 views
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
# Resolve redirects if allowed.
662
if allow_redirects:
663
# Redirect resolving generator.
664
gen = self.resolve_redirects(r, request, **kwargs)
665
history = [resp for resp in gen]
666
else:
667
history = []
668
669
# Shuffle things around if there's history.
670
if history:
671
# Insert the first (original) request at the start
672
history.insert(0, r)
673
# Get the last request made
674
r = history.pop()
675
r.history = history
676
677
# If redirects aren't being followed, store the response on the Request for Response.next().
678
if not allow_redirects:
679
try:
680
r._next = next(self.resolve_redirects(r, request, yield_requests=True, **kwargs))
681
except StopIteration:
682
pass
683
684
if not stream:
685
r.content
686
687
return r
688
689
def merge_environment_settings(self, url, proxies, stream, verify, cert):
690
"""
691
Check the environment and merge it with some settings.
692
693
:rtype: dict
694
"""
695
# Gather clues from the surrounding environment.
696
if self.trust_env:
697
# Set environment's proxies.
698
no_proxy = proxies.get('no_proxy') if proxies is not None else None
699
env_proxies = get_environ_proxies(url, no_proxy=no_proxy)
700
for (k, v) in env_proxies.items():
701
proxies.setdefault(k, v)
702
703
# Look for requests environment configuration and be compatible
704
# with cURL.
705
if verify is True or verify is None:
706
verify = (os.environ.get('REQUESTS_CA_BUNDLE') or
707
os.environ.get('CURL_CA_BUNDLE'))
708
709
# Merge all the kwargs.
710
proxies = merge_setting(proxies, self.proxies)
711
stream = merge_setting(stream, self.stream)
712
verify = merge_setting(verify, self.verify)
713
cert = merge_setting(cert, self.cert)
714
715
return {'verify': verify, 'proxies': proxies, 'stream': stream,
716
'cert': cert}
717
718
def get_adapter(self, url):
719
"""
720
Returns the appropriate connection adapter for the given URL.
721
722
:rtype: requests.adapters.BaseAdapter
723
"""
724
for (prefix, adapter) in self.adapters.items():
725
726
if url.lower().startswith(prefix.lower()):
727
return adapter
728
729
# Nothing matches :-/
730
raise InvalidSchema("No connection adapters were found for {!r}".format(url))
731
732
def close(self):
733
"""Closes all adapters and as such the session"""
734
for v in self.adapters.values():
735
v.close()
736
737
def mount(self, prefix, adapter):
738
"""Registers a connection adapter to a prefix.
739
740
Adapters are sorted in descending order by prefix length.
741
"""
742
self.adapters[prefix] = adapter
743
keys_to_move = [k for k in self.adapters if len(k) < len(prefix)]
744
745
for key in keys_to_move:
746
self.adapters[key] = self.adapters.pop(key)
747
748
def __getstate__(self):
749
state = {attr: getattr(self, attr, None) for attr in self.__attrs__}
750
return state
751
752
def __setstate__(self, state):
753
for attr, value in state.items():
754
setattr(self, attr, value)
755
756
757
def session():
758
"""
759
Returns a :class:`Session` for context-management.
760
761
.. deprecated:: 1.0.0
762
763
This method has been deprecated since version 1.0.0 and is only kept for
764
backwards compatibility. New code should use :class:`~requests.sessions.Session`
765
to create a session. This may be removed at a future date.
766
767
:rtype: Session
768
"""
769
return Session()
770
771