Skip to content

Commit

Permalink
Merge pull request #2258 from willingc/add-json
Browse files Browse the repository at this point in the history
Add json parameter
  • Loading branch information
kennethreitz committed Oct 5, 2014
2 parents 20ca9fe + 8ed941f commit 1e79cf6
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 10 deletions.
6 changes: 4 additions & 2 deletions requests/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def request(method, url, **kwargs):
:param url: URL for the new :class:`Request` object.
:param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`.
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
:param json: (optional) json data to send in the body of the :class:`Request`.
:param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
:param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.
:param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': ('filename', fileobj)}``) for multipart encoding upload.
Expand Down Expand Up @@ -81,15 +82,16 @@ def head(url, **kwargs):
return request('head', url, **kwargs)


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

return request('post', url, data=data, **kwargs)
return request('post', url, data=data, json=json, **kwargs)


def put(url, data=None, **kwargs):
Expand Down
23 changes: 17 additions & 6 deletions requests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
CONTENT_CHUNK_SIZE = 10 * 1024
ITER_CHUNK_SIZE = 512

json_dumps = json.dumps


class RequestEncodingMixin(object):
@property
Expand Down Expand Up @@ -189,7 +191,8 @@ class Request(RequestHooksMixin):
:param url: URL to send.
:param headers: dictionary of headers to send.
:param files: dictionary of {filename: fileobject} files to multipart upload.
:param data: the body to attach the request. If a dictionary is provided, form-encoding will take place.
:param data: the body to attach to the request. If a dictionary is provided, form-encoding will take place.
:param json: json for the body to attach to the request (if data is not specified).
:param params: dictionary of URL parameters to append to the URL.
:param auth: Auth handler or (user, pass) tuple.
:param cookies: dictionary or CookieJar of cookies to attach to this request.
Expand All @@ -209,6 +212,7 @@ def __init__(self,
headers=None,
files=None,
data=None,
json=None,
params=None,
auth=None,
cookies=None,
Expand All @@ -230,6 +234,7 @@ def __init__(self,
self.headers = headers
self.files = files
self.data = data
self.json = json
self.params = params
self.auth = auth
self.cookies = cookies
Expand All @@ -246,6 +251,7 @@ def prepare(self):
headers=self.headers,
files=self.files,
data=self.data,
json=self.json,
params=self.params,
auth=self.auth,
cookies=self.cookies,
Expand Down Expand Up @@ -289,14 +295,15 @@ def __init__(self):
self.hooks = default_hooks()

def prepare(self, method=None, url=None, headers=None, files=None,
data=None, params=None, auth=None, cookies=None, hooks=None):
data=None, params=None, auth=None, cookies=None, hooks=None,
json=None):
"""Prepares the entire request with the given parameters."""

self.prepare_method(method)
self.prepare_url(url, params)
self.prepare_headers(headers)
self.prepare_cookies(cookies)
self.prepare_body(data, files)
self.prepare_body(data, files, json)
self.prepare_auth(auth, url)
# Note that prepare_auth must be last to enable authentication schemes
# such as OAuth to work on a fully prepared request.
Expand Down Expand Up @@ -400,7 +407,7 @@ def prepare_headers(self, headers):
else:
self.headers = CaseInsensitiveDict()

def prepare_body(self, data, files):
def prepare_body(self, data, files, json=None):
"""Prepares the given HTTP body data."""

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

if json is not None:
content_type = 'application/json'
body = json_dumps(json)

is_stream = all([
hasattr(data, '__iter__'),
not isinstance(data, (basestring, list, tuple, dict))
Expand All @@ -436,7 +447,7 @@ def prepare_body(self, data, files):
if files:
(body, content_type) = self._encode_files(files, data)
else:
if data:
if data and json is None:
body = self._encode_params(data)
if isinstance(data, basestring) or hasattr(data, 'read'):
content_type = None
Expand All @@ -446,7 +457,7 @@ def prepare_body(self, data, files):
self.prepare_content_length(body)

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

self.body = body
Expand Down
10 changes: 8 additions & 2 deletions requests/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ def prepare_request(self, request):
url=request.url,
files=request.files,
data=request.data,
json=request.json,
headers=merge_setting(request.headers, self.headers, dict_class=CaseInsensitiveDict),
params=merge_setting(request.params, self.params),
auth=merge_setting(auth, self.auth),
Expand All @@ -377,6 +378,7 @@ def prepare_request(self, request):
def request(self, method, url,
params=None,
data=None,
json=None,
headers=None,
cookies=None,
files=None,
Expand All @@ -397,6 +399,8 @@ def request(self, method, url,
string for the :class:`Request`.
:param data: (optional) Dictionary or bytes to send in the body of the
:class:`Request`.
:param json: (optional) json to send in the body of the
:class:`Request`.
:param headers: (optional) Dictionary of HTTP Headers to send with the
:class:`Request`.
:param cookies: (optional) Dict or CookieJar object to send with the
Expand Down Expand Up @@ -430,6 +434,7 @@ def request(self, method, url,
headers = headers,
files = files,
data = data or {},
json = json,
params = params or {},
auth = auth,
cookies = cookies,
Expand Down Expand Up @@ -483,15 +488,16 @@ def head(self, url, **kwargs):
kwargs.setdefault('allow_redirects', False)
return self.request('HEAD', url, **kwargs)

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

return self.request('POST', url, data=data, **kwargs)
return self.request('POST', url, data=data, json=json, **kwargs)

def put(self, url, data=None, **kwargs):
"""Sends a PUT request. Returns :class:`Response` object.
Expand Down
9 changes: 9 additions & 0 deletions test_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,15 @@ def test_requests_history_is_saved(self):
assert item.history == total[0:i]
i=i+1

def test_json_param_post_content_type_works(self):
r = requests.post(
httpbin('post'),
json={'life': 42}
)
assert r.status_code == 200
assert 'application/json' in r.request.headers['Content-Type']
assert {'life': 42} == r.json()['json']


class TestContentEncodingDetection(unittest.TestCase):

Expand Down

0 comments on commit 1e79cf6

Please sign in to comment.