Reformat and cleanup code.

This commit is contained in:
Fabio Caccamo 2023-02-09 19:19:02 +01:00
parent f70d733c24
commit dc29f17aec
40 changed files with 102 additions and 261 deletions

View File

@ -204,9 +204,7 @@ class benedict(KeypathDict, IODict, ParseDict):
"""
_move(self, key_src, key_dest)
def nest(
self, key, id_key="id", parent_id_key="parent_id", children_key="children"
):
def nest(self, key, id_key="id", parent_id_key="parent_id", children_key="children"):
"""
Nest a list of dicts at the given key and return a new nested list
using the specified keys to establish the correct items hierarchy.

View File

@ -121,7 +121,7 @@ def read_content_from_url(url, requests_options, format=None):
binary_format = is_binary_format(format)
if binary_format:
dirpath = tempfile.gettempdir()
filepath = fsutil.download_file(url, dirpath, **requests_options)
filepath = fsutil.download_file(url, dirpath=dirpath, **requests_options)
return filepath
return fsutil.read_file_from_url(url, **requests_options)

View File

@ -31,18 +31,12 @@ class ParseDict(BaseDict):
return default
# If choices and value in choices return value otherwise default.
if (
type_util.is_list_or_tuple(choices)
and len(choices)
and value not in choices
):
if type_util.is_list_or_tuple(choices) and len(choices) and value not in choices:
return default
return value
def _get_values_list(
self, key, default, separator, parser_func, parser_kwargs=None
):
def _get_values_list(self, key, default, separator, parser_func, parser_kwargs=None):
"""
Get value by key or keypath trying to return it as list of bool values.
If separator is specified and value is a string it will be splitted.

View File

@ -1,4 +0,0 @@
import unittest
if __name__ == "__main__":
unittest.main()

View File

@ -1,6 +1,5 @@
import datetime as dt
import unittest
from decimal import Decimal
from benedict.core import dump as _dump
@ -69,4 +68,4 @@ class dump_test_case(unittest.TestCase):
_dump(d)
d["dt"] = dt
with self.assertRaises(TypeError):
o = _dump(d, sort_keys=False, default=None)
_dump(d, sort_keys=False, default=None)

View File

@ -18,7 +18,7 @@ class filter_test_case(unittest.TestCase):
"g": 7,
}
with self.assertRaises(ValueError):
f = _filter(i, True)
_filter(i, True)
o = _filter(i, lambda key, val: isinstance(val, int))
r = {
"a": 1,

View File

@ -70,7 +70,7 @@ class flatten_test_case(unittest.TestCase):
},
}
with self.assertRaises(KeyError):
o = _flatten(i)
_ = _flatten(i)
# r = {
# 'a': 1,
# 'b': 2,

View File

@ -10,7 +10,7 @@ class groupby_test_case(unittest.TestCase):
"""
def test_groupby(self):
l = [
ls = [
{"id": 1, "name": "John"},
{"id": 2, "name": "Frank"},
{"id": 3, "name": "Tony"},
@ -21,9 +21,9 @@ class groupby_test_case(unittest.TestCase):
{"id": 4, "name": "Paul"},
{"id": 1, "name": "Michael"},
]
l_clone = _clone(l)
d = _groupby(l, "id")
self.assertEqual(l, l_clone)
ls_clone = _clone(ls)
d = _groupby(ls, "id")
self.assertEqual(ls, ls_clone)
self.assertTrue(isinstance(d, dict))
self.assertEqual(len(d), 4)
self.assertTrue(
@ -52,12 +52,12 @@ class groupby_test_case(unittest.TestCase):
self.assertEqual(len(d[4]), 2)
def test_groupby_with_wrong_input(self):
l = {"id": 1, "name": "John"}
ls = {"id": 1, "name": "John"}
with self.assertRaises(ValueError):
d = _groupby(l, "id")
l = [
_ = _groupby(ls, "id")
ls = [
[{"id": 1, "name": "John"}],
[{"id": 2, "name": "Frank"}],
]
with self.assertRaises(ValueError):
d = _groupby(l, "id")
_ = _groupby(ls, "id")

View File

@ -77,7 +77,7 @@ class keypaths_test_case(unittest.TestCase):
},
}
with self.assertRaises(ValueError):
o = _keypaths(i, separator=True)
_ = _keypaths(i, separator=True)
def test_keypaths_without_separator(self):
i = {

View File

@ -58,4 +58,4 @@ class match_test_case(unittest.TestCase):
def test_match_with_invalid_pattern(self):
d = self._get_dict()
with self.assertRaises(ValueError):
values = _match(d, 100)
_ = _match(d, 100)

View File

@ -10,7 +10,7 @@ class nest_test_case(unittest.TestCase):
"""
def test_nest(self):
l = [
ls = [
{"id": 1, "parent_id": None, "name": "John"},
{"id": 2, "parent_id": 1, "name": "Frank"},
{"id": 3, "parent_id": 2, "name": "Tony"},
@ -21,8 +21,8 @@ class nest_test_case(unittest.TestCase):
{"id": 8, "parent_id": 3, "name": "Paul"},
{"id": 9, "parent_id": None, "name": "Michael"},
]
l_clone = _clone(l)
n = _nest(l, "id", "parent_id", "children")
ls_clone = _clone(ls)
n = _nest(ls, "id", "parent_id", "children")
r = [
{
"id": 1,
@ -82,11 +82,11 @@ class nest_test_case(unittest.TestCase):
"children": [],
},
]
self.assertEqual(l, l_clone)
self.assertEqual(ls, ls_clone)
self.assertEqual(n, r)
def test_nest_with_wrong_keys(self):
l = [
ls = [
{"id": 1, "parent_id": None, "name": "John"},
{"id": 2, "parent_id": 1, "name": "Frank"},
{"id": 3, "parent_id": 2, "name": "Tony"},
@ -98,19 +98,19 @@ class nest_test_case(unittest.TestCase):
{"id": 9, "parent_id": None, "name": "Michael"},
]
with self.assertRaises(ValueError):
n = _nest(l, "id", "id", "children")
_ = _nest(ls, "id", "id", "children")
with self.assertRaises(ValueError):
n = _nest(l, "id", "parent_id", "id")
_ = _nest(ls, "id", "parent_id", "id")
with self.assertRaises(ValueError):
n = _nest(l, "id", "parent_id", "parent_id")
_ = _nest(ls, "id", "parent_id", "parent_id")
def test_nest_with_wrong_input(self):
l = {"id": 1, "parent_id": None, "name": "John"}
ls = {"id": 1, "parent_id": None, "name": "John"}
with self.assertRaises(ValueError):
d = _nest(l, "id", "parent_id", "children")
l = [
_ = _nest(ls, "id", "parent_id", "children")
ls = [
[{"id": 1, "parent_id": None, "name": "John"}],
[{"id": 2, "parent_id": 1, "name": "Frank"}],
]
with self.assertRaises(ValueError):
d = _nest(l, "id", "parent_id", "children")
_ = _nest(ls, "id", "parent_id", "children")

View File

@ -1,5 +1,4 @@
import copy
import sys
import unittest
from collections.abc import Iterable
@ -224,17 +223,6 @@ class base_dict_test_case(unittest.TestCase):
self.assertEqual(str(d), str(b))
self.assertEqual(b, b.dict())
@unittest.skipIf(sys.version_info[0] > 2, "No unicode in Python 3")
def test__unicode__(self):
d = BaseDict()
d["name"] = "pythòn-bènèdìçt"
# print(unicode(d))
@unittest.skipIf(sys.version_info[0] > 2, "No unicode in Python > 2")
def test__unicode__with_pointer(self):
d = BaseDict({"name": "pythòn-bènèdìçt"})
# print(unicode(d))
def test_clear(self):
d = {
"a": 1,

View File

@ -45,4 +45,4 @@ class io_dict_test_case(unittest.TestCase):
def test_init_with_invalid_data(self):
with self.assertRaises(ValueError):
d = IODict("invalid json data")
_ = IODict("invalid json data")

View File

@ -354,7 +354,7 @@ class io_dict_csv_test_case(io_dict_test_case):
}
)
with self.assertRaises(KeyError):
s = d.to_csv(
_ = d.to_csv(
"invalid_values", columns=["id", "name", "age", "height", "weight"]
)

View File

@ -76,7 +76,7 @@ ForwardX11 = no
def test_from_ini_with_valid_file_valid_content_invalid_format(self):
filepath = self.input_path("valid-content.base64")
with self.assertRaises(ValueError):
d = IODict.from_ini(filepath)
IODict.from_ini(filepath)
filepath = self.input_path("valid-content.json")
with self.assertRaises(ValueError):
IODict.from_ini(filepath)

View File

@ -1,5 +1,4 @@
import datetime as dt
import plistlib
from benedict.dicts.io import IODict

View File

@ -113,13 +113,6 @@ class io_dict_query_string_test_case(io_dict_test_case):
IODict(url, format="query_string")
def test_to_query_string(self):
data = {
"ok": "1",
"test": "2",
"page": "3",
"lib": "python benedict",
"author": "Fabio Caccamo",
}
d = IODict(
{
"ok": "1",

View File

@ -179,8 +179,7 @@ class keypath_dict_test_case(unittest.TestCase):
}
b = KeypathDict(d)
with self.assertRaises(KeyError):
val = b["b"]
# print(val)
_ = b["b"]
def test_getitem_with_1_not_str_key(self):
d = {
@ -192,8 +191,7 @@ class keypath_dict_test_case(unittest.TestCase):
self.assertEqual(b[None], None)
self.assertEqual(b[False], False)
with self.assertRaises(KeyError):
val = b[True]
# print(val)
_ = b[True]
self.assertEqual(b[0], 0)
@ -232,8 +230,7 @@ class keypath_dict_test_case(unittest.TestCase):
}
b = KeypathDict(d)
with self.assertRaises(KeyError):
val = b["b.a"]
# print(val)
_ = b["b.a"]
def test_get_with_3_valid_keys(self):
d = {
@ -325,8 +322,7 @@ class keypath_dict_test_case(unittest.TestCase):
}
b = KeypathDict(d)
with self.assertRaises(KeyError):
val = b["c.b.a"]
# print(val)
_ = b["c.b.a"]
def test_get_item_with_keys_list(self):
d = {
@ -348,8 +344,7 @@ class keypath_dict_test_case(unittest.TestCase):
self.assertEqual(b[["a", "b", "d"]], 2)
self.assertEqual(b[("a", "b", "d")], 2)
with self.assertRaises(KeyError):
val = b["a", "b", "e"]
# print(val)
_ = b["a", "b", "e"]
def test_get_item_with_keys_list_and_no_keypath_separator(self):
d = {
@ -362,8 +357,8 @@ class keypath_dict_test_case(unittest.TestCase):
}
b = KeypathDict(d, keypath_separator=None)
with self.assertRaises(KeyError):
val = b["a", "b.c"]
# print(val)
_ = b["a", "b.c"]
self.assertEqual(b["a", "b", "c"], 1)
self.assertEqual(b[["a", "b", "c"]], 1)
self.assertEqual(b[("a", "b", "c")], 1)
@ -371,8 +366,7 @@ class keypath_dict_test_case(unittest.TestCase):
self.assertEqual(b[["a", "b", "d"]], 2)
self.assertEqual(b[("a", "b", "d")], 2)
with self.assertRaises(KeyError):
val = b["a", "b", "e"]
# print(val)
_ = b["a", "b", "e"]
def test_has_with_1_key(self):
d = {
@ -543,20 +537,17 @@ class keypath_dict_test_case(unittest.TestCase):
b = KeypathDict(d, keypath_separator=None)
b["a", "b", "c"] = 3
with self.assertRaises(KeyError):
val = b["a.b.c"]
# print(val)
_ = b["a.b.c"]
self.assertEqual(b["a", "b", "c"], 3)
b["a", "b", "d"] = 4
with self.assertRaises(KeyError):
val = b["a.b.d"]
# print(val)
_ = b["a.b.d"]
self.assertEqual(b["a", "b", "d"], 4)
b["a", "b", "e"] = 5
with self.assertRaises(KeyError):
val = b["a.b.e"]
# print(val)
_ = b["a.b.e"]
self.assertEqual(b["a", "b", "e"], 5)
def test_setitem_with_dict_value_with_separator_in_keys(self):
@ -743,7 +734,7 @@ class keypath_dict_test_case(unittest.TestCase):
val = b.pop("a")
with self.assertRaises(KeyError):
val = b.pop("a")
_ = b.pop("a")
self.assertEqual(val, {})
def test_pop_with_2_invalid_keys(self):
@ -757,13 +748,13 @@ class keypath_dict_test_case(unittest.TestCase):
val = b.pop("a.c", 2)
self.assertEqual(val, 2)
with self.assertRaises(KeyError):
val = b.pop("a.c")
_ = b.pop("a.c")
self.assertEqual(b.get("a"), {"b": 1})
val = b.pop("x.y", 1)
self.assertEqual(val, 1)
with self.assertRaises(KeyError):
val = b.pop("x.y")
_ = b.pop("x.y")
def test_pop_with_keys_list(self):
d = {
@ -776,13 +767,13 @@ class keypath_dict_test_case(unittest.TestCase):
val = b.pop(["a", "c"], 2)
self.assertEqual(val, 2)
with self.assertRaises(KeyError):
val = b.pop(["a", "c"])
_ = b.pop(["a", "c"])
self.assertEqual(b.get("a"), {"b": 1})
val = b.pop(["x", "y"], 1)
self.assertEqual(val, 1)
with self.assertRaises(KeyError):
val = b.pop(["x", "y"])
_ = b.pop(["x", "y"])
val = b.pop(["a", "b"])
self.assertEqual(val, 1)
@ -798,13 +789,13 @@ class keypath_dict_test_case(unittest.TestCase):
val = b.pop(["a", "c"], 2)
self.assertEqual(val, 2)
with self.assertRaises(KeyError):
val = b.pop(["a", "c"])
_ = b.pop(["a", "c"])
self.assertEqual(b.get("a"), {"b": 1})
val = b.pop(["x", "y"], 1)
self.assertEqual(val, 1)
with self.assertRaises(KeyError):
val = b.pop(["x", "y"])
_ = b.pop(["x", "y"])
val = b.pop(["a", "b"])
self.assertEqual(val, 1)

View File

@ -1,6 +1,5 @@
import unittest
from benedict.dicts.keylist import keylist_util
from benedict.dicts.keypath import keypath_util

View File

@ -55,7 +55,9 @@ class parse_util_test_case(unittest.TestCase):
pass
def test_parse_list(self):
f = lambda value: parse_util.parse_list(value, separator=",")
def f(value):
return parse_util.parse_list(value, separator=",")
self.assertEqual(
f(["0", "1", "2", "Hello World"]),
["0", "1", "2", "Hello World"],
@ -67,15 +69,21 @@ class parse_util_test_case(unittest.TestCase):
self.assertEqual(f(None), None)
def test_parse_list_with_valid_json(self):
f = lambda value: parse_util.parse_list(value, separator=None)
def f(value):
return parse_util.parse_list(value, separator=None)
self.assertEqual(f("[0,1,2,3]"), [0, 1, 2, 3])
def test_parse_list_with_invalid_json_with_separator(self):
f = lambda value: parse_util.parse_list(value, separator=",")
def f(value):
return parse_util.parse_list(value, separator=",")
self.assertEqual(f("[a,b,c]"), ["[a", "b", "c]"])
def test_parse_list_with_invalid_json_without_separator(self):
f = lambda value: parse_util.parse_list(value, separator=None)
def f(value):
return parse_util.parse_list(value, separator=None)
self.assertEqual(f("[a,b,c]"), None)
def test_parse_phonenumber(self):

View File

@ -370,7 +370,7 @@ class benedict_test_case(unittest.TestCase):
self.assertEqual(f, r)
self.assertTrue(isinstance(f, benedict))
def test_filter(self):
def test_find(self):
d = {
"a": 1,
"b": 2,
@ -477,7 +477,7 @@ class benedict_test_case(unittest.TestCase):
}
b = benedict(d)
with self.assertRaises(KeyError):
f = b.flatten()
_ = b.flatten()
# r = {
# 'a': 1,
# 'b': 2,
@ -910,16 +910,16 @@ b:
]
}
b = benedict(d)
l = b.get_list("a")
ls = b.get_list("a")
# self.assertTrue(isinstance(l[0], benedict))
# self.assertTrue(isinstance(l[1], benedict))
# self.assertTrue(isinstance(l[2], benedict))
# self.assertEqual(l[0].get('b.c'), 1)
# self.assertEqual(l[1].get('b.c'), 2)
# self.assertEqual(l[2].get('b.c'), 3)
self.assertEqual(benedict(l[0]).get("b.c"), 1)
self.assertEqual(benedict(l[1]).get("b.c"), 2)
self.assertEqual(benedict(l[2]).get("b.c"), 3)
self.assertEqual(benedict(ls[0]).get("b.c"), 1)
self.assertEqual(benedict(ls[1]).get("b.c"), 2)
self.assertEqual(benedict(ls[2]).get("b.c"), 3)
def test_get_list_item(self):
d = {

View File

@ -39,21 +39,23 @@ Outputs:
Value: !GetAtt LoremIpsum.Arn
"""
r = {
"AWSTemplateFormatVersion": "2010-09-09",
"Transform": "AWS::Serverless-2016-10-31",
"Outputs": {
"Description": "LoremIpsum Ex nisi incididunt occaecat dolor.",
"Value": GetAtt("LoremIpsum.Arn"),
},
}
# r = {
# "AWSTemplateFormatVersion": "2010-09-09",
# "Transform": "AWS::Serverless-2016-10-31",
# "Outputs": {
# "Description": "LoremIpsum Ex nisi incididunt occaecat dolor.",
# "Value": GetAtt("LoremIpsum.Arn"),
# },
# }
b = benedict(yaml_str, format="yaml")
# print(b.dump())
self.assertTrue(b["AWSTemplateFormatVersion"] == "2010-09-09")
self.assertTrue(b["Transform"] == "AWS::Serverless-2016-10-31")
self.assertTrue(
b["Outputs.Description"] == "LoremIpsum Ex nisi incididunt occaecat dolor."
self.assertEqual(b["AWSTemplateFormatVersion"], "2010-09-09")
self.assertEqual(b["Transform"], "AWS::Serverless-2016-10-31")
self.assertEqual(
b["Outputs.Description"], "LoremIpsum Ex nisi incididunt occaecat dolor."
)
self.assertTrue(isinstance(b["Outputs.Value"], GetAtt))
# self.assertEqual(b["Outputs.Value"], r["Outputs"]["Value"])
# self.assertEqual(b, r)

View File

@ -26,7 +26,7 @@ class github_issue_0039_test_case(unittest.TestCase):
# print(b.dump())
e = time.time() - t
# print(f'benedict set: {e} seconds')
# self.assertTrue(e < 5)
self.assertTrue(e < 10)
t = time.time()
for i in range(0, i_iterations):
@ -34,7 +34,7 @@ class github_issue_0039_test_case(unittest.TestCase):
b.get(f"{i}.{j}", None)
e = time.time() - t
# print(f'benedict get: {e} seconds')
# self.assertTrue(e < 5)
self.assertTrue(e < 10)
b.clear()
t = time.time()
@ -43,4 +43,4 @@ class github_issue_0039_test_case(unittest.TestCase):
b.get(f"{i}.{j}", None)
e = time.time() - t
# print(f'benedict get (default): {e} seconds')
# self.assertTrue(e < 5)
self.assertTrue(e < 10)

View File

@ -75,7 +75,9 @@ class github_issue_0046_test_case(unittest.TestCase):
# import json
# json.encoder.c_make_encoder = None
json_encoder = None
json_dumps = lambda d: json.dumps(d, sort_keys=True, cls=json_encoder)
def json_dumps(d):
return json.dumps(d, sort_keys=True, cls=json_encoder)
d_new_raw = {
"id": "37e4f6e876",

View File

@ -1,4 +1,3 @@
import json
import unittest
from benedict import benedict

View File

@ -72,7 +72,7 @@ class github_issue_0066_test_case(unittest.TestCase):
def test_pop_with_tuple(self):
d = self._get_dict()
with self.assertRaises(TypeError):
loc = d.pop("results[-1].locations[-1]")
_ = d.pop("results[-1].locations[-1]")
# loc = d.pop('results[-1].locations[-1]')
# self.assertEqual(loc, 12)
# self.assertEqual(len(d.get('results[-1].locations')), 2)

View File

@ -20,10 +20,10 @@ class github_issue_0088_test_case(unittest.TestCase):
def test_flatten_with_separator_equal_to_keypath_separator(self):
d = benedict({"a": {"b": {"c": 1}}}, keypath_separator=".")
with self.assertRaises(ValueError):
f = d.flatten(".")
_ = d.flatten(".")
d = benedict({"a": {"b": {"c": 1}}}, keypath_separator="_")
with self.assertRaises(ValueError):
f = d.flatten("_")
_ = d.flatten("_")
def test_flatten_with_separator_different_from_keypath_separator(self):
d = benedict({"a": {"b": {"c": 1}}}, keypath_separator="_")

View File

@ -1,4 +1,3 @@
import json
import unittest
import orjson

View File

@ -23,3 +23,4 @@ class github_issue_0110_test_case(unittest.TestCase):
t = b.to_toml()
# print(t)
self.assertTrue(isinstance(t, str))

View File

@ -1,6 +1,6 @@
import unittest
from benedict.serializers import Base64Serializer
# from benedict.serializers import Base64Serializer
class base64_serializer_test_case(unittest.TestCase):

View File

@ -1,6 +1,6 @@
import unittest
from benedict.serializers import CSVSerializer
# from benedict.serializers import CSVSerializer
class csv_serializer_test_case(unittest.TestCase):

View File

@ -1,6 +1,6 @@
import unittest
from benedict.serializers import JSONSerializer
# from benedict.serializers import JSONSerializer
class json_serializer_test_case(unittest.TestCase):

View File

@ -1,6 +1,6 @@
import unittest
from benedict.serializers import PListSerializer
# from benedict.serializers import PListSerializer
class plist_serializer_test_case(unittest.TestCase):

View File

@ -1,6 +1,6 @@
import unittest
from benedict.serializers import QueryStringSerializer
# from benedict.serializers import QueryStringSerializer
class query_string_serializer_test_case(unittest.TestCase):

View File

@ -1,6 +1,6 @@
import unittest
from benedict.serializers import TOMLSerializer
# from benedict.serializers import TOMLSerializer
class toml_serializer_test_case(unittest.TestCase):

View File

@ -1,6 +1,6 @@
import unittest
from benedict.serializers import XLSSerializer
# from benedict.serializers import XLSSerializer
class xls_serializer_test_case(unittest.TestCase):

View File

@ -1,6 +1,6 @@
import unittest
from benedict.serializers import XMLSerializer
# from benedict.serializers import XMLSerializer
class xml_serializer_test_case(unittest.TestCase):

View File

@ -1,6 +1,6 @@
import unittest
from benedict.serializers import YAMLSerializer
# from benedict.serializers import YAMLSerializer
class yaml_serializer_test_case(unittest.TestCase):

View File

@ -146,3 +146,4 @@ class stackoverflow_question_59176476_test_case(unittest.TestCase):
author = bdict(data[["DetalheMateria", "Materia", "Autoria", "Autor"]][0])
author_name = author["NomeAutor"]
# print(author_name)
self.assertEqual(author_name, "Câmara dos Deputados")

View File

@ -595,134 +595,6 @@ class stackoverflow_question_60072709_test_case(unittest.TestCase):
}
"""
json_output = """
[
{
"id": 1,
"name": "Project 1",
"amount": 442228,
"breakdown": [
{
"id": 1,
"name": "Development",
"amount": 259428,
"breakdown": [
{
"id": 4,
"name": "Website Development",
"amount": 169857,
"breakdown": [
{
"id": 12,
"name": "Payment Gateway License",
"amount": 92801,
"breakdown": []
},
{
"id": 13,
"name": "JavaScript Plugin License",
"amount": 77056,
"breakdown": []
}
]
},
{
"id": 5,
"name": "Mobile App Development",
"amount": 8709,
"breakdown": [
{
"id": 14,
"name": "Google Play Store Fees",
"amount": 3412,
"breakdown": []
},
{
"id": 15,
"name": "Apple App Store Fees",
"amount": 5297,
"breakdown": []
}
]
},
{
"id": 6,
"name": "DevOps",
"amount": 80862,
"breakdown": [
{
"id": 16,
"name": "Servers",
"amount": 75020,
"breakdown": []
},
{
"id": 17,
"name": "Domain Name",
"amount": 1217,
"breakdown": []
},
{
"id": 18,
"name": "SSL Certificate",
"amount": 4625,
"breakdown": []
}
]
}
]
},
{
"id": 2,
"name": "Designing",
"amount": 101824,
"breakdown": [
{
"id": 7,
"name": "Wireframing",
"amount": 51479,
"breakdown": []
},
{
"id": 8,
"name": "UI Design",
"amount": 37204,
"breakdown": []
},
{
"id": 9,
"name": "Brochure Design",
"amount": 13141,
"breakdown": []
}
]
},
{
"id": 3,
"name": "Marketing",
"amount": 80976,
"breakdown": [
{
"id": 10,
"name": "Social Media Marketing",
"amount": 39591,
"breakdown": []
},
{
"id": 11,
"name": "Print Media Marketing",
"amount": 41385,
"breakdown": []
}
]
}
]
}
]
"""
data = bdict.from_json(json_input)
keys = list(data.keys())
items = []