2
2
from __future__ import unicode_literals
3
3
from collections import OrderedDict
4
4
from coreapi import exceptions , utils
5
- from coreapi .compat import urlparse
5
+ from coreapi .compat import cookiejar , urlparse
6
6
from coreapi .document import Document , Object , Link , Array , Error
7
7
from coreapi .transports .base import BaseTransport
8
8
from coreapi .utils import guess_filename , is_file , File
11
11
import itypes
12
12
import mimetypes
13
13
import uritemplate
14
+ import warnings
14
15
15
16
16
17
Params = collections .namedtuple ('Params' , ['path' , 'query' , 'data' , 'files' ])
17
18
empty_params = Params ({}, {}, {}, {})
18
19
19
20
20
21
class ForceMultiPartDict (dict ):
21
- # A dictionary that always evaluates as True.
22
- # Allows us to force requests to use multipart encoding, even when no
23
- # file parameters are passed.
22
+ """
23
+ A dictionary that always evaluates as True.
24
+ Allows us to force requests to use multipart encoding, even when no
25
+ file parameters are passed.
26
+ """
24
27
def __bool__ (self ):
25
28
return True
26
29
27
30
def __nonzero__ (self ):
28
31
return True
29
32
30
33
34
+ class BlockAll (cookiejar .CookiePolicy ):
35
+ """
36
+ A cookie policy that rejects all cookies.
37
+ Used to override the default `requests` behavior.
38
+ """
39
+ return_ok = set_ok = domain_return_ok = path_return_ok = lambda self , * args , ** kwargs : False
40
+ netscape = True
41
+ rfc2965 = hide_cookie2 = False
42
+
43
+
44
+ class DomainCredentials (requests .auth .AuthBase ):
45
+ """
46
+ Custom auth class to support deprecated 'credentials' argument.
47
+ """
48
+ allow_cookies = False
49
+ credentials = None
50
+
51
+ def __init__ (self , credentials = None ):
52
+ self .credentials = credentials
53
+
54
+ def __call__ (self , request ):
55
+ if not self .credentials :
56
+ return request
57
+
58
+ # Include any authorization credentials relevant to this domain.
59
+ url_components = urlparse .urlparse (request .url )
60
+ host = url_components .hostname
61
+ if host in self .credentials :
62
+ request .headers ['Authorization' ] = self .credentials [host ]
63
+ return request
64
+
65
+
66
+ class CallbackAdapter (requests .adapters .HTTPAdapter ):
67
+ """
68
+ Custom requests HTTP adapter, to support deprecated callback arguments.
69
+ """
70
+ def __init__ (self , request_callback = None , response_callback = None ):
71
+ self .request_callback = request_callback
72
+ self .response_callback = response_callback
73
+
74
+ def send (self , request , ** kwargs ):
75
+ if self .request_callback is not None :
76
+ self .request_callback (request )
77
+ response = super (CallbackAdapter , self ).send (request , ** kwargs )
78
+ if self .response_callback is not None :
79
+ self .response_callback (response )
80
+ return response
81
+
82
+
31
83
def _get_method (action ):
32
84
if not action :
33
85
return 'GET'
@@ -107,7 +159,7 @@ def _get_url(url, path_params):
107
159
return url
108
160
109
161
110
- def _get_headers (url , decoders , credentials = None ):
162
+ def _get_headers (url , decoders ):
111
163
"""
112
164
Return a dictionary of HTTP headers to use in the outgoing request.
113
165
"""
@@ -120,13 +172,6 @@ def _get_headers(url, decoders, credentials=None):
120
172
'user-agent' : 'coreapi'
121
173
}
122
174
123
- if credentials :
124
- # Include any authorization credentials relevant to this domain.
125
- url_components = urlparse .urlparse (url )
126
- host = url_components .hostname
127
- if host in credentials :
128
- headers ['authorization' ] = credentials [host ]
129
-
130
175
return headers
131
176
132
177
@@ -254,7 +299,8 @@ def _decode_result(response, decoders, force_codec=False):
254
299
# Coerce 4xx and 5xx codes into errors.
255
300
is_error = response .status_code >= 400 and response .status_code <= 599
256
301
if is_error and not isinstance (result , Error ):
257
- result = _coerce_to_error (result , default_title = response .reason )
302
+ default_title = '%d %s' % (response .status_code , response .reason )
303
+ result = _coerce_to_error (result , default_title = default_title )
258
304
259
305
return result
260
306
@@ -288,24 +334,34 @@ def _handle_inplace_replacements(document, link, link_ancestors):
288
334
class HTTPTransport (BaseTransport ):
289
335
schemes = ['http' , 'https' ]
290
336
291
- def __init__ (self , credentials = None , headers = None , session = None , request_callback = None , response_callback = None ):
337
+ def __init__ (self , credentials = None , headers = None , auth = None , session = None , request_callback = None , response_callback = None ):
292
338
if headers :
293
339
headers = {key .lower (): value for key , value in headers .items ()}
294
340
if session is None :
295
341
session = requests .Session ()
296
- self ._credentials = itypes .Dict (credentials or {})
342
+ if auth is not None :
343
+ session .auth = auth
344
+ if not getattr (session .auth , 'allow_cookies' , False ):
345
+ session .cookies .set_policy (BlockAll ())
346
+
347
+ if credentials is not None :
348
+ warnings .warn (
349
+ "The 'credentials' argument is now deprecated in favor of 'auth'." ,
350
+ DeprecationWarning
351
+ )
352
+ auth = DomainCredentials (credentials )
353
+ if request_callback is not None or response_callback is not None :
354
+ warnings .warn (
355
+ "The 'request_callback' and 'response_callback' arguments are now deprecated. "
356
+ "Use a custom 'session' instance instead." ,
357
+ DeprecationWarning
358
+ )
359
+ session .mount ('https://' , CallbackAdapter (request_callback , response_callback ))
360
+ session .mount ('http://' , CallbackAdapter (request_callback , response_callback ))
361
+
297
362
self ._headers = itypes .Dict (headers or {})
298
363
self ._session = session
299
364
300
- # Fallback for v1.x overrides.
301
- # Will be removed at some point, most likely in a 2.1 release.
302
- self ._request_callback = request_callback
303
- self ._response_callback = response_callback
304
-
305
- @property
306
- def credentials (self ):
307
- return self ._credentials
308
-
309
365
@property
310
366
def headers (self ):
311
367
return self ._headers
@@ -316,19 +372,11 @@ def transition(self, link, decoders, params=None, link_ancestors=None, force_cod
316
372
encoding = _get_encoding (link .encoding )
317
373
params = _get_params (method , encoding , link .fields , params )
318
374
url = _get_url (link .url , params .path )
319
- headers = _get_headers (url , decoders , self . credentials )
375
+ headers = _get_headers (url , decoders )
320
376
headers .update (self .headers )
321
377
322
378
request = _build_http_request (session , url , method , headers , encoding , params )
323
-
324
- if self ._request_callback is not None :
325
- self ._request_callback (request )
326
-
327
379
response = session .send (request )
328
-
329
- if self ._response_callback is not None :
330
- self ._response_callback (response )
331
-
332
380
result = _decode_result (response , decoders , force_codec )
333
381
334
382
if isinstance (result , Document ) and link_ancestors :
0 commit comments