Skip to content

Splice your own step with .pipe()

Available in: Python (a fluent-chain idiom of the Python handle)

When: the chain doesn't have a method for the thing you want to do next — inline a function without breaking out of the flow. .pipe(fn, *args) passes the handle as fn's first argument and returns whatever fn returns.

# what this shows: .pipe(fn, *args) splices your own step into the chain — fn receives the handle as its first arg — on both Ags4File and AgsQuery.
import laterite

ags = laterite.read("examples/sample_site.ags")

# On an Ags4File: fn(self, *args) — the file handle is passed first, your extra args follow.
out = ags.pipe(lambda a, n: a.groups[:n], 3)
print("first 3 group codes:", out)

# On an AgsQuery: same contract — the query handle is passed in, you return whatever you like.
height = ags.query("SELECT * FROM LOCA").pipe(lambda q: q.frame().height)
print("LOCA row count via pipe:", height)

# .pipe returns your function's result verbatim, and passes the object as the first argument.
assert out == ["PROJ", "TRAN", "UNIT"]
assert ags.pipe(lambda a: a is ags) is True
assert height == 14
assert ags.query("SELECT * FROM LOCA").pipe(lambda q: q is not None) is True
first 3 group codes: ['PROJ', 'TRAN', 'UNIT']
LOCA row count via pipe: 14

.pipe(fn, *args) calls fn(handle, *args) and returns the result verbatim — so it's an escape hatch that keeps the chain flowing instead of forcing a temporary variable. It works on both Ags4File and AgsQuery, and the contract is the same on each: the handle goes in first, your extra positional args follow, and you get back exactly what fn returns (a list, a scalar, another handle — anything).

Because fn receives the live handle, anything you can read off the object is fair game: ags.pipe(lambda a, n: a.groups[:n], 3) slices the group list, q.pipe(lambda q: q.frame().height) reaches through a query terminal for a row count. Return the handle itself and the chain continues:

ags = (
    laterite.read("delivery.ags")
    .pipe(lambda a: a.validate())       # returns the Ags4File → chain flows on
    .query("SELECT * FROM LOCA")
)

Gotcha: .pipe doesn't materialise or copy anything — it just hands fn the same handle you already hold (ags.pipe(lambda a: a is ags) is True). If fn returns a non-handle value (a count, a list), that value is your chain's new end — you can't .query() off an int. To stay in the chain, have fn return a handle.

See also: Chaining.