diff --git a/fixtures/python_output/multipart_post.py b/fixtures/python_output/multipart_post.py
index c945b4a..17c3c05 100644
--- a/fixtures/python_output/multipart_post.py
+++ b/fixtures/python_output/multipart_post.py
@@ -4,9 +4,9 @@ headers = {
'Authorization': 'Bearer ACCESS_TOKEN',
}
-files = {
- 'attributes': '{"name":"tigers.jpeg", "parent":{"id":"11446498"}}',
- 'file': open('myfile.jpg', 'rb')
-}
+files = [
+ ('attributes', '{"name":"tigers.jpeg", "parent":{"id":"11446498"}}'),
+ ('file', open('myfile.jpg', 'rb')),
+]
requests.post('https://upload.box.com/api/2.0/files/content', headers=headers, files=files)
diff --git a/fixtures/python_output/post_basic_auth_url_encoded_data.py b/fixtures/python_output/post_basic_auth_url_encoded_data.py
index e9e05aa..06f5e7e 100644
--- a/fixtures/python_output/post_basic_auth_url_encoded_data.py
+++ b/fixtures/python_output/post_basic_auth_url_encoded_data.py
@@ -1,7 +1,7 @@
import requests
-data = {
- 'grant_type': 'client_credentials'
-}
+data = [
+ ('grant_type', 'client_credentials'),
+]
requests.post('http://localhost/api/oauth/token/', data=data, auth=('foo', 'bar'))
diff --git a/fixtures/python_output/post_data_binary_with_equals.py b/fixtures/python_output/post_data_binary_with_equals.py
index d34c26c..4d40a6c 100644
--- a/fixtures/python_output/post_data_binary_with_equals.py
+++ b/fixtures/python_output/post_data_binary_with_equals.py
@@ -44,7 +44,7 @@ params = (
('AC', '1'),
)
-data = '{"__type":"CreateItemJsonRequest:#Exchange","Header":{"__type":"JsonRequestHeaders:#Exchange","RequestServerVersion":"Exchange2013","TimeZoneContext":{"__type":"TimeZoneContext:#Exchange","TimeZoneDefinition":{"__type":"TimeZoneDefinitionType:#Exchange","Id":"France Standard Time"}}},"Body":{"__type":"CreateItemRequest:#Exchange","Items":[{"__type":"Message:#Exchange","Subject":"API","Body":{"__type":"BodyContentType:#Exchange","BodyType":"HTML","Value":"
API Test for NickC
"},"Importance":"Normal","From":null,"ToRecipients":[{"Name":"George LUCAS","EmailAddress":"George.LUCAS@nih.mail.edu.fr","RoutingType":"SMTP","MailboxType":"Mailbox","OriginalDisplayName":"George.LUCAS@nih.mail.edu.fr","SipUri":" "}],"CcRecipients":[],"BccRecipients":[],"Sensitivity":"Normal","IsDeliveryReceiptRequested":false,"IsReadReceiptRequested":false}],"ClientSupportsIrm":true,"OutboundCharset":"AutoDetect","MessageDisposition":"SendAndSaveCopy","ComposeOperation":"newMail"}}'
+data = '{"__type":"CreateItemJsonRequest:#Exchange","Header":{"__type":"JsonRequestHeaders:#Exchange","RequestServerVersion":"Exchange2013","TimeZoneContext":{"__type":"TimeZoneContext:#Exchange","TimeZoneDefinition":{"__type":"TimeZoneDefinitionType:#Exchange","Id":"France Standard Time"}}},"Body":{"__type":"CreateItemRequest:#Exchange","Items":[{"__type":"Message:#Exchange","Subject":"API","Body":{"__type":"BodyContentType:#Exchange","BodyType":"HTML","Value":"API Test for NickC
"},"Importance":"Normal","From":null,"ToRecipients":[{"Name":"George LUCAS","EmailAddress":"George.LUCAS@nih.mail.edu.fr","RoutingType":"SMTP","MailboxType":"Mailbox","OriginalDisplayName":"George.LUCAS@nih.mail.edu.fr","SipUri":" "}],"CcRecipients":[],"BccRecipients":[],"Sensitivity":"Normal","IsDeliveryReceiptRequested":false,"IsReadReceiptRequested":false}],"ClientSupportsIrm":true,"OutboundCharset":"AutoDetect","MessageDisposition":"SendAndSaveCopy","ComposeOperation":"newMail"}}'
requests.post('https://localhost/api/service.svc', headers=headers, params=params, cookies=cookies, data=data)
diff --git a/fixtures/python_output/post_escaped_double_quotes_in_single_quotes.py b/fixtures/python_output/post_escaped_double_quotes_in_single_quotes.py
index d837f88..bfcd4e1 100644
--- a/fixtures/python_output/post_escaped_double_quotes_in_single_quotes.py
+++ b/fixtures/python_output/post_escaped_double_quotes_in_single_quotes.py
@@ -1,7 +1,7 @@
import requests
-data = {
- 'foo': '\"bar\"'
-}
+data = [
+ ('foo', '\\"bar\\"'),
+]
requests.post('http://example.com/', data=data)
diff --git a/fixtures/python_output/post_escaped_single_quotes_in_double_quotes.py b/fixtures/python_output/post_escaped_single_quotes_in_double_quotes.py
index c0941a1..e4c1cf1 100644
--- a/fixtures/python_output/post_escaped_single_quotes_in_double_quotes.py
+++ b/fixtures/python_output/post_escaped_single_quotes_in_double_quotes.py
@@ -1,7 +1,7 @@
import requests
-data = {
- 'foo': '\\\'bar\\\''
-}
+data = [
+ ('foo', '\\\'bar\\\''),
+]
requests.post('http://example.com/', data=data)
diff --git a/fixtures/python_output/post_quotes_inside_data.py b/fixtures/python_output/post_quotes_inside_data.py
new file mode 100644
index 0000000..5abd403
--- /dev/null
+++ b/fixtures/python_output/post_quotes_inside_data.py
@@ -0,0 +1,7 @@
+import requests
+
+data = [
+ ('field', 'don\'t you like quotes'),
+]
+
+requests.post('google.com', data=data)
diff --git a/fixtures/python_output/post_same_field_multiple_times.py b/fixtures/python_output/post_same_field_multiple_times.py
index 4a0380f..d7d257e 100644
--- a/fixtures/python_output/post_same_field_multiple_times.py
+++ b/fixtures/python_output/post_same_field_multiple_times.py
@@ -3,7 +3,7 @@ import requests
data = [
('foo', 'bar'),
('foo', ''),
- ('foo', 'barbar')
+ ('foo', 'barbar'),
]
requests.post('http://example.com/', data=data)
diff --git a/fixtures/python_output/post_with_double_quotes_inside_single_quotes.py b/fixtures/python_output/post_with_double_quotes_inside_single_quotes.py
index 669618d..f60c044 100644
--- a/fixtures/python_output/post_with_double_quotes_inside_single_quotes.py
+++ b/fixtures/python_output/post_with_double_quotes_inside_single_quotes.py
@@ -1,7 +1,7 @@
import requests
-data = {
- 'foo': '"bar"'
-}
+data = [
+ ('foo', '"bar"'),
+]
requests.post('http://example.com/', data=data)
diff --git a/fixtures/python_output/post_with_escaped_double_quotes.py b/fixtures/python_output/post_with_escaped_double_quotes.py
index 669618d..f60c044 100644
--- a/fixtures/python_output/post_with_escaped_double_quotes.py
+++ b/fixtures/python_output/post_with_escaped_double_quotes.py
@@ -1,7 +1,7 @@
import requests
-data = {
- 'foo': '"bar"'
-}
+data = [
+ ('foo', '"bar"'),
+]
requests.post('http://example.com/', data=data)
diff --git a/fixtures/python_output/post_with_single_quotes_inside_double_quotes.py b/fixtures/python_output/post_with_single_quotes_inside_double_quotes.py
index 95805dc..88f3c44 100644
--- a/fixtures/python_output/post_with_single_quotes_inside_double_quotes.py
+++ b/fixtures/python_output/post_with_single_quotes_inside_double_quotes.py
@@ -1,7 +1,7 @@
import requests
-data = {
- 'foo': '\'bar\''
-}
+data = [
+ ('foo', '\'bar\''),
+]
requests.post('http://example.com/', data=data)
diff --git a/fixtures/python_output/post_with_urlencoded_data.py b/fixtures/python_output/post_with_urlencoded_data.py
index 88dddc7..f00cdd9 100644
--- a/fixtures/python_output/post_with_urlencoded_data.py
+++ b/fixtures/python_output/post_with_urlencoded_data.py
@@ -12,9 +12,9 @@ headers = {
'Connection': 'keep-alive',
}
-data = {
- 'msg1': 'wow',
- 'msg2': 'such'
-}
+data = [
+ ('msg1', 'wow'),
+ ('msg2', 'such'),
+]
requests.post('http://fiddle.jshell.net/echo/html/', headers=headers, data=data)
diff --git a/fixtures/python_output/post_with_urlencoded_data_and_headers.py b/fixtures/python_output/post_with_urlencoded_data_and_headers.py
index 5259dbe..900b9aa 100644
--- a/fixtures/python_output/post_with_urlencoded_data_and_headers.py
+++ b/fixtures/python_output/post_with_urlencoded_data_and_headers.py
@@ -11,28 +11,28 @@ headers = {
'Connection': 'keep-alive',
}
-data = {
- 'CultureId': '1',
- 'ApplicationId': '1',
- 'RecordsPerPage': '200',
- 'MaximumResults': '200',
- 'PropertyTypeId': '300',
- 'TransactionTypeId': '2',
- 'StoreyRange': '0-0',
- 'BuildingTypeId': '1',
- 'BedRange': '0-0',
- 'BathRange': '0-0',
- 'LongitudeMin': '-79.3676805496215',
- 'LongitudeMax': '-79.27300930023185',
- 'LatitudeMin': '43.660358732823845',
- 'LatitudeMax': '43.692390574029936',
- 'SortOrder': 'A',
- 'SortBy': '1',
- 'viewState': 'm',
- 'Longitude': '-79.4107246398925',
- 'Latitude': '43.6552047278685',
- 'ZoomLevel': '13',
- 'CurrentPage': '1'
-}
+data = [
+ ('CultureId', '1'),
+ ('ApplicationId', '1'),
+ ('RecordsPerPage', '200'),
+ ('MaximumResults', '200'),
+ ('PropertyTypeId', '300'),
+ ('TransactionTypeId', '2'),
+ ('StoreyRange', '0-0'),
+ ('BuildingTypeId', '1'),
+ ('BedRange', '0-0'),
+ ('BathRange', '0-0'),
+ ('LongitudeMin', '-79.3676805496215'),
+ ('LongitudeMax', '-79.27300930023185'),
+ ('LatitudeMin', '43.660358732823845'),
+ ('LatitudeMax', '43.692390574029936'),
+ ('SortOrder', 'A'),
+ ('SortBy', '1'),
+ ('viewState', 'm'),
+ ('Longitude', '-79.4107246398925'),
+ ('Latitude', '43.6552047278685'),
+ ('ZoomLevel', '13'),
+ ('CurrentPage', '1'),
+]
requests.post('http://www.realtor.ca/api/Listing.svc/PropertySearch_Post', headers=headers, data=data)
diff --git a/generators/python.js b/generators/python.js
index b4edb3f..93f8d93 100644
--- a/generators/python.js
+++ b/generators/python.js
@@ -4,22 +4,110 @@ var querystring = require('querystring')
require('string.prototype.startswith')
-function pythonReprString (value) {
+function repr (value) {
// In context of url parameters, don't accept nulls and such.
if (!value) {
return "''"
} else {
- return "'" + value.replace('\\', '\\\\').replace("'", "\\'") + "'"
+ return "'" + jsesc(value, { quotes: 'single' }) + "'"
}
}
+function getQueryDict (request) {
+ var queryDict = 'params = (\n'
+ for (var paramName in request.query) {
+ var rawValue = request.query[paramName]
+ var paramValue
+ if (Array.isArray(rawValue)) {
+ paramValue = rawValue.map(repr).join(', ')
+ } else {
+ paramValue = repr(rawValue)
+ }
+ queryDict += ' (' + repr(paramName) + ', ' + paramValue + '),\n'
+ }
+ queryDict += ')\n'
+ return queryDict
+}
+
+function getDataString (request) {
+ if (request.data.startsWith('@')) {
+ var filePath = request.data.slice(1)
+ if (request.isDataBinary) {
+ return 'data = open(\'' + filePath + '\', \'rb\').read()'
+ } else {
+ return 'data = open(\'' + filePath + '\')'
+ }
+ }
+
+ var parsedQueryString = querystring.parse(request.data)
+ var keyCount = Object.keys(parsedQueryString).length
+ var singleKeyOnly = keyCount === 1 && !parsedQueryString[Object.keys(parsedQueryString)[0]]
+ var singularData = request.isDataBinary || singleKeyOnly
+ if (singularData) {
+ return 'data = ' + repr(request.data) + '\n'
+ } else {
+ return getMultipleDataString(request, parsedQueryString)
+ }
+}
+
+function getMultipleDataString (request, parsedQueryString) {
+ var repeatedKey = false
+ for (var key in parsedQueryString) {
+ var value = parsedQueryString[key]
+ if (Array.isArray(value)) {
+ repeatedKey = true
+ }
+ }
+
+ var dataString
+ if (repeatedKey) {
+ dataString = 'data = [\n'
+ for (key in parsedQueryString) {
+ value = parsedQueryString[key]
+ if (Array.isArray(value)) {
+ for (var i = 0; i < value.length; i++) {
+ dataString += ' (' + repr(key) + ', ' + repr(value[i]) + '),\n'
+ }
+ } else {
+ dataString += ' (' + repr(key) + ', ' + repr(value) + '),\n'
+ }
+ }
+ dataString += ']\n'
+ } else {
+ dataString = 'data = [\n'
+ for (key in parsedQueryString) {
+ value = parsedQueryString[key]
+ dataString += ' (' + repr(key) + ', ' + repr(value) + '),\n'
+ }
+ dataString += ']\n'
+ }
+
+ return dataString
+}
+
+function getFilesString (request) {
+ // http://docs.python-requests.org/en/master/user/quickstart/#post-a-multipart-encoded-file
+ var filesString = 'files = [\n'
+ for (var multipartKey in request.multipartUploads) {
+ var multipartValue = request.multipartUploads[multipartKey]
+ if (multipartValue.startsWith('@')) {
+ filesString += ' (' + repr(multipartKey) + ', open(' + repr(multipartValue.slice(1)) + ", 'rb')),\n"
+ } else {
+ filesString += ' (' + repr(multipartKey) + ', ' + repr(multipartValue) + '),\n'
+ }
+ }
+ filesString += ']\n'
+
+ return filesString
+}
+
var toPython = function (curlCommand) {
var request = util.parseCurlCommand(curlCommand)
var cookieDict
if (request.cookies) {
cookieDict = 'cookies = {\n'
for (var cookieName in request.cookies) {
- cookieDict += " '" + cookieName + "': '" + request.cookies[cookieName] + "',\n"
+ cookieDict += ' ' + repr(cookieName) + ': ' + repr(request.cookies[cookieName]) + ',\n'
}
cookieDict += '}\n'
}
@@ -27,114 +115,22 @@ var toPython = function (curlCommand) {
if (request.headers) {
headerDict = 'headers = {\n'
for (var headerName in request.headers) {
- headerDict += " '" + headerName + "': '" + request.headers[headerName] + "',\n"
+ headerDict += ' ' + repr(headerName) + ': ' + repr(request.headers[headerName]) + ',\n'
}
headerDict += '}\n'
}
var queryDict
if (request.query) {
- queryDict = 'params = (\n'
- for (var paramName in request.query) {
- var rawValue = request.query[paramName]
- var paramValue
- if (Array.isArray(rawValue)) {
- paramValue = rawValue.map(pythonReprString).join(', ')
- } else {
- paramValue = pythonReprString(rawValue)
- }
- queryDict += ' (' + pythonReprString(paramName) + ', ' + paramValue + '),\n'
- }
- queryDict += ')\n'
+ queryDict = getQueryDict(request)
}
var dataString
var filesString
if (request.data) {
- if (request.data.startsWith('@')) {
- var filePath = request.data.slice(1)
- if (request.isDataBinary) {
- dataString = 'data = open(\'' + filePath + '\', \'rb\').read()'
- } else {
- dataString = 'data = open(\'' + filePath + '\')'
- }
- } else {
- var escapedData = request.data.replace(/'/g, "\\'")
- if (escapedData.indexOf("'") > -1) {
- escapedData = jsesc(request.data)
- }
- var parsedQueryString = querystring.parse(escapedData)
- var keyCount = Object.keys(parsedQueryString).length
- if (request.isDataBinary) {
- dataString = "data = '" + request.data + "'\n"
- } else if (keyCount === 1 && !parsedQueryString[Object.keys(parsedQueryString)[0]]) {
- dataString = "data = '" + request.data + "'\n"
- } else {
- var dataIndex = 0
- var repeatedKey = false
- var valueCount = 0
- for (var key in parsedQueryString) {
- var value = parsedQueryString[key]
- if (Array.isArray(value)) {
- repeatedKey = true
- valueCount += value.length
- } else {
- valueCount++
- }
- }
- if (repeatedKey) {
- dataString = 'data = [\n'
- for (key in parsedQueryString) {
- value = parsedQueryString[key]
- if (Array.isArray(value)) {
- for (var i = 0; i < value.length; i++) {
- dataString += " ('" + key + "', '" + value[i] + "')"
- if (dataIndex < valueCount - 1) {
- dataString += ',\n'
- }
- dataIndex++
- }
- } else {
- dataString += " ('" + key + "', '" + value + "')"
- if (dataIndex < keyCount - 1) {
- dataString += ',\n'
- }
- dataIndex++
- }
- }
- dataString += '\n]\n'
- } else {
- dataString = 'data = {\n'
- for (key in parsedQueryString) {
- value = parsedQueryString[key]
- dataString += " '" + key + "': '" + value + "'"
- if (dataIndex < keyCount - 1) {
- dataString += ',\n'
- }
- dataIndex++
- }
- dataString += '\n}\n'
- }
- }
- }
+ dataString = getDataString(request)
} else if (request.multipartUploads) {
- // http://docs.python-requests.org/en/master/user/quickstart/#post-a-multipart-encoded-file
- filesString = 'files = {\n'
- var filesIndex = 0
- var filesCount = Object.keys(request.multipartUploads).length
- for (var multipartKey in request.multipartUploads) {
- var multipartValue = request.multipartUploads[multipartKey]
- if (multipartValue.startsWith('@')) {
- filesString += " '" + multipartKey + "': open('" + multipartValue.slice(1) + "', 'rb')"
- } else {
- filesString += " '" + multipartKey + "': '" + multipartValue + "'"
- }
- if (filesIndex < filesCount - 1) {
- filesString += ',\n'
- }
- filesIndex++
- }
- filesString += '\n}\n'
+ filesString = getFilesString(request)
}
var requestLineWithUrlParams = 'requests.' + request.method + '(\'' + request.urlWithoutQuery + '\''
@@ -162,7 +158,7 @@ var toPython = function (curlCommand) {
var splitAuth = request.auth.split(':')
var user = splitAuth[0] || ''
var password = splitAuth[1] || ''
- requestLineBody += ", auth=('" + user + "', '" + password + "')"
+ requestLineBody += ', auth=(' + repr(user) + ', ' + repr(password) + ')'
}
requestLineBody += ')'
diff --git a/util.js b/util.js
index 00f27c5..25e1b4f 100644
--- a/util.js
+++ b/util.js
@@ -31,8 +31,8 @@ var parseCurlCommand = function (curlCommand) {
var cookieString
var cookies
var url = parsedArguments._[1]
- // if url argument wasn't where we expected it, check other places
- // it shows up
+ // if url argument wasn't where we expected it, check other places
+ // it shows up
if (!url && parsedArguments['L']) {
url = parsedArguments['L']
}
@@ -63,7 +63,7 @@ var parseCurlCommand = function (curlCommand) {
parsedArguments.F = [parsedArguments.F]
}
parsedArguments.F.forEach(function (multipartArgument) {
- // input looks like key=value. value could be json or a file path prepended with an @
+ // input looks like key=value. value could be json or a file path prepended with an @
var splitArguments = multipartArgument.split('=', 2)
var key = splitArguments[0]
var value = splitArguments[1]