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
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-sdict[full]"
# pip install "jsonc-sdict[full] @ git+https://github.com/AClon314/jsonc-sdict.git"For local development:
git clone https://github.com/AClon314/jsonc-sdict.git
cd jsonc-sdict
pip install -e ".[dev]"from jsonc_sdict import jsoncDict, CommentIn, NONE
jc = jsoncDict(
{
CommentIn(NONE, "a"): "// before a",
"a": 1,
CommentIn("a", "b"): "// between a and b",
"b": 2,
}
)
jc[CommentIn("b")] = {CommentIn(":", "v"): "/* before value */"}
jc["b"] = 3
print(jc.full)Use CommentIn to mark comment positions. See test_jsonc.py.
CommentIn(left, right)means a comment between two logical items.CommentIn(key)means comments attached to one pair's internalk:/:v/v,slots.
If you start from JSONC/HJSON text instead of a mapping, use jsoncDict(raw, loads=hjson.loads, dumps=hjson.dumps).
/* // this is block comment */ trailing-text-is-illegalSee test_sdict.py.
from jsonc_sdict import sdict
data = sdict({"node": {"items": [0, {"value": 1}]}, "a": 1, "b": 2, "c": 2})
print(data["node", "items", 1, "value"])
data["node", "items", 1, "value"] = 2
node = data["node"]
print(node.keypath)
print(node.parent is data)
data.insert({"x": 9}, key="a", after=True)
data.rename_key("x", "y")
data.sort(reverse=True)
print(list(data.items()))
print(data.unref())from functools import partial
from jsonc_sdict import get1, merge
old = {"children": [{"id": 1, "name": "1", "old": None}]}
new = {"children": [{"id": 1, "name": "2", "new": ""}, {"id": 2, "name": "3"}]}
result = merge(
(old, new),
dictDict={"value_of_idKey": partial(get1.item, keys="id")},
unMergeable="new",
)()
print(result)merge((old, new))() is the shortest form. For list[dict], pass dictDict=... so items can be matched by an id-like key before diff/merge.
from functools import partial
from jsonc_sdict import get1, merge
old = {"items": [{"id": 1, "name": "old", "keep": True}]}
new = {"items": [{"id": 1, "name": "new"}, {"id": 2, "name": "add"}]}
merged = merge(
(old, new),
dictDict={"value_of_idKey": partial(get1.item, keys="id")},
unMergeable="new",
)()
print(merged)deep-merge -i '{a:{b:1}}' '{a:{b:2}}' -fo json -m new
# {"a": {"b": 2}}See test_get_set_del.py.
from jsonc_sdict import get1, set1
from jsonc_sdict.GetSetDel import del1
obj = {"a": {"b": 1}}
print(get1.item(obj, ("a", "b")))
print(set1.item(obj, ("a", "b"), 2))
print(set1.item(obj, ("a", "c"), 3))
del1.item(obj, ("a", "b"))
print(obj)LOG=DEBUG enables debug-level logging.
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.CommentIn(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 | comment |
|---|---|---|---|---|
| spyoungtech/json-five |
Python JSON5 parser with round-trip preservation of comments | can keep comment in another API style (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 */