Metadata-Version: 2.4
Name: athena-openpyxl
Version: 0.11.2
Summary: Drop-in replacement for openpyxl that connects to XLSX Studio for real-time collaboration
Project-URL: Homepage, https://github.com/Athena-Intel/demo-app-monorepo/tree/staging/xlsx-studio
Project-URL: Documentation, https://github.com/Athena-Intel/demo-app-monorepo/tree/staging/xlsx-studio/python-sdk
Project-URL: Issues, https://github.com/Athena-Intel/demo-app-monorepo/issues
Author-email: Athena Intelligence <engineering@athenaintelligence.ai>
License-Expression: MIT
Keywords: api,excel,openpyxl,sdk,spreadsheet,xlsx
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business :: Financial :: Spreadsheet
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: requests>=2.28.0
Provides-Extra: dev
Requires-Dist: mypy>=1.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: responses>=0.23; extra == 'dev'
Requires-Dist: ruff>=0.1; extra == 'dev'
Provides-Extra: e2e
Requires-Dist: openpyxl>=3.1.0; extra == 'e2e'
Requires-Dist: pytest>=7.0; extra == 'e2e'
Description-Content-Type: text/markdown

# athena-openpyxl

`openpyxl`-shaped Python SDK that talks to xlsx-studio's HTTP API. Writes go through `POST /workbooks/:id/commands`; the Fastify service applies them to a server-side `pycrdt` Doc and pushes Y.Doc updates to Keryx so Olympus's `@rowsncolumns/y-spreadsheet` renderer sees the change live. The SDK process never opens its own y-websocket — there is no `pycrdt` dependency on the SDK side.

**Status:** v0.2.0 — Tier-A surface complete (full openpyxl public API up to formatting + dates), Tier-B surfaces (tables / data validation / conditional formatting / defined names / comments / images / hyperlinks) wired through the Keryx Y.Doc.

## Quick start

```python
from openpyxl import Workbook

with Workbook("asset_abc123") as wb:   # opens Keryx session, runs initial sync
    ws = wb.active
    ws["A1"] = "Hello"
    ws["A2"] = 42
    ws["A3"] = "=SUM(A2)"
    wb.save()                          # flushes pending updates to Keryx
```

Branch + agent attribution:

```python
from openpyxl import Workbook

with Workbook(
    "asset_abc",
    branch="suggest-run-7",
    custom_attributions=[
        {"k": "agent_id", "v": "spreadsheet-author"},
        {"k": "user_message_tracking_id", "v": "msg_xyz"},
    ],
) as wb:
    wb.active["A1"] = "agent edit"
    wb.save()
```

Bulk writes via batch context (one logical activity-log entry):

```python
from openpyxl import Workbook

with Workbook("asset_abc") as wb:
    ws = wb.active
    with wb.batch():
        for row_idx in range(1, 1001):
            ws.cell(row_idx, 1, f"row {row_idx}")
        wb.save()
```

## Environment

The SDK reads these env vars (Daytona-managed in production):

| Variable | Required | Notes |
|---|---|---|
| `ATHENA_XLSX_BASE_URL` | ✓ | xlsx-studio API URL, e.g. `https://xlsx-api.stg.athenaintel.com` |
| `ATHENA_XLSX_API_KEY` |   | Bearer token for the apps/api ownership middleware (omit for local dev with no auth) |
| `ATHENA_ORG_ID` |   | Workspace/org override; the API resolves the workspace from the API key when this is unset |

## Install (development)

```bash
cd xlsx-studio/python-sdk
uv venv && uv pip install -e ".[dev]"
uv run pytest tests/
```

## Public surface (v0.2.0)

**Tier A — Core (fully implemented):**

| Surface | Status |
|---|---|
| Workbook lifecycle (`Workbook(asset_id)`, `load_workbook`, `save`, `close`, ctx mgr) | ✅ |
| Sheet listing (`sheetnames`, `worksheets`, `active`, `wb[title]`) | ✅ |
| Single-cell I/O (`ws['A1']`, `ws.cell(r, c)`, `cell.value`) | ✅ |
| Range access (`ws['A1:C3']`, `ws['A:C']`, `ws[1]`) | ✅ |
| Bulk writes (`ws.append`, `iter_rows`, `iter_cols`) | ✅ |
| Dimensions (`column_dimensions`, `row_dimensions`, `width`, `height`, `hidden`, `outline_level`, `group`) | ✅ |
| Structural mutations (`create_sheet`, `remove`, `move_sheet`, `copy_worksheet`, `ws.title = x`) | ✅ |
| Merged cells (`merge_cells`, `unmerge_cells`, `merged_cells`) | ✅ |
| Freeze panes (`ws.freeze_panes`) | ✅ |
| Auto filter (`ws.auto_filter.ref`) | ✅ |
| Cell formatting (`font`, `fill`, `alignment`, `border`, `protection`, `number_format`, `style`) | ✅ |
| Date / datetime / time values | ✅ |

**Tier B — Common (wired through Keryx Y.Doc):**

| Surface | Status |
|---|---|
| `wb.defined_names` / `DefinedName` | ✅ |
| `ws.tables` / `Table` / `TableStyleInfo` | ✅ |
| `ws.data_validations` / `DataValidation` | ✅ |
| `ws.conditional_formatting` / Rule classes | ✅ |
| `cell.comment` / `Comment` | ✅ |
| `cell.hyperlink` / `Hyperlink` | ✅ |
| `ws.add_image` / `Image` | ✅ |
| `wb.named_styles` / `NamedStyle` (object model only) | partial |

**Tier C — Advanced (raises `UnsupportedFeatureError`):**

- Charts and chartsheets (waiting on the cross-studio chart engine extraction from `pptx-studio` — see `pptx-studio/docs/CHARTING_REFACTOR_PLAN_2026-04-21.md`).
- Pivot tables.
- Sheet/workbook protection write side.
- Page setup write side.
- Macros / VBA passthrough.

See [`docs/API_PARITY_EXCEPTIONS.md`](docs/API_PARITY_EXCEPTIONS.md) for the canonical list of intentional deviations.

## Architecture

```
Agent code (openpyxl idiom)
    ↓
Workbook / Worksheet / Cell           (sync facade)
    ↓  CommandBuffer.append(<cmd>)
batching.CommandBuffer                (groups + flushes)
    ↓  Client.post_commands(...)
HTTP POST /workbooks/:id/commands     (Bearer auth + ownership middleware)
    ↓
xlsx-studio apps/api (Fastify)        (validates schema, runs applier.ts)
    ↓  pycrdt Doc transactions
Keryx  ←→  Olympus (@rowsncolumns/y-spreadsheet renderer)
  (Y.Doc lives server-side; room = "{workspace}/{asset_id}")
```

- `client.py` — `requests`-backed HTTP client: auth, retries (`urllib3 Retry`), 401/409/4xx error mapping (`AuthenticationError`/`ConflictError`/`RemoteError`), and the workbook / commands / snapshot / export endpoints.
- `batching.py` — `CommandBuffer` queues SDK calls into a single `POST /commands` payload (so one cell or one bulk write becomes one HTTP round-trip, not N) and `flush_all()` for end-of-script drain.
- `commands.py` — typed dataclasses (`SetCellValue`, `SetCellStyle`, `SetIterativeCalculation`, …) with `.validate()` and `.to_dict()`. Each one round-trips against `apps/api/src/commands/types.ts` Zod schemas.
- `cell/`, `worksheet/`, `workbook/`, `styles/`, `comments/`, `formatting/`, `drawing/`, `pivot/`, `tables.py` — openpyxl-shaped surface; reads materialize from snapshot (`Client.get_snapshot`), writes append commands to the buffer.

## Publishing

```bash
bash ../scripts/publish-python-sdk.sh 0.2.0
```

## Development workflow

```bash
# Install editable + dev tools.
uv venv && uv pip install -e ".[dev]"

# Run the unit suite (no Keryx required).
uv run pytest tests/ -x

# Lint.
uv run ruff check openpyxl tests
```

## Tests

The SDK ships ~190 unit tests covering: utility helpers, all five style descriptors (Font / Fill / Alignment / Border / Protection / NamedStyle), Workbook lifecycle / registry / `flush_all`, single-cell I/O, range access, `iter_rows` / `iter_cols`, `append`, `max_row` / `max_column`, dimensions, structural mutations, merges, freeze panes, auto filter, cell formatting, dates, comments, hyperlinks, and the `UnsupportedFeatureError` boundary.

Tests stub the HTTP transport (`Client._request`) and assert on the captured command payloads — no network access required.

The integration / parity / fidelity lanes live separately (see the roadmap doc at `xlsx-studio/docs/ATHENA_OPENPYXL_ROADMAP_2026-04-29.md`).
