finprint
Analysts import finprint as fp
Finprint writes down your pandas prep as you do it. Save the cleaned file and a recipe lands beside it: inputs by hash, every step with its row counts, and the source of your own helpers.
It has no dependency on the rest of UMP, so it installs in any notebook environment. Runtime needs are pandas, numpy, pydantic and httpx. The recipe format is part of the UMP standard and keeps its wire names (ump-recipe), so recipes saved under the package’s old name still verify.
Quick path
Section titled “Quick path”- Install:
pip install -e 'packages/finprint[notebook]'from a checkout. - Start a session, read through it, work as usual, and save.
- Verify the recipe reproduces the file.
import finprint as fp
rec = fp.session("weekly prep")raw = rec.read_csv("raw.csv", parse_dates=["week"])
clean = raw.drop(index=[0]) # recorded: "Dropped 1 row: 6 to 5"clean["tv"] = clean["tv"].interpolate() # recorded with the expression, so it replays
@rec.step # your own function: recorded with its sourcedef rebase_to_net(df, fee=0.15): out = df.copy() out["spend_net"] = out["spend"] * (1 - fee) return out
clean = rebase_to_net(clean, fee=0.15)rec.save(clean, "clean.csv") # writes clean.csv and clean.recipe.jsonfp.verify("clean.recipe.json").status # "reproduced"In a notebook, %load_ext finprint starts a session and also records the cells you ran.
Main entry points
Section titled “Main entry points”| Call | What it does |
|---|---|
fp.session(name) | Starts recording. Read through rec.read_csv, read_excel, read_parquet or read_catalogue. |
@rec.step | Records one of your functions with its source, so the step can replay. |
rec.save(frame, path) | Writes the data and <name>.recipe.json beside it. |
fp.verify(recipe) | Replays the recipe and asks: does it still make this exact file? |
fp.apply(recipe, inputs) | Runs the same prep on new data, such as next quarter’s longer file. |
fp.describe(recipe) | The steps in plain words. |
Verify or apply
Section titled “Verify or apply”The two answer different questions.
verifyrefuses any input whose hash differs. Use it to prove a file came from its recipe.applycompares no hashes. It binds inputs by id, then name, then file basename, and checks that each step adds and removes the same columns it did when recorded.
res = fp.apply("clean.recipe.json", {"raw.csv": "q3_raw.csv"})res.status, res.frame, res.notes # "applied" or "refused" (res.code and res.step_id say why)fp.row_bound_steps(fp.load_recipe("clean.recipe.json")) # steps tied to specific rows, such as drop(index=[0])Trust and named-step code
A recipe can carry the source of your @rec.step functions. Code that this machine did not record is printed and runs only after you trust it: --trust on the command line, or a yes at the prompt. The trust store lives under FINPRINT_HOME.
Things that are not a DataFrame
Tracked frames are proxies. Pandas’ module-level functions reject them with a TypeError that names the alternative: use a.merge(b) instead of pd.merge(a, b), rec.concat([...]) instead of pd.concat, and rec.call(pd.to_datetime, a["week"]) for other functions you want recorded.
Command line
Section titled “Command line”finprint show clean.recipe.json # plain step listfinprint verify clean.recipe.json --inputs data/ # exit 0 only when reproducedfinprint apply clean.recipe.json --input raw.csv=q3_raw.csv -o q3_clean.csv