Document
matchlab.document
¶
Serialise a plan to a portable document, and rebuild it somewhere else.
A PlanDocument is a derived view of a plan, not a source format. Humans write
Python, and a document is what you hand to another environment so it can run the same
plan. It is dumped, transferred and loaded, never hand-authored. That is why nodes
refer to each other by position rather than by any human-facing name.
Nodes come out in lineage.walk order, so every input index is smaller than the index
of the step that consumes it. Positions also preserve structural sharing. A record step
feeding two models is one node referenced twice. Nesting each step's inputs inside it
would have inlined the whole subtree twice over instead.
A node is three things, and they are separate for a reason. Its spec is what the
fingerprint hashes, so it carries everything that changes the step's output and nothing
else. Its inputs are the edges, which a fingerprint already covers by folding in its
parents' fingerprints — recording them in the spec too would mean a rename invalidating
a subtree that produces identical bytes. Its resources name what the step reads
through, which changes no output and so belongs in neither.
Putting any two of them in one field would force a choice between a spec that lies about identity and a document that cannot be rebuilt.
What a document cannot carry:
- Resources. Engines, connections, credentials, frames. A document records only the
name each one was given (
matchlab.resources.Resource), inStepNode.resources, keyed by the settings field it fills.loadtakes the real objects and fills them in, so nothing secret ever enters a document. Because they live in their own field rather than among the settings, no resource can reach a fingerprint — that is structural, not a convention. Every kind of step may name one; in practice only sources do, because a resource answers "where do these rows come from". - Code.
model_classandresolver_classare registry names, so the target environment must have the same classes registered (add_model_class). A document is portable across environments, not across codebases. - Labels. Publishing is something you do to a result, using
Resolver.publish. It is not part of the plan, so the receiving environment collects and then publishes under whatever label it wants. The only names in a document are sources' names, which are part of their output. - Data, or any hash of it. A source's fingerprint folds in a content hash of what it actually read, and that hash is derived on load by reading the target's own rows. Same rows give the same fingerprints, so the target store hits cache instead of recomputing. Different rows give different fingerprints, so it re-runs. Both are the intended behaviour.
A rebuilt plan therefore fingerprints identically, as long as every methodology it names
declares a version. One that declares none is keyed by a nonce on every collect, here as
anywhere else, so the steps from it down re-run wherever the document is loaded. See
matchlab.core.versioning.
Classes:
-
StepNode–One step: its kind, what it specifies, what it reads, and what it needs.
-
PlanDocument–A whole plan: its steps in topological order, and the edges between them.
Functions:
-
dump–Describe
rootand everything it reads as a portable document. -
load–Rebuild a plan from a document, returning its apex.
Attributes:
StepNode
¶
Bases: BaseModel
flowchart TD
matchlab.document.StepNode[StepNode]
click matchlab.document.StepNode href "" "matchlab.document.StepNode"
One step: its kind, what it specifies, what it reads, and what it needs.
Attributes:
-
model_config– -
kind(StepKind) – -
spec(StepSpec) – -
inputs(tuple[int, ...]) – -
resources(dict[str, str]) –
kind
class-attribute
instance-attribute
¶
spec
class-attribute
instance-attribute
¶
spec: StepSpec = Field(description="This step's own settings, exactly what its fingerprint hashes.")
inputs
class-attribute
instance-attribute
¶
inputs: tuple[int, ...] = Field(default=(), description="Positions of this step's inputs, in order. Always smaller than this step's own position, and order matters: it is the order the fingerprint folds parents in, and the order a linker's left and right arrive in.")
resources
class-attribute
instance-attribute
¶
resources: dict[str, str] = Field(default_factory=dict, description="Settings field name to resource name, for every field this step's methodology was given as a `matchlab.resources.Resource`. Here rather than in the spec because a resource describes reconstruction, not output: renaming one changes no fingerprint. `load` fills each from its `resources` argument.")
PlanDocument
¶
Bases: BaseModel
flowchart TD
matchlab.document.PlanDocument[PlanDocument]
click matchlab.document.PlanDocument href "" "matchlab.document.PlanDocument"
A whole plan: its steps in topological order, and the edges between them.
Methods:
-
required_resources–Every resource name
loadmust be given to rebuild this plan.
Attributes:
-
model_config– -
steps(tuple[StepNode, ...]) –
dump
¶
Describe root and everything it reads as a portable document.
JSON rather than an object, because a document exists to be put somewhere: a column, an object store, a request body, a file.
Parameters:
-
(root¶Step) –The apex of the plan. Only what is reachable upstream of it is included, exactly as
collect()would run. -
(indent¶int | None, default:None) –How the JSON is laid out.
None, the default, is compact.
Returns:
-
str–The document, as JSON.
Raises:
-
ResourceError–If a resource was passed without a name, so there is nothing for a document to record. A name covering two different objects is refused earlier, when the plan is built.
load
¶
Rebuild a plan from a document, returning its apex.
Nothing is collected. This reconstructs the same lazy plan, so the returned step fingerprints identically to the one that was dumped, given the same data.
Parameters:
-
(document¶str | bytes) –The JSON
dumpproduced. -
(resources¶Mapping[str, Any]) –Name to object, for every resource the document names.
Returns:
-
Step–The plan's apex, the last step in the document.
Raises:
-
ValidationError–If the JSON does not describe a plan document.
-
ValueError–If the document is empty, names an unregistered location class, or wires a step to an input of the wrong kind.
-
ResourceError–If a named resource was not supplied.