DEV Community

Paul Crinigan
Paul Crinigan

Posted on

One Parser For Every Lab Instrument Export

Plate readers, spectrometers and every other bench instrument invent their own export format. Repeated well grids, kinetic dumps, wide tables, long tables, Excel workbooks with a plate grid buried somewhere inside. Most labs answer this with one throwaway script per instrument, and those scripts rot on somebody's laptop.

labparse is a free MIT licensed Python package that takes a different route.

pip install labparse
Enter fullscreen mode Exit fullscreen mode
import labparse
result = labparse.parse("growth.asc")
result.data          # tidy pandas DataFrame
result.wide()        # one column per well
result.save_csv("tidy.csv")
Enter fullscreen mode Exit fullscreen mode

Or from the shell:

labparse growth.asc --out tidy.csv
labparse kinetic.txt --wide
Enter fullscreen mode Exit fullscreen mode

Recipes, Not Parsing Scripts

A recipe is a small JSON description of a format that a deterministic engine executes. Tecan ASCII exports, Molecular Devices SoftMax Pro and SpectraMax kinetic exports, generic wide and long CSV or TSV, and Excel workbooks with a well header row or a plate grid all ship as bundled recipes.

Recipes are plain JSON. You can read one, edit it, drop new ones into the recipe folder, and share them with your lab. labparse --list-recipes shows everything installed.

Where The AI Actually Sits

This is the part worth stealing even if you never touch a plate reader.

When labparse meets a format it does not know, it shows the raw file to your own model once and the model writes a recipe. The recipe is only accepted if it actually parses your file. A wrong one is rejected and retried, so it cannot quietly produce bad data. Accepted recipes are cached in your home directory, so each format costs at most one call ever and cached formats parse offline.

The parsing engine itself never calls a model. The model proposes, the deterministic engine disposes, and your measurements only ever flow through code you can read.

It looks for a model in this order: the Claude CLI, the Codex CLI, an Anthropic key, then an OpenAI key, where setting a base URL points it at any OpenAI compatible server including a local model. --llm off disables it entirely, and everything with a bundled or cached recipe still works. No model configured means unknown formats give a clear message instead of a wrong guess.

The Output Schema Is Always The Same

Every parse returns the same columns whatever the instrument:

column meaning
well normalized well id, A1 to P24
row plate row letter
col plate column number
cycle reading number in file order, starting at 1
time_s seconds, NaN when the format has no time
value the measurement

Extra instrument columns like temperature are kept alongside. Tidy is the shape pandas, R and every statistics tool actually want, and .wide() gives the one column per well layout spreadsheets expect, from the same parse.

Why This Matters More Than It Sounds

The reason instrument data ends up in spreadsheets is that the spreadsheet is where the file lands, not because anyone decided that was a good idea. Ten years after the Genome Biology paper on Excel mangling gene names, that is still the default failure mode across the bench sciences.

Parsing the raw export directly into a tidy table removes the step where numbers get retyped, reformatted and quietly changed. The source of truth stays the file the instrument wrote.

Source, issues and README are on GitHub, and if your instrument's export defeats it, open an issue with a sample file. That is exactly the kind of format the recipe system exists to swallow.

Top comments (0)