> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lagerdata.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Python

> Run Python scripts on box

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

## Syntax

```bash theme={null}
lager python [OPTIONS] [RUNNABLE] [ARGS]...
```

## Global Options

| Option              | Short | Type     | Default   | Description                                              |
| ------------------- | ----- | -------- | --------- | -------------------------------------------------------- |
| `--box TEXT`        |       | String   |           | Lagerbox name or IP address                              |
| `--env FOO=BAR`     |       | Multiple |           | Set environment variables for the script                 |
| `--passenv VAR`     |       | Multiple |           | Pass environment variables from current shell            |
| `--kill`            |       | Flag     |           | Terminate a running Python script                        |
| `--signal SIGNAL`   |       | Choice   | `SIGTERM` | Signal to use with `--kill`                              |
| `--download FILE`   |       | Multiple |           | Download files from box after script completes           |
| `--allow-overwrite` |       | Flag     |           | Allow overwriting existing local files with `--download` |
| `--timeout SECONDS` |       | Integer  | 0 (none)  | Maximum runtime in seconds                               |
| `--detach`          | `-d`  | Flag     |           | Run in detached mode (background)                        |
| `--port PORT`       | `-p`  | Multiple |           | Forward ports to the Python process                      |
| `--add-file FILE`   |       | Multiple |           | Add extra files to upload with script                    |
| `--help`            |       | Flag     |           | Show help message and exit                               |

**Arguments:**

* `RUNNABLE` - Python script file or directory to execute (required unless `--kill` is used)
* `ARGS` - Additional arguments passed to the script

**Signal choices for `--kill`:** SIGINT, SIGQUIT, SIGABRT, SIGKILL, SIGUSR1, SIGUSR2, SIGTERM, SIGSTOP

## Basic Usage

```bash theme={null}
# Run a Python script on the box
lager python script.py --box my-box

# Run with arguments
lager python test.py --box my-box -- --verbose --target DUT1

# Run a directory as a module
lager python my_test_suite/ --box my-box
```

## Environment Variables

### Setting Variables

```bash theme={null}
# Set explicit environment variables
lager python test.py --box my-box --env API_KEY=abc123 --env DEBUG=true

# Pass variables from your current shell
export SECRET_TOKEN=xyz
lager python test.py --box my-box --passenv SECRET_TOKEN
```

### Auto-Injected Variables

The following environment variables are automatically available inside your script:

| Variable               | Description                                                   |
| ---------------------- | ------------------------------------------------------------- |
| `LAGER_OUTPUT_CHANNEL` | File path for structured output (see Structured Output below) |
| `LAGER_PROCESS_ID`     | Unique UUID for this execution                                |
| `LAGER_RUNNABLE`       | Path to the script being executed                             |
| `LAGER_BOX`            | Box name (if `--box` was provided)                            |

## File Downloads

Download files generated by your script after it completes:

```bash theme={null}
# Download a single file
lager python data_processor.py --box my-box --download results.csv

# Download multiple files
lager python test.py --box my-box --download report.json --download log.txt

# Allow overwriting existing local files
lager python test.py --box my-box --download results.csv --allow-overwrite
```

Files are downloaded to the current working directory using the basename of the remote path. If a local file with the same name already exists, the command fails unless `--allow-overwrite` is set. Gzip-compressed files are automatically decompressed during download.

## Detached Mode

Run scripts in the background without waiting for output:

```bash theme={null}
# Start a long-running script in the background
lager python long_running.py --box my-box --detach
```

In detached mode:

* The command returns immediately after the script starts
* No stdout/stderr is streamed back
* The script continues running on the box
* Use `--kill` to stop it later

## Killing Running Scripts

```bash theme={null}
# Kill with default SIGTERM
lager python --box my-box --kill

# Kill with specific signal
lager python --box my-box --kill --signal SIGKILL
```

## Port Forwarding

Forward network ports from the box to your local machine:

```bash theme={null}
# Forward port 8080
lager python web_server.py --box my-box -p 8080

# Forward with different local/remote ports
lager python server.py --box my-box -p 8080:80

# Forward with protocol
lager python server.py --box my-box -p 8080:80/tcp
```

Port format: `SRC_PORT[:DST_PORT][/PROTOCOL]`

## Timeout

Limit script execution time:

```bash theme={null}
# Kill after 5 minutes
lager python analysis.py --box my-box --timeout 300
```

When a script exceeds the timeout:

* First, SIGTERM is sent (exit code 124)
* If the script doesn't exit, SIGKILL is sent (exit 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

```python theme={null}
from lager.core import output, OutputEncoders

# Output a Python dict (default: pickle encoding)
output({'status': 'pass', 'measurement': 3.14})

# Output as JSON
output({'voltage': 3.3, 'current': 0.5}, encoder=OutputEncoders.JSON)

# Output as YAML
output({'device': 'PSU-1', 'readings': [1.0, 2.0]}, encoder=OutputEncoders.YAML)

# Output raw binary data
output(image_bytes, encoder=OutputEncoders.Raw)
```

**Available encoders:**

| Encoder                 | ID | Use Case                    |
| ----------------------- | -- | --------------------------- |
| `OutputEncoders.Raw`    | 1  | Binary data (images, files) |
| `OutputEncoders.Pickle` | 2  | Python objects (default)    |
| `OutputEncoders.JSON`   | 3  | JSON-serializable data      |
| `OutputEncoders.YAML`   | 4  | YAML-serializable data      |

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:

```yaml theme={null}
# .lager (in project root)
includes:
  my_lib: /path/to/my_lib
  fixtures: /path/to/fixtures
```

The CLI searches up the directory tree for a `.lager` file, then zips the script along with all include directories before uploading to the box.

```bash theme={null}
# Script can import from included directories
lager python test.py --box my-box
```

In `test.py`:

```python theme={null}
from my_lib import helpers
from fixtures import test_data
```

## Additional Files

Upload extra files alongside your script:

```bash theme={null}
lager python flash_and_test.py --box my-box --add-file firmware.hex --add-file config.json
```

Files are available in the same directory as your script on the box.

## Exit Codes

| Exit Code | Meaning                                   |
| --------- | ----------------------------------------- |
| 0         | Success                                   |
| -1        | Failed to retrieve exit code from box     |
| 124       | Script terminated by SIGTERM (timeout)    |
| 137       | Script killed by SIGKILL (timeout, force) |
| Other     | Script's own exit code                    |

## Examples

```bash theme={null}
# Basic script execution
lager python script.py --box my-box

# Run with environment variables
lager python test.py --box my-box --env API_KEY=abc123 --env DEBUG=true

# Run in detached mode
lager python long_running.py --box my-box --detach

# Download files after completion
lager python data_processor.py --box my-box --download results.csv

# Kill running script
lager python --box my-box --kill

# Run with port forwarding
lager python web_server.py --box my-box -p 8080

# Run with timeout
lager python analysis.py --box my-box --timeout 300

# Upload extra files with script
lager python flash_test.py --box my-box --add-file firmware.hex

# Pass arguments to the script
lager python test.py --box my-box -- --device DUT1 --verbose
```

### Hardware Test Script Example

```python theme={null}
# test_power.py - run with: lager python test_power.py --box my-box
from lager import Net, NetType
from lager.core import output, OutputEncoders
import time

# Get the power supply net
psu = Net.get("PSU_CH1", type=NetType.PowerSupply)

# Set voltage and enable
psu.voltage(value=3.3, ovp=3.6)
psu.enable()
time.sleep(1)

# Read state
state = psu.get_full_state()
print(f"Voltage: {state['voltage']}V, Current: {state['current']}A")

# Send structured results
output({
    'test': 'power_on',
    'voltage': state['voltage'],
    'current': state['current'],
    'status': 'pass' if state['voltage'] > 3.0 else 'fail'
}, encoder=OutputEncoders.JSON)

# Cleanup
psu.disable()
```

## 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)
* Port forwarding syntax: `SRC_PORT[:DST_PORT][/PROTOCOL]`
* After script execution, the hardware cache on the box is automatically cleared to release VISA connections
* Output is streamed in real time via a multiplexed HTTP protocol with keepalive (20-second interval)

***

## pip Command

Run pip commands in the Python container on the box. Useful for installing packages that your scripts depend on.

### Syntax

```bash theme={null}
lager pip [OPTIONS] [ARGS]...
```

### Options

| Option      | Description                 |
| ----------- | --------------------------- |
| `--box BOX` | Lagerbox name or IP address |
| `--help`    | Show help message and exit  |

### Examples

```bash theme={null}
# Install a package
lager pip install pandas --box my-box

# List installed packages
lager pip list --box my-box

# Uninstall a package
lager pip uninstall numpy --box my-box

# Install from requirements file
lager pip install -r requirements.txt --box my-box
```

### Notes

* Runs pip in the Lager Python container, not on your local machine
* Installed packages persist across `lager python` invocations on the same box
* All standard pip commands and arguments are supported
