0
# Class Integration
1
2
Base classes and utilities for integrating JSON serialization directly into your Python classes. The `JsonSerializable` class provides a convenient way to add built-in JSON capabilities to your objects through inheritance.
3
4
## Capabilities
5
6
### JsonSerializable Base Class
7
8
```python { .api }
9
class JsonSerializable:
10
"""
11
Base class that provides JSON serialization capabilities to any class that inherits from it.
12
Offers an alternative to using jsons.load and jsons.dump methods directly.
13
"""
14
15
@property
16
def json(self):
17
"""
18
Serialize this instance to a JSON-compatible dictionary.
19
20
Returns:
21
dict: JSON representation of this instance (equivalent to jsons.dump(self))
22
"""
23
24
@classmethod
25
def from_json(cls, json_obj, **kwargs):
26
"""
27
Deserialize a JSON object into an instance of this class.
28
29
Parameters:
30
- json_obj: JSON-compatible object (dict, list, etc.) to deserialize
31
- **kwargs: Additional arguments passed to the load function
32
33
Returns:
34
Instance of this class reconstructed from json_obj
35
36
Raises:
37
- DeserializationError: If json_obj cannot be deserialized to this class
38
"""
39
40
def dump(self, **kwargs):
41
"""
42
Serialize this instance (equivalent to json property but allows kwargs).
43
44
Parameters:
45
- **kwargs: Additional arguments passed to jsons.dump
46
47
Returns:
48
dict: JSON representation of this instance
49
"""
50
51
@classmethod
52
def load(cls, json_obj, **kwargs):
53
"""
54
Deserialize JSON object into instance (equivalent to from_json but allows kwargs).
55
56
Parameters:
57
- json_obj: JSON-compatible object to deserialize
58
- **kwargs: Additional arguments passed to jsons.load
59
60
Returns:
61
Instance of this class
62
"""
63
```
64
65
### Fork Management
66
67
```python { .api }
68
class JsonSerializable:
69
@classmethod
70
def fork(cls, name=None):
71
"""
72
Create a 'fork' of JsonSerializable with separate serializer/deserializer configuration.
73
74
Parameters:
75
- name: Optional name for the new type (defaults to auto-generated)
76
77
Returns:
78
type: New JsonSerializable-based class with separate configuration
79
"""
80
81
@classmethod
82
def with_dump(cls, fork=False, **kwargs):
83
"""
84
Return a class based on JsonSerializable with dump method pre-configured with kwargs.
85
86
Parameters:
87
- fork: Bool determining if a new fork should be created
88
- **kwargs: Keyword arguments automatically passed to dump method
89
90
Returns:
91
type: Class with customized dump behavior
92
"""
93
94
@classmethod
95
def with_load(cls, fork=False, **kwargs):
96
"""
97
Return a class based on JsonSerializable with load method pre-configured with kwargs.
98
99
Parameters:
100
- fork: Bool determining if a new fork should be created
101
- **kwargs: Keyword arguments automatically passed to load method
102
103
Returns:
104
type: Class with customized load behavior
105
"""
106
```
107
108
## Usage Examples
109
110
### Basic JsonSerializable Usage
111
112
```python
113
import jsons
114
from jsons import JsonSerializable
115
from typing import List
116
117
class Person(JsonSerializable):
118
def __init__(self, name: str, age: int, hobbies: List[str]):
119
self.name = name
120
self.age = age
121
self.hobbies = hobbies
122
123
class Company(JsonSerializable):
124
def __init__(self, name: str, employees: List[Person]):
125
self.name = name
126
self.employees = employees
127
128
# Create objects
129
employees = [
130
Person("Alice", 30, ["reading", "hiking"]),
131
Person("Bob", 25, ["gaming", "cooking"])
132
]
133
company = Company("Tech Corp", employees)
134
135
# Serialize using json property
136
company_dict = company.json
137
print(company_dict)
138
# {
139
# 'name': 'Tech Corp',
140
# 'employees': [
141
# {'name': 'Alice', 'age': 30, 'hobbies': ['reading', 'hiking']},
142
# {'name': 'Bob', 'age': 25, 'hobbies': ['gaming', 'cooking']}
143
# ]
144
# }
145
146
# Deserialize using from_json class method
147
company_restored = Company.from_json(company_dict)
148
print(company_restored.name) # "Tech Corp"
149
print(company_restored.employees[0].name) # "Alice"
150
print(company_restored.employees[1].hobbies[0]) # "gaming"
151
```
152
153
### Custom Configuration with with_dump and with_load
154
155
```python
156
import jsons
157
from jsons import JsonSerializable, KEY_TRANSFORMER_CAMELCASE, KEY_TRANSFORMER_SNAKECASE
158
159
# Create custom serializable with camelCase keys for JSON
160
CustomSerializable = JsonSerializable.with_dump(
161
key_transformer=KEY_TRANSFORMER_CAMELCASE
162
).with_load(
163
key_transformer=KEY_TRANSFORMER_SNAKECASE
164
)
165
166
class APIResponse(CustomSerializable):
167
def __init__(self, user_name: str, is_active: bool, last_login_date: str):
168
self.user_name = user_name
169
self.is_active = is_active
170
self.last_login_date = last_login_date
171
172
response = APIResponse("john_doe", True, "2023-12-01")
173
174
# Serializes with camelCase keys
175
json_response = response.json
176
print(json_response)
177
# {'userName': 'john_doe', 'isActive': True, 'lastLoginDate': '2023-12-01'}
178
179
# Can deserialize from camelCase JSON
180
camel_data = {'userName': 'jane_smith', 'isActive': False, 'lastLoginDate': '2023-11-15'}
181
response = APIResponse.from_json(camel_data)
182
print(response.user_name) # "jane_smith" (converted back to snake_case)
183
```
184
185
### Fork Management for Separate Configurations
186
187
```python
188
import jsons
189
from jsons import JsonSerializable
190
191
# Create a fork with separate serializer configuration
192
CustomJsonSerializable = JsonSerializable.fork("CustomJSON")
193
194
# Configure the fork with custom serializers
195
def custom_string_serializer(s: str, **kwargs):
196
return s.upper() # All strings serialized in uppercase
197
198
jsons.set_serializer(custom_string_serializer, str, fork_inst=CustomJsonSerializable)
199
200
class RegularPerson(JsonSerializable):
201
def __init__(self, name: str):
202
self.name = name
203
204
class CustomPerson(CustomJsonSerializable):
205
def __init__(self, name: str):
206
self.name = name
207
208
regular = RegularPerson("Alice")
209
custom = CustomPerson("Bob")
210
211
print(regular.json) # {'name': 'Alice'}
212
print(custom.json) # {'name': 'BOB'} (uppercase due to custom serializer)
213
```
214
215
### Advanced Fork Configuration
216
217
```python
218
import jsons
219
from jsons import JsonSerializable, Verbosity
220
221
# Create fork with verbose output
222
VerboseSerializable = JsonSerializable.with_dump(
223
fork=True, # Create new fork
224
verbosity=Verbosity.WITH_EVERYTHING
225
)
226
227
class DebugObject(VerboseSerializable):
228
def __init__(self, data: str):
229
self.data = data
230
231
debug_obj = DebugObject("test data")
232
verbose_json = debug_obj.json
233
print(verbose_json)
234
# Includes additional metadata like class info and dump timestamp
235
```
236
237
### Integration with Regular jsons Functions
238
239
```python
240
import jsons
241
from jsons import JsonSerializable
242
243
class Product(JsonSerializable):
244
def __init__(self, name: str, price: float):
245
self.name = name
246
self.price = price
247
248
# JsonSerializable objects work seamlessly with regular jsons functions
249
product = Product("Laptop", 999.99)
250
251
# These are equivalent:
252
json1 = product.json
253
json2 = jsons.dump(product)
254
print(json1 == json2) # True
255
256
# Can also use jsons.load with JsonSerializable classes
257
product_data = {'name': 'Phone', 'price': 599.99}
258
product1 = Product.from_json(product_data)
259
product2 = jsons.load(product_data, Product)
260
print(product1.name == product2.name) # True
261
```
262
263
### Error Handling
264
265
```python
266
import jsons
267
from jsons import JsonSerializable, DeserializationError
268
269
class StrictUser(JsonSerializable):
270
def __init__(self, username: str, email: str):
271
self.username = username
272
self.email = email
273
274
# Handle deserialization errors
275
invalid_data = {'username': 'test'} # Missing required 'email' field
276
277
try:
278
user = StrictUser.from_json(invalid_data)
279
except DeserializationError as e:
280
print(f"Failed to deserialize: {e}")
281
print(f"Source data: {e.source}")
282
print(f"Target type: {e.target}")
283
```