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%
4.9 KB · 155 lines markdown
Rendered Raw Blame History
1<!--2Author: Simon-Pierre Boucher3Contact: contact@spboucher.ai4-->56# JSON Recipes78## Contents9- Create10- Read / query11- Modify12- Convert (json ↔ jsonl, json → CSV)13- Validate14- Gotchas1516## Create1718**New file with non-ASCII content kept readable:**19```python20import json21data = {"name": "Café Müller", "items": [1, 2, 3]}22with open("out.json", "w", encoding="utf-8") as f:23    json.dump(data, f, indent=2, ensure_ascii=False)24    f.write("\n")                     # trailing newline: POSIX-friendly diffs25```2627**Compact machine-to-machine output:**28```python29json.dumps(data, separators=(",", ":"), ensure_ascii=False)30```3132## Read / query3334**Safe nested access:**35```python36value = data.get("config", {}).get("db", {}).get("host")   # None if any level missing37```3839**Filter a list of records:**40```python41active = [r for r in data["users"] if r.get("active")]42```4344**jq equivalents for large files (jq must be installed):**45```bash46jq '.users[] | select(.active) | .email' big.json      # filter + project47jq 'length' big.json                                   # count48jq -r '.items[].id' big.json                           # raw strings, no quotes49```5051**Detect duplicate keys while parsing:**52```python53def no_dupes(pairs):54    keys = [k for k, _ in pairs]55    dupes = {k for k in keys if keys.count(k) > 1}56    if dupes:57        raise ValueError(f"duplicate keys: {sorted(dupes)}")58    return dict(pairs)5960data = json.load(open("in.json", encoding="utf-8"), object_pairs_hook=no_dupes)61```6263## Modify6465**Atomic in-place update (the only sanctioned write pattern for existing files):**66```python67import json, os, tempfile6869def update_json(path, mutate):70    with open(path, encoding="utf-8") as f:71        data = json.load(f)72    mutate(data)73    fd, tmp = tempfile.mkstemp(dir=os.path.dirname(os.path.abspath(path)))74    with os.fdopen(fd, "w", encoding="utf-8") as f:75        json.dump(data, f, indent=2, ensure_ascii=False)76        f.write("\n")77    os.replace(tmp, path)             # atomic on POSIX7879update_json("config.json", lambda d: d.setdefault("features", {}).update(dark_mode=True))80```8182**Deep merge (dict-over-dict, right side wins):**83```python84def deep_merge(base, override):85    out = dict(base)86    for k, v in override.items():87        out[k] = deep_merge(out[k], v) if isinstance(out.get(k), dict) and isinstance(v, dict) else v88    return out89```9091**Shallow diff of two objects:**92```python93def diff(a, b):94    keys = a.keys() | b.keys()95    return {k: (a.get(k), b.get(k)) for k in keys if a.get(k) != b.get(k)}96```9798## Convert99100**jsonl → json array:**101```python102records = [json.loads(l) for l in open("in.jsonl", encoding="utf-8") if l.strip()]103json.dump(records, open("out.json", "w", encoding="utf-8"), indent=2, ensure_ascii=False)104```105106**json array → jsonl (streams better, appends safely):**107```python108with open("out.jsonl", "w", encoding="utf-8") as f:109    for r in json.load(open("in.json", encoding="utf-8")):110        f.write(json.dumps(r, ensure_ascii=False) + "\n")111```112113**Flat records → CSV** (nested values must be flattened or stringified first):114```python115import csv116rows = json.load(open("in.json", encoding="utf-8"))117fields = sorted({k for r in rows for k in r})118with open("out.csv", "w", newline="", encoding="utf-8") as f:119    w = csv.DictWriter(f, fieldnames=fields)120    w.writeheader(); w.writerows(rows)121```122123**Flatten nested keys with dots:**124```python125def flatten(d, prefix=""):126    out = {}127    for k, v in d.items():128        key = f"{prefix}{k}"129        out.update(flatten(v, key + ".")) if isinstance(v, dict) else out.setdefault(key, v)130    return out131```132133## Validate134135**Syntax:** `python3 -m json.tool file.json > /dev/null` — prints the error with line/column, exit 1 on failure.136137**Schema:**138```python139# pip install jsonschema140from jsonschema import validate, ValidationError141try:142    validate(instance=data, schema=schema)143except ValidationError as e:144    print(f"invalid at {list(e.absolute_path)}: {e.message}")145```146147## Gotchas148- **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.149- **`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`.150- **Encoding:** JSON files are UTF-8 by spec; always pass `encoding="utf-8"` — Windows defaults to cp1252 and corrupts round-trips.151- **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)`.152- **Large ints** round-trip fine in Python but break JavaScript beyond 2^53 − 1; stringify IDs above that when the consumer is JS.153- **`sort_keys=True` rewrites the whole file's order** — a huge diff for a one-key change. Leave order alone unless asked.154- **BOM:** files from Windows tools may start with U+FEFF; open with `encoding="utf-8-sig"` if `json.load` fails on character 0.155