Skip to main content

Reference Python executor for the Lace probe scripting language. Depends on lacelang-validator for parsing and semantic checks.

Project description

lacelang-executor (python)

Canonical Python executor for Lace — the reference implementation with 100% spec conformance. Runs .lace scripts against real HTTP endpoints and emits ProbeResult JSON.

This is the executor that the Lace specification is developed and tested against. Conformance vectors, error codes, and wire-format schemas are verified against this implementation before each spec release.

Parsing and semantic validation are delegated to lacelang-validator — this package contains only the runtime (HTTP client, assertion evaluation, cookie jars, extension dispatch). See lace-spec.md §15 for the validator / executor package separation rule.

Install

pip install lacelang-executor

This automatically installs lacelang-validator as a dependency.

Or from source:

pip install git+https://github.com/tracedown/lacelang-python-executor.git

Usage

# Parse (delegates to validator)
lacelang-executor parse script.lace

# Validate (delegates to validator)
lacelang-executor validate script.lace --context context.json --vars-list vars.json

# Run — full HTTP execution
lacelang-executor run script.lace \
    --vars vars.json \
    --prev prev.json \
    --bodies-dir ./bodies

# Enable extensions (laceNotifications is built in)
lacelang-executor run script.lace --enable-extension laceNotifications

All subcommands support --pretty for indented JSON.

Library usage

Project layout

The executor expects Lace files under a dedicated lace/ directory:

my-project/
  lace/
    lace.config                      # executor config (auto-discovered)
    config.staging.json              # env-specific overrides (optional)
    extensions/                      # third-party extensions
      myext/
        myext.laceext
        myext.config
    scripts/
      health/
        health.lace                  # script (name = directory name)
        vars.json                    # default variables
        vars.staging.json            # env-specific variables
      auth-flow/
        auth-flow.lace
        vars.json

All paths are overridable at runtime — the layout is a convention, not a requirement.

LaceExecutor + LaceProbe

from lacelang_executor import LaceExecutor

# Point to the lace/ directory — config loaded once
executor = LaceExecutor("lace")

# Or override the config path directly
executor = LaceExecutor(config="path/to/lace.config", env="staging")

# Register third-party extensions
executor.extension("lace/extensions/myext")           # directory (finds myext.laceext + myext.config)
executor.extension("path/to/custom.laceext", "path/to/custom.config")  # explicit paths

# Prepare a probe by name — resolves to lace/scripts/health/health.lace
# AST is parsed and validated once, reused across runs
probe = executor.probe("health")

# Run — returns a ProbeResult dict
result = probe.run(vars={"base_url": "https://api.example.com"})

# Run again — prev result from last run injected automatically
result = probe.run()

# All inputs accept file paths or dicts
result = probe.run(
    vars="lace/scripts/health/vars.staging.json",
    prev="results/last_run.json",    # explicit prev overrides auto-tracking
)

One-shot execution

# No probe caching, no prev tracking
result = executor.run("lace/scripts/health/health.lace", vars={"key": "val"})

# Inline source
result = executor.run('''
get("https://api.example.com/health")
    .expect(status: 200)
''')

Development mode

# Re-read and re-parse the script file on every run()
probe = executor.probe("health", always_reparse=True)

API reference

LaceExecutor(root, *, config, env, extensions, track_prev)

Parameter Type Default Description
root str | None None Path to the lace/ directory. Discovers lace.config and resolves script names relative to {root}/scripts/.
config str | None None Explicit path to lace.config (overrides root-based discovery).
env str | None None Selects [lace.config.{env}] section (overrides LACE_ENV).
extensions list[str] | None None Built-in extensions to activate (e.g. ["laceNotifications"]).
track_prev bool True Auto-store last result as prev for next run on each probe.

executor.extension(path, config_path=None) — register a third-party extension.

executor.probe(script, *, vars, always_reparse) — prepare a reusable probe.

Parameter Type Default Description
script str Script name ("health"), file path ("path/to.lace"), or inline source.
always_reparse bool False Re-read script file on every run().

probe.run(vars, prev, *, reparse) — execute and return ProbeResult.

Parameter Type Default Description
vars str | dict | None None Script variables — dict or path to JSON.
prev str | dict | None None Previous result — dict or path to JSON. Overrides auto-tracking.
reparse bool False Re-read script from disk for this run only.

Config and environment overrides

There is exactly one config file per executor. The env parameter selects a section within that file, not a different file.

# lace/lace.config

[executor]
maxRedirects = 10
maxTimeoutMs = 300000

# Staging overlay — deep-merged on top of base.
# Only the keys you specify are overridden; the rest is inherited.
[lace.config.staging]
[lace.config.staging.executor]
maxTimeoutMs = 60000           # overridden
# maxRedirects is inherited (10)

[lace.config.production]
[lace.config.production.executor]
user_agent = "lace-probe/0.9.1 (acme-platform)"

Resolution by constructor arguments:

Constructor Config file Env overlay
LaceExecutor("lace") lace/lace.config none (base only)
LaceExecutor("lace", env="staging") lace/lace.config [lace.config.staging] merged on base
LaceExecutor(config="/path/lace.config", env="prod") /path/lace.config [lace.config.prod] merged on base
LaceExecutor("lace", config="/other/lace.config") /other/lace.config none (root still used for script names)
LACE_ENV=staging + LaceExecutor("lace") lace/lace.config [lace.config.staging] (from env var)
LACE_ENV=staging + LaceExecutor("lace", env="prod") lace/lace.config [lace.config.prod] (kwarg wins)

The config= kwarg overrides where the file is loaded from. The env= kwarg (or LACE_ENV) selects which section inside that file is overlaid. They are independent — setting one does not affect the other.

Return value

Both probe.run() and executor.run() return a dict matching the ProbeResult wire format (spec §9):

{
    "outcome": "success",        # "success" | "failure" | "timeout"
    "startedAt": "2026-04-20T10:00:00.000Z",
    "endedAt":   "2026-04-20T10:00:01.234Z",
    "elapsedMs": 1234,
    "runVars":   {},             # run-scoped variables from .store()
    "calls":     [...],          # per-call result records
    "actions":   {},             # write-back variables, notifications, etc.
}

Low-level API

The stateless run_script() function is available for callers that need full control over parsing, validation, and config:

from lacelang_validator.parser import parse
from lacelang_executor.executor import run_script
from lacelang_executor.config import load_config

ast = parse(open("script.lace").read())
config = load_config(explicit_path="lace.config")

result = run_script(ast, script_vars={"key": "val"}, config=config)

User-Agent

Per lace-spec.md §3.6, this executor sets a default User-Agent on outgoing requests:

User-Agent: lace-probe/<version> (lacelang-python)

Precedence (highest first): per-request headers: { "User-Agent": ... }lace.config [executor].user_agent → the default above.

Responsible use

This software is designed for monitoring endpoints you own or have explicit authorization to probe. You are solely responsible for ensuring your use complies with all applicable laws, terms of service, and acceptable use policies. See NOTICE for the full statement.

License

Apache License 2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lacelang_executor-0.1.0.tar.gz (70.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lacelang_executor-0.1.0-py3-none-any.whl (73.7 kB view details)

Uploaded Python 3

File details

Details for the file lacelang_executor-0.1.0.tar.gz.

File metadata

  • Download URL: lacelang_executor-0.1.0.tar.gz
  • Upload date:
  • Size: 70.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for lacelang_executor-0.1.0.tar.gz
Algorithm Hash digest
SHA256 00329a130e5bbbf2bc2bf61d8d1b83164082c9c83b84ef0b41f417dd2baee15e
MD5 db88dc1c083461e5c98ab49fa34968c6
BLAKE2b-256 fc67b96f07e11dcf9cc3db93ac416cf202ed3d51b7030072759eab37a8e53425

See more details on using hashes here.

Provenance

The following attestation bundles were made for lacelang_executor-0.1.0.tar.gz:

Publisher: release.yml on tracedown/lacelang-python-executor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lacelang_executor-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for lacelang_executor-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4d538c0a53b9269e2bbcea5dbe5f5d8aeca3f897132cfc69e784c594ea624e04
MD5 a09e4b06f1b2b2aad506ee14acd2f845
BLAKE2b-256 c2a1f9bc5b36d45f9ab8a6e24537483ff1e591a4b54da45a75f31950a4723c2e

See more details on using hashes here.

Provenance

The following attestation bundles were made for lacelang_executor-0.1.0-py3-none-any.whl:

Publisher: release.yml on tracedown/lacelang-python-executor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page