PD-01-003-P · Primer — Reading CSV Text
The idea in one sentence
pd.read_csv turns comma-separated text into a tidy DataFrame — and when your text lives in a string instead of a file, you wrap it in StringIO so pandas can read it like a file.
Why it exists
CSV ("comma-separated values") is the plainest, most universal way to move tabular data around: spreadsheets export it, APIs return it, and databases dump it. But raw CSV is just text — rows separated by newlines, columns separated by commas. Someone has to do the tedious work of splitting that text, spotting the header row, guessing the data types, and stacking everything into aligned columns. read_csv does all of it in one call. The StringIO trick matters because read_csv was built to read files, yet you often already have CSV sitting in a variable — from a web response, a test fixture, or a code sandbox like this one where there's no real file to open.
How it works
read_csv expects a "file-like" object or a path. When your data is a plain Python string, io.StringIO(text) hands pandas an in-memory object that behaves like an open file — so no disk, no cleanup, no external files needed. By default pandas treats the first line as the header row, using those values as column names, then parses each remaining line into a row. It also infers types automatically: text that looks numeric becomes integers or floats, everything else stays as strings. You get back a DataFrame with a clean integer index (0, 1, 2, …) and named columns you can select and filter. This is the same call whether the source is a 3-line snippet or a million-row export.
import pandas as pd
from io import StringIO
csv_text = """name,city,age
Ada,London,36
Grace,New York,45
Alan,Cambridge,41"""
df = pd.read_csv(StringIO(csv_text))
print(df)
# name city age
# 0 Ada London 36
# 1 Grace New York 45
# 2 Alan Cambridge 41
print(df.shape) # (3, 3) -> 3 rows, 3 columns
print(list(df.columns)) # ['name', 'city', 'age']
The one gotcha
If your text has no header row and you forget to say so, pandas silently steals your first data row and turns it into column names — so you lose a record and get columns like Ada and 36. When the file truly has no header, pass header=None (pandas then names columns 0, 1, 2, …), and add names=["name","city","age"] if you want real labels.
See it — CSV text becomes a shaped DataFrame
flowchart LR A["raw CSV text<br/>(one big string)"] --> B["StringIO(text)<br/>looks like a file"] B --> C["pd.read_csv(...)<br/>splits + infers types"] C --> D["DataFrame<br/>3 rows x 3 cols<br/>header: name city age"]
The one-line takeaway
To read CSV that lives in a string, wrap it in StringIO and hand it to read_csv — the first line becomes your headers unless you say otherwise.
Where you'll meet it
You'll reach for this every time you load data from an API response, paste a sample dataset into a notebook, write a quick test with inline data, or work in a browser sandbox (like Pyodide) where there's no file system to open a .csv from. It's the very first step of almost every pandas workflow: get the text in, get a DataFrame out.
Named concepts: read_csv, StringIO, parsing, header row
