Developer recipes

Publish a read-only CSV report with the Python standard library

Sometimes a shareable CSV snapshot is all a stakeholder needs, not a live dashboard. This recipe uses only the Python 3 standard library, no pandas, to generate, save, and publish the report.

On this page

What this does

The Python download builds a small checks report with csv.writer, writes it as UTF-8 to a local file with exclusive creation, then uploads the identical bytes using urllib. The demo rows are demo-alpha at 8 of 10 checks and demo-beta at 10 of 10. Everything after the local write is a read-only public snapshot of what you generated.

Run it

Use a fresh directory so the exclusive-create write cannot clash with an earlier report:

sh
work=$(mktemp -d)
cd "$work"
curl --fail-with-body --silent --show-error \
  --connect-timeout 10 --max-time 60 --retry 2 \
  https://yoink.zip/examples/public-report.py -o public-report.py

Run the downloaded script using the command in the next section. On success, stdout carries only the public URL. All progress and error detail goes to stderr, including the failing stage, HTTP status, and a truncated response body, and the script exits nonzero on any failure.

Separate the URL from the local file

Keep two facts distinct in your shell session: public-report.csv on disk is your original record for reruns and recovery, and the printed URL is the snapshot others can fetch. If a later run changes the data, the old link still points at the old snapshot.

sh
url=$(python3 public-report.py) || exit 1
printf 'Report: %s\n' "$url"

Request details

The script uses urllib with a 60 second socket timeout. The presign POST sends JSON with the filename, text/csv content type, and the byte length computed with len(data) after encoding the CSV as UTF-8 bytes, rather than counting characters. The PUT sends the exact same bytes to the signed URL with the returned Content-Type header, no multipart and no authorization header. Transient failures retry at most twice; 400, 401, 403, and 413 responses stop the script for diagnosis instead of retrying.

Sanitize before you share

The public link is public to anyone holding it, there is no delete API, and there is no retention guarantee. Aggregate your data before sharing. The demo uses project codenames deliberately; adapt the script so real runs never leak personal names, email addresses, or customer records into the CSV. If your source data contains per-user rows, roll them up into counts and pass rates first.

What recipients see

The content type is text/csv, and MIME type controls how servers describe the file, but the client decides what to do with it. Many browsers will download a CSV rather than preview it inline, so tell recipients to expect a download they open in a spreadsheet tool.

Scope

This is a point-in-time artifact, not a live dashboard, and not a pipeline for bulk storage. For repeated reporting, keep the script as the generator, keep each local CSV as the original, and save each successful URL alongside the report date so you know which snapshot a ticket or document refers to. Consult the API reference when changing the upload step.