Skip to content

Instantly share code, notes, and snippets.

@orientalperil
Forked from kazqvaizer/multipartify.py
Created April 16, 2021 15:39
Show Gist options
  • Select an option

  • Save orientalperil/f96239e63c1e13e373931dbb5b9f59da to your computer and use it in GitHub Desktop.

Select an option

Save orientalperil/f96239e63c1e13e373931dbb5b9f59da to your computer and use it in GitHub Desktop.
Python dict to multipart/form-data converter to use it requests
"""
Here is a way to flatten python dictionaries for making multipart/form-data POST requests.
{"some": ["balls", "toys"], "field": "value", "nested": {"objects": "here"}}
->
{"some[0]": "balls", "some[1]": "toys", "field": "value", "nested[objects]": "here"}
"""
def multipartify(data, parent_key=None, formatter: callable = None) -> dict:
if formatter is None:
formatter = lambda v: (None, v) # Multipart representation of value
if type(data) is not dict:
return {parent_key: formatter(data)}
converted = []
for key, value in data.items():
current_key = key if parent_key is None else f"{parent_key}[{key}]"
if type(value) is dict:
converted.extend(multipartify(value, current_key, formatter).items())
elif type(value) is list:
for ind, list_value in enumerate(value):
iter_key = f"{current_key}[{ind}]"
converted.extend(multipartify(list_value, iter_key, formatter).items())
else:
converted.append((current_key, formatter(value)))
return dict(converted)
"""
Usage examples with `requests` library:
"""
import requests
payload = {
"person": {"name": "John", "age": "31"},
"pets": ["Dog", "Parrot"],
"special_mark": 42,
}
requests.post("https://example.com/", files=multipartify(payload))
# Feel free to add some files to this (depends on endpoint configuration)
converted_data = multipartify(payload)
converted_data["attachment[0]"] = ("file.png", b'binary-file', "image/png")
requests.post("https://example.com/", files=converted_data)
"""
Pytests for Multipartify method.
"""
import pytest
@pytest.mark.parametrize(
"incoming, converted",
(
({"a": "b"}, {"a": "b"}),
({"a": {"Not", "serializable", "set"}}, {"a": {"Not", "serializable", "set"}}),
({"a": {"b1": "c", "b2": "d"}}, {"a[b1]": "c", "a[b2]": "d"}),
({"a": {"b": {"c": "d"}}}, {"a[b][c]": "d"}),
({"a": ["c", "e"]}, {"a[0]": "c", "a[1]": "e"}),
({"a": [{"b": "c"}, {"d": "e"}]}, {"a[0][b]": "c", "a[1][d]": "e"}),
({}, {}),
),
)
def test(incoming, converted):
assert multipartify(incoming, formatter=lambda v: v) == converted
def test_default_formatter():
assert multipartify({"a": "b"}) == {"a": (None, "b")}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment