Hjson, a user interface for JSON - human-friendly JSON configuration file format with comments, unquoted keys, and multiline strings
npx @tessl/cli install tessl/pypi-hjson@3.1.00
# Hjson
1
2
Hjson (Human JSON) is a user interface for JSON that makes configuration files more readable and maintainable. It extends JSON with comments, unquoted keys, optional commas, multiline strings, and other human-friendly features while maintaining full JSON compatibility. The library provides both Hjson parsing/generation and standard JSON encoding/decoding capabilities with an API that mirrors Python's built-in json module.
3
4
## Package Information
5
6
- **Package Name**: hjson
7
- **Language**: Python
8
- **Installation**: `pip install hjson`
9
- **Version**: 3.1.0
10
- **License**: MIT
11
12
## Core Imports
13
14
```python
15
import hjson
16
```
17
18
Direct imports for common functionality:
19
20
```python
21
from hjson import loads, dumps, load, dump
22
from hjson import dumpsJSON, dumpJSON
23
from hjson import HjsonDecoder, HjsonEncoder, JSONEncoder
24
from hjson import HjsonDecodeError, OrderedDict
25
```
26
27
## Basic Usage
28
29
```python
30
import hjson
31
32
# Parse Hjson string with human-friendly syntax
33
hjson_text = """{
34
// This is a comment
35
name: John Doe
36
age: 30
37
'quoted key': value with spaces
38
multiline: '''
39
This is a
40
multiline string
41
'''
42
}"""
43
44
# Parse to Python object
45
data = hjson.loads(hjson_text)
46
print(data) # OrderedDict([('name', 'John Doe'), ('age', 30), ...])
47
48
# Convert Python object to Hjson string
49
hjson_output = hjson.dumps(data)
50
print(hjson_output)
51
52
# Convert to standard JSON
53
json_output = hjson.dumpsJSON(data)
54
print(json_output) # Standard JSON format
55
```
56
57
## Architecture
58
59
Hjson provides dual encoding/decoding capabilities:
60
61
- **Hjson Format**: Human-readable format with comments, unquoted keys, trailing commas, and multiline strings
62
- **JSON Format**: Standard JSON with performance optimizations and compatibility with Python's json module
63
- **Flexible Parsing**: Extensive customization options for object hooks, number parsing, and encoding settings
64
- **OrderedDict Support**: Preserves key ordering by default using OrderedDict
65
- **CLI Tool**: Command-line interface for converting between formats
66
67
## Capabilities
68
69
### Hjson Parsing
70
71
Parse Hjson format strings and files into Python objects with support for comments, unquoted keys, and human-friendly syntax.
72
73
```python { .api }
74
def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None,
75
parse_int=None, object_pairs_hook=None, use_decimal=False, **kw):
76
"""
77
Deserialize Hjson string to Python object.
78
79
Parameters:
80
- s: str or bytes, Hjson document to parse
81
- encoding: str, character encoding (default: 'utf-8')
82
- cls: HjsonDecoder subclass for custom decoding
83
- object_hook: callable, called with result of every JSON object decoded
84
- parse_float: callable, used for parsing JSON floats
85
- parse_int: callable, used for parsing JSON integers
86
- object_pairs_hook: callable, called with ordered list of pairs
87
- use_decimal: bool, use decimal.Decimal for floats (default: False)
88
89
Returns:
90
Parsed Python object (typically OrderedDict)
91
"""
92
93
def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None,
94
parse_int=None, object_pairs_hook=OrderedDict, use_decimal=False,
95
namedtuple_as_object=True, tuple_as_array=True, **kw):
96
"""
97
Deserialize Hjson from file-like object to Python object.
98
99
Parameters:
100
- fp: file-like object with .read() method containing Hjson document
101
- encoding: str, character encoding (default: 'utf-8')
102
- cls: HjsonDecoder subclass for custom decoding
103
- object_hook: callable, called with result of every JSON object decoded
104
- parse_float: callable, used for parsing JSON floats
105
- parse_int: callable, used for parsing JSON integers
106
- object_pairs_hook: callable, called with ordered list of pairs (default: OrderedDict)
107
- use_decimal: bool, use decimal.Decimal for floats (default: False)
108
- namedtuple_as_object: bool, encode namedtuples as objects (default: True)
109
- tuple_as_array: bool, encode tuples as arrays (default: True)
110
111
Returns:
112
Parsed Python object
113
"""
114
```
115
116
### Hjson Encoding
117
118
Convert Python objects to human-readable Hjson format with customizable formatting options.
119
120
```python { .api }
121
def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
122
cls=None, indent=None, encoding='utf-8', default=None,
123
use_decimal=True, namedtuple_as_object=True, tuple_as_array=True,
124
bigint_as_string=False, sort_keys=False, item_sort_key=None,
125
for_json=False, int_as_string_bitcount=None, **kw):
126
"""
127
Serialize Python object to Hjson formatted string.
128
129
Parameters:
130
- obj: Python object to serialize
131
- skipkeys: bool, skip non-basic dict keys (default: False)
132
- ensure_ascii: bool, escape non-ASCII characters (default: True)
133
- check_circular: bool, check for circular references (default: True)
134
- cls: HjsonEncoder subclass for custom encoding
135
- indent: int or str, indentation for pretty-printing (default: 2 spaces)
136
- encoding: str, character encoding (default: 'utf-8')
137
- default: callable, called for objects not serializable by default
138
- use_decimal: bool, natively serialize Decimal (default: True)
139
- namedtuple_as_object: bool, encode namedtuples as objects (default: True)
140
- tuple_as_array: bool, encode tuples as arrays (default: True)
141
- bigint_as_string: bool, encode large ints as strings (default: False)
142
- sort_keys: bool, sort dictionary output by key (default: False)
143
- item_sort_key: callable, custom key sorting function
144
- for_json: bool, use for_json() method if available (default: False)
145
- int_as_string_bitcount: int, bit threshold for string encoding
146
147
Returns:
148
Hjson formatted string
149
"""
150
151
def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
152
cls=None, indent=None, encoding='utf-8', default=None,
153
use_decimal=True, namedtuple_as_object=True, tuple_as_array=True,
154
bigint_as_string=False, sort_keys=False, item_sort_key=None,
155
for_json=False, int_as_string_bitcount=None, **kw):
156
"""
157
Serialize Python object to Hjson formatted stream.
158
159
Parameters:
160
- obj: Python object to serialize
161
- fp: file-like object with .write() method
162
- skipkeys: bool, skip non-basic dict keys (default: False)
163
- ensure_ascii: bool, escape non-ASCII characters (default: True)
164
- check_circular: bool, check for circular references (default: True)
165
- cls: HjsonEncoder subclass for custom encoding
166
- indent: int or str, indentation for pretty-printing (default: 2 spaces)
167
- encoding: str, character encoding (default: 'utf-8')
168
- default: callable, called for objects not serializable by default
169
- use_decimal: bool, natively serialize Decimal (default: True)
170
- namedtuple_as_object: bool, encode namedtuples as objects (default: True)
171
- tuple_as_array: bool, encode tuples as arrays (default: True)
172
- bigint_as_string: bool, encode large ints as strings (default: False)
173
- sort_keys: bool, sort dictionary output by key (default: False)
174
- item_sort_key: callable, custom key sorting function
175
- for_json: bool, use for_json() method if available (default: False)
176
- int_as_string_bitcount: int, bit threshold for string encoding
177
178
Returns:
179
None (writes to file-like object)
180
"""
181
```
182
183
### JSON Encoding
184
185
Convert Python objects to standard JSON format with performance optimizations and compatibility with Python's json module.
186
187
```python { .api }
188
def dumpsJSON(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
189
cls=None, indent=None, separators=None, encoding='utf-8',
190
default=None, use_decimal=True, namedtuple_as_object=True,
191
tuple_as_array=True, bigint_as_string=False, sort_keys=False,
192
item_sort_key=None, for_json=False, int_as_string_bitcount=None, **kw):
193
"""
194
Serialize Python object to JSON formatted string.
195
196
Parameters:
197
- obj: Python object to serialize
198
- skipkeys: bool, skip non-basic dict keys (default: False)
199
- ensure_ascii: bool, escape non-ASCII characters (default: True)
200
- check_circular: bool, check for circular references (default: True)
201
- cls: JSONEncoder subclass for custom encoding
202
- indent: int or str, indentation for pretty-printing
203
- separators: tuple, (item_separator, key_separator) for formatting
204
- encoding: str, character encoding (default: 'utf-8')
205
- default: callable, called for objects not serializable by default
206
- use_decimal: bool, natively serialize Decimal (default: True)
207
- namedtuple_as_object: bool, encode namedtuples as objects (default: True)
208
- tuple_as_array: bool, encode tuples as arrays (default: True)
209
- bigint_as_string: bool, encode large ints as strings (default: False)
210
- sort_keys: bool, sort dictionary output by key (default: False)
211
- item_sort_key: callable, custom key sorting function
212
- for_json: bool, use for_json() method if available (default: False)
213
- int_as_string_bitcount: int, bit threshold for string encoding
214
215
Returns:
216
JSON formatted string
217
"""
218
219
def dumpJSON(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
220
cls=None, indent=None, separators=None, encoding='utf-8',
221
default=None, use_decimal=True, namedtuple_as_object=True,
222
tuple_as_array=True, bigint_as_string=False, sort_keys=False,
223
item_sort_key=None, for_json=False, int_as_string_bitcount=None, **kw):
224
"""
225
Serialize Python object to JSON formatted stream.
226
227
Parameters:
228
- obj: Python object to serialize
229
- fp: file-like object with .write() method
230
- skipkeys: bool, skip non-basic dict keys (default: False)
231
- ensure_ascii: bool, escape non-ASCII characters (default: True)
232
- check_circular: bool, check for circular references (default: True)
233
- cls: JSONEncoder subclass for custom encoding
234
- indent: int or str, indentation for pretty-printing
235
- separators: tuple, (item_separator, key_separator) for formatting
236
- encoding: str, character encoding (default: 'utf-8')
237
- default: callable, called for objects not serializable by default
238
- use_decimal: bool, natively serialize Decimal (default: True)
239
- namedtuple_as_object: bool, encode namedtuples as objects (default: True)
240
- tuple_as_array: bool, encode tuples as arrays (default: True)
241
- bigint_as_string: bool, encode large ints as strings (default: False)
242
- sort_keys: bool, sort dictionary output by key (default: False)
243
- item_sort_key: callable, custom key sorting function
244
- for_json: bool, use for_json() method if available (default: False)
245
- int_as_string_bitcount: int, bit threshold for string encoding
246
247
Returns:
248
None (writes to file-like object)
249
"""
250
```
251
252
### Custom Encoding and Decoding
253
254
Advanced classes for custom serialization and deserialization behavior.
255
256
```python { .api }
257
class HjsonDecoder(object):
258
"""
259
Hjson decoder with customizable parsing behavior.
260
"""
261
def __init__(self, encoding=None, object_hook=None, object_pairs_hook=None,
262
parse_float=None, parse_int=None, strict=True, use_decimal=False):
263
"""
264
Initialize Hjson decoder.
265
266
Parameters:
267
- encoding: str, character encoding
268
- object_hook: callable, called with every decoded object
269
- object_pairs_hook: callable, called with ordered pairs
270
- parse_float: callable, custom float parsing
271
- parse_int: callable, custom int parsing
272
- strict: bool, strict parsing mode
273
- use_decimal: bool, use Decimal for floats
274
"""
275
276
def decode(self, s, _w=None):
277
"""
278
Decode Hjson string to Python object.
279
280
Parameters:
281
- s: str, Hjson string to decode
282
283
Returns:
284
Decoded Python object
285
"""
286
287
def raw_decode(self, s, idx=0):
288
"""
289
Decode Hjson from string starting at given index.
290
291
Parameters:
292
- s: str, Hjson string
293
- idx: int, starting index
294
295
Returns:
296
tuple: (decoded_object, end_index)
297
"""
298
299
class HjsonEncoder(object):
300
"""
301
Hjson encoder with customizable formatting behavior.
302
"""
303
def __init__(self, skipkeys=False, ensure_ascii=True, check_circular=True,
304
indent=None, encoding='utf-8', default=None, use_decimal=True,
305
namedtuple_as_object=True, tuple_as_array=True,
306
bigint_as_string=False, sort_keys=False, item_sort_key=None,
307
for_json=False, int_as_string_bitcount=None):
308
"""
309
Initialize Hjson encoder.
310
311
Parameters:
312
- skipkeys: bool, skip non-basic dict keys
313
- ensure_ascii: bool, escape non-ASCII characters
314
- check_circular: bool, check for circular references
315
- indent: int or str, indentation for pretty-printing
316
- encoding: str, character encoding
317
- default: callable, fallback for non-serializable objects
318
- use_decimal: bool, natively serialize Decimal
319
- namedtuple_as_object: bool, encode namedtuples as objects
320
- tuple_as_array: bool, encode tuples as arrays
321
- bigint_as_string: bool, encode large ints as strings
322
- sort_keys: bool, sort dictionary keys
323
- item_sort_key: callable, custom key sorting function
324
- for_json: bool, use for_json() method if available
325
- int_as_string_bitcount: int, bit threshold for string encoding
326
"""
327
328
def default(self, o):
329
"""
330
Override to implement custom encoding for objects.
331
332
Parameters:
333
- o: object to encode
334
335
Returns:
336
Serializable representation of object
337
338
Raises:
339
TypeError: if object is not serializable
340
"""
341
342
def encode(self, o):
343
"""
344
Encode Python object to Hjson string.
345
346
Parameters:
347
- o: object to encode
348
349
Returns:
350
Hjson formatted string
351
"""
352
353
def iterencode(self, o, _one_shot=False):
354
"""
355
Encode Python object as iterator of string chunks.
356
357
Parameters:
358
- o: object to encode
359
- _one_shot: bool, internal optimization flag
360
361
Yields:
362
str: chunks of encoded Hjson
363
"""
364
365
class JSONEncoder(object):
366
"""
367
JSON encoder compatible with Python's json module.
368
"""
369
def __init__(self, skipkeys=False, ensure_ascii=True, check_circular=True,
370
indent=None, separators=None, encoding='utf-8', default=None,
371
use_decimal=True, namedtuple_as_object=True, tuple_as_array=True,
372
bigint_as_string=False, sort_keys=False, item_sort_key=None,
373
for_json=False, int_as_string_bitcount=None):
374
"""
375
Initialize JSON encoder.
376
377
Parameters:
378
- skipkeys: bool, skip non-basic dict keys
379
- ensure_ascii: bool, escape non-ASCII characters
380
- check_circular: bool, check for circular references
381
- indent: int or str, indentation for pretty-printing
382
- separators: tuple, (item_separator, key_separator)
383
- encoding: str, character encoding
384
- default: callable, fallback for non-serializable objects
385
- use_decimal: bool, natively serialize Decimal
386
- namedtuple_as_object: bool, encode namedtuples as objects
387
- tuple_as_array: bool, encode tuples as arrays
388
- bigint_as_string: bool, encode large ints as strings
389
- sort_keys: bool, sort dictionary keys
390
- item_sort_key: callable, custom key sorting function
391
- for_json: bool, use for_json() method if available
392
- int_as_string_bitcount: int, bit threshold for string encoding
393
"""
394
395
def default(self, o):
396
"""
397
Override to implement custom encoding for objects.
398
399
Parameters:
400
- o: object to encode
401
402
Returns:
403
Serializable representation of object
404
405
Raises:
406
TypeError: if object is not serializable
407
"""
408
409
def encode(self, o):
410
"""
411
Encode Python object to JSON string.
412
413
Parameters:
414
- o: object to encode
415
416
Returns:
417
JSON formatted string
418
"""
419
420
def iterencode(self, o, _one_shot=False):
421
"""
422
Encode Python object as iterator of string chunks.
423
424
Parameters:
425
- o: object to encode
426
- _one_shot: bool, internal optimization flag
427
428
Yields:
429
str: chunks of encoded JSON
430
"""
431
```
432
433
### Utility Functions and Classes
434
435
Helper functions and data structures for enhanced functionality.
436
437
```python { .api }
438
def simple_first(kv):
439
"""
440
Helper function for item_sort_key to sort simple elements first.
441
442
Sorts simple data types (strings, numbers, booleans, None) before
443
container types (lists, dicts, tuples) in dictionary output.
444
445
Parameters:
446
- kv: tuple, (key, value) pair from dictionary
447
448
Returns:
449
tuple: sort key tuple for ordering
450
"""
451
452
class OrderedDict(dict):
453
"""
454
Dictionary that preserves insertion order of keys.
455
456
Used as default object_pairs_hook to maintain key ordering
457
when parsing Hjson/JSON documents. Provides full dict interface
458
with ordering preservation.
459
"""
460
def __init__(self, *args, **kwargs):
461
"""Initialize ordered dictionary."""
462
463
# Standard dict methods with ordering preservation
464
def __setitem__(self, key, value): ...
465
def __delitem__(self, key): ...
466
def __iter__(self): ...
467
def keys(self): ...
468
def values(self): ...
469
def items(self): ...
470
def popitem(self, last=True): ...
471
def move_to_end(self, key, last=True): ...
472
473
class HjsonDecodeError(ValueError):
474
"""
475
Exception raised when Hjson decoding fails.
476
477
Provides detailed error information including position
478
and context for debugging malformed Hjson documents.
479
"""
480
def __init__(self, msg, doc, pos):
481
"""
482
Initialize decode error.
483
484
Parameters:
485
- msg: str, error message
486
- doc: str, source document
487
- pos: int, character position of error
488
"""
489
490
@property
491
def lineno(self):
492
"""int: Line number where error occurred."""
493
494
@property
495
def colno(self):
496
"""int: Column number where error occurred."""
497
498
@property
499
def msg(self):
500
"""str: Error message."""
501
502
@property
503
def doc(self):
504
"""str: Source document."""
505
506
@property
507
def pos(self):
508
"""int: Character position of error."""
509
```
510
511
## Command Line Interface
512
513
Hjson includes a command-line tool for converting between Hjson and JSON formats.
514
515
### Installation and Usage
516
517
After installing the package with `pip install hjson`, the `hjson` command becomes available:
518
519
```bash
520
# Convert Hjson to formatted Hjson (default)
521
echo '{name: value}' | hjson
522
523
# Convert to formatted JSON
524
echo '{name: value}' | hjson -j
525
526
# Convert to compact JSON
527
echo '{name: value}' | hjson -c
528
529
# Process files
530
hjson input.hjson
531
hjson -j input.hjson > output.json
532
533
# Show help
534
hjson --help
535
536
# Show version
537
hjson --version
538
```
539
540
### CLI Options
541
542
- **Default**: Output as formatted Hjson
543
- **`-j`**: Output as formatted JSON with indentation
544
- **`-c`**: Output as compact JSON without extra whitespace
545
- **`-h, --help`**: Show help message
546
- **`-V, --version`**: Show version information
547
548
## Advanced Usage Examples
549
550
### Custom Object Hooks
551
552
```python
553
import hjson
554
from decimal import Decimal
555
556
# Custom parsing with Decimal for high precision
557
def decimal_hook(pairs):
558
result = {}
559
for key, value in pairs:
560
if isinstance(value, float):
561
result[key] = Decimal(str(value))
562
else:
563
result[key] = value
564
return result
565
566
data = hjson.loads('{"price": 19.99}', object_pairs_hook=decimal_hook)
567
print(type(data['price'])) # <class 'decimal.Decimal'>
568
```
569
570
### Custom Encoding
571
572
```python
573
import hjson
574
from datetime import datetime
575
576
class DateTimeEncoder(hjson.HjsonEncoder):
577
def default(self, obj):
578
if isinstance(obj, datetime):
579
return obj.isoformat()
580
return super().default(obj)
581
582
data = {'timestamp': datetime.now(), 'value': 42}
583
result = hjson.dumps(data, cls=DateTimeEncoder)
584
print(result)
585
```
586
587
### Preserving Key Order
588
589
```python
590
import hjson
591
592
# OrderedDict is used by default for object_pairs_hook
593
hjson_text = """{
594
z: last
595
a: first
596
m: middle
597
}"""
598
599
data = hjson.loads(hjson_text)
600
print(list(data.keys())) # ['z', 'a', 'm'] - preserves original order
601
```
602
603
## Error Handling
604
605
```python
606
import hjson
607
608
try:
609
# Invalid Hjson syntax
610
data = hjson.loads('{invalid syntax}')
611
except hjson.HjsonDecodeError as e:
612
print(f"Parse error at line {e.lineno}, column {e.colno}: {e.msg}")
613
print(f"Position {e.pos} in document")
614
```
615
616
## Configuration Management Example
617
618
```python
619
import hjson
620
import os
621
622
def load_config(config_path):
623
"""Load configuration from Hjson file with environment variable support."""
624
with open(config_path, 'r') as f:
625
config_text = f.read()
626
627
# Parse Hjson configuration
628
config = hjson.load(f)
629
630
# Override with environment variables
631
if 'DATABASE_URL' in os.environ:
632
config['database']['url'] = os.environ['DATABASE_URL']
633
634
return config
635
636
# config.hjson:
637
# {
638
# // Database configuration
639
# database: {
640
# url: localhost:5432
641
# pool_size: 10
642
# }
643
# // Feature flags
644
# features: {
645
# caching: true
646
# analytics: false
647
# }
648
# }
649
650
config = load_config('config.hjson')
651
print(hjson.dumps(config, indent=2))
652
```