Lesson 3.4Lesson 3.4 · Functions, Modules & Files
CSV & JSON Data
Schedules, exports and settings live as CSV and JSON - two formats every designer meets and both easy to read in Python
Every schedule you export and every settings file you touch is CSV or JSON. Two small modules read both - and suddenly your scripts speak the language of real design data.
Loose text files got you started, but real design data has structure. A room schedule is a table of rows and columns. A material library or a set of project settings is a tree of named values, some nested. Two formats carry almost all of it: CSV (comma-separated values - flat, spreadsheet-like) and JSON (JavaScript Object Notation - nested and richer).
Python reads and writes both with two small standard-library modules, csv and json, and nothing to install. This lesson shows you how to pull a schedule out of a CSV, hand structured data to and from JSON, and - just as important - choose which format fits a given job. It is where the file plumbing of the last lesson becomes genuinely useful.
CSV = table (DictReader/DictWriter). JSON = tree (load/dump). Both standard library, both plain text.
Two formats, two shapes of data
Before any code, get the mental picture, because choosing right saves hours. CSV is a table: the first line is usually a header of column names, and every line after is one record with values separated by commas. It maps exactly onto a spreadsheet, which is why every schedule tool and BIM export offers 'export to CSV'. JSON is a tree: it stores named values ("area": 18.0), lists (["oak", "linen"]) and nested objects, so it can hold richer, hierarchical data that a flat table cannot.
A rough rule you can lean on: if your data is rows that all share the same columns - a room list, a door schedule, a BOQ - reach for CSV. If it is nested or mixed - a project's settings, a material with a list of finishes and a supplier object, anything tree-shaped - reach for JSON. Both are plain text you could open in an editor and read, which is part of why they have lasted: no proprietary format, no lock-in, human-inspectable, and readable by nearly every tool. Understanding which shape your data really has is half the skill; the modules that read them are the easy other half.
It helps to know why these two formats, of all the possibilities, are the ones you keep meeting. Both are open - no company owns them, no licence is needed, and any tool can read and write them - which is why they became the common tongue between programs that otherwise share nothing. Both are also human-readable: open either in a text editor and you can see exactly what is there, which makes debugging a data problem a matter of looking rather than guessing. CSV predates the personal computer and survives because spreadsheets everywhere speak it; JSON grew up with the web and is now the default way apps and services exchange data. For a designer, the practical consequence is that learning these two formats is not learning a niche skill - it is learning the language your BIM exports, your spreadsheets, and the web APIs of Module 8 all already speak.
CSV = flat table, shared columns. JSON = nested tree of named values and lists. Both plain text.
Reading a schedule with the csv module
You could read a CSV by splitting each line on commas yourself, but that breaks the moment a value contains a comma. The csv module handles the fiddly rules for you. Its DictReader is the designer's friend: it reads the header row and hands you each record as a dictionary keyed by column name:
import csv
total = 0.0
with open("rooms.csv", newline="") as f:
reader = csv.DictReader(f)
for row in reader:
area = float(row["area"]) # values come in as text
total += area
print(row["room"], area)
print(f"Total area: {total} m2")Each row is a dict like {"room": "living", "area": "18.0", "floor": "1"}, so you grab fields by name - row["area"] - which stays readable even with many columns. Two details to bank: pass newline="" when opening a CSV (it prevents blank-line glitches on some systems), and remember every value arrives as a string, so wrap numbers in float() or int() before doing maths. That single loop - open, DictReader, pull fields by name, convert, accumulate - is the workhorse for totalling a BOQ, filtering a schedule, or checking an export.
The same loop does far more than total a column. Because each row is a dictionary, you can filter (if row["floor"] == "2"), group, spot problems, or check for missing data - a genuinely useful quality-control move on real exports, where a blank area or a mistyped room name is exactly the kind of error a script catches instantly and the eye misses. A quick validity pass might collect every row where row["area"] is empty or does not convert to a number, and print them for you to fix at source. There is also a plainer csv.reader that hands you each row as a simple list rather than a dict; it is fine when a file has no header, but DictReader is almost always nicer because reading row["area"] tells you what you are grabbing where row[3] makes you count columns. Reach for DictReader by default, and keep reader in mind only for headerless files.
csv.DictReader gives each row as a dict keyed by column. Values are strings - float()/int() them.
Writing CSV back out
Producing a clean CSV is just as direct, and it is how your script hands results to a spreadsheet or another tool. DictWriter is the mirror of DictReader: you tell it the column names, write the header, then write each row as a dict:
import csv
rooms = [
{"room": "living", "area": 18.0},
{"room": "kitchen", "area": 12.0},
]
with open("out.csv", "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["room", "area"])
writer.writeheader()
writer.writerows(rooms)Open the resulting out.csv in Excel or Google Sheets and it is a proper two-column table. This closes a genuinely useful loop: read a messy export in with DictReader, clean or filter or total it in plain Python, and write a tidy CSV back out with DictWriter - a schedule your team can open without ever knowing a script touched it. Because CSV is universal, this is often the most practical way to deliver results: not a fancy app, just a clean spreadsheet file that slots into everyone's existing workflow. Keep the fieldnames list and your row dictionaries using the same keys and the two halves fit together cleanly.
A few practical points make CSV writing reliable. Use newline="" in the open() call for writing just as you did for reading - it stops an extra blank line appearing between rows on some systems, a small glitch that puzzles people the first time. If a dictionary is missing one of the declared fieldnames, DictWriter writes an empty cell rather than crashing, which is forgiving but worth knowing so blanks do not surprise you. And the fieldnames list also fixes the column order of the output, so you control how the spreadsheet reads left to right. Because the result is an ordinary CSV, it drops straight into whatever your colleagues already use - no plugin, no import wizard, just a file they double-click. That is often the quiet win of scripting in a practice: not a shiny tool, but a clean, correct spreadsheet produced in a second that would have taken an afternoon by hand, handed over in a format everyone already trusts.
csv.DictWriter: set fieldnames, writeheader(), writerows(). Out comes a real spreadsheet.
JSON: nested data in and out
When data is nested rather than tabular, JSON is the natural fit, and the json module makes the round trip almost trivial. It maps neatly onto Python: JSON objects become dicts, arrays become lists, and the rest becomes strings, numbers, booleans and None. Four functions cover it - load/dump work with files, loads/dumps with strings:
import json
project = {
"name": "Riverside Flat",
"rooms": ["living", "kitchen", "bedroom"],
"finishes": {"floor": "oak", "walls": "linen white"},
}
with open("project.json", "w") as f:
json.dump(project, f, indent=2) # write, nicely indented
with open("project.json") as f:
loaded = json.load(f) # read it back as a dict
print(loaded["finishes"]["floor"]) # oakNotice how a JSON file preserves the structure - the list of rooms and the nested finishes object survive the round trip intact, unlike a flat CSV which would have to flatten them. The indent=2 argument pretty-prints the file so a human can read and diff it. Because JSON is the language of web APIs and countless config files, json.load and json.dump are also exactly the functions you will reach for in Module 8 when you start pulling data from the web. Getting comfortable with this now means structured data holds no fear later.
The file-versus-string distinction is the one thing to fix in memory: the plain names load and dump work with a file object, while the s-suffixed loads and dumps work with a string (the s stands for string). You will use dumps to turn data into a string for printing or sending, and loads to turn a string received from a web API back into a dict - which is precisely the Module 8 use. A couple of honest limits keep you out of trouble: JSON can hold strings, numbers, booleans, lists, nested objects and null, but not arbitrary Python objects like a datetime or a set - those you convert to a string or list first. And a JSON object's keys are always strings, so a dictionary with number keys comes back with string keys after a round trip. These are minor once you know them, and in return you get a format that preserves rich, nested structure perfectly and is understood by virtually every language and service on earth.
json.dump/load for files, dumps/loads for strings. JSON objects <-> dicts, arrays <-> lists.
Choosing the right format
With both tools in hand, the real skill is picking well. Ask what shape your data is and who receives it. CSV wins when data is a flat table with consistent columns and a human on the other end will likely open it in a spreadsheet - schedules, BOQs, quantity lists, exports for a client or contractor. It is compact, universal and effortless in Excel. JSON wins when data is nested, mixed or hierarchical, when structure must be preserved exactly, or when another program (an app, a web API, a config-driven tool) will read it - project settings, a material library, anything tree-shaped.
When they overlap, let the destination decide: a spreadsheet-bound deliverable leans CSV, a program-bound one leans JSON. And it is common to convert between them - read a CSV schedule, enrich each row with nested data, and write JSON for an app, which is exactly the little pipeline the figure shows. Both are plain-text, standard-library, install-nothing formats, so you can move fluidly between them. Master these two and you can exchange data with virtually any design tool, spreadsheet or service - which is what turns an isolated script into part of a real workflow.
Flat table for humans -> CSV. Nested data for programs -> JSON. When unsure, follow the destination.
csv module
Reading and writing comma-separated tables correctly
Standard library; handles quoting and delimiters that naive string splitting gets wrong.
csv.DictReader
Reading each CSV row as a dict keyed by column name
Readable field access by header name; remember values arrive as strings - convert with float/int.
csv.DictWriter
Writing dicts back out as a CSV table
Set fieldnames, writeheader(), then writerows() - produces a file any spreadsheet opens.
json module
Reading and writing nested JSON data
load/dump for files, loads/dumps for strings; JSON objects map to dicts, arrays to lists.
CSV vs JSON
Flat table versus nested tree
CSV for spreadsheet-shaped data and human recipients; JSON for nested structure and programs.
Workshop - read a CSV schedule, write JSON
You will read a room schedule from a CSV, total the areas, and write an enriched JSON file - the small but genuinely useful CSV-to-JSON pipeline in full.
Python 3 only - csv and json are both standard library. A spreadsheet app is handy to inspect the CSV.
Goal: read a CSV, transform it, write JSON Inputs: a rooms.csv you create with room,area,floor columns Time: ~40 minutes
- 1Create rooms.csv with a header line room,area,floor and a handful of rows, saved next to your script.
- 2Read it with csv.DictReader inside a with open(..., newline='') block; loop the rows, convert row['area'] to float, and print each room with its area.
- 3While looping, accumulate a running total of area and count the rooms; after the loop, print the total and the count.
- 4Build a Python dictionary that holds the project name, the list of rooms (each as a small dict), and a summary block with the total area and room count.
- 5Write that dictionary to project.json with json.dump(..., indent=2), then read it back with json.load and print one nested value to prove the round trip worked.
You’ll walk away with
Your rooms.csv, the script, and the generated project.json - plus a one-line note on why you chose JSON for the output rather than another CSV.
Three altitudes on the same idea
Read the band that fits you — or all three.
CSV and JSON are how your scripts exchange data with the rest of the toolchain. Revit, spreadsheets and most schedule tools export CSV, so reading one to total areas, check for missing data or filter a door list is immediately useful - and writing a clean CSV back gives your team a schedule they can open anywhere. JSON, meanwhile, is how settings and richer project data move between apps and the web services Module 8 reaches.
Your FF&E and finishes schedules are CSV waiting to be scripted. Read a supplier's export with csv.DictReader, apply your markup or wastage, total the quantities, and write a tidy CSV back for the client - all without retyping a cell. When a material carries nested detail - variants, a list of finishes, a supplier block - JSON keeps that structure intact where a flat spreadsheet would lose it.
These two formats are the data currency of real projects, so employers assume you can handle them. Reading a CSV schedule and writing JSON is a small, concrete skill that shows up constantly in computational-design and BIM work. Practise the DictReader loop and the json.load / json.dump round trip until they are second nature - Module 4's pandas builds directly on the same CSV-reading foundation.
“CSV is just text split on commas, so I do not need a special module - I will split each line myself.”
Do it yourself
Predict each answer, then run to confirm.
- 1When would you choose CSV over JSON, and when the reverse?
- 2What does csv.DictReader give you for each row, and why is that easier than splitting on commas?
- 3After reading a CSV, why must you often call float() or int() on a value before doing maths?
- 4Which json functions work with files and which with strings?
- 5What does JSON preserve that a flat CSV cannot - give a concrete example?
The one line to carry out
Peer-reviewed journals & authoritative standards
- 01Comma-separated values — Wikipedia, 2026.
- 02JSON — Wikipedia, 2026.
- 03csv - CSV File Reading and Writing — Python Software Foundation, 2026.
- 04json - JSON encoder and decoder — Python Software Foundation, 2026.
You can now move structured data in and out of files by hand. Module 4 hands that same CSV to pandas, which turns a whole schedule into an analysable table you can filter, total and chart in a line or two - the same data, far more power.
The author
Amogh N P
Architect, interior designer, and creative polymath. Studio Matrx began in his notebooks — his vision of design made honest, useful, and open to everyone. Its Academy is written and taught in his memory, and free, forever.
More about Amogh →