Metadata-Version: 2.5
Name: renovara-sql
Version: 0.2.0
Summary: Python client for the Renovara SQL API: DuckDB SQL over Australian NEM and east coast gas market data from AEMO
Project-URL: Homepage, https://renovara.co/sql-api
Project-URL: Documentation, https://renovara.co/how-renovara-sql-works
Project-URL: API description, https://sql.api.renovara.co/v1/openapi.json
Author-email: "Scoptico Pty Ltd (Renovara)" <info@renovara.co>
License-Expression: MIT
License-File: LICENSE
Keywords: aemo,australia,duckdb,electricity,energy,gas,nem,sql
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.9
Provides-Extra: pandas
Requires-Dist: pandas; extra == 'pandas'
Requires-Dist: pyarrow; extra == 'pandas'
Description-Content-Type: text/markdown

# Renovara SQL API — Python client

Read-only SQL over Australian National Electricity Market (NEM) and east
coast gas market data from AEMO, from your own code. The SQL is DuckDB's.

```bash
pip install renovara-sql
```

## See what the data is — no credentials needed

```python
from renovara_sql import Client

public = Client("https://sql.api.renovara.co/v1")
print(public.guide()[:2000])       # which table answers what, and the traps
for t in public.tables():          # every table, one line each
    print(t["table"], "-", t["description"][:80])
print(public.table("silver_dispatchis_reports_dispatch_price")["columns"][:5])
```

## Credentials

Your Renovara credentials page gives you a file:

```json
{
  "api_url": "https://sql.api.renovara.co/v1/",
  "token_url": "https://auth.api.renovara.co/oauth2/token",
  "client_id": "…",
  "client_secret": "…",
  "scope": "renovara-sql/query"
}
```

Keep it private: anyone holding it can query as your organisation. It is an
OAuth client-credentials pair, exchanged for an access token that lasts an
hour; the client keeps the token for the hour and renews it for you.

## Run queries

```python
from renovara_sql import Client

client = Client.from_file("~/.config/renovara-sql/acme.json")
result = client.query("""
    SELECT REGIONID, round(avg(RRP), 2) AS avg_price
    FROM silver_dispatchis_reports_dispatch_price
    WHERE SETTLEMENTDATE >= current_timestamp + INTERVAL 10 HOUR - INTERVAL 7 DAY
      AND INTERVENTION = 0
    GROUP BY 1 ORDER BY 1
""")
print(result.column_names, result.rows)
print(result.usage)                 # your plan, query time used, statements today
frame = result.to_pandas()          # needs pandas; pyarrow for exact types
result.download("prices.parquet")   # the full result, any size
```

`python quickstart.py <credentials file>` runs a short tour.

## What to know

- **DuckDB SQL**, one `SELECT` per request (or `EXPLAIN SELECT …` for the
  plan). `client.guide()` lists the differences from Databricks SQL. Tables
  answer to their bare names or to `external_data.nemweb.<table>`.
- **Times**: `SETTLEMENTDATE` and the other NEM timestamps are AEST market
  time (UTC+10, no daylight saving) already. Don't shift them. "Now" in market
  time is `current_timestamp + INTERVAL 10 HOUR`.
- **Long queries**: `query()` returns when the query finishes, polling if the
  server needs more than ~20 s. A statement stops at 300 s. For control, use
  `submit(sql)`, `status(statement_id)` and `cancel(statement_id)`.
- **Results**: up to 10,000 rows come back inline as `result.rows`; every
  result is also a Parquet file at `result.parquet_url` for an hour. Over
  5,000,000 rows a statement is refused: aggregate in SQL. Statements and
  results last 24 hours.
- **Retries are safe**: `query()` sends an idempotency key, so a retry never
  runs a statement twice.
- **Errors** raise `QueryFailed` (a statement that ran and failed: `code` is
  `QUERY_REJECTED`, `SQL_ERROR`, `QUERY_TIMEOUT`, `RESULT_TOO_LARGE` or
  `CANCELLED`) or `RenovaraError` (a refused request, e.g. `DAILY_LIMIT`,
  `ALLOWANCE_USED`). Each has a `docs_url`.

## Without the client

```bash
TOKEN=$(curl -s -u "$CLIENT_ID:$CLIENT_SECRET" -d grant_type=client_credentials \
  -d scope=renovara-sql/query "$TOKEN_URL" | jq -r .access_token)
# Keep $TOKEN for its hour: each one issued is billed, so not one per query.

curl -s -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"sql": "SELECT count(*) FROM silver_dispatchis_reports_dispatch_price", "wait_seconds": 20}' \
  "${API_URL}statements"
# -> {"statement_id": "…", "state": "SUCCEEDED", "result": {"columns": …, "rows": …}}
#    or "state": "RUNNING": then GET ${API_URL}statements/<statement_id> until it isn't
```

The API describes itself: `GET ${API_URL}` and `GET ${API_URL}openapi.json`.
