Skip to content

Commit 1e79cf6

Browse files
committed
Merge pull request #2258 from willingc/add-json
Add json parameter
2 parents 20ca9fe + 8ed941f commit 1e79cf6

4 files changed

Lines changed: 38 additions & 10 deletions

File tree

requests/api.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ def request(method, url, **kwargs):
2222
:param url: URL for the new :class:`Request` object.
2323
:param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`.
2424
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
25+
:param json: (optional) json data to send in the body of the :class:`Request`.
2526
:param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
2627
:param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.
2728
:param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': ('filename', fileobj)}``) for multipart encoding upload.
@@ -81,15 +82,16 @@ def head(url, **kwargs):
8182
return request('head', url, **kwargs)
8283

8384

84-
def post(url, data=None, **kwargs):
85+
def post(url, data=None, json=None, **kwargs):
8586
"""Sends a POST request. Returns :class:`Response` object.
8687
8788
:param url: URL for the new :class:`Request` object.
8889
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
90+
:param json: (optional) json data to send in the body of the :class:`Request`.
8991
:param \*\*kwargs: Optional arguments that ``request`` takes.
9092
"""
9193

92-
return request('post', url, data=data, **kwargs)
94+
return request('post', url, data=data, json=json, **kwargs)
9395

9496

9597
def put(url, data=None, **kwargs):

requests/models.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
CONTENT_CHUNK_SIZE = 10 * 1024
4747
ITER_CHUNK_SIZE = 512
4848

49+
json_dumps = json.dumps
50+
4951

5052
class RequestEncodingMixin(object):
5153
@property
@@ -189,7 +191,8 @@ class Request(RequestHooksMixin):
189191
:param url: URL to send.
190192
:param headers: dictionary of headers to send.
191193
:param files: dictionary of {filename: fileobject} files to multipart upload.
192-
:param data: the body to attach the request. If a dictionary is provided, form-encoding will take place.
194+
:param data: the body to attach to the request. If a dictionary is provided, form-encoding will take place.
195+
:param json: json for the body to attach to the request (if data is not specified).
193196
:param params: dictionary of URL parameters to append to the URL.
194197
:param auth: Auth handler or (user, pass) tuple.
195198
:param cookies: dictionary or CookieJar of cookies to attach to this request.
@@ -209,6 +212,7 @@ def __init__(self,
209212
headers=None,
210213
files=None,
211214
data=None,
215+
json=None,
212216
params=None,
213217
auth=None,
214218
cookies=None,
@@ -230,6 +234,7 @@ def __init__(self,
230234
self.headers = headers
231235
self.files = files
232236
self.data = data
237+
self.json = json
233238
self.params = params
234239
self.auth = auth
235240
self.cookies = cookies
@@ -246,6 +251,7 @@ def prepare(self):
246251
headers=self.headers,
247252
files=self.files,
248253
data=self.data,
254+
json=self.json,
249255
params=self.params,
250256
auth=self.auth,
251257
cookies=self.cookies,
@@ -289,14 +295,15 @@ def __init__(self):
289295
self.hooks = default_hooks()
290296

291297
def prepare(self, method=None, url=None, headers=None, files=None,
292-
data=None, params=None, auth=None, cookies=None, hooks=None):
298+
data=None, params=None, auth=None, cookies=None, hooks=None,
299+
json=None):
293300
"""Prepares the entire request with the given parameters."""
294301

295302
self.prepare_method(method)
296303
self.prepare_url(url, params)
297304
self.prepare_headers(headers)
298305
self.prepare_cookies(cookies)
299-
self.prepare_body(data, files)
306+
self.prepare_body(data, files, json)
300307
self.prepare_auth(auth, url)
301308
# Note that prepare_auth must be last to enable authentication schemes
302309
# such as OAuth to work on a fully prepared request.
@@ -400,7 +407,7 @@ def prepare_headers(self, headers):
400407
else:
401408
self.headers = CaseInsensitiveDict()
402409

403-
def prepare_body(self, data, files):
410+
def prepare_body(self, data, files, json=None):
404411
"""Prepares the given HTTP body data."""
405412

406413
# Check if file, fo, generator, iterator.
@@ -411,6 +418,10 @@ def prepare_body(self, data, files):
411418
content_type = None
412419
length = None
413420

421+
if json is not None:
422+
content_type = 'application/json'
423+
body = json_dumps(json)
424+
414425
is_stream = all([
415426
hasattr(data, '__iter__'),
416427
not isinstance(data, (basestring, list, tuple, dict))
@@ -436,7 +447,7 @@ def prepare_body(self, data, files):
436447
if files:
437448
(body, content_type) = self._encode_files(files, data)
438449
else:
439-
if data:
450+
if data and json is None:
440451
body = self._encode_params(data)
441452
if isinstance(data, basestring) or hasattr(data, 'read'):
442453
content_type = None
@@ -446,7 +457,7 @@ def prepare_body(self, data, files):
446457
self.prepare_content_length(body)
447458

448459
# Add content-type if it wasn't explicitly provided.
449-
if (content_type) and (not 'content-type' in self.headers):
460+
if content_type and ('content-type' not in self.headers):
450461
self.headers['Content-Type'] = content_type
451462

452463
self.body = body

requests/sessions.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ def prepare_request(self, request):
366366
url=request.url,
367367
files=request.files,
368368
data=request.data,
369+
json=request.json,
369370
headers=merge_setting(request.headers, self.headers, dict_class=CaseInsensitiveDict),
370371
params=merge_setting(request.params, self.params),
371372
auth=merge_setting(auth, self.auth),
@@ -377,6 +378,7 @@ def prepare_request(self, request):
377378
def request(self, method, url,
378379
params=None,
379380
data=None,
381+
json=None,
380382
headers=None,
381383
cookies=None,
382384
files=None,
@@ -397,6 +399,8 @@ def request(self, method, url,
397399
string for the :class:`Request`.
398400
:param data: (optional) Dictionary or bytes to send in the body of the
399401
:class:`Request`.
402+
:param json: (optional) json to send in the body of the
403+
:class:`Request`.
400404
:param headers: (optional) Dictionary of HTTP Headers to send with the
401405
:class:`Request`.
402406
:param cookies: (optional) Dict or CookieJar object to send with the
@@ -430,6 +434,7 @@ def request(self, method, url,
430434
headers = headers,
431435
files = files,
432436
data = data or {},
437+
json = json,
433438
params = params or {},
434439
auth = auth,
435440
cookies = cookies,
@@ -483,15 +488,16 @@ def head(self, url, **kwargs):
483488
kwargs.setdefault('allow_redirects', False)
484489
return self.request('HEAD', url, **kwargs)
485490

486-
def post(self, url, data=None, **kwargs):
491+
def post(self, url, data=None, json=None, **kwargs):
487492
"""Sends a POST request. Returns :class:`Response` object.
488493
489494
:param url: URL for the new :class:`Request` object.
490495
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
496+
:param json: (optional) json to send in the body of the :class:`Request`.
491497
:param \*\*kwargs: Optional arguments that ``request`` takes.
492498
"""
493499

494-
return self.request('POST', url, data=data, **kwargs)
500+
return self.request('POST', url, data=data, json=json, **kwargs)
495501

496502
def put(self, url, data=None, **kwargs):
497503
"""Sends a PUT request. Returns :class:`Response` object.

test_requests.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,15 @@ def test_requests_history_is_saved(self):
10071007
assert item.history == total[0:i]
10081008
i=i+1
10091009

1010+
def test_json_param_post_content_type_works(self):
1011+
r = requests.post(
1012+
httpbin('post'),
1013+
json={'life': 42}
1014+
)
1015+
assert r.status_code == 200
1016+
assert 'application/json' in r.request.headers['Content-Type']
1017+
assert {'life': 42} == r.json()['json']
1018+
10101019

10111020
class TestContentEncodingDetection(unittest.TestCase):
10121021

0 commit comments

Comments
 (0)