Metadata-Version: 2.5
Name: less-sdk
Version: 0.1.2
Summary: Less Python SDK - build custom python scripts with the convenience of the Less platform.
Project-URL: Homepage, https://less.tech
Project-URL: Documentation, https://docs.less.tech/guides/python-sdk
Requires-Python: >=3.11
Requires-Dist: numpy<2,>=1.24
Requires-Dist: pandas<3,>=2.1
Requires-Dist: pyarrow>=13.0
Requires-Dist: requests>=2.32
Description-Content-Type: text/markdown

# Less Python SDK

Build custom Python scripts that integrate with the [Less Platform](https://less.tech). Develop and test locally, then paste the same script into Less to get scheduling, logs, job status, notifications, and flexible compute.

Full documentation: [docs.less.tech/guides/python-sdk](https://docs.less.tech/guides/python-sdk)

## What the SDK is for

Use the SDK when you want to:

1. Write custom Python scripts.
2. Read tables already in Less and write new tables to Less.
3. Run the script on Less with scheduling, logs, job status, notifications, and flexible compute.

## Install

Requires Python 3.11 or later.

```bash
pip install less-sdk
```

Dependencies are pinned to stay compatible with common scientific Python stacks (NumPy 1.x, pandas 2.x). This avoids breaking pre-installed packages in images like `jupyter/scipy-notebook`.

If you previously installed `less-sdk` 0.1.0 and saw NumPy conflicts, upgrade:

```bash
pip install --upgrade less-sdk
```

## Typical workflow

1. Install the SDK if you do not already have it installed.
2. Create and save a Python asset in Less.
3. After saving, the **Local SDK setup** modal opens. Copy the generated script into your local environment. You can reopen this later from the ⋯ menu by clicking **Generate local SDK setup**.
4. Develop and test locally.
5. Copy the script back into Less — omit the `os.environ` block at the top. The platform sets those variables when the job runs.
6. Add a schedule to run the asset on a regular basis.

## Set up credentials

Copy the script from the **Local SDK setup** modal in Less. The top of the file sets credentials for local development:

```python
# LOCAL ONLY — the os.environ block below is for running on your machine.
# When copying this script into Less, omit the os.environ section entirely.
# The platform sets LESS_API_URL, LESS_API_TOKEN, and LESS_ASSET_ID for you.

import os

os.environ["LESS_API_URL"] = "your-less-api-url"
os.environ["LESS_API_TOKEN"] = "your-script-api-token"
os.environ["LESS_ASSET_ID"] = "your-python-asset-id"

import less

less.reload_config()  # pick up env if less was already imported

# END LOCAL ONLY
```

Keep credentials out of the script you paste into Less. The platform injects `LESS_API_URL`, `LESS_API_TOKEN`, and `LESS_ASSET_ID` automatically when the job runs.

| Env | Purpose |
|-----|---------|
| `LESS_API_URL` | e.g. `https://app.example.com/api` |
| `LESS_API_TOKEN` | script-api-token from the UI (expires after 24 hours) |
| `LESS_ASSET_ID` | Python asset id |
| `LESS_JOB_ID` | set only on platform runs |

## Quick start

```python
import less
import pandas as pd

less.log("Connected to Less")

tables = less.list_tables()

less.log(f"Found {len(tables)} tables")

first_table = tables.iloc[0]

less.log(f"Reading table {first_table['table_name']}")

df = less.read_table(first_table["id"])

less.log(f"Successfully read {df.shape[0]} rows and {df.shape[1]} columns")

# Send a warning back to Less
# less.warning("check this")

# Send an error back to Less - this will stop the script
# less.error("something went wrong")

# Send an error back to Less - the script will continue to run
# less.error("something went wrong", continue_on=True)

demo_df = pd.DataFrame(
    {
        "order_id": [1, 2, 3],
        "amount": [10.5, 20.0, 7.25],
    }
)

# Write a table back to Less
less.write_table(
    "demo_orders",
    demo_df,
)

less.log("The script ran successfully")
```

## Available functions

### `less.list_tables()`

Returns a pandas DataFrame with available tables. Columns: `id`, `table_name`.

```python
tables = less.list_tables()
print(tables[["id", "table_name"]].head())
```

### `less.read_table(table_id)`

Reads a Less table into a pandas DataFrame. Find `table_id` in Less or from `list_tables()`.

```python
tables = less.list_tables()
df = less.read_table(tables.iloc[0]["id"])
```

### `less.write_table(name, df)`

Stores a pandas DataFrame as a table in Less.

```python
less.write_table("customers", df)
```

Notes:

- `df` must be a pandas DataFrame.
- Empty DataFrames are skipped.

### Logging

```python
less.log("Connected to Less")
less.info("Fetched 12 rows")
less.debug("Request payload accepted")
less.warning("Missing optional column")
less.error("Could not fetch rates")                 # stops the script
less.error("Non-fatal issue", continue_on=True)     # logs and continues
less.warning("Stop here", continue_on=False)        # stops the script
```

Each call takes a **message**. `warning` continues by default. `error` stops the script unless you pass `continue_on=True`. Stopping raises `less.LessException`.
