a better json library
Project description
JsonBind
JsonBind is an advanced JSON handling library for Python, designed to enhance the capabilities of the standard json module. It offers seamless serialization and deserialization of Python data types not typically supported by the default JSON library, including datetime.datetime, tuples, sets, enumerations (enum), bytes, and custom classes.
Installation
pip install jsonbind
Features
- Compatibility: Functions prototypes designed to match the standard json library.
- Extended Data Type Support: Handle complex Python data types effortlessly.
- Custom Class Serialization: Easily serialize and deserialize your custom classes.
- Intuitive API: Designed to be familiar to users of the standard json module.
The Python JSON standard library
The standard JSON library in Python expertly facilitates the serialization and deserialization of JSON data types into native Python data types, as detailed in the following table:
JSON Data Type | Python Data Type |
---|---|
object | dict |
array | list |
string | str |
number | int, float |
bool | bool |
null | None |
This compatibility with JSON significantly enhances its utility for data sharing, communication, and storage purposes. However, it is important to recognize that the JSON format's inherent limitations in representing more complex data structures can sometimes restrict its applicability. Crafting specific encoders and decoders to address these limitations often presents a substantial technical challenge, requiring thoughtful consideration and expertise.
Type-bindings
JsonBind operates on the principle of utilizing type bindings to facilitate the transformation between JSON types and Python types. It comes equipped with an extensive array of pre-defined bindings for commonly used types, including tuples, sets, datetime objects, bytes, classes, and more. Additionally, JsonBind is designed to simplify the process of creating new bindings. This flexibility allows users to seamlessly integrate JSON types with novel Python data types, enhancing the library's adaptability and ease of use in various programming scenarios.
To extend the JSON's functionality, multiple bindings can be created for the same json data type. This allows, for example, strings to be decoded as datetime objects and bytes, object to class dictionaries and instances, etc.
Out-of-the-box bindings
JSON Data Type | Python Data Type |
---|---|
object | dict, class |
array | list, tuple, set |
string | str, datetime, bytes, enum |
number | int, float, enum |
bool | bool |
null | None |
Side by side
Standard Library | JsonBind |
---|---|
Serializing a datetime to JSON is not possible by default:
import json
import datetime
mydate = datetime.datetime.now().date()
mydate = json.dumps(mydate)
output
To do it, it is necessary to create an Encoder: import json
import datetime
class DateTimeEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, (datetime.datetime, datetime.date, datetime.time)):
return obj.isoformat()
elif isinstance(obj, datetime.timedelta):
return (datetime.datetime.min + obj).time().isoformat()
return super(DateTimeEncoder, self).default(obj)
mydate = datetime.datetime.now().date()
encoder = DateTimeEncoder()
encoder.encode(mydate)
Output:
However, this only works converting from python to json. To read values from json to python it is necessary to write an additional Decoder class. |
By default datetime values are fully supported by JsonBind:
Output:
|
Creating new bindings for python types
JsonBind allows the creation of new Bindings with very little code.
In this example a new binding for the type datetime is created to encode to the object Json datatype (dict):
import jsonbind as jb
import datetime
class MyDateBinding(jb.TypeBinding):
def __init__(self):
super().__init__(json_type=dict, python_type=datetime.datetime)
def to_json_value(self, python_value: datetime.datetime) -> dict:
return {"year": python_value.year,
"month": python_value.month,
"day": python_value.day}
def to_python_value(self, json_value: dict, python_type: type) -> datetime.datetime:
return datetime.datetime(year=json_value["year"],
month=json_value["month"],
day=json_value["day"])
jb.Bindings.set_binding(MyDateBinding())
print(jb.dumps(datetime.datetime.now()))
Output:
{"year":2023,"month":12,"day":20}
To convert a JSON value to date time using the new binding, we need the following code:
new_date = jb.loads('{"year":2025,"month":10,"day":22}', cls=datetime.datetime)
print(new_date, type(new_date))
Output:
2025-10-22 00:00:00 <class 'datetime.datetime'>
JsonBind automatically matches the expected type to the custom binding as there can only exist one binding per python type. This means that in this code the default binding for datetime was replaced during the set_binding operation.
Creating bound classes
import jsonbind as jb
import datetime
class MyClass(jb.BoundClass):
def __init__(self):
self.text = "Hello World"
self.date = datetime.datetime.now()
self.data = [3,1,4,1,5,9,2]
my_object=MyClass()
print("Serialization test:")
print(jb.dumps(my_object))
new_object = jb.loads('{"text":"Deseralization test","date":"2023-12-23","data":[6,2,8,3,1,8,4]}', cls=MyClass)
print()
print("Deserialization test:")
print ("Text: ",new_object.text, new_object.text.__class__)
print ("Date: ",new_object.date, new_object.date.__class__)
print ("Data: ",new_object.data, new_object.data.__class__)
Output:
Serialization test:
{"text":"Hello World","date":"2023-12-20","data":[3,1,4,1,5,9,2]}
Deserialization test:
Text: Deseralization test <class 'str'>
Date: 2023-12-23 00:00:00 <class 'datetime.datetime'>
Data: [6, 2, 8, 3, 1, 8, 4] <class 'list'>
Standard Json load and dump functions
Loading a json string to its default python type
import jsonbind as jb
mydict = jb.loads('{"name":"German Espinosa","age":41,"weight":190.0}')
print(mydict, type(mydict))
mylist = jb.loads('[1, 2, 3, 4]')
print(mylist, type(mylist))
myint = jb.loads('1')
print(myint, type(myint))
myfloat = jb.loads('10.5')
print(myfloat, type(myfloat))
mystring = jb.loads('"Hello World"')
print(mystring, type(mystring))
mybool = jb.loads('true')
print(mybool, type(mybool))
output
{'name': 'German Espinosa', 'age': 41, 'weight': 190.0} <class 'dict'>
[1, 2, 3, 4] <class 'list'>
1 <class 'int'>
10.5 <class 'float'>
Hello World <class 'str'>
True <class 'bool'>
Serializing a json string from its default python type
import jsonbind as jb
mydict = {"name":"German Espinosa","age":41,"weight":190.0}
print(jb.dumps(mydict), type(mydict))
mylist = [1, 2, 3, 4]
print(jb.dumps(mylist), type(mylist))
myint = 1
print(jb.dumps(myint), type(myint))
myfloat = 10.5
print(jb.dumps(myfloat), type(myfloat))
mystring = "Hello World"
print(jb.dumps(mystring), type(mystring))
mybool = True
print(jb.dumps(mybool), type(mybool))
output
{'name': 'German Espinosa', 'age': 41, 'weight': 190.0} <class 'dict'>
[1, 2, 3, 4] <class 'list'>
1 <class 'int'>
10.5 <class 'float'>
Hello World <class 'str'>
True <class 'bool'>
Loading a json string to a non-default python type
import jsonbind as jb
mytuple = jb.loads('[1, 2, 3, 4]', cls=tuple)
print(mytuple, type(mytuple))
myset = jb.loads('[1, 2, 3, 4]', cls=set)
print(myset, type(myset))
mybytes=jb.loads('"SGVsbG8gV29ybGQ="', cls=bytes)
print (mybytes, type(mybytes))
import datetime
mydate = jb.loads('"2023-12-19"', cls=datetime.datetime)
print(mydate, type(mydate))
output
(1, 2, 3, 4) <class 'tuple'>
{1, 2, 3, 4} <class 'set'>
b'Hello World' <class 'bytes'>
2023-12-19 00:00:00 <class 'datetime.datetime'>
Serializing a json string from a non-default python type
import jsonbind as jb
mydict = {"name":"German Espinosa","age":41,"weight":190.0}
print(jb.dumps(mydict), type(mydict))
mylist = [1, 2, 3, 4]
print(jb.dumps(mylist), type(mylist))
myint = 1
print(jb.dumps(myint), type(myint))
myfloat = 10.5
print(jb.dumps(myfloat), type(myfloat))
mystring = "Hello World"
print(jb.dumps(mystring), type(mystring))
mybool = True
print(jb.dumps(mybool), type(mybool))
output
{'name': 'German Espinosa', 'age': 41, 'weight': 190.0} <class 'dict'>
[1, 2, 3, 4] <class 'list'>
1 <class 'int'>
10.5 <class 'float'>
Hello World <class 'str'>
True <class 'bool'>
JsonBind Object & List
JsonBind provides special implementations of Object and List datatypes that provide a lot of functionality to interact with data in JSON format.
Create your first json object:
After installing the package, try the following python script:
import jsonbind as jb
myobject = jb.Object(name="German Espinosa", age=41, weight=190.0)
print("name:", myobject.name, type(myobject.name).__name__)
print("age:", myobject.age, type(myobject.age).__name__)
print("weight:", myobject.weight, type(myobject.weight).__name__)
print(myobject)
output
name: German Espinosa str
age: 41 int
weight: 190.0 float
{"name":"German Espinosa","age":41,"weight":190.0}
Loading json_data:
To quickly load json data into objects, use the load command:
import jsonbind as jb
myobject = jb.Object.load("{\"name\":\"German Espinosa\",\"age\":41,\"weight\":190.0}")
print("name:", myobject.name, type(myobject.name).__name__)
print("age:", myobject.age, type(myobject.age).__name__)
print("weight:", myobject.weight, type(myobject.weight).__name__)
output
name: German Espinosa str
age: 41 int
weight: 190.0 float
Formatting outputs:
You can easily format data, even in complex json hierarchical structures:
import jsonbind as jb
myobject = jb.Object.parse("{\"name\":\"German Espinosa\",\"age\":41,\"weight\":190.0,\"place_of_birth\":{\"country\":\"Argentina\",\"city\":\"Buenos Aires\"}}")
print(myobject.format("{name} was born in {place_of_birth.city}, {place_of_birth.country}"))
output
German Espinosa was born in Buenos Aires, Argentina
Working with pre-structured data:
A powerful way to read and write json is to pre-define the structure of the data. This creates standarized data samples that are easire to be consumed by other tools. To pre-define structure of a json object, you need to create your own custom class extending the JsonObject:
import jsonbind as jb
class MyJsonClass(jb.Object):
def __init__(self, name="", age=0, weight=0.0):
self.name = name
self.age = age
self.weight = weight
myobject = MyJsonClass('German Espinosa', 41, 190.0)
json_string = str(myobject)
print(json_string)
output
{"name":"German Espinosa","age":41,"weight":190.0}
Loading values into an existing object:
You can also load values from a json string directly into an existing custom JsonObject:
import jsonbind as jb
class MyJsonClass(jb.Object):
def __init__(self, name="", age=0, weight=0.0):
self.name = name
self.age = age
self.weight = weight
myobject = MyJsonClass('German Espinosa', 41, 190.0)
myobject.parse("{\"name\":\"Benjamin Franklin\",\"age\":84,\"weight\":195.5}")
json_string = str(myobject)
print(json_string)
output
{"name":"Benjamin Franklin","age":84,"weight":195.5}
Object to json conversion:
All objects with type MyJsonClass will produce perfectly formed json when converted to string. If you need to retrieve the json string representing the object:
import jsonbind as jb
class MyJsonClass(jb.Object):
def __init__(self, name="", age=0, weight=0.0):
self.name = name
self.age = age
self.weight = weight
myobject = MyJsonClass('German Espinosa', 41, 190.0)
json_string = str(myobject)
print (json_string)
output
{"name":"German Espinosa","age":41,"weight":190.0}
Json to object conversion:
You can create instances of your json objects from strings containing a correct json representation:
import jsonbind as jb
class MyJsonClass(jb.Object):
def __init__(self, name="", age=0, weight=0.0):
self.name = name # string
self.age = age # int
self.weight = weight # float
json_string = "{\"name\":\"German Espinosa\",\"age\":41,\"weight\":190.0}"
myobject = MyJsonClass.parse(json_string)
print("name:", myobject.name, type(myobject.name).__name__)
print("age:", myobject.age, type(myobject.age).__name__)
print("weight:", myobject.weight, type(myobject.weight).__name__)
output
name: German Espinosa str
age: 41 int
weight: 190.0 float
note: all members are populated with the right values using the same data type declared in the default constructor of the class
Nested json structures:
You can create complex structures with nested objects:
import jsonbind as jb
class Person(jb.Object):
def __init__(self, name="", age=0):
self.name = name
self.age = age
class Transaction(jb.Object):
def __init__(self, buyer=None, seller=None, product="", amount=0.0):
self.buyer = buyer if buyer else Person()
self.seller = seller if seller else Person()
self.product = product
self.amount = amount
mytransaction = Transaction(Person("German Espinosa", 41), Person("Benjamin Franklin", 84), "kite", 150.5)
print (mytransaction)
output
{"buyer":{"name":"German Espinosa","age":41},"seller":{"name":"Benjamin Franklin","age":84},"product":"kite","amount":150.5}
Json lists:
You can load full lists with values from a json string to a JsonList:
import jsonbind as jb
fibonacci = jb.List(list_type=int)
json_string = "[1,1,2,3,5,8,13,21]"
fibonacci.parse(json_string)
You can also load a list of json objects:
import jsonbind as jb
class Person(jb.Object):
def __init__(self, name="", surname=""):
self.name = name
self.surname = surname
person_list = jb.List(list_type=Person)
json_string = "[{\"name\":\"german\",\"surname\":\"espinosa\"},{\"name\":\"benjamin\",\"surname\":\"franklin\"}]"
person_list.parse(json_string)
Lists can also be used as members of other objects:
import jsonbind as jb
class Person(jb.Object):
def __init__(self):
self.name = ""
self.surname = ""
self.languages = List(list_type=str)
person = Person.parse("{\"name\":\"German\",\"surname\":\"Espinosa\", \"languages\":[\"english\",\"spanish\",\"portuguese\"]}")
print(person)
output
{"name":"German","surname":"Espinosa","languages":["english","spanish","portuguese"]}
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file jsonbind-0.0.10.tar.gz
.
File metadata
- Download URL: jsonbind-0.0.10.tar.gz
- Upload date:
- Size: 70.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.12.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 38e94a1a5abd42230a36496627b15abc2799de5b3c470ad9a57773a553469f3f |
|
MD5 | 04e1c53e5110911f45a17e02bdd3b7a6 |
|
BLAKE2b-256 | 676396a5e20b81cd777bf48ef2f0c5ddf2625aaf2388493cf014b63a9a15cddf |