Files
wehub-resource-sync 8cb1f9f479
Publish SDK (PyPI) / publish (push) Waiting to run
Publish SDK (npm) / publish (@aionui/officecli-sdk) (push) Waiting to run
Publish SDK (npm) / publish (@officecli/officecli-sdk) (push) Waiting to run
Publish SDK (npm) / publish (@officecli/sdk) (push) Waiting to run
Publish SDK (npm) / publish (officecli-sdk) (push) Waiting to run
SDK smoke / smoke (windows-latest) (push) Waiting to run
SDK smoke / smoke (macos-latest) (push) Waiting to run
SDK smoke / smoke (ubuntu-latest) (push) Waiting to run
Skill parity / diff (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 13:09:29 +08:00

94 lines
3.8 KiB
Python

#!/usr/bin/env python3
"""
Demo: build a small sales report .xlsx using the officecli Python client.
Run: python3 demo.py [path-to-officecli-binary]
Shows the whole loop over a single resident:
create -> writes applied as one batch -> read back -> save -> close -> reopen.
"""
import os
import sys
import officecli # the client (officecli.py next to this file)
# Locate the binary: 1st arg, else "officecli" on PATH.
BIN = sys.argv[1] if len(sys.argv) > 1 else "officecli"
OUT = os.path.abspath("sales_report.xlsx")
# Sample data: (region, units, price)
ROWS = [
("North", 120, 9.5),
("South", 95, 11.0),
("East", 140, 8.75),
("West", 60, 12.5),
("Central", 110, 10.0),
]
COL = "ABCDE" # A..E
def cell(c, r):
return f"/Sheet1/{c}{r}"
def main():
# create returns a live handle bound to the resident it auto-starts.
# --force overwrites a leftover from a previous run.
with officecli.create(OUT, "--force", binary=BIN) as doc: # make file + get handle
# Build every write as a batch-shaped item, then apply them all in ONE
# round-trip. Same dict shape officecli's `batch` command documents.
items = []
# Header row
for j, title in enumerate(["Region", "Units", "Price", "Revenue"]):
items.append({"command": "set", "path": cell(COL[j], 1),
"props": {"text": title, "bold": "true"}})
# Data rows + a live formula for Revenue (=Units*Price)
for i, (region, units, price) in enumerate(ROWS, start=2):
items.append({"command": "set", "path": cell("A", i), "props": {"text": region}})
items.append({"command": "set", "path": cell("B", i), "props": {"text": str(units)}})
items.append({"command": "set", "path": cell("C", i), "props": {"text": str(price)}})
items.append({"command": "set", "path": cell("D", i), "props": {"formula": f"=B{i}*C{i}"}})
# Totals row
last = len(ROWS) + 1
items.append({"command": "set", "path": cell("A", last + 1),
"props": {"text": "TOTAL", "bold": "true"}})
items.append({"command": "set", "path": cell("B", last + 1),
"props": {"formula": f"=SUM(B2:B{last})"}})
items.append({"command": "set", "path": cell("D", last + 1),
"props": {"formula": f"=SUM(D2:D{last})"}})
doc.batch(items) # all writes, one pipe round-trip
# Read one cell back over the pipe (single command, same dict shape).
node = doc.send({"command": "get", "path": cell("A", 1)})
results = node.get("data", {}).get("results", [{}])
print("A1 reads back as:", results[0].get("text") if results else None)
# In-session validate over the pipe (no extra process spawn). This is
# the path that used to corrupt styles.xml; safe now that ValidateDocument
# validates a clone instead of the live package.
v = doc.send({"command": "validate"})
print("validate (in-session):", "OK" if v.get("success") else v)
doc.send({"command": "save"}) # flush in-memory doc to disk
# context exit -> close the resident (which flushes to disk too)
# Round-trip proof: reopen the CLOSED file fresh and confirm it both
# validates and kept its content. open() does the one-shot bootstrap spawn
# for us, so the demo stays entirely on the SDK — no hand-rolled subprocess.
with officecli.open(OUT, binary=BIN) as doc:
v = doc.send({"command": "validate"})
print("validate (reopened):", "OK" if v.get("success") else v)
a1 = doc.send({"command": "get", "path": cell("A", 1)})
print("A1 after reopen:", a1.get("data", {}).get("results", [{}])[0].get("text"))
print(f"wrote {OUT} ({os.path.getsize(OUT)} bytes)")
if __name__ == "__main__":
main()