0
# Key Transformation
1
2
Utilities for transforming dictionary keys between different naming conventions. The jsons library provides built-in functions to convert keys between camelCase, snake_case, PascalCase, and lisp-case formats, which is especially useful for API integration and cross-platform data exchange.
3
4
## Capabilities
5
6
### Case Transformation Functions
7
8
```python { .api }
9
def camelcase(str_):
10
"""
11
Transform string to camelCase format.
12
13
Parameters:
14
- str_: String to be transformed
15
16
Returns:
17
str: String in camelCase format (first letter lowercase, subsequent words capitalized)
18
19
Examples:
20
- 'hello_world' -> 'helloWorld'
21
- 'user-name' -> 'userName'
22
- 'API_KEY' -> 'apiKey'
23
"""
24
25
def snakecase(str_):
26
"""
27
Transform string to snake_case format.
28
29
Parameters:
30
- str_: String to be transformed
31
32
Returns:
33
str: String in snake_case format (all lowercase with underscores)
34
35
Examples:
36
- 'helloWorld' -> 'hello_world'
37
- 'UserName' -> 'user_name'
38
- 'API-Key' -> 'api_key'
39
"""
40
41
def pascalcase(str_):
42
"""
43
Transform string to PascalCase format.
44
45
Parameters:
46
- str_: String to be transformed
47
48
Returns:
49
str: String in PascalCase format (first letter uppercase, subsequent words capitalized)
50
51
Examples:
52
- 'hello_world' -> 'HelloWorld'
53
- 'user-name' -> 'UserName'
54
- 'api_key' -> 'ApiKey'
55
"""
56
57
def lispcase(str_):
58
"""
59
Transform string to lisp-case format.
60
61
Parameters:
62
- str_: String to be transformed
63
64
Returns:
65
str: String in lisp-case format (all lowercase with hyphens)
66
67
Examples:
68
- 'helloWorld' -> 'hello-world'
69
- 'UserName' -> 'user-name'
70
- 'api_key' -> 'api-key'
71
"""
72
```
73
74
### Key Transformer Constants
75
76
```python { .api }
77
# Pre-defined constants for use with dump/load functions
78
KEY_TRANSFORMER_SNAKECASE = snakecase
79
KEY_TRANSFORMER_CAMELCASE = camelcase
80
KEY_TRANSFORMER_PASCALCASE = pascalcase
81
KEY_TRANSFORMER_LISPCASE = lispcase
82
```
83
84
## Usage Examples
85
86
### Basic Key Transformation
87
88
```python
89
import jsons
90
from jsons import camelcase, snakecase, pascalcase, lispcase
91
92
# Transform individual strings
93
original = "user_profile_data"
94
95
print(camelcase(original)) # 'userProfileData'
96
print(snakecase(original)) # 'user_profile_data' (no change)
97
print(pascalcase(original)) # 'UserProfileData'
98
print(lispcase(original)) # 'user-profile-data'
99
100
# Transform from camelCase
101
camel_string = "firstName"
102
print(snakecase(camel_string)) # 'first_name'
103
print(pascalcase(camel_string)) # 'FirstName'
104
print(lispcase(camel_string)) # 'first-name'
105
106
# Transform with hyphens and mixed formats
107
mixed_string = "API-Response-Data"
108
print(camelcase(mixed_string)) # 'apiResponseData'
109
print(snakecase(mixed_string)) # 'api_response_data'
110
print(pascalcase(mixed_string)) # 'ApiResponseData'
111
```
112
113
### Key Transformation in Serialization
114
115
```python
116
import jsons
117
from jsons import KEY_TRANSFORMER_CAMELCASE, KEY_TRANSFORMER_SNAKECASE
118
from dataclasses import dataclass
119
120
@dataclass
121
class UserProfile:
122
first_name: str
123
last_name: str
124
email_address: str
125
phone_number: str
126
is_active: bool
127
128
user = UserProfile(
129
first_name="John",
130
last_name="Doe",
131
email_address="john.doe@example.com",
132
phone_number="+1-555-0100",
133
is_active=True
134
)
135
136
# Serialize with camelCase keys
137
camel_json = jsons.dump(user, key_transformer=KEY_TRANSFORMER_CAMELCASE)
138
print(camel_json)
139
# {
140
# 'firstName': 'John',
141
# 'lastName': 'Doe',
142
# 'emailAddress': 'john.doe@example.com',
143
# 'phoneNumber': '+1-555-0100',
144
# 'isActive': True
145
# }
146
147
# Serialize with snake_case keys (default, no transformation needed)
148
snake_json = jsons.dump(user)
149
print(snake_json)
150
# {
151
# 'first_name': 'John',
152
# 'last_name': 'Doe',
153
# 'email_address': 'john.doe@example.com',
154
# 'phone_number': '+1-555-0100',
155
# 'is_active': True
156
# }
157
```
158
159
### Key Transformation in Deserialization
160
161
```python
162
import jsons
163
from jsons import KEY_TRANSFORMER_SNAKECASE, KEY_TRANSFORMER_CAMELCASE
164
from dataclasses import dataclass
165
166
@dataclass
167
class APIResponse:
168
user_id: int
169
user_name: str
170
created_at: str
171
is_verified: bool
172
173
# Deserialize from camelCase JSON (common in JavaScript APIs)
174
camel_data = {
175
'userId': 12345,
176
'userName': 'alice_smith',
177
'createdAt': '2023-12-01T10:30:00Z',
178
'isVerified': True
179
}
180
181
# Transform camelCase keys to snake_case during deserialization
182
response = jsons.load(camel_data, APIResponse, key_transformer=KEY_TRANSFORMER_SNAKECASE)
183
print(response.user_id) # 12345
184
print(response.user_name) # 'alice_smith'
185
print(response.created_at) # '2023-12-01T10:30:00Z'
186
print(response.is_verified) # True
187
```
188
189
### Bidirectional API Integration
190
191
```python
192
import jsons
193
from jsons import KEY_TRANSFORMER_CAMELCASE, KEY_TRANSFORMER_SNAKECASE
194
from dataclasses import dataclass
195
from typing import List
196
197
@dataclass
198
class ProductInfo:
199
product_id: int
200
product_name: str
201
unit_price: float
202
in_stock: bool
203
category_tags: List[str]
204
205
# Python uses snake_case internally
206
product = ProductInfo(
207
product_id=101,
208
product_name="Wireless Headphones",
209
unit_price=99.99,
210
in_stock=True,
211
category_tags=["electronics", "audio", "wireless"]
212
)
213
214
# Send to JavaScript API (requires camelCase)
215
api_payload = jsons.dump(product, key_transformer=KEY_TRANSFORMER_CAMELCASE)
216
print("Sending to API:")
217
print(api_payload)
218
# {
219
# 'productId': 101,
220
# 'productName': 'Wireless Headphones',
221
# 'unitPrice': 99.99,
222
# 'inStock': True,
223
# 'categoryTags': ['electronics', 'audio', 'wireless']
224
# }
225
226
# Receive from JavaScript API (camelCase format)
227
api_response = {
228
'productId': 102,
229
'productName': 'Bluetooth Speaker',
230
'unitPrice': 79.99,
231
'inStock': False,
232
'categoryTags': ['electronics', 'audio', 'bluetooth']
233
}
234
235
# Convert back to Python object with snake_case
236
received_product = jsons.load(api_response, ProductInfo, key_transformer=KEY_TRANSFORMER_SNAKECASE)
237
print("Received from API:")
238
print(f"Product: {received_product.product_name}")
239
print(f"Price: ${received_product.unit_price}")
240
print(f"Available: {received_product.in_stock}")
241
```
242
243
### Custom JsonSerializable with Key Transformation
244
245
```python
246
import jsons
247
from jsons import JsonSerializable, KEY_TRANSFORMER_CAMELCASE, KEY_TRANSFORMER_SNAKECASE
248
249
# Create specialized classes for different API formats
250
JavaScriptAPI = JsonSerializable.with_dump(
251
key_transformer=KEY_TRANSFORMER_CAMELCASE
252
).with_load(
253
key_transformer=KEY_TRANSFORMER_SNAKECASE
254
)
255
256
class WebUser(JavaScriptAPI):
257
def __init__(self, user_id: int, full_name: str, email_address: str):
258
self.user_id = user_id
259
self.full_name = full_name
260
self.email_address = email_address
261
262
user = WebUser(123, "Jane Doe", "jane@example.com")
263
264
# Automatically uses camelCase for JSON output
265
user_json = user.json
266
print(user_json)
267
# {'userId': 123, 'fullName': 'Jane Doe', 'emailAddress': 'jane@example.com'}
268
269
# Automatically converts camelCase input to snake_case attributes
270
camel_input = {'userId': 456, 'fullName': 'Bob Smith', 'emailAddress': 'bob@example.com'}
271
new_user = WebUser.from_json(camel_input)
272
print(new_user.user_id) # 456
273
print(new_user.full_name) # 'Bob Smith'
274
print(new_user.email_address) # 'bob@example.com'
275
```
276
277
### Complex Nested Key Transformation
278
279
```python
280
import jsons
281
from jsons import KEY_TRANSFORMER_CAMELCASE, KEY_TRANSFORMER_SNAKECASE
282
from dataclasses import dataclass
283
from typing import Dict, List
284
285
@dataclass
286
class ContactInfo:
287
phone_number: str
288
email_address: str
289
home_address: str
290
291
@dataclass
292
class EmployeeRecord:
293
employee_id: int
294
first_name: str
295
last_name: str
296
contact_info: ContactInfo
297
skill_ratings: Dict[str, int]
298
project_history: List[str]
299
300
# Create complex nested object
301
employee = EmployeeRecord(
302
employee_id=1001,
303
first_name="Sarah",
304
last_name="Johnson",
305
contact_info=ContactInfo(
306
phone_number="555-0123",
307
email_address="sarah.j@company.com",
308
home_address="123 Oak Street"
309
),
310
skill_ratings={"python_programming": 9, "project_management": 8, "data_analysis": 7},
311
project_history=["web_redesign", "mobile_app", "data_migration"]
312
)
313
314
# Transform all nested keys to camelCase
315
camel_json = jsons.dump(employee, key_transformer=KEY_TRANSFORMER_CAMELCASE)
316
print(camel_json)
317
# {
318
# 'employeeId': 1001,
319
# 'firstName': 'Sarah',
320
# 'lastName': 'Johnson',
321
# 'contactInfo': {
322
# 'phoneNumber': '555-0123',
323
# 'emailAddress': 'sarah.j@company.com',
324
# 'homeAddress': '123 Oak Street'
325
# },
326
# 'skillRatings': {'pythonProgramming': 9, 'projectManagement': 8, 'dataAnalysis': 7},
327
# 'projectHistory': ['web_redesign', 'mobile_app', 'data_migration']
328
# }
329
330
# Deserialize camelCase back to snake_case structure
331
restored_employee = jsons.load(camel_json, EmployeeRecord, key_transformer=KEY_TRANSFORMER_SNAKECASE)
332
print(restored_employee.employee_id) # 1001
333
print(restored_employee.contact_info.phone_number) # '555-0123'
334
print(restored_employee.skill_ratings['python_programming']) # 9
335
```
336
337
### Working with Different API Styles
338
339
```python
340
import jsons
341
from jsons import KEY_TRANSFORMER_PASCALCASE, KEY_TRANSFORMER_LISPCASE, KEY_TRANSFORMER_SNAKECASE
342
from dataclasses import dataclass
343
344
@dataclass
345
class ConfigData:
346
server_host: str
347
server_port: int
348
database_url: str
349
cache_timeout: int
350
debug_mode: bool
351
352
config = ConfigData(
353
server_host="localhost",
354
server_port=8080,
355
database_url="postgresql://localhost/mydb",
356
cache_timeout=300,
357
debug_mode=True
358
)
359
360
# Generate different formats for different systems
361
formats = {
362
"JavaScript API": jsons.dump(config, key_transformer=jsons.camelcase),
363
"C# API": jsons.dump(config, key_transformer=KEY_TRANSFORMER_PASCALCASE),
364
"Lisp/Clojure": jsons.dump(config, key_transformer=KEY_TRANSFORMER_LISPCASE),
365
"Python/Ruby": jsons.dump(config, key_transformer=KEY_TRANSFORMER_SNAKECASE)
366
}
367
368
for system, format_data in formats.items():
369
print(f"{system}:")
370
print(format_data)
371
print()
372
373
# Output:
374
# JavaScript API:
375
# {'serverHost': 'localhost', 'serverPort': 8080, 'databaseUrl': '...', 'cacheTimeout': 300, 'debugMode': True}
376
#
377
# C# API:
378
# {'ServerHost': 'localhost', 'ServerPort': 8080, 'DatabaseUrl': '...', 'CacheTimeout': 300, 'DebugMode': True}
379
#
380
# Lisp/Clojure:
381
# {'server-host': 'localhost', 'server-port': 8080, 'database-url': '...', 'cache-timeout': 300, 'debug-mode': True}
382
#
383
# Python/Ruby:
384
# {'server_host': 'localhost', 'server_port': 8080, 'database_url': '...', 'cache_timeout': 300, 'debug_mode': True}
385
```