Intermediate20 min

Files, JSON, and paths

Read and write data safely with context managers, and move between Python objects and JSON.

Why this matters in AI / ML / GenAI

Datasets arrive as JSONL, configs as YAML/JSON, prompts as text files, and eval results go back out as JSON. Every LLM API call is JSON on the wire. Path handling is where Windows/Linux bugs hide.

with open(...) — always

with open(path, "r", encoding="utf-8") as f: opens the file and guarantees it closes, even if the block raises. Never call open() without with in real code.

Always pass encoding="utf-8". Without it, Python uses the OS default, and a script that works on Linux CI crashes on a Windows laptop the moment a document contains an accented character or emoji.

Modes: "r" read, "w" write (truncates), "a" append, add "b" for bytes.

JSON and JSONL

json.dumps(obj) turns a dict into a string; json.loads(s) parses it back. The file variants are json.dump(obj, f) and json.load(f).

JSONL (one JSON object per line) is the standard format for fine-tuning datasets and eval sets, because you can stream it line by line without parsing the whole file.

json.dumps(obj, indent=2) for human-readable config. Use ensure_ascii=False when your text contains non-English characters, otherwise they are escaped into unreadable \u sequences.

pathlib over string concatenation

Use from pathlib import Path. Join with /: Path("data") / "train.jsonl". It produces correct separators on every OS.

Useful methods: .exists(), .mkdir(parents=True, exist_ok=True), .suffix, .stem, .read_text(), .write_text(), and .glob("*.jsonl") to list matching files.

Copy-paste examples

Copy into your own editor, or load one into the compiler below and press Run.

Write and read JSON

Runs in the browser compiler — Pyodide gives you a virtual filesystem.

import json

config = {"model": "gpt-4.1-mini", "temperature": 0.2, "tools": ["search", "calc"]}

with open("config.json", "w", encoding="utf-8") as f:
    json.dump(config, f, indent=2)

with open("config.json", "r", encoding="utf-8") as f:
    loaded = json.load(f)

print(loaded)
print("tools:", loaded["tools"])
print(json.dumps(loaded, indent=2))

Stream a JSONL dataset

One object per line — the format fine-tuning and eval pipelines expect.

import json

rows = [
    {"prompt": "What is MLOps?", "completion": "Operating ML in production."},
    {"prompt": "What is RAG?", "completion": "Retrieval plus generation."},
]

with open("train.jsonl", "w", encoding="utf-8") as f:
    for row in rows:
        f.write(json.dumps(row, ensure_ascii=False) + "\n")

with open("train.jsonl", "r", encoding="utf-8") as f:
    for i, line in enumerate(f, start=1):
        record = json.loads(line)
        print(i, record["prompt"], "->", record["completion"])

pathlib basics

Never build paths with string + '/' — pathlib handles Windows and Linux.

from pathlib import Path

data_dir = Path("artifacts") / "run-12"
data_dir.mkdir(parents=True, exist_ok=True)

metrics_path = data_dir / "metrics.json"
metrics_path.write_text('{"accuracy": 0.91}', encoding="utf-8")

print("exists:", metrics_path.exists())
print("suffix:", metrics_path.suffix, "| stem:", metrics_path.stem)
print("content:", metrics_path.read_text(encoding="utf-8"))
print("files:", [str(p) for p in data_dir.glob("*.json")])

Save an eval report

Try it — in-browser Python

Add another result row and confirm the accuracy recomputes.

Output

Python runs in your browser. First run downloads the runtime.

Press Run (or Ctrl+Enter) to execute.

CPython in WebAssembly. Stdlib works. NumPy and pandas load on demand. No input(), no GPU, no network installs.

Takeaways

  • Always use with open(..., encoding="utf-8") — it closes the file and avoids OS encoding bugs.
  • JSONL is the standard for training and eval datasets because it streams.
  • Build paths with pathlib, not string concatenation.