Round-trip comments for JSONC/HJSON, with dict-like APIs for config editing.
- Keep comments on read and write (
loads→ edit →body/full). - Work with nested structures via
sdict≈ deepmerge + deepdiff + benedict - Use weak-reference ordered containers via
weakList/OrderedWeakSet.
Comments are data too, just like codes are data too by John von Neumann
Warning
This project is currently 0.2.x and still evolving.
pip install jsonc-sdictFor local development:
pip install -e ".[dev]"import hjson
from jsonc_sdict import jsoncDict, Within, NONE
raw = """
{
"a": 1,
"b": 2
}
""".strip()
jc = jsoncDict(raw, loads=hjson.loads, dumps=hjson.dumps)
jc["b"] = 3
jc[Within(NONE, "a")] = "// inserted before a"
print(jc.full)import hjson
from jsonc_sdict import jsoncDict, Within, NONE
raw = """
// header
{
"a": 1, // inline
"b": 2
}
// footer
""".strip()
jc = jsoncDict(raw, loads=hjson.loads, dumps=hjson.dumps)
jc[Within(NONE, "a")] = "// before a"
jc[Within("a")] = {
Within("k", ":"): "/* key slot */",
Within(":", "v"): "/* value slot */",
Within("v", ","): "/* tail slot */",
}
print(jc.full)jsoncDict.comments stores comment positions with Within(...) keys.
Within(left, right)means a comment between two logical items.Within(key)means comments attached to one pair's internal slots.- Slot comments use a dict with
Within("k", ":"),Within(":", "v"),Within("v", ","). Within(NONE, first_key)andWithin(last_key, NONE)handle boundary comments.
Examples:
jc.comments[Within("a", "b")] = "// between a and b"
jc.comments[Within("b")] = {
Within("k", ":"): "/* before colon */",
Within(":", "v"): "/* before value */",
}Invalid JSONC examples:
/* // this is block comment */ trailing-text-is-illegalLOG=DEBUG enables debug-level logging in project loggers.
Common setup:
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
LOG=DEBUG pytest -qjsoncDict.loads()parses comments with tree-sitter and stores them intocomments.jsoncDict.bodyrenders the current value with comments restored.jsoncDict.fullreturnsheader + body + footer.Within(key)comments are stored as slot maps, not raw strings, so key/colon/value/comma placement stays explicit.
sdictwraps both mapping and iterable nodes; nested access may returnsdictviews, not raw dict/list.jsoncDictoutput depends on comment/data mutation paths; bypassing public APIs can leave internal state inconsistent.dfs()warns against mutating yielded data during iteration.insert(update, key=...|index=...)is ordering-oriented: it inserts by reordering keys after update.
- Items must support both
__hash__and weak references (__weakref__); built-inint/str/list/dictdo not qualify. - Weak references can disappear when no strong references exist; list length can shrink unexpectedly.
WeakList(noRepeat=True)is not identical toOrderedWeakSet: repeated append/insert can move item position.
| pypi | commits | issues | about | lack |
|---|---|---|---|---|
| spyoungtech/json-five |
Python JSON5 parser with round-trip preservation of comments | can keep comment, but in AST-tree style with lots of re-defined concepts (e.g: BlockComment/wsc_before) |
||
| tusharsadhwani/json5kit |
A Roundtrip parser and CST for JSON, JSONC and JSON5. | |||
| dpranke/pyjson5 |
A Python implementation of the JSON5 data format | |||
| austinyu/ujson5 |
A fast JSON5 encoder/decoder for Python | |||
| qvecs/qjson5 |
📎 A quick JSON5 implementation written in C, with Python bindings. |
// /* this is still single-line comment so this line is illegal */