SPB Git

spb/ultra-sharp-agent-skills Public

Ultra-Sharp Agent Skills — a research-first skill-authoring system + 72 production-ready skills for AI agents.

Python 100%

# JSON Recipes

# Contents

  • Create
  • Read / query
  • Modify
  • Convert (json ↔ jsonl, json → CSV)
  • Validate
  • Gotchas

# Create

New file with non-ASCII content kept readable:

python
import json
data = {"name": "Café Müller", "items": [1, 2, 3]}
with open("out.json", "w", encoding="utf-8") as f:
    json.dump(data, f, indent=2, ensure_ascii=False)
    f.write("\n")                     # trailing newline: POSIX-friendly diffs

Compact machine-to-machine output:

python
json.dumps(data, separators=(",", ":"), ensure_ascii=False)

# Read / query

Safe nested access:

python
value = data.get("config", {}).get("db", {}).get("host")   # None if any level missing

Filter a list of records:

python
active = [r for r in data["users"] if r.get("active")]

jq equivalents for large files (jq must be installed):

bash
jq '.users[] | select(.active) | .email' big.json      # filter + project
jq 'length' big.json                                   # count
jq -r '.items[].id' big.json                           # raw strings, no quotes

Detect duplicate keys while parsing:

python
def no_dupes(pairs):
    keys = [k for k, _ in pairs]
    dupes = {k for k in keys if keys.count(k) > 1}
    if dupes:
        raise ValueError(f"duplicate keys: {sorted(dupes)}")
    return dict(pairs)

data = json.load(open("in.json", encoding="utf-8"), object_pairs_hook=no_dupes)

# Modify

Atomic in-place update (the only sanctioned write pattern for existing files):

python
import json, os, tempfile

def update_json(path, mutate):
    with open(path, encoding="utf-8") as f:
        data = json.load(f)
    mutate(data)
    fd, tmp = tempfile.mkstemp(dir=os.path.dirname(os.path.abspath(path)))
    with os.fdopen(fd, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=2, ensure_ascii=False)
        f.write("\n")
    os.replace(tmp, path)             # atomic on POSIX

update_json("config.json", lambda d: d.setdefault("features", {}).update(dark_mode=True))

Deep merge (dict-over-dict, right side wins):

python
def deep_merge(base, override):
    out = dict(base)
    for k, v in override.items():
        out[k] = deep_merge(out[k], v) if isinstance(out.get(k), dict) and isinstance(v, dict) else v
    return out

Shallow diff of two objects:

python
def diff(a, b):
    keys = a.keys() | b.keys()
    return {k: (a.get(k), b.get(k)) for k in keys if a.get(k) != b.get(k)}

# Convert

jsonl → json array:

python
records = [json.loads(l) for l in open("in.jsonl", encoding="utf-8") if l.strip()]
json.dump(records, open("out.json", "w", encoding="utf-8"), indent=2, ensure_ascii=False)

json array → jsonl (streams better, appends safely):

python
with open("out.jsonl", "w", encoding="utf-8") as f:
    for r in json.load(open("in.json", encoding="utf-8")):
        f.write(json.dumps(r, ensure_ascii=False) + "\n")

Flat records → CSV (nested values must be flattened or stringified first):

python
import csv
rows = json.load(open("in.json", encoding="utf-8"))
fields = sorted({k for r in rows for k in r})
with open("out.csv", "w", newline="", encoding="utf-8") as f:
    w = csv.DictWriter(f, fieldnames=fields)
    w.writeheader(); w.writerows(rows)

Flatten nested keys with dots:

python
def flatten(d, prefix=""):
    out = {}
    for k, v in d.items():
        key = f"{prefix}{k}"
        out.update(flatten(v, key + ".")) if isinstance(v, dict) else out.setdefault(key, v)
    return out

# Validate

Syntax: python3 -m json.tool file.json > /dev/null — prints the error with line/column, exit 1 on failure.

Schema:

python
# pip install jsonschema
from jsonschema import validate, ValidationError
try:
    validate(instance=data, schema=schema)
except ValidationError as e:
    print(f"invalid at {list(e.absolute_path)}: {e.message}")

# Gotchas

  • Trailing commas, single quotes, comments are the top three causes of JSONDecodeError — they are JavaScript habits, not JSON. Fix the exact character the error points at.
  • NaN, Infinity: json.dumps emits them by default but no strict parser accepts them. Use allow_nan=False to force the error at write time, then substitute null.
  • Encoding: JSON files are UTF-8 by spec; always pass encoding="utf-8" — Windows defaults to cp1252 and corrupts round-trips.
  • Float precision: json.load gives you binary floats (0.1 + 0.2 != 0.3); for money, parse with json.load(f, parse_float=decimal.Decimal).
  • Large ints round-trip fine in Python but break JavaScript beyond 2^53 − 1; stringify IDs above that when the consumer is JS.
  • sort_keys=True rewrites the whole file's order — a huge diff for a one-key change. Leave order alone unless asked.
  • BOM: files from Windows tools may start with U+FEFF; open with encoding="utf-8-sig" if json.load fails on character 0.