Skip to content

ump_workflow.bundle

module ump-workflow

The bundle format (ump.workflow_bundle/0.1): a folder of data and source, never pickles.

::

workflow.json name, version, entry, seed, params, modes, tier, training, code_sha256, env, files
contract.json the ump_spec InputContract
prep.recipe.json optional finprint recipe (finprint.apply on new data)
code/<module>.py the analyst's source
state/state.json {"meta": {...}, "arrays": {name: {file, dtype, shape}}}
state/<name>.npy numeric arrays (allow_pickle=False)
questions.json the questions and their estimand templates
summary.json Tier D model_manifest of the fit-time answers (the fallback rung)
data/training.csv only when the analyst opts in and no input is transient_only
README.md a generated model card, never executed
SHA256SUMS sha256 of every file but itself

read_bundle verifies every file before it parses anything but SHA256SUMS and workflow.json: a hash that differs, a missing file, an unlisted file or any link refuses the load (BUNDLE_TAMPERED). Files are read once and parsed from those verified bytes.

class

class BundleData

A verified bundle, parsed. Nothing here has run the bundle’s code.

Fields

NameTypeDefaultDescription
rootPath
workflowdict[str, Any]
contractInputContract
codestr
code_sha256str
state_metadict[str, Any]
state_arraysdict[str, np.ndarray]
questionslist[dict[str, Any]]
summarydict[str, Any]
recipedict[str, Any] | NoneNone
data_pathPath | NoneNone
filesdict[str, str]field(default_factory=dict)
Methods and properties (2)

recipe_path property

recipe_path: Path | None

init constructor

BundleData(
self,
root: Path,
workflow: dict[str, Any],
contract: InputContract,
code: str,
code_sha256: str,
state_meta: dict[str, Any],
state_arrays: dict[str, np.ndarray],
questions: list[dict[str, Any]],
summary: dict[str, Any],
recipe: dict[str, Any] | None = None,
data_path: Path | None = None,
files: dict[str, str] = dict(),
) -> None

Source: packages/ump-workflow/src/ump_workflow/bundle.py, line 56

function

def sha256(data: bytes) -> str

Source: packages/ump-workflow/src/ump_workflow/bundle.py, line 48

function

def write_bundle(
path: str | Path,
*,
workflow: dict[str, Any],
contract: InputContract | dict[str, Any],
recipe_path: str | Path | None,
code_path: str | Path,
state_meta: dict[str, Any],
state_arrays: dict[str, Any],
questions: list[dict[str, Any]],
summary: dict[str, Any],
include_data_frame: pd.DataFrame | None = None,
transient_only: bool = False,
code: bytes | None = None,
) -> Path

Write a bundle folder at path (which must not exist). Everything is written to a temporary sibling and renamed into place, so a refusal leaves nothing behind. workflow holds name, version, seed, params, training and optionally author, created_at, tier, dependence, notes; the rest is filled here. code is the module’s bytes as the caller ran them (read once); without it code_path is read here. code_path always gives the file name.

Source: packages/ump-workflow/src/ump_workflow/bundle.py, line 98

function

def top_level_functions(source: str) -> set[str]

Names of the top-level def statements in source (read with ast; nothing runs). Workflow roles and question functions must be one of these, so a hand-edited workflow.json or questions.json can only point at code the reader read and trusted, never at an import or a dunder of the module.

Source: packages/ump-workflow/src/ump_workflow/bundle.py, line 196

function

def read_bundle(path: str | Path) -> BundleData

Verify every file’s hash, then parse (data only: no code runs). Only SHA256SUMS and workflow.json are read before the file lists are compared, so an unlisted file is refused unread.

Source: packages/ump-workflow/src/ump_workflow/bundle.py, line 232

NameTypeValueDescription
BUNDLE_FORMAT'ump.workflow_bundle/0.1'
SUMS'SHA256SUMS'
WORKFLOW'workflow.json'