Skip to main content
Run Python scripts inside the container on the specified box for test automation, hardware control, and data processing.

Syntax

Global Options

Arguments:
  • RUNNABLE - Python script file or directory to execute (required unless a process-management flag such as --kill, --kill-all, --reattach, --continue, or --console is used)
  • ARGS - Additional arguments passed to the script
Signal choices for --kill/--kill-all: SIGINT, SIGQUIT, SIGABRT, SIGKILL, SIGUSR1, SIGUSR2, SIGTERM, SIGSTOP

Basic Usage

Environment Variables

Setting Variables

Auto-Injected Variables

The following environment variables are automatically available inside your script:

File Downloads

Each run has its own output folder on the box. Write the files your script makes to lager.output_dir():
Then add --download to get all of them back:
When the script finishes, the CLI makes a new folder in the current directory, named after the run. It copies into that folder every file the script wrote to lager.output_dir(), with any subfolders, and the run record. The CLI then compares each file with the hash in the record:
The run record lists every file in the output folder, with or without --download. Without --download, the CLI does not save anything on your computer. Outside lager python, lager.output_dir() returns a lager-output folder in the current directory, so the script still runs on your computer.

Detached Mode

Run scripts in the background without waiting for output:
In detached mode:
  • The command returns as soon as the box accepts the job. It returns before the script starts, and before any setup that the script needs (unpacking a module directory, installing its requirements.txt)
  • No stdout/stderr is streamed back
  • The script continues running on the box
  • Use --reattach to see its output, --kill to stop it later
The launch returns before the setup runs. A job can therefore fail to start after the prompt comes back — a requirements.txt that will not install, say. You see that failure through the job, not at the prompt. --reattach shows the failure and exits non-zero:
A detached run takes the box lock. A box on 0.42.0 or later then holds that lock while the job runs, and releases it when the job ends. The CLI prints Box 'my-lager-box' is held for the detached run and released when it ends. An older box keeps the lock after the job ends. The CLI then prints release with: lager boxes unlock --box my-lager-box. See locking.

Killing Running Scripts

--kill takes the process ID that the detached launch printed.

Port Forwarding

Forward network ports from the box to your local machine:
Port format: SRC_PORT[:DST_PORT][/PROTOCOL]

Timeout

Limit script execution time:
  • 0, the default, means no limit.
  • An attached run is capped at 300 seconds. A larger value runs for 300 seconds, and the box writes the cap to its log.
  • A detached run has no cap. The box applies the value only when you give one.
When a script exceeds the timeout, the box sends the signals:
  • First, SIGTERM is sent. The CLI prints Script terminated due to timeout. and exits with code 124
  • If the script does not exit within 5 seconds, SIGKILL is sent. The CLI prints Script forcibly killed due to timeout. and exits with code 137

Structured Output

Scripts running on the box can send structured data back to the CLI using the lager.core.output() function. This uses a dedicated output channel (file descriptor 3) separate from stdout/stderr.

Box-Side API

Available encoders: Structured output is printed to the CLI console as it arrives. Standard stdout and stderr are streamed separately in real time.

Module Includes

If your script depends on local modules, configure includes in a .lager file in your project. The file is JSON:
A relative path is relative to the .lager file. The CLI starts at the directory of the script, and searches up the directory tree for a .lager file. It then zips the script along with all include directories before uploading to the box.
In test.py:

Additional Files

Upload extra files alongside your script:
Files are available in the same directory as your script on the box.

Exit Codes

Run Record

The box writes a run record for each run. The record is a JSON file. It shows what ran, on which box, in which state, and what came out:
  • The SHA-256 hash of each file that the box received
  • The box state when the run started: the Lager version, the OS, the net configuration, and the serial number of each instrument
  • The start time, the end time, and the exit code
  • Why the run ended: it exited, it timed out, it was cancelled, or the client disconnected
  • The SHA-256 hash of the output and of each file in the run’s output folder
Where the record is kept:
  • On the box, for every run. The box keeps the records of its most recent 500 runs.
  • In the box’s outbox, if a collector manages the box. A collector is a service that takes each record from the box and keeps it somewhere else. These records stay in the outbox until the collector takes them.
  • On your computer, only with --download. The CLI writes the record as <process-id>.lager-run.json in the run’s folder, next to the downloaded files (see File Downloads). The CLI compares the output and the downloaded files with the hashes in the record. If they are different, the CLI shows a warning.
Add labels to find a run later:
A script can add values that only the script knows, for example the firmware version of the device under test:
The box does not verify labels or values from a script. Do not put secrets in them. For the full format, see docs/reference/run-record.md in the Lager repository.

Box Lock

lager python takes the box lock when it runs a script. Another user then cannot drive the same box at the same time. See locking.
  • An attached run holds the lock while the script runs. The command releases it when it exits.
  • If another user holds the lock, the command fails at once on your computer. In CI, it waits for the lock.
  • --kill, --kill-all, --reattach, --continue, and --console do not take the lock.
  • Set LAGER_AUTO_LOCK_DISABLE=1 to run without the lock.

Examples

Hardware Test Script Example

Notes

  • Use --env for script-specific configuration values
  • Use --passenv for secrets/tokens from your current shell
  • --download retrieves files only after script completion (not during), and only the files in lager.output_dir()
  • Port forwarding syntax: SRC_PORT[:DST_PORT][/PROTOCOL]
  • Output is streamed in real time via a multiplexed HTTP protocol with keepalive (20-second interval)

Installing Python packages

Scripts run inside the Lager Python container on the box. To install the packages that your scripts depend on, use the declarative lager box-config pip commands. Those commands record the packages in the box config and rebuild the container. The packages then persist across lager python runs and box updates.
See the Box Config reference for the full declarative provisioning workflow (pip/cargo/npm packages, apt, udev, mounts, env, and more).
The standalone lager pip command was removed and folded into lager box-config pip.