wrds-download

TUI/CLI tool for browsing and downloading WRDS data
Log | Files | Refs | README

commit ef9bb21aaabc5bde89a1d94dbf476e704ab73c83
parent 4d8c975f9b6c9c457db5af251b4da03a30c1a197
Author: Erik Loualiche <eloualiche@users.noreply.github.com>
Date:   Sun,  1 Mar 2026 22:05:40 -0600

Merge pull request #12 from LouLouLibs/demo/vhs-tape

Add VHS demo with credential redaction and redesign README
Diffstat:
M.gitignore | 3+++
AMakefile | 13+++++++++++++
MREADME.md | 76+++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Ademo-wrds-download.gif | 0
Ademo-wrds-download.tape | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ascripts/redact-demo.sh | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 290 insertions(+), 29 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -4,6 +4,9 @@ wrds-dl-* *.csv .claude/ +# Demo (raw GIF contains unredacted credentials) +demo-wrds-download-raw.gif + # Python python/.venv/ python/uv.lock diff --git a/Makefile b/Makefile @@ -0,0 +1,13 @@ +.PHONY: demo demo-record demo-redact + +# Record the VHS demo and blur the username in one step. +demo: demo-record demo-redact + +# Step 1: Record the raw GIF with VHS (outputs demo-wrds-download-raw.gif). +demo-record: + vhs demo-wrds-download.tape + +# Step 2: Blur the username on the login screen (raw -> clean). +# Override blur coordinates: BLUR_X=500 BLUR_Y=280 make demo-redact +demo-redact: + ./scripts/redact-demo.sh demo-wrds-download-raw.gif demo-wrds-download.gif diff --git a/README.md b/README.md @@ -1,4 +1,7 @@ +<div align="center"> + # wrds-dl +### Browse and download WRDS data from your terminal [![CI (Go)](https://github.com/LouLouLibs/wrds-download/actions/workflows/ci.yml/badge.svg)](https://github.com/LouLouLibs/wrds-download/actions/workflows/ci.yml) [![CI (Python)](https://github.com/LouLouLibs/wrds-download/actions/workflows/ci-python.yml/badge.svg)](https://github.com/LouLouLibs/wrds-download/actions/workflows/ci-python.yml) @@ -6,9 +9,25 @@ [![Python](https://img.shields.io/badge/Python-3.10+-3776AB?logo=python&logoColor=white)](python/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) -A terminal tool for browsing and downloading data from the [WRDS](https://wrds-www.wharton.upenn.edu/) PostgreSQL database. Output is Parquet or CSV. +<img src="./demo-wrds-download.gif" width="800" alt="Demo of the TUI browsing WRDS schemas and downloading data"> + +</div> + +--- + +## Features + +- **Interactive TUI** — browse schemas, tables, and column metadata with keyboard navigation +- **CLI download** — script-friendly `download` and `info` commands for automation and HPC +- **Parquet & CSV** — output to compressed Parquet (ZSTD) or CSV +- **Dry run** — preview queries, row counts, and sample rows before downloading +- **Raw SQL** — run arbitrary queries when schema/table syntax isn't enough +- **Streaming** — server-side cursors keep memory usage low on large tables +- **Saved credentials** — authenticate once, connect instantly + +## Two implementations -Two implementations with the same CLI interface — pick whichever fits your environment: +Same CLI interface — pick whichever fits your environment: | | [Go](go/) | [Python](python/) | |---|---|---| @@ -41,7 +60,7 @@ uv tool install wrds-dl --from ./python cd python && uv run wrds-dl --help ``` -## CLI (both implementations) +## Usage ```sh # CRSP monthly stock file — prices and returns for 2020 @@ -57,12 +76,7 @@ wrds-dl info --schema crsp --table msf wrds-dl download --schema crsp --table msf \ --where "date = '2020-01-31'" --dry-run -# CRSP daily stock file -wrds-dl download --schema crsp --table dsf \ - --where "date >= '2020-01-01' AND date < '2021-01-01'" \ - --out crsp_dsf_2020.parquet - -# Select specific columns from Compustat +# Compustat fundamentals wrds-dl download --schema comp --table funda \ --columns "gvkey,datadate,sale,at" \ --out funda_subset.parquet @@ -78,24 +92,6 @@ wrds-dl download --schema crsp --table msf \ --out crsp_msf_sample.csv ``` -## Claude Code skill - -Bundled [Claude Code](https://claude.com/claude-code) skills let you download WRDS data using natural language: - -``` -/wrds-download CRSP daily stock data for 2020 -``` - -Two variants available: -- [`claude-skill-wrds-download/`](claude-skill-wrds-download/) — uses the Go binary -- [`claude-skill-wrds-download-py/`](claude-skill-wrds-download-py/) — uses the Python CLI (no binary needed) - -Install by copying the skill into your skills directory: - -```sh -cp -r claude-skill-wrds-download-py ~/.claude/skills/wrds-download -``` - ## Authentication WRDS uses Duo two-factor authentication. Configure credentials before using the CLI. @@ -117,7 +113,7 @@ export PGDATABASE=wrds ### Option 2: Saved credentials -Store credentials at `~/.config/wrds-dl/credentials` (or `$XDG_CONFIG_HOME/wrds-dl/credentials`) with `0600` permissions: +Store at `~/.config/wrds-dl/credentials` (or `$XDG_CONFIG_HOME/wrds-dl/credentials`) with `0600` permissions: ``` PGUSER=your_username @@ -125,7 +121,7 @@ PGPASSWORD=your_password PGDATABASE=wrds ``` -The Go TUI can save these automatically on first login. +The Go TUI saves these automatically on first login. ### Option 3: ~/.pgpass @@ -135,6 +131,24 @@ Standard PostgreSQL password file: wrds-pgdata.wharton.upenn.edu:9737:*:your_username:your_password ``` +## Claude Code skill + +Bundled [Claude Code](https://claude.com/claude-code) skills let you download WRDS data using natural language: + +``` +/wrds-download CRSP daily stock data for 2020 +``` + +Two variants available: +- [`claude-skill-wrds-download/`](claude-skill-wrds-download/) — uses the Go binary +- [`claude-skill-wrds-download-py/`](claude-skill-wrds-download-py/) — uses the Python CLI (no binary needed) + +Install by copying the skill into your skills directory: + +```sh +cp -r claude-skill-wrds-download-py ~/.claude/skills/wrds-download +``` + ## Project structure ``` @@ -150,3 +164,7 @@ wrds-download/ ├── claude-skill-wrds-download-py/ # Claude skill (Python/uv) └── .github/workflows/ # CI for both implementations ``` + +## License + +MIT diff --git a/demo-wrds-download.gif b/demo-wrds-download.gif Binary files differ. diff --git a/demo-wrds-download.tape b/demo-wrds-download.tape @@ -0,0 +1,167 @@ +# VHS tape for recording wrds-dl TUI demo GIF. +# Usage: vhs demo-wrds-download.tape +# +# Prerequisites: +# - wrds-dl binary built and in PATH (or ./go/wrds-dl) +# - WRDS credentials saved (~/.config/wrds-dl/credentials) +# or exported as PGUSER / PGPASSWORD environment variables +# - Active network connection to WRDS (Duo 2FA approved) + +Output demo-wrds-download-raw.gif + +Set FontSize 18 +Set Width 1400 +Set Height 700 +Set Padding 20 +Set Theme "GruvboxDarkHard" + +Set TypingSpeed 80ms + +Set Shell "bash" + +Hide + Type 'export PS1="> "' + Enter + Type "clear" + Enter +Show + +# ─── 1. LAUNCH THE TUI ─── +Type "./wrds-dl tui" +Enter + +# Wait for login screen to render +Sleep 2s + +# ─── 2. LOGIN WITH SAVED CREDENTIALS ─── +# The login form shows "Login as <user> [enter]" when credentials exist. +# Press Enter to connect with saved credentials. +Enter + +# Wait for connection + Duo 2FA + schemas to load +Sleep 2s + +# ─── 3. BROWSE SCHEMAS ─── +# Schemas pane is focused by default. Navigate to find "crsp". +Sleep 500ms +Down 1 +Sleep 300ms +Down 1 +Sleep 300ms +Down 1 +Sleep 300ms +Down 1 +Sleep 300ms +Down 1 +Sleep 1s + +# Use "/" to filter schemas +Type "/" +Sleep 300ms +Type "crsp" +Sleep 1s +Enter +Sleep 1s + +# ─── 4. DRILL INTO SCHEMA ─── +# Press right arrow to select the schema and load its tables. +Right +Sleep 2s + +# ─── 5. BROWSE TABLES ─── +# Tables pane is now focused. Filter for "msf" (monthly stock file). +Type "/" +Sleep 300ms +Type "msf" +Sleep 1s +Enter +Sleep 2s + +# ─── 6. VIEW TABLE METADATA ─── +# Press right to drill into the table and see the preview pane. +Right +Sleep 3s + +# ─── 7. SCROLL THROUGH COLUMNS ─── +# Preview pane shows column catalog. Scroll with j/k. +Sleep 500ms +Down 1 +Sleep 300ms +Down 1 +Sleep 300ms +Down 1 +Sleep 300ms +Down 1 +Sleep 300ms +Down 1 +Sleep 1s + +# Scroll back up +Up 1 +Sleep 200ms +Up 1 +Sleep 200ms +Up 1 +Sleep 1s + +# ─── 8. FILTER COLUMNS ─── +# Press "/" in the preview pane to filter columns. +Type "/" +Sleep 300ms +Type "ret" +Sleep 1s +# Press Escape to clear the filter +Escape +Sleep 1s + +# ─── 9. OPEN DOWNLOAD DIALOG ─── +# Press "d" to open the download form. +Type "d" +Sleep 1s + +# ─── 10. FILL IN DOWNLOAD FORM ─── +# SELECT columns field — clear prepopulated "*" then type columns +Ctrl+U +Sleep 200ms +Type "permno,date,prc,ret,shrout" +Sleep 500ms + +# Move to WHERE clause +Tab +Sleep 300ms +Type "date >= '2024-01-01' AND date < '2024-02-01'" +Sleep 500ms + +# Move to LIMIT — leave empty (no limit) +Tab +Sleep 300ms + +# Move to Output path +Tab +Sleep 300ms +# Clear prepopulated path then type custom path +Ctrl+U +Sleep 200ms +Type "./crsp_msf_2024_jan.parquet" +Sleep 500ms + +# Move to Format — keep default "parquet" +Tab +Sleep 1s + +# ─── 11. SUBMIT DOWNLOAD ─── +Enter +Sleep 5s + +# ─── 12. DISMISS SUCCESS MESSAGE ─── +Escape +Sleep 1s + +# ─── 13. QUIT ─── +Type "q" +Sleep 500ms + +# ─── 14. VERIFY OUTPUT ─── +Type "du -h crsp_msf_2024_jan.parquet" +Enter +Sleep 3s diff --git a/scripts/redact-demo.sh b/scripts/redact-demo.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# redact-demo.sh — Blur the WRDS username on the login screen of a VHS-recorded GIF. +# +# Usage: +# ./scripts/redact-demo.sh # default paths +# ./scripts/redact-demo.sh raw.gif clean.gif # explicit paths +# +# All blur parameters can be overridden via environment variables. +# Record once, inspect the raw GIF, then tweak BLUR_X/Y/W/H if needed. +# +# Requires: ffmpeg + +set -euo pipefail + +INPUT="${1:-demo-wrds-download-raw.gif}" +OUTPUT="${2:-demo-wrds-download.gif}" + +if [[ ! -f "$INPUT" ]]; then + echo "Error: $INPUT not found. Run 'vhs demo-wrds-download.tape' first." >&2 + exit 1 +fi + +if ! command -v ffmpeg &>/dev/null; then + echo "Error: ffmpeg is required. Install with: brew install ffmpeg" >&2 + exit 1 +fi + +# ── Blur region (pixels) ── +# These cover the username text inside the "Login as <user> [enter]" button. +# Calibrated from the login frame at t≈2s (1400x700, FontSize 18, Padding 20). +BLUR_X="${BLUR_X:-490}" +BLUR_Y="${BLUR_Y:-210}" +BLUR_W="${BLUR_W:-100}" +BLUR_H="${BLUR_H:-20}" + +# ── Time window (seconds) ── +# The login screen is visible from launch until schemas load. +BLUR_START="${BLUR_START:-0}" +BLUR_END="${BLUR_END:-5}" + +# ── Pixelation factor (higher = more pixelated, less readable) ── +PIXEL_FACTOR="${PIXEL_FACTOR:-10}" + +TEMP=$(mktemp -d) +trap 'rm -rf "$TEMP"' EXIT + +echo "Pixelating region (${BLUR_X},${BLUR_Y}) ${BLUR_W}x${BLUR_H} during t=${BLUR_START}s-${BLUR_END}s (factor=${PIXEL_FACTOR})..." + +ffmpeg -y -loglevel error -i "$INPUT" -filter_complex \ + "[0:v]crop=${BLUR_W}:${BLUR_H}:${BLUR_X}:${BLUR_Y}, \ + scale=iw/${PIXEL_FACTOR}:ih/${PIXEL_FACTOR}, \ + scale=${BLUR_W}:${BLUR_H}:flags=neighbor[px]; \ + [0:v][px]overlay=${BLUR_X}:${BLUR_Y}:enable='between(t,${BLUR_START},${BLUR_END})'[v]; \ + [v]split[s0][s1]; \ + [s0]palettegen=max_colors=256:stats_mode=diff[p]; \ + [s1][p]paletteuse=dither=bayer:bayer_scale=3" \ + "$TEMP/out.gif" + +mv "$TEMP/out.gif" "$OUTPUT" +echo "Done: $INPUT -> $OUTPUT"