write_salmon_datapackage

write_salmon_datapackage(
    resources,
    dataset_meta,
    table_meta,
    dict_df,
    codes=None,
    path='.',
    format='csv',
    overwrite=False,
    write_datapackage=True,
    prune=False,
)

Write the canonical Salmon Data Package layout.

Metadata is written under metadata/, table resources under data/, and the Frictionless descriptor at the package root.

overwrite=True updates the package in place. Since the 0.2.0 rung it replaces only the files this writer owns — the metadata/ SDP CSVs, the data/ resources declared in tables.csv (including any a previous write declared and this one does not), datapackage.json, and the ownership sentinel. Everything else is preserved: reviewed SSSOM mappings and measurement decompositions under metadata/semantic/, EML and EDH XML, eml-mapping.yml, review notes, publication/ artifacts, and the reproducibility manifest. A read → edit → write loop used to delete all of them.

prune=True restores the previous behaviour, deleting every entry in the directory first. It requires overwrite=True.

overwrite is about destroying something, so an empty directory does not need it. An existing directory with nothing in it is written into with overwrite=False; “nothing in it” means list(path.iterdir()) is empty, so a dot-file, a stale ownership sentinel, or an empty data/ subdirectory each make the directory non-empty and the overwrite gate applies as before. Emptiness is never recursive. metasalmon adopted this order on hub Q15 (2026-08-24) — see PARITY.md row 54; it had been the one behaviour neither package’s tests pinned.

The write is transactional over the files it owns. The full write set — data resources, metadata CSVs, datapackage.json and the ownership sentinel — is rendered to bytes before anything on disk is touched, then installed through a staged-sibling write set that rolls the originals back if any install fails. An abort at any point therefore leaves the caller’s previous package byte-intact and readable. Before this, the managed paths were unlinked first and the replacements written afterwards, so any exception in between destroyed the package (hub backlog #96’s ordering half; metasalmon PR #77).

prune=True is the one honest exception, and it is narrower rather than absent. The wipe removes files this writer does not own, so those sidecars are not in the write set and nothing can restore them. The wipe now runs as late as possible — after every input-dependent computation and the full byte rendering have succeeded, so an input-triggered abort still leaves everything intact — but a pure filesystem failure (disk full, permissions revoked) between the wipe and the install remains unrecoverable. That is deliberate: prune=True is an explicit request to delete everything this call does not write.

Back to top