Manifest lists and manifests are Avro 129 files, so fastavro (Protocol Buffers) can follow the chain by hand. The REST catalog returns the current metadata JSON with the table; the script then reads the manifest list and the first entry of a manifest, decoding statistics as the spec stores them (integers and timestamps little-endian):
"""Follow the orders metadata by hand: catalog -> manifest list -> manifest -> statistics."""
import io, json, subprocess, urllib.request
from datetime import datetime, timezone
import fastavro
def avro(uri): # read an s3:// Avro object through mc's alias
raw = subprocess.run(["mc", "cat", uri.replace("s3://", "lake/")], capture_output=True)
return list(fastavro.reader(io.BytesIO(raw.stdout)))
url = "http://localhost:31181/v1/namespaces/booknest/tables/orders"
meta = json.load(urllib.request.urlopen(url))["metadata"] # the current metadata JSON
cur = next(s for s in meta["snapshots"] if s["snapshot-id"] == meta["current-snapshot-id"])
le = lambda b: int.from_bytes(b, "little") # ints and timestamps: little-endian
for m in (manifests := avro(cur["manifest-list"])):
p = m["partitions"][0] # month = months since 1970-01
print(f'{m["manifest_path"][-12:]} content={m["content"]} seq={m["sequence_number"]} '
f'added={m["added_files_count"]} '
f'months {le(p["lower_bound"])}..{le(p["upper_bound"])}')
f = avro(manifests[0]["manifest_path"])[0]["data_file"] # first file of a manifest
ts = lambda b: datetime.fromtimestamp(le(b) / 1e6, timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
lo, hi = ({kv["key"]: kv["value"] for kv in f[k]} for k in ("lower_bounds", "upper_bounds"))
print(f["partition"], f["record_count"], "rows,", f["file_size_in_bytes"], "bytes")
print("order_ts (field 3) from", ts(lo[3]), "to", ts(hi[3]))Output
8c69-m0.avro content=0 seq=2 added=6 months 672..677
3277-m0.avro content=0 seq=1 added=12 months 660..671
{'order_ts_month': 672} 5643 rows, 56718 bytes
order_ts (field 3) from 2026-01-01 00:01:58 to 2026-01-31 23:58:30The current snapshot reuses the 2025 manifest (sequence 1) unchanged beside its own 2026 one, and their month ranges let a planner skip a whole manifest. Each entry's column bounds let a filter such as order_ts >= '2026-02-01' skip January's file unopened: Apache Parquet In Depth's predicate pushdown, moved up to whole files.