wend.conditions¶
Conditions: what a path must be, and may be used for, when it is realised.
An expression can declare conditions about the filesystem (Exists,
Absent), about the kind of thing it names (File, Dir), about how it
will be used (Readable, Writable, Creatable, Listable) and
about where it may lead (Under(base))::
src = (P(root) / "raw" / T(t"{name}.csv")).requires(File, Exists, Readable)
dst = (P(root) / "out" / T(t"{name}.parquet")).requires(Absent, Creatable)
dst = dst.ensures(File, Exists)
PathExpr.render stays pure: the only condition it enforces is the lexical
part of Under, which needs no filesystem. Everything else is checked by an
explicit step, PathExpr.check (preconditions) and PathExpr.confirm
(postconditions), or by a Step that groups the paths of one pipeline step.
Checks are point in time. A path that exists when it is checked may be gone when it is opened, and a symlink may be swapped between the two: checks describe and catch mistakes, they are not a sandbox and do not prevent races. See docs/SEMANTICS.md §10.
Absent
module-attribute
¶
Nothing occupies the path's name, not even a broken symlink.
Condition
¶
Condition(name: str)
Bases: Generic[Pre, Post]
A property of a path, checked when the path is realised. For a type
checker it adds its atom Pre to what an expression requires, and
Post to what it ensures (the same atom, for every condition).
Creatable
module-attribute
¶
The path exists, or could be created now: no broken symlink occupies its name or a name above it, and its nearest existing ancestor is a directory the process may write to and search.
Declarations
¶
Bases: NamedTuple
What an expression declares (docs/SEMANTICS.md §10.1): the atoms it
requires before it is used, the atoms it ensures after it is produced,
and the bases it is declared Under.
A declaration is an obligation, not a fact about the filesystem. Only
containment holds of every path the expression renders (render checks
it); every other atom holds when a check finds it, at that moment.
verbs
property
¶
The effects declared (what Step.effects reports): each permission
in either phase, create for exists ensured but not required,
and delete for absent ensured but not required.
__and__
¶
__and__(other: object) -> Declarations
What both declare: the atoms of each phase in both, and the bases both are declared under.
Dir
module-attribute
¶
The path names a directory: if it exists it is one.
Effect
¶
Exists
module-attribute
¶
Something exists at the path (symlinks are followed).
File
module-attribute
¶
File: Final[FileCondition] = FileCondition('File')
The path names a regular file: if it exists it is one, and nothing can be
joined below it. Add Exists to require that it exists.
Listable
module-attribute
¶
The path is an existing directory the process may list.
Readable
module-attribute
¶
The path exists and the process may read it.
Step
¶
The paths one step of a pipeline uses, with their conditions.
A single declaration of what must hold before the step runs (each path's
requires) and after it finishes (each path's ensures)::
convert = Step(src=src, dst=dst)
with convert(root="/data", name="a") as p:
write(transform(read(p["src"])), p["dst"])
Entering checks every precondition and yields the rendered paths; leaving without an exception checks every postcondition. The bindings are shared: each path takes the parameters it uses.
paths
instance-attribute
¶
paths: dict[str, PathExpr] = {k: _coerce(v, at_head=True) for k, v in {**paths or {}, **named}.items()}
check
¶
Render every path and check its preconditions, in declaration order,
on fs (a wend.fs filesystem; the local disk by default).
confirm
¶
Render every path and check its postconditions, in declaration order,
on fs.
__call__
¶
effects
¶
The filesystem effects each path declares: read, write,
create, list (capabilities), plus create for a path that
must exist afterwards but need not before, and delete for one that
must be absent afterwards but need not be before. Paths declaring none
are listed with no verbs. This reports declarations, not behaviour.
Under
dataclass
¶
Bases: Condition['Under[B] | Under[str]', 'Under[B] | Under[str]'], Generic[B]
The path stays under base: lexically when it is rendered, and after
resolving symlinks when it is checked.
base is rendered with the same bindings as the path, so its parameters
must be among the path's. Lexically, the path must start with the base's
components and have no .. after them.
For a type checker, a literal string base gives the atom its identity
(Under[Literal["/srv/static"]]); every base, literal or not, also
declares Under[str], "under its own base".