Skip to content

🧰 Built-ins Reference

fimod injects the following functions and globals into every mold — no import needed.


🔍 Regex functions (re_*)

Powered by fancy-regex — supports PCRE2 features: lookahead, lookbehind, backreferences, atomic groups.

Two functions for replacementsre_sub uses Python syntax (\1, \g<name>); re_sub_fancy uses fancy-regex syntax ($1, ${name}).

Pattern syntax differences from Python re

Only the replacement syntax differs by mode. The pattern syntax always uses fancy-regex:

  • Named groups: (?P<name>...) (same as Python) or (?<name>...)
  • Advanced features: atomic groups (?>...), possessive quantifiers a++ — not in Python re
  • Flags: inline (?i), (?m), (?s) — no separate re.IGNORECASE etc.

Match result format

re_search and re_match return a dict (or None):

{
    "match":  "full match text",
    "start":  0,     # byte offset
    "end":    5,     # byte offset
    "groups": ["group1", "group2", ...],  # numbered capture groups (1..N)
    "named":  {"name": "value", ...}      # named groups, or None if no named groups
}

groups is always present (empty list if no capture groups). named is None unless the pattern uses (?P<name>...).

Function reference

Function Signature Returns
re_search re_search(pattern, text) Match dict (see above) or None
re_match re_match(pattern, text) Match dict or None — anchored to start of text
re_findall re_findall(pattern, text) Python-style: see below
re_sub re_sub(pattern, replacement, text [, count]) str — Python syntax: \1, \g<name>
re_sub_fancy re_sub_fancy(pattern, replacement, text [, count]) str — fancy-regex syntax: $1, ${name}
re_split re_split(pattern, text) [str, ...] — captured groups included

re_findall — Python-style group behaviour

Pattern groups Returns Example
No groups ["match1", "match2", ...] re_findall(r"\d+", "a1b2")["1", "2"]
1 group ["group1_val", ...] re_findall(r"(\d+)@", "1@2@")["1", "2"]
N groups [["g1", "g2"], ...] re_findall(r"(\w+)=(\d+)", "a=1 b=2")[["a","1"], ["b","2"]]

re_sub / re_sub_fancy — count and syntax

Both functions replace all occurrences by default. Pass an optional count to limit substitutions.

re_sub(r"\d+", "X", "a1b2c3")       # → "aXbXcX"  (all)
re_sub(r"\d+", "X", "a1b2c3", 1)    # → "aXb2c3"  (first only)

re_sub — Python re syntax in replacements:

re_sub(r"(\w+)@(\w+)", r"\2/\1", "user@host")              # → "host/user"
re_sub(r"(?P<u>\w+)@(?P<d>\w+)", r"\g<d>/\g<u>", "a@b")   # → "b/a"

re_sub_fancy — fancy-regex syntax ($1, ${name}):

re_sub_fancy(r"(\w+)@(\w+)", "$2/$1", "user@host")         # → "host/user"
re_sub_fancy(r"(\w+)@(\w+)", "$2/$1", "user@host", 1)      # first only

re_split — captured groups included

When the pattern has capture groups, captured text is included in the result (same as Python re.split):

re_split(r"([,;])\s*", "a, b;c")    # → ["a", ",", "b", ";", "c"]
re_split(r"[,;]\s*", "a, b;c")      # → ["a", "b", "c"]  (no groups = no extras)

🗂️ Dotpath functions (dp_*)

Navigate and mutate nested structures using dot-separated paths.

Function Signature Returns
dp_get dp_get(data, path) Value at path, or None if not found
dp_get dp_get(data, path, default) Value at path, or default if not found
dp_set dp_set(data, path, value) New deep copy of data with value at path

Path syntax

Segment Meaning Example
Text dict key "user.address.city"
Integer array index "items.0" (first), "items.-1" (last)

Tip

Missing intermediate keys or out-of-range indices return None for dp_get. dp_set creates missing intermediate keys automatically.


🔁 Iteration helpers (it_*)

Convenience functions for common list/dict operations not natively supported by Monty.

Function Signature Returns
it_keys it_keys(dict) List of keys
it_values it_values(dict) List of values
it_flatten it_flatten(array) Recursively flattened list
it_group_by it_group_by(array, key) Dict of lists, grouped by field name
it_sort_by it_sort_by(array, key) Sorted list by field name (stable sort)
it_unique it_unique(array) Deduplicated list (first occurrence kept)
it_unique_by it_unique_by(array, key) Deduplicated by field name (first occurrence kept)

Field name, not lambda

it_group_by, it_sort_by, and it_unique_by take a field name string — not a lambda.

it_flatten is recursive

[1, [2, [3, 4]]][1, 2, 3, 4]


#️⃣ Hash functions (hs_*)

Function Signature Returns
hs_md5 hs_md5(text) MD5 hex digest (lowercase)
hs_sha1 hs_sha1(text) SHA-1 hex digest (lowercase)
hs_sha256 hs_sha256(text) SHA-256 hex digest (lowercase)

All functions accept a single string and return a lowercase hex string.


📢 Message functions (msg_*)

Output diagnostic messages to stderr without affecting the data pipeline. All functions take a single string and return None.

Which functions produce output depends on the --quiet / --msg-level flags:

Function Stderr output Visible by default --quiet --msg-level=verbose --msg-level=trace
msg_print text
msg_info [INFO] text
msg_warn [WARN] text
msg_error [ERROR] text
msg_verbose [VERBOSE] text
msg_trace [TRACE] text
def transform(data, args, env, headers):
    msg_verbose(f"Input has {len(data)} records")
    missing = [r for r in data if not r.get("email")]
    if missing:
        msg_warn(f"{len(missing)} records without email")
    msg_trace(f"First record: {data[0]}")
    return data

🛡️ Gatekeeper functions (gk_*)

Validation helpers for asserting conditions and controlling pipeline failure. Work with set_exit()gk_fail and gk_assert set exit code to 1.

Function Signature Behavior
gk_fail gk_fail(msg) Emit [ERROR] msg to stderr, set exit code to 1
gk_assert gk_assert(condition, msg) If condition is falsy → gk_fail(msg)
gk_warn gk_warn(condition, msg) If condition is falsy → [WARN] msg to stderr (no exit)

gk_assert and gk_warn use Python-style truthiness: None, False, 0, 0.0, "", [] are falsy.

def transform(data, args, env, headers):
    gk_assert(data.get("version"), "missing 'version' field")
    gk_warn(len(data.get("items", [])) > 0, "items list is empty")
    if data.get("coverage", 0) < 80:
        gk_fail(f"Coverage {data['coverage']}% below 80% threshold")
    return data

Tip

The mold continues executing after gk_fail / gk_assert — this lets you collect multiple errors in one run. The exit code is set to 1 at process exit.


🔄 Environment substitution (env_subst)

Function Signature Returns
env_subst env_subst(template, dict) str — template with ${VAR} placeholders replaced

Unknown variables are left as-is (standard envsubst behavior). Only ${VAR} syntax is supported ($VAR without braces is not substituted).

def transform(data, args, env, headers):
    url = env_subst("https://${HOST}:${PORT}/api", env)
    return {"url": url, "data": data}
fimod s -i data.json --env 'HOST,PORT' -m inject_url.py

🚦 Exit control

Function Signature Returns
set_exit set_exit(code) None

Sets the process exit code from inside a mold. code is an integer 0–255. The mold continues executing to completion after the call.

See Exit Codes for the interaction with --check.


🔀 Format control

Function Signature Returns
set_input_format set_input_format(name) None
cast_input_format cast_input_format(name, value) value
set_output_format set_output_format(name) None

set_input_format(name) — re-parses the output of the current step as the given format before feeding it as input to the next step. Useful with --input-format http to re-parse a string body as JSON, CSV, etc.

cast_input_format(name, value) — same as set_input_format but returns value. Useful as a single-expression one-liner when both the format hint and the return value are needed.

set_output_format(name) — overrides the final output format (like a dynamic --output-format). Also accepts "raw" for binary pass-through (HTTP downloads).

# Fetch raw HTTP response, then re-parse body as JSON
fimod s -i https://jsonplaceholder.typicode.com/todos/1 \
    --input-format http \
    -e 'cast_input_format("json", data["body"])' \
    -e 'data["title"]' --output-format txt

Supported format names for set_input_format: json, ndjson, yaml, toml, csv, txt, lines, http. set_output_format additionally accepts "raw" (binary pass-through, requires --input-format http).


🧩 Transform parameters

All mold scripts receive four parameters: def transform(data, args, env, headers).

args

Dict of --arg name=value pairs. Empty dict {} when no --arg is passed:

def transform(data, args, env, headers):
    limit  = int(args["threshold"])
    prefix = args.get("prefix", "")   # with default
    return [u for u in data if u["name"].startswith(prefix) and u["age"] > limit]

env

Dict of filtered environment variables. Populated by --env PATTERN (glob patterns, comma-separated, repeatable). Empty dict {} when no --env is passed:

fimod s -i data.json --env 'HOME,USER' -e 'env["HOME"]'
fimod s -i data.json --env 'GITHUB_*' -e 'env'
fimod s -i data.json --env '*' -e 'env.get("CI", "false")'

headers

List of CSV column names when the input format is CSV with a header row. None for non-CSV input or when using --csv-no-input-header:

name,score,passed
Alice,87,true
Bob,42,false
Carol,95,true
def transform(data, args, env, headers):
    # headers = ["name", "score", "passed"] for CSV, None otherwise
    if headers and "score" in headers:
        return it_sort_by(data, "score")
    return data
fimod s -i grades.csv -m sort_by_score.py