Package: jsonbourne
jsonbourneInstall:pip install jsonbournePython json lib/pkg that makes json feel like the JSON module in javascript/typescript:from jsonbourne import JSON; JSON.parse(JSON.stringify({"key": "value"}))Automatically uses best json-lib-backend available (orjson/python-rapidjson) ~ can be configuredHybrid dict/class object (jsonbourne.JsonObj):Dot-notation getting/setting (featuring protected attributes!)All your favorite python dictionary methods (items,keys,update,values) and more!Works withpydanticandattrsFastAPI:JSONBOURNEResponse ~ auto use the bestNo hard dependencies ~ works with python-stdlib-json as well asorjsonandpython-rapidjsonjsonbourne.JsonObjuses list/dict comprehensions (some are recursive) everywhere because 'why not?' and it is a bit fasterUsage:JSON ~from jsonbourne import JSONImporting:# Importing JSON:fromjsonbourneimportJSON# orimportJSON# Importing jsonbourne:importjsonbourneimportdavid_webb# jsonbourne's `True` identityJSON basics:importJSON# Module included with jsonbournestring_stringify=JSON.stringify({"a":1,"b":2,"c":3})# '{"a": 1, "b": 2, "c": 3}'string_dumps=JSON.dumps({"a":1,"b":2,"c":3})# '{"a": 1, "b": 2, "c": 3}'string_dumps'{"a":1,"b":2,"c":3}'JSON option kwargs ~pretty&sort_keyspretty:string_dumps=JSON.stringify({"b":2,"a":1,"c":3},pretty=True)# '{"a": 1, "b": 2, "c": 3}'print(string_dumps){
  "b": 2,
  "a": 1,
  "c": 3
}sort_keys:string_dumps=JSON.stringify({"b":2,"a":1,"c":3},pretty=True,sort_keys=True)# '{"a": 1, "b": 2, "c": 3}'print(string_dumps){
  "a": 1,
  "b": 2,
  "c": 3
}JsonObj & JSONPython dictionary/object with dot accessProtections against setting class/obj attributesIs as javascript-y as possible (keys have to be strings -- ints/floats will be converted to strings)Create ajsonbourne.JsonObjwithjsonbourne.JSONRecursive jsonificationAllows for kwarging (**json_obj)Works withpydanticandattrsMake an empty JsonObjThe following 3 examples all produce the same thingfromjsonbourneimportJSONj=JSON()# j => JsonObj(**{})# ORimportJSONj=JSON()# j => JsonObj(**{})# ORfromjsonbourneimportJsonObjj=JsonObj()# j => JsonObj(**{})From a dictionary o dataimportdatetimedata={"key":"value","list":[1,2,3,4,5],"dt":datetime.datetime(1970,1,1,0,0,0,1),"sub":{"b":3,"key":"val","a":1,},"timedelta":datetime.timedelta(days=2),}JSON(data)JsonObj(**{
    'dt': datetime.datetime(1970, 1, 1, 0, 0, 0, 1),
    'key': 'value',
    'list': [1, 2, 3, 4, 5],
    'sub': {'a': 1, 'b': 3, 'key': 'val'},
    'timedelta': datetime.timedelta(days=2)
})Dot accessJSON(data).sub.b3stringified_data=JSON(data).stringify(pretty=True)print(stringified_data){
  "key": "value",
  "list": [
    1,
    2,
    3,
    4,
    5
  ],
  "dt": "1970-01-01T00:00:00.000001",
  "sub": {
    "b": 3,
    "key": "val",
    "a": 1
  },
  "timedelta": 172800.0
}parsed_data=JSON(stringified_data)parsed_dataJsonObj(**{
    'dt': '1970-01-01T00:00:00.000001',
    'key': 'value',
    'list': [1, 2, 3, 4, 5],
    'sub': {'a': 1, 'b': 3, 'key': 'val'},
    'timedelta': 172800.0
})list(parsed_data.keys())['key', 'list', 'dt', 'sub', 'timedelta']list(parsed_data.items())[('key', 'value'),
 ('list', [1, 2, 3, 4, 5]),
 ('dt', '1970-01-01T00:00:00.000001'),
 ('sub', JsonObj(**{'b': 3, 'key': 'val', 'a': 1})),
 ('timedelta', 172800.0)]list(parsed_data.dot_keys())[('key',),
 ('list',),
 ('dt',),
 ('sub', 'b'),
 ('sub', 'key'),
 ('sub', 'a'),
 ('timedelta',)]list(parsed_data.dot_items())[(('key',), 'value'),
 (('list',), [1, 2, 3, 4, 5]),
 (('dt',), '1970-01-01T00:00:00.000001'),
 (('sub', 'b'), 3),
 (('sub', 'key'), 'val'),
 (('sub', 'a'), 1),
 (('timedelta',), 172800.0)]parsed_data[("sub","key")]'val'parsed_data.dot_lookup("sub.key")'val'{**parsed_data}{'key': 'value',
 'list': [1, 2, 3, 4, 5],
 'dt': '1970-01-01T00:00:00.000001',
 'sub': JsonObj(**{'b': 3, 'key': 'val', 'a': 1}),
 'timedelta': 172800.0}# fully ejectparsed_data.eject(){'key': 'value',
 'list': [1, 2, 3, 4, 5],
 'dt': '1970-01-01T00:00:00.000001',
 'sub': {'b': 3, 'key': 'val', 'a': 1},
 'timedelta': 172800.0}Protected keysjsonbourne.JsonObjprotects against setting attributes like'items'through dot-notation.fromjsonbourneimportJSONj=JSON()j.key="value"try:# CANNOT set 'items' using dot-accessj.items=[1,2,3,4]exceptValueError:pass# CAN set 'items' through key/item accessj["items"]=[1,2,3,4]print(j.__dict__)print(j)j_items=j.itemsprint("items",j_items)# Getting 'items' through dot-access returns the `items()` methodassertj.items!=[1,2,3,4]# Getting 'items' with key-access returns the stored valueassertj["items"]==[1,2,3,4]{'_data': {'key': 'value', 'items': [1, 2, 3, 4]}}
JsonObj(**{
    'items': [1, 2, 3, 4], 'key': 'value'
})
items <bound method JsonObj.items of JsonObj(**{'key': 'value', 'items': [1, 2, 3, 4]})>pydantic & jsonbournefrom jsonbourne.pydantic import JsonBaseModelAllows for aliases when getting/setting attribute(s)Supports__post_init__(like dataclasses)Basic usage:fromjsonbourneimportJsonObjfromjsonbourne.pydanticimportJsonBaseModelclassJsonSubObj(JsonBaseModel):herm:intdefto_dict(self):returnself.dict()defto_json(self,*args,**kwargs):returnself.json()@classmethoddeffrom_json(cls,json_string:str):returnJsonSubObj(json.loads(json_string))classJsonObjModel(JsonBaseModel):a:intb:intc:strd:JsonObje:JsonSubObj#@propertydefa_property(self)->str:return"prop_value"defto_json(self,*args,**kwargs):returnself.json()@classmethoddeffrom_json(cls,json_string:str):returncls(**json.loads(json_string))obj=JsonObjModel(**{"a":1,"b":2,"c":"herm","d":{"nested":"nestedval"},"e":{"herm":2}})objJsonObjModel(**{
     'a': 1,
     'b': 2,
     'c': 'herm',
     'd': JsonObj(**{'nested': 'nestedval'}),
     'e': {'herm': 2}
})# respects properties (which I don't think pydantic does(currently))obj.a_property'prop_value'JSON backend/libjsonbournefinds the best json-lib (python-rapidjson/orjson) it can!On importjsonbournegets to
work spying on your python env.jsonbourne, the most highly qualified json-CIA-agent, will import the best
python-json library it can find; ifjsonbourne's cover is blown (meaning: the
only json library found is the python stdlib json),jsonbournewill fallback
to
the python stdlib json.jsonbournewill look for the following json-packages in the following order:rapidjsonorjsonCustom lib preferencesfromjsonbourneimportimport_jsonjson=import_json(("rapidjson","orjson"))# prefer rapidjson over orjsonstring=json.dumps({"a":1,"b":2,"c":3})print(json)print(string)<class 'jsonbourne.jsonlib.RAPIDJSON'>
{"a":1,"b":2,"c":3}Installing better JSON lib:orjsonpip install orjson[pip]rapidjson/python-rapidjsonpip install python-rapidjson[pip]conda install -c anaconda python-rapidjson[conda anaconda/defaults]conda install -c conda-forge python-rapidjson[conda-forge]