From 39d6773fda989efac4c3a032a9184953e5300a1f Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Thu, 15 Oct 2020 17:40:48 -0700 Subject: [PATCH 1/3] feat: cleaner python json snippets --- src/targets/python/helpers.js | 79 +++++++++++++++++++ src/targets/python/requests.js | 43 +++++++--- .../requests/application-form-encoded.py | 2 +- .../python/requests/application-json.py | 13 ++- .../output/python/requests/cookies.py | 2 +- test/fixtures/output/python/requests/full.py | 8 +- .../output/python/requests/headers.py | 6 +- .../python/requests/jsonObj-multiline.py | 6 +- .../python/requests/jsonObj-null-value.py | 6 +- .../output/python/requests/multipart-data.py | 2 +- .../output/python/requests/multipart-file.py | 2 +- .../python/requests/multipart-form-data.py | 2 +- .../output/python/requests/text-plain.py | 2 +- 13 files changed, 140 insertions(+), 33 deletions(-) create mode 100644 src/targets/python/helpers.js diff --git a/src/targets/python/helpers.js b/src/targets/python/helpers.js new file mode 100644 index 000000000..dfbd3f352 --- /dev/null +++ b/src/targets/python/helpers.js @@ -0,0 +1,79 @@ +'use strict' + +var util = require('util') + +/** + * Create an string of given length filled with blank spaces + * + * @param {number} length Length of the array to return + * @return {string} + */ +function buildString (length, str) { + return Array.apply(null, new Array(length)).map(String.prototype.valueOf, str).join('') +} + +/** + * Create a string corresponding to a Dictionary or Array literal representation with pretty option + * and indentation. + */ +function concatValues (concatType, values, pretty, indentation, indentLevel) { + var currentIndent = buildString(indentLevel, indentation) + var closingBraceIndent = buildString(indentLevel - 1, indentation) + var join = pretty ? ',\n' + currentIndent : ', ' + var openingBrace = concatType === 'object' ? '{' : '[' + var closingBrace = concatType === 'object' ? '}' : ']' + + if (pretty) { + return openingBrace + '\n' + currentIndent + values.join(join) + '\n' + closingBraceIndent + closingBrace + } else { + return openingBrace + values.join(join) + closingBrace + } +} + +module.exports = { + /** + * Create a valid Python string of a literal value according to its type. + * + * @param {*} value Any JavaScript literal + * @param {Object} opts Target options + * @return {string} + */ + literalRepresentation: function (value, opts, indentLevel) { + indentLevel = indentLevel === undefined ? 1 : indentLevel + 1 + + switch (Object.prototype.toString.call(value)) { + case '[object Number]': + return value + + case '[object Array]': + var pretty = false + var valuesRepresentation = value.map(function (v) { + // Switch to prettify if the value is a dictionary with multiple keys + if (Object.prototype.toString.call(v) === '[object Object]') { + pretty = Object.keys(v).length > 1 + } + return this.literalRepresentation(v, opts, indentLevel) + }.bind(this)) + return concatValues('array', valuesRepresentation, pretty, opts.indent, indentLevel) + + case '[object Object]': + var keyValuePairs = [] + for (var k in value) { + keyValuePairs.push(util.format('"%s": %s', k, this.literalRepresentation(value[k], opts, indentLevel))) + } + return concatValues('object', keyValuePairs, opts.pretty && keyValuePairs.length > 1, opts.indent, indentLevel) + + case '[object Null]': + return 'None' + + case '[object Boolean]': + return value ? 'True' : 'False' + + default: + if (value === null || value === undefined) { + return '' + } + return '"' + value.toString().replace(/"/g, '\\"') + '"' + } + } +} diff --git a/src/targets/python/requests.js b/src/targets/python/requests.js index 7adfc0ecb..c3f2dc9ce 100644 --- a/src/targets/python/requests.js +++ b/src/targets/python/requests.js @@ -12,8 +12,14 @@ var util = require('util') var CodeBuilder = require('../../helpers/code-builder') +var helpers = require('./helpers') module.exports = function (source, options) { + var opts = Object.assign({ + indent: ' ', + pretty: true + }, options) + // Start snippet var code = new CodeBuilder(' ') @@ -34,10 +40,23 @@ module.exports = function (source, options) { } // Construct payload - var payload = JSON.stringify(source.postData.text) + let hasPayload = false + let jsonPayload = false + switch (source.postData.mimeType) { + case 'application/json': + if (source.postData.jsonObj) { + code.push('payload = %s', helpers.literalRepresentation(source.postData.jsonObj, opts)) + jsonPayload = true + hasPayload = true + } + break - if (payload) { - code.push('payload = %s', payload) + default: + var payload = JSON.stringify(source.postData.text) + if (payload) { + code.push('payload = %s', payload) + hasPayload = true + } } // Construct headers @@ -47,7 +66,7 @@ module.exports = function (source, options) { if (headerCount === 1) { for (header in headers) { - code.push('headers = {\'%s\': \'%s\'}', header, headers[header]) + code.push('headers = {"%s": "%s"}', header, headers[header]) .blank() } } else if (headerCount > 1) { @@ -57,13 +76,13 @@ module.exports = function (source, options) { for (header in headers) { if (count++ !== headerCount) { - code.push(1, '\'%s\': "%s",', header, headers[header]) + code.push(1, '"%s": "%s",', header, headers[header]) } else { - code.push(1, '\'%s\': "%s"', header, headers[header]) + code.push(1, '"%s": "%s"', header, headers[header]) } } - code.push(1, '}') + code.push('}') .blank() } @@ -71,8 +90,12 @@ module.exports = function (source, options) { var method = source.method var request = util.format('response = requests.request("%s", url', method) - if (payload) { - request += ', data=payload' + if (hasPayload) { + if (jsonPayload) { + request += ', json=payload' + } else { + request += ', data=payload' + } } if (headerCount > 0) { @@ -100,5 +123,3 @@ module.exports.info = { link: 'http://docs.python-requests.org/en/latest/api/#requests.request', description: 'Requests HTTP library' } - -// response = requests.request("POST", url, data=payload, headers=headers, params=querystring) diff --git a/test/fixtures/output/python/requests/application-form-encoded.py b/test/fixtures/output/python/requests/application-form-encoded.py index 54556d0f1..308126b0e 100644 --- a/test/fixtures/output/python/requests/application-form-encoded.py +++ b/test/fixtures/output/python/requests/application-form-encoded.py @@ -3,7 +3,7 @@ url = "http://mockbin.com/har" payload = "foo=bar&hello=world" -headers = {'content-type': 'application/x-www-form-urlencoded'} +headers = {"content-type": "application/x-www-form-urlencoded"} response = requests.request("POST", url, data=payload, headers=headers) diff --git a/test/fixtures/output/python/requests/application-json.py b/test/fixtures/output/python/requests/application-json.py index a60dcd215..cfb2c4830 100644 --- a/test/fixtures/output/python/requests/application-json.py +++ b/test/fixtures/output/python/requests/application-json.py @@ -2,9 +2,16 @@ url = "http://mockbin.com/har" -payload = "{\"number\":1,\"string\":\"f\\\"oo\",\"arr\":[1,2,3],\"nested\":{\"a\":\"b\"},\"arr_mix\":[1,\"a\",{\"arr_mix_nested\":{}}],\"boolean\":false}" -headers = {'content-type': 'application/json'} +payload = { + "number": 1, + "string": "f\"oo", + "arr": [1, 2, 3], + "nested": {"a": "b"}, + "arr_mix": [1, "a", {"arr_mix_nested": {}}], + "boolean": False +} +headers = {"content-type": "application/json"} -response = requests.request("POST", url, data=payload, headers=headers) +response = requests.request("POST", url, json=payload, headers=headers) print(response.text) diff --git a/test/fixtures/output/python/requests/cookies.py b/test/fixtures/output/python/requests/cookies.py index 96977a509..3387a1d8f 100644 --- a/test/fixtures/output/python/requests/cookies.py +++ b/test/fixtures/output/python/requests/cookies.py @@ -2,7 +2,7 @@ url = "http://mockbin.com/har" -headers = {'cookie': 'foo=bar; bar=baz'} +headers = {"cookie": "foo=bar; bar=baz"} response = requests.request("POST", url, headers=headers) diff --git a/test/fixtures/output/python/requests/full.py b/test/fixtures/output/python/requests/full.py index 621d12a22..82b97e3c9 100644 --- a/test/fixtures/output/python/requests/full.py +++ b/test/fixtures/output/python/requests/full.py @@ -6,10 +6,10 @@ payload = "foo=bar" headers = { - 'cookie': "foo=bar; bar=baz", - 'accept': "application/json", - 'content-type': "application/x-www-form-urlencoded" - } + "cookie": "foo=bar; bar=baz", + "accept": "application/json", + "content-type": "application/x-www-form-urlencoded" +} response = requests.request("POST", url, data=payload, headers=headers, params=querystring) diff --git a/test/fixtures/output/python/requests/headers.py b/test/fixtures/output/python/requests/headers.py index 847323fb6..ae2b4d047 100644 --- a/test/fixtures/output/python/requests/headers.py +++ b/test/fixtures/output/python/requests/headers.py @@ -3,9 +3,9 @@ url = "http://mockbin.com/har" headers = { - 'accept': "application/json", - 'x-foo': "Bar" - } + "accept": "application/json", + "x-foo": "Bar" +} response = requests.request("GET", url, headers=headers) diff --git a/test/fixtures/output/python/requests/jsonObj-multiline.py b/test/fixtures/output/python/requests/jsonObj-multiline.py index 49d6071fc..60eb971ac 100644 --- a/test/fixtures/output/python/requests/jsonObj-multiline.py +++ b/test/fixtures/output/python/requests/jsonObj-multiline.py @@ -2,9 +2,9 @@ url = "http://mockbin.com/har" -payload = "{\n \"foo\": \"bar\"\n}" -headers = {'content-type': 'application/json'} +payload = {"foo": "bar"} +headers = {"content-type": "application/json"} -response = requests.request("POST", url, data=payload, headers=headers) +response = requests.request("POST", url, json=payload, headers=headers) print(response.text) diff --git a/test/fixtures/output/python/requests/jsonObj-null-value.py b/test/fixtures/output/python/requests/jsonObj-null-value.py index 99d3a6bcc..9a9f79937 100644 --- a/test/fixtures/output/python/requests/jsonObj-null-value.py +++ b/test/fixtures/output/python/requests/jsonObj-null-value.py @@ -2,9 +2,9 @@ url = "http://mockbin.com/har" -payload = "{\"foo\":null}" -headers = {'content-type': 'application/json'} +payload = {"foo": None} +headers = {"content-type": "application/json"} -response = requests.request("POST", url, data=payload, headers=headers) +response = requests.request("POST", url, json=payload, headers=headers) print(response.text) diff --git a/test/fixtures/output/python/requests/multipart-data.py b/test/fixtures/output/python/requests/multipart-data.py index 4b9cc5c81..9760d47b5 100644 --- a/test/fixtures/output/python/requests/multipart-data.py +++ b/test/fixtures/output/python/requests/multipart-data.py @@ -3,7 +3,7 @@ url = "http://mockbin.com/har" payload = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\nHello World\r\n-----011000010111000001101001--\r\n" -headers = {'content-type': 'multipart/form-data; boundary=---011000010111000001101001'} +headers = {"content-type": "multipart/form-data; boundary=---011000010111000001101001"} response = requests.request("POST", url, data=payload, headers=headers) diff --git a/test/fixtures/output/python/requests/multipart-file.py b/test/fixtures/output/python/requests/multipart-file.py index 5c3188b84..be3bde71a 100644 --- a/test/fixtures/output/python/requests/multipart-file.py +++ b/test/fixtures/output/python/requests/multipart-file.py @@ -3,7 +3,7 @@ url = "http://mockbin.com/har" payload = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\n\r\n-----011000010111000001101001--\r\n" -headers = {'content-type': 'multipart/form-data; boundary=---011000010111000001101001'} +headers = {"content-type": "multipart/form-data; boundary=---011000010111000001101001"} response = requests.request("POST", url, data=payload, headers=headers) diff --git a/test/fixtures/output/python/requests/multipart-form-data.py b/test/fixtures/output/python/requests/multipart-form-data.py index 77bbb3438..6dcb650e7 100644 --- a/test/fixtures/output/python/requests/multipart-form-data.py +++ b/test/fixtures/output/python/requests/multipart-form-data.py @@ -3,7 +3,7 @@ url = "http://mockbin.com/har" payload = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n" -headers = {'content-type': 'multipart/form-data; boundary=---011000010111000001101001'} +headers = {"content-type": "multipart/form-data; boundary=---011000010111000001101001"} response = requests.request("POST", url, data=payload, headers=headers) diff --git a/test/fixtures/output/python/requests/text-plain.py b/test/fixtures/output/python/requests/text-plain.py index ba42964e3..fda6ebba1 100644 --- a/test/fixtures/output/python/requests/text-plain.py +++ b/test/fixtures/output/python/requests/text-plain.py @@ -3,7 +3,7 @@ url = "http://mockbin.com/har" payload = "Hello World" -headers = {'content-type': 'text/plain'} +headers = {"content-type": "text/plain"} response = requests.request("POST", url, data=payload, headers=headers) From d097f9424fd5289aa49767a5d8fb51e759e08a7e Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Wed, 21 Oct 2020 14:14:44 -0700 Subject: [PATCH 2/3] docs: updating a method docblock --- src/targets/python/helpers.js | 2 +- src/targets/swift/helpers.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/targets/python/helpers.js b/src/targets/python/helpers.js index dfbd3f352..ebf53042d 100644 --- a/src/targets/python/helpers.js +++ b/src/targets/python/helpers.js @@ -6,7 +6,7 @@ var util = require('util') * Create an string of given length filled with blank spaces * * @param {number} length Length of the array to return - * @return {string} + * @param {string} str String to pad out with */ function buildString (length, str) { return Array.apply(null, new Array(length)).map(String.prototype.valueOf, str).join('') diff --git a/src/targets/swift/helpers.js b/src/targets/swift/helpers.js index fdc26fd82..04c0b0d97 100644 --- a/src/targets/swift/helpers.js +++ b/src/targets/swift/helpers.js @@ -6,6 +6,7 @@ var util = require('util') * Create an string of given length filled with blank spaces * * @param {number} length Length of the array to return + * @param {string} str String to pad out with * @return {string} */ function buildString (length, str) { From 78d89029c33130328ab8ee1fe54fcd6966ecb35d Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Tue, 1 Dec 2020 11:31:33 -0800 Subject: [PATCH 3/3] test: fixing a broken test --- test/fixtures/output/python/requests/multipart-form-data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/output/python/requests/multipart-form-data.py b/test/fixtures/output/python/requests/multipart-form-data.py index 53f598512..978e19b03 100644 --- a/test/fixtures/output/python/requests/multipart-form-data.py +++ b/test/fixtures/output/python/requests/multipart-form-data.py @@ -3,7 +3,7 @@ url = "http://mockbin.com/har" payload = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n" -headers = {'Content-Type': 'multipart/form-data; boundary=---011000010111000001101001'} +headers = {"Content-Type": "multipart/form-data; boundary=---011000010111000001101001"} response = requests.request("POST", url, data=payload, headers=headers)