Location: source_modelling/gsf.py:115
What happens: write_gsf fills in optional columns by assigning directly into the caller's DataFrame:
if "init_time" not in gsf_df:
gsf_df["init_time"] = -1 # :115-116
if "slip" not in gsf_df:
gsf_df["slip"] = -1 # :117-118
The caller's object is modified in place, gaining two columns of sentinel -1 values it never asked for. Because these assignments sit above the column validation at :120, the mutation happens even when write_gsf then raises and writes nothing.
Why that's wrong: write_gsf(gsf_df, gsf_filepath) is a serialisation function — its documented job is to write a file. Nothing in its signature or docstring suggests the input is consumed or modified. A caller that writes a GSF and then continues using its DataFrame (or writes it again through another path) silently carries init_time = -1 and slip = -1 sentinels, which will be interpreted as real values downstream.
How to reproduce:
import pandas as pd, tempfile
from pathlib import Path
from source_modelling.gsf import write_gsf
df = pd.DataFrame({"lon":[172.6],"lat":[-43.5],"dep":[1.0],"sub_dx":[1.0],"sub_dy":[1.0],
"loc_stk":[0.0],"loc_dip":[0.0],"loc_rake":[0.0],"seg_no":[0]})
write_gsf(df, Path(tempfile.mkdtemp())/"y.gsf")
print(df.columns)
# ... 'seg_no', 'init_time', 'slip'] <- injected, values -1
The failure path mutates too — drop loc_rake from the frame above and write_gsf raises ValueError: The DataFrame must have a 'loc_rake' column. after having already appended init_time and slip.
Suggested direction: Work on a shallow copy (gsf_df = gsf_df.copy()) before the defaulting block, or build the output frame explicitly from the required columns. Moving the validation at :120 above the defaulting would additionally stop the failure path from leaving debris.
Confidence: high
Location:
source_modelling/gsf.py:115What happens:
write_gsffills in optional columns by assigning directly into the caller's DataFrame:The caller's object is modified in place, gaining two columns of sentinel
-1values it never asked for. Because these assignments sit above the column validation at:120, the mutation happens even whenwrite_gsfthen raises and writes nothing.Why that's wrong:
write_gsf(gsf_df, gsf_filepath)is a serialisation function — its documented job is to write a file. Nothing in its signature or docstring suggests the input is consumed or modified. A caller that writes a GSF and then continues using its DataFrame (or writes it again through another path) silently carriesinit_time = -1andslip = -1sentinels, which will be interpreted as real values downstream.How to reproduce:
The failure path mutates too — drop
loc_rakefrom the frame above andwrite_gsfraisesValueError: The DataFrame must have a 'loc_rake' column.after having already appendedinit_timeandslip.Suggested direction: Work on a shallow copy (
gsf_df = gsf_df.copy()) before the defaulting block, or build the output frame explicitly from the required columns. Moving the validation at:120above the defaulting would additionally stop the failure path from leaving debris.Confidence: high