Async API¶
To interact with the Excel object model, scripts and notebooks let you use the same syntax as the classic, locally installed xlwings (sync API). This often works fine, but because xlwings Lite runs in a browser, it talks to Excel differently. That difference creates three limitations, and the async API gives you a method to work around each one:
All cell values are loaded up front. Getting a sync book (
xw.books.activefor notebooks or using thexw.Booktype hint in scripts) fetches all values from the entire workbook, which can be slow and may cause the browser to run out of memory for large workbooks.→
await myrange.get_value()with an asyncBookreads only the values you ask for.Writes are queued. When you assign a value to a range, for example, it’s only applied at the end of a notebook cell or when a script finishes, not immediately.
→
await book.flush()applies queued writes immediately.Reads can be outdated. Anything you read via the sync API reflects the workbook state from the start of the notebook cell or the start of the script.
→
await book.load()refreshes everything.
The following sections cover each method in detail.
get_value(): reading values on demand¶
To read values on demand:
Use an async
Bookobject, which disables the loading of all values up front:Notebook:
await xw.books.get_active()Script:
xw.BookAsync(type hint)
Use
await myrange.get_value()instead ofmyrange.valueto load the values live.
In the following example, only the value of a single cell is loaded, no matter how big the workbook is:
# %%
import xlwings as xw
book = await xw.books.get_active() # sync version: book = xw.books.active
myrange = book.sheets[0]["A1"]
await myrange.get_value() # sync version: myrange.value
import xlwings as xw
from xlwings import script
@script
async def my_script(book: xw.BookAsync): # sync version: def my_script(book: xw.Book)
myrange = book.sheets[0]["A1"]
await myrange.get_value() # sync version: myrange.value
Note
Notebooks let you
awaitat the top level without requiring anasync def.Scripts must use
awaitinside of anasync def.
get_value() respects the same converters and options as value, so you can, for example, read a range directly into a pandas DataFrame:
import pandas as pd
df = await (
book.sheets["Sheet1"]["A1:C10"]
.options(pd.DataFrame, index=False)
.get_value()
)
While await get_value() technically also works with a sync book to get the current values, a sync book still loads the whole workbook up front.
flush(): writing immediately¶
When writing to a workbook, xlwings Lite queues every action and applies them in order at the end of a notebook cell or when the script finishes. If you need to flush queued writes to Excel before the automatic flush happens, call await book.flush():
# %%
book = await xw.books.get_active()
book.sheets[0]["A1"].value = "Hello xlwings!"
await book.flush()
await book.sheets[0]["A1"].get_value()
# Output
# 'Hello xlwings!'
import xlwings as xw
from xlwings import script
@script
async def my_script(book: xw.BookAsync):
book.sheets[0]["A1"].value = "Hello xlwings!"
await book.flush()
print(await book.sheets[0]["A1"].get_value())
# prints 'Hello xlwings!'
Here are some common scenarios where you need to use await book.flush():
After writing a value to an Excel cell, call
await book.flush()before reading that value—or a dependent cell—within the same notebook cell or script (example above).If you want to see the printed output immediately in the Output pane, use
await book.flush()afterprint().If you call a method that writes to the file system, such as
mysheet["A1:D10"].to_png("/data/range.png"), callawait book.flush()before accessing the file in the same notebook cell or script.
load(): reading the current workbook state¶
Before running a script or a notebook cell, xlwings Lite automatically runs await book.load(), so you rarely need to call it explicitly. To refresh the workbook state midway through a notebook cell or script, use await book.load() or await mysheet.load():
# %%
book = await xw.books.get_active()
sheet1 = book.sheets[0]
await book.load() # or: await sheet1.load()
sheet1.tables
import xlwings as xw
from xlwings import script
@script
async def my_script(book: xw.BookAsync):
sheet1 = book.sheets[0]
await book.load() # or: await sheet1.load()
sheet1.tables
A few things to keep in mind:
On an async book,
await book.load()fetches everything except values since you should access values viaawait myrange.get_value(). On a sync book,await book.load()includes values. If you want to exclude values on a sync book, useawait book.load(values=False).Calling
load()on a sheet object rather than the book loads only that sheet instead of the whole book, so it’s slightly more efficient.