A Python implementation of the JSON5 data format.
npx @tessl/cli install tessl/pypi-json5@0.12.00
# JSON5
1
2
A Python implementation of the JSON5 data format. JSON5 extends standard JSON with JavaScript-style features including single and multi-line comments, unquoted object keys for valid ECMAScript identifiers, trailing commas in objects and arrays, single-quoted strings, and multi-line string literals. This library mirrors the standard Python JSON API for ease of use.
3
4
## Package Information
5
6
- **Package Name**: json5
7
- **Language**: Python
8
- **Installation**: `pip install json5`
9
10
## Core Imports
11
12
```python
13
import json5
14
```
15
16
All functions are available at the top level:
17
18
```python
19
from json5 import load, loads, dump, dumps, parse, JSON5Encoder, QuoteStyle
20
```
21
22
## Basic Usage
23
24
```python
25
import json5
26
27
# Parse JSON5 string
28
data = json5.loads('''
29
{
30
// JavaScript-style comments
31
unquoted: "keys are allowed",
32
'single': 'quotes work too',
33
"trailing": "commas are ok",
34
}
35
''')
36
37
# Serialize Python object to JSON5
38
obj = {"name": "example", "values": [1, 2, 3]}
39
json5_string = json5.dumps(obj, indent=2, trailing_commas=True)
40
print(json5_string)
41
# Output:
42
# {
43
# name: 'example',
44
# values: [
45
# 1,
46
# 2,
47
# 3,
48
# ],
49
# }
50
51
# Parse from file
52
with open('config.json5', 'r') as f:
53
config = json5.load(f)
54
55
# Write to file
56
with open('output.json5', 'w') as f:
57
json5.dump(data, f, indent=2, quote_keys=False)
58
```
59
60
## Capabilities
61
62
### Parsing Functions
63
64
Load and parse JSON5 documents into Python objects, supporting file objects and strings with extensive customization options.
65
66
```python { .api }
67
def load(
68
fp,
69
*,
70
encoding=None,
71
cls=None,
72
object_hook=None,
73
parse_float=None,
74
parse_int=None,
75
parse_constant=None,
76
strict=True,
77
object_pairs_hook=None,
78
allow_duplicate_keys=True,
79
consume_trailing=True,
80
start=None
81
):
82
"""
83
Deserialize fp (a .read()-supporting file-like object containing a JSON5 document) to a Python object.
84
85
Parameters:
86
- fp: file-like object with .read() method
87
- encoding: character encoding (default: UTF-8)
88
- cls: ignored (for json compatibility)
89
- object_hook: optional function to transform decoded objects
90
- parse_float: optional function to parse float values
91
- parse_int: optional function to parse integer values
92
- parse_constant: optional function to parse constants (Infinity, NaN)
93
- strict: if True, control characters (\\x00-\\x1f) in strings raise ValueError
94
- object_pairs_hook: optional function called with ordered list of key-value pairs
95
- allow_duplicate_keys: if False, duplicate keys raise ValueError
96
- consume_trailing: if True, trailing non-whitespace raises ValueError
97
- start: offset position to start parsing from in file
98
99
Returns:
100
Parsed Python object
101
102
Raises:
103
- ValueError: invalid JSON5 document
104
- UnicodeDecodeError: invalid UTF-8 encoding
105
"""
106
107
def loads(
108
s,
109
*,
110
encoding=None,
111
cls=None,
112
object_hook=None,
113
parse_float=None,
114
parse_int=None,
115
parse_constant=None,
116
strict=True,
117
object_pairs_hook=None,
118
allow_duplicate_keys=True,
119
consume_trailing=True,
120
start=None
121
):
122
"""
123
Deserialize s (a string containing a JSON5 document) to a Python object.
124
125
Parameters:
126
- s: JSON5 string to parse
127
- encoding: character encoding (default: UTF-8)
128
- cls: ignored (for json compatibility)
129
- object_hook: optional function to transform decoded objects
130
- parse_float: optional function to parse float values
131
- parse_int: optional function to parse integer values
132
- parse_constant: optional function to parse constants (Infinity, NaN)
133
- strict: if True, control characters (\\x00-\\x1f) in strings raise ValueError
134
- object_pairs_hook: optional function called with ordered list of key-value pairs
135
- allow_duplicate_keys: if False, duplicate keys raise ValueError
136
- consume_trailing: if True, trailing non-whitespace raises ValueError
137
- start: offset position to start parsing from in string
138
139
Returns:
140
Parsed Python object
141
142
Raises:
143
- ValueError: invalid JSON5 document
144
- UnicodeDecodeError: invalid UTF-8 encoding
145
"""
146
147
def parse(
148
s,
149
*,
150
encoding=None,
151
cls=None,
152
object_hook=None,
153
parse_float=None,
154
parse_int=None,
155
parse_constant=None,
156
strict=True,
157
object_pairs_hook=None,
158
allow_duplicate_keys=True,
159
consume_trailing=True,
160
start=None
161
):
162
"""
163
Parse s, returning positional information along with a value.
164
165
Useful for parsing multiple values from a single string by repeatedly calling
166
with start parameter set to the position returned from previous call.
167
168
Parameters:
169
- s: JSON5 string to parse
170
- encoding: character encoding (default: UTF-8)
171
- cls: ignored (for json compatibility)
172
- object_hook: optional function to transform decoded objects
173
- parse_float: optional function to parse float values
174
- parse_int: optional function to parse integer values
175
- parse_constant: optional function to parse constants (Infinity, NaN)
176
- strict: if True, control characters (\\x00-\\x1f) in strings raise ValueError
177
- object_pairs_hook: optional function called with ordered list of key-value pairs
178
- allow_duplicate_keys: if False, duplicate keys raise ValueError
179
- consume_trailing: if True, trailing non-whitespace raises ValueError
180
- start: offset position to start parsing from in string
181
182
Returns:
183
Tuple of (value, error_string, position):
184
- value: parsed Python object or None if error
185
- error_string: None if successful, error message if failed
186
- position: zero-based offset where parsing stopped
187
188
Raises:
189
- UnicodeDecodeError: invalid UTF-8 encoding
190
"""
191
```
192
193
#### Usage Examples
194
195
```python
196
import json5
197
198
# Basic parsing
199
data = json5.loads('{"name": "example"}')
200
201
# Parse with custom hooks
202
def custom_object_hook(obj):
203
return {k.upper(): v for k, v in obj.items()}
204
205
data = json5.loads('{"name": "example"}', object_hook=custom_object_hook)
206
# Result: {"NAME": "example"}
207
208
# Parse multiple values from string
209
s = '{"a": 1} {"b": 2} {"c": 3}'
210
values = []
211
start = 0
212
while start < len(s):
213
value, error, pos = json5.parse(s, start=start, consume_trailing=False)
214
if error:
215
break
216
values.append(value)
217
start = pos
218
# Skip whitespace
219
while start < len(s) and s[start].isspace():
220
start += 1
221
222
# Reject duplicate keys
223
try:
224
json5.loads('{"key": 1, "key": 2}', allow_duplicate_keys=False)
225
except ValueError as e:
226
print(f"Duplicate key error: {e}")
227
```
228
229
### Serialization Functions
230
231
Serialize Python objects to JSON5 format with extensive formatting and style options.
232
233
```python { .api }
234
def dump(
235
obj,
236
fp,
237
*,
238
skipkeys=False,
239
ensure_ascii=True,
240
check_circular=True,
241
allow_nan=True,
242
cls=None,
243
indent=None,
244
separators=None,
245
default=None,
246
sort_keys=False,
247
quote_keys=False,
248
trailing_commas=True,
249
allow_duplicate_keys=True,
250
quote_style=QuoteStyle.ALWAYS_DOUBLE,
251
**kwargs
252
):
253
"""
254
Serialize obj to a JSON5-formatted stream to fp (a .write()-supporting file-like object).
255
256
Parameters:
257
- obj: Python object to serialize
258
- fp: file-like object with .write() method
259
- skipkeys: if True, skip keys that are not basic types
260
- ensure_ascii: if True, escape non-ASCII characters
261
- check_circular: if True, check for circular references
262
- allow_nan: if True, allow NaN, Infinity, -Infinity
263
- cls: custom JSON5Encoder class
264
- indent: indentation (int for spaces, str for custom, None for compact)
265
- separators: (item_separator, key_separator) tuple
266
- default: function to handle non-serializable objects
267
- sort_keys: if True, sort object keys
268
- quote_keys: if True, always quote object keys
269
- trailing_commas: if True, add trailing commas in multiline output
270
- allow_duplicate_keys: if True, allow duplicate keys in output
271
- quote_style: QuoteStyle enum value controlling string quoting
272
273
Raises:
274
- TypeError: non-serializable object
275
- ValueError: circular reference or invalid value
276
"""
277
278
def dumps(
279
obj,
280
*,
281
skipkeys=False,
282
ensure_ascii=True,
283
check_circular=True,
284
allow_nan=True,
285
cls=None,
286
indent=None,
287
separators=None,
288
default=None,
289
sort_keys=False,
290
quote_keys=False,
291
trailing_commas=True,
292
allow_duplicate_keys=True,
293
quote_style=QuoteStyle.ALWAYS_DOUBLE,
294
**kwargs
295
):
296
"""
297
Serialize obj to a JSON5-formatted string.
298
299
Parameters:
300
- obj: Python object to serialize
301
- skipkeys: if True, skip keys that are not basic types
302
- ensure_ascii: if True, escape non-ASCII characters
303
- check_circular: if True, check for circular references
304
- allow_nan: if True, allow NaN, Infinity, -Infinity
305
- cls: custom JSON5Encoder class
306
- indent: indentation (int for spaces, str for custom, None for compact)
307
- separators: (item_separator, key_separator) tuple
308
- default: function to handle non-serializable objects
309
- sort_keys: if True, sort object keys
310
- quote_keys: if True, always quote object keys
311
- trailing_commas: if True, add trailing commas in multiline output
312
- allow_duplicate_keys: if True, allow duplicate keys in output
313
- quote_style: QuoteStyle enum value controlling string quoting
314
315
Returns:
316
JSON5-formatted string
317
318
Raises:
319
- TypeError: non-serializable object
320
- ValueError: circular reference or invalid value
321
"""
322
```
323
324
#### Usage Examples
325
326
```python
327
import json5
328
from json5 import QuoteStyle
329
330
# Basic serialization
331
data = {"name": "example", "values": [1, 2, 3]}
332
json5_str = json5.dumps(data)
333
334
# Pretty-printed with unquoted keys and trailing commas
335
json5_str = json5.dumps(data, indent=2, quote_keys=False, trailing_commas=True)
336
337
# Use single quotes for strings
338
json5_str = json5.dumps(data, quote_style=QuoteStyle.ALWAYS_SINGLE)
339
340
# JSON compatibility mode
341
json_str = json5.dumps(data, quote_keys=True, trailing_commas=False)
342
343
# Custom serialization
344
def custom_serializer(obj):
345
if hasattr(obj, '__dict__'):
346
return obj.__dict__
347
raise TypeError(f"Object of type {type(obj)} is not JSON5 serializable")
348
349
class Person:
350
def __init__(self, name, age):
351
self.name = name
352
self.age = age
353
354
person = Person("Alice", 30)
355
json5_str = json5.dumps(person, default=custom_serializer, indent=2)
356
```
357
358
### Encoder Classes
359
360
Customizable JSON5 encoder for advanced serialization control and extensibility.
361
362
```python { .api }
363
class JSON5Encoder:
364
"""
365
Customizable JSON5 encoder class.
366
"""
367
368
def __init__(
369
self,
370
*,
371
skipkeys=False,
372
ensure_ascii=True,
373
check_circular=True,
374
allow_nan=True,
375
indent=None,
376
separators=None,
377
default=None,
378
sort_keys=False,
379
quote_keys=False,
380
trailing_commas=True,
381
allow_duplicate_keys=True,
382
quote_style=QuoteStyle.ALWAYS_DOUBLE,
383
**kwargs
384
):
385
"""
386
Initialize JSON5 encoder with formatting options.
387
388
Parameters match those of dumps() function.
389
"""
390
391
def default(self, obj):
392
"""
393
Override to provide custom serialization for objects that are not
394
natively JSON5 serializable.
395
396
Parameters:
397
- obj: object to serialize
398
399
Returns:
400
JSON5-serializable representation of obj
401
402
Raises:
403
- TypeError: if obj cannot be serialized
404
"""
405
406
def encode(self, obj, seen, level, *, as_key=False):
407
"""
408
Return JSON5-encoded version of obj.
409
410
Parameters:
411
- obj: object to encode
412
- seen: set of object ids for circular reference detection
413
- level: current nesting level
414
- as_key: if True, encode as object key
415
416
Returns:
417
JSON5-encoded string
418
419
Raises:
420
- TypeError: unsupported object type
421
- ValueError: circular reference or invalid value
422
"""
423
424
def is_identifier(self, key):
425
"""
426
Check if key can be used as unquoted object key.
427
428
Parameters:
429
- key: string to check
430
431
Returns:
432
True if key is valid ECMAScript identifier
433
"""
434
435
def is_reserved_word(self, key):
436
"""
437
Check if key is ECMAScript reserved word.
438
439
Parameters:
440
- key: string to check
441
442
Returns:
443
True if key is reserved word
444
"""
445
```
446
447
#### Usage Examples
448
449
```python
450
import json5
451
from json5 import JSON5Encoder, QuoteStyle
452
453
# Custom encoder for special objects
454
class CustomEncoder(JSON5Encoder):
455
def default(self, obj):
456
if isinstance(obj, set):
457
return list(obj)
458
if hasattr(obj, 'isoformat'): # datetime objects
459
return obj.isoformat()
460
return super().default(obj)
461
462
# Use custom encoder
463
from datetime import datetime
464
data = {
465
"timestamp": datetime.now(),
466
"tags": {"python", "json5", "serialization"}
467
}
468
json5_str = json5.dumps(data, cls=CustomEncoder, indent=2)
469
470
# Encoder with custom quote style
471
encoder = JSON5Encoder(
472
quote_style=QuoteStyle.PREFER_SINGLE,
473
indent=2,
474
trailing_commas=True
475
)
476
json5_str = encoder.encode(data, set(), 0, as_key=False)
477
```
478
479
### String Quoting Styles
480
481
Control how strings are quoted during JSON5 serialization.
482
483
```python { .api }
484
class QuoteStyle(enum.Enum):
485
"""
486
Enum controlling how strings are quoted during encoding.
487
"""
488
489
ALWAYS_DOUBLE = 'always_double' # Always use double quotes
490
ALWAYS_SINGLE = 'always_single' # Always use single quotes
491
PREFER_DOUBLE = 'prefer_double' # Prefer double, use single if fewer escapes
492
PREFER_SINGLE = 'prefer_single' # Prefer single, use double if fewer escapes
493
```
494
495
#### Usage Examples
496
497
```python
498
import json5
499
from json5 import QuoteStyle
500
501
text = "It's a \"wonderful\" day"
502
503
# Different quote styles
504
double_quoted = json5.dumps(text, quote_style=QuoteStyle.ALWAYS_DOUBLE)
505
# Result: "\"It's a \\\"wonderful\\\" day\""
506
507
single_quoted = json5.dumps(text, quote_style=QuoteStyle.ALWAYS_SINGLE)
508
# Result: "'It\\'s a \"wonderful\" day'"
509
510
prefer_double = json5.dumps(text, quote_style=QuoteStyle.PREFER_DOUBLE)
511
# Result: "'It\\'s a \"wonderful\" day'" (fewer escapes with single quotes)
512
513
prefer_single = json5.dumps(text, quote_style=QuoteStyle.PREFER_SINGLE)
514
# Result: "'It\\'s a \"wonderful\" day'" (preferred single quotes)
515
```
516
517
### Version Information
518
519
Access package version information for compatibility and debugging.
520
521
```python { .api }
522
__version__: str # Package version string (e.g., "0.12.1")
523
VERSION: str # Backward compatibility alias for __version__
524
```
525
526
#### Usage Examples
527
528
```python
529
import json5
530
531
print(f"Using json5 version: {json5.__version__}")
532
print(f"Version (legacy): {json5.VERSION}")
533
534
# Version checking
535
from packaging import version
536
if version.parse(json5.__version__) >= version.parse("0.12.0"):
537
print("QuoteStyle enum is available")
538
```
539
540
## JSON5 Features Supported
541
542
This implementation supports all JSON5 language features:
543
544
- **Comments**: Single-line `//` and multi-line `/* */` comments
545
- **Unquoted Keys**: Object keys that are valid ECMAScript identifiers don't need quotes
546
- **Trailing Commas**: Objects and arrays can have trailing commas
547
- **Single Quotes**: Strings can be single-quoted
548
- **Multi-line Strings**: String literals can span multiple lines
549
- **Additional Number Formats**: Hexadecimal numbers (0xFF), positive/negative infinity, NaN
550
- **Escape Sequences**: All JSON escape sequences plus single quote and vertical tab
551
552
## Error Handling
553
554
The library raises standard Python exceptions:
555
556
- **ValueError**: Invalid JSON5 syntax, duplicate keys (when disabled), circular references
557
- **TypeError**: Non-serializable objects during encoding
558
- **UnicodeDecodeError**: Invalid UTF-8 byte sequences
559
560
```python
561
import json5
562
563
# Handle parsing errors
564
try:
565
data = json5.loads('{"invalid": syntax}')
566
except ValueError as e:
567
print(f"Parse error: {e}")
568
569
# Handle encoding errors
570
try:
571
json5.dumps(object()) # object() is not serializable
572
except TypeError as e:
573
print(f"Encoding error: {e}")
574
```