Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/requests/sessions.py @ 1:56ad4e20f292 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
| author | guerler |
|---|---|
| date | Fri, 31 Jul 2020 00:32:28 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:d30785e31577 | 1:56ad4e20f292 |
|---|---|
| 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() |
