Skip to content

API reference

rustpy_xlsxwriter

RustPy-XlsxWriter

High-performance Excel file generation powered by Rust. ~9x faster than Python's xlsxwriter.

Quick start::

from rustpy_xlsxwriter import FastExcel

# One-liner
FastExcel("output.xlsx").sheet("Sheet1", records).save()

# Multiple sheets with options
(
    FastExcel("report.xlsx", password="secret")
    .format(float_format="0.00", index_columns=["Name"], bold_headers=True)
    .freeze(row=1, col=1)
    .sheet("Users", user_records)
    .sheet("Orders", order_records)
    .save()
)

# Context manager (auto-saves on exit)
with FastExcel("output.xlsx") as f:
    f.sheet("Users", user_records)
    f.sheet("Orders", order_records)

# Pandas DataFrame
FastExcel("df.xlsx").sheet("Sheet1", pandas_df).save()

# Polars DataFrame
FastExcel("df.xlsx").sheet("Sheet1", polars_df).save()

# In-memory buffer
import io
buf = io.BytesIO()
FastExcel(buf).sheet("Sheet1", records).save()

# Generator streaming (memory-efficient)
def rows():
    for i in range(1_000_000):
        yield {"id": i, "value": f"row_{i}"}

FastExcel("big.xlsx").sheet("Data", rows()).save()

You can also use the lower-level functional API directly::

from rustpy_xlsxwriter import write_worksheet, write_worksheets
write_worksheet([{"Name": "Alice"}], "output.xlsx")

Format

A reusable cell format (font, fill, border, alignment, number format).

Setters are chainable — each returns self::

Format().set_bold().set_font_color("#FF0000").set_num_format("0.00%")

Colors accept "#RRGGBB" / "RRGGBB" hex or a color name (e.g. "red"). Enum-valued setters accept lowercase string names.

FastExcel

Fluent builder for creating Excel files.

Examples::

# Minimal
FastExcel("out.xlsx").sheet("Sheet1", records).save()

# Full options
(
    FastExcel("report.xlsx", password="s3cret")
    .format(float_format="0.00", index_columns=["ID"])
    .freeze(row=1)
    .sheet("Users", user_records)
    .sheet("Orders", order_records)
    .save()
)
__init__
__init__(
    target: Union[str, PathLike, BinaryIO],
    *,
    output_format: Optional[str] = None,
    password: Optional[str] = None,
    autofit: bool = True,
    sanitize_formulas: bool = False,
    bom: bool = False,
    columns: Optional[List[str]] = None,
    header: bool = True
) -> None

Create a new writer.

Parameters:

Name Type Description Default
target Union[str, PathLike, BinaryIO]

File path (str or :class:os.PathLike, e.g. pathlib.Path) or writable binary buffer (e.g. io.BytesIO).

required
output_format Optional[str]

"xlsx", "csv" or "tsv". Defaults to the target's file extension, and to "xlsx" for a buffer, which has none — so this is what writes CSV into an :class:io.BytesIO. For a delimiter other than , or tab, call :func:write_csv directly.

None
password Optional[str]

Optional worksheet-protection password. NOTE: this sets Excel's sheet protection flag only — it does not encrypt the file. The cell data is stored in plaintext and the protection is trivially removed; do not rely on it to keep data confidential.

None
autofit bool

Automatically adjust column widths (default True). Under constant-memory mode (the default for every Excel sheet, unless sheet(..., dedupe_strings=True) opts out) autofit sizing is approximate. Set to False for large datasets to improve performance.

True
sanitize_formulas bool

CSV/TSV only. When True, string fields that begin with = + - @ are prefixed with a single quote so spreadsheet apps open them as text instead of executing them as formulas (CSV-injection mitigation). Off by default to keep output byte-identical. Has no effect on .xlsx output, where values are already written as text cells.

False
bom bool

CSV/TSV only. Prefix the UTF-8 byte order mark, which is what makes Excel on Windows read the file as UTF-8 rather than the system code page. Off by default so output stays byte-identical.

False
columns Optional[List[str]]

CSV/TSV only. Select and order the output columns by name. An unknown name raises ValueError.

None
header bool

CSV/TSV only. Write the header row (default True).

True
format
format(
    *,
    float_format: Optional[str] = None,
    datetime_format: Optional[str] = None,
    index_columns: Optional[List[str]] = None,
    bold_headers: Optional[bool] = None,
    na_rep: Optional[str] = None,
    inf_value: Optional[str] = None
) -> "FastExcel"

Set number formatting and column styling.

Parameters:

Name Type Description Default
float_format Optional[str]

Excel number format for floats (e.g. "0.00").

None
datetime_format Optional[str]

Excel number format for datetimes (default "yyyy-mm-ddThh:mm:ss").

None
index_columns Optional[List[str]]

Column names to render bold.

None
bold_headers Optional[bool]

Whether to render header row in bold.

None
na_rep Optional[str]

Text written for NaN. Left unset, the cell is empty — which is what every earlier version did, so a column of NaN arrives as a column of blanks that cannot be told apart from missing data. Applies to Excel and CSV alike.

None
inf_value Optional[str]

Text written for inf; -inf gets the same text with a - in front, matching Excel's INF/-INF.

None
freeze
freeze(
    *,
    row: Optional[int] = None,
    col: Optional[int] = None,
    sheet: Optional[str] = None
) -> "FastExcel"

Configure freeze panes.

Parameters:

Name Type Description Default
row Optional[int]

Freeze panes above this row number.

None
col Optional[int]

Freeze panes to the left of this column number.

None
sheet Optional[str]

Apply to a specific sheet only. If None, applies to all sheets ("general").

None
sheet
sheet(
    name: str,
    data: Any,
    *,
    column_width: Optional[float] = None,
    column_widths: Optional[
        Union[Dict[str, float], List[float]]
    ] = None,
    column_formats: Optional[
        Union[Dict[str, "Format"], List["Format"]]
    ] = None,
    header_format: Optional["Format"] = None,
    dedupe_strings: bool = False,
    header_row: int = 0,
    merge_ranges: Optional[List[Tuple]] = None,
    row_heights: Optional[Dict[int, float]] = None,
    row_formats: Optional[Dict[int, "Format"]] = None,
    banded_rows: Optional[str] = None,
    autofilter: bool = False,
    url_columns: Optional[
        Union[List[str], Dict[str, str]]
    ] = None,
    totals_row: Optional[Dict[str, str]] = None,
    totals_label: Optional[str] = None,
    totals_format: Optional["Format"] = None,
    formula_columns: Optional[Dict[str, str]] = None,
    page_setup: Optional[Dict[str, Any]] = None,
    conditional_formats: Optional[Dict[str, Any]] = None,
    sheet_view: Optional[Dict[str, Any]] = None,
    ignore_errors: Optional[
        Union[List[str], Dict[str, str]]
    ] = None,
    data_validations: Optional[
        Dict[str, Dict[str, Any]]
    ] = None,
    outline: Optional[Dict[str, Any]] = None,
    notes: Optional[Dict[str, Any]] = None,
    images: Optional[List[Dict[str, Any]]] = None,
    sparklines: Optional[Dict[str, Dict[str, Any]]] = None,
    charts: Optional[List[Dict[str, Any]]] = None
) -> "FastExcel"

Add a worksheet with data.

Parameters:

Name Type Description Default
name str

Sheet name (≤ 31 chars, no [ ] : * ? / \).

required
data Any

List of dicts, generator of dicts, or pandas DataFrame.

required
column_width Optional[float]

Uniform width applied to every column of this sheet.

None
column_widths Optional[Union[Dict[str, float], List[float]]]

Per-column width — a dict keyed by header name ({"name": 22}) or a positional list ([7, 22, 40]). Overrides column_width for the columns it names.

None
column_formats Optional[Union[Dict[str, 'Format'], List['Format']]]

Per-column :class:Format — a dict keyed by header name ({"name": Format().set_bold()}) or a positional list ([Format().set_bold(), None]).

None
header_format Optional['Format']

:class:Format applied to every header cell of this sheet.

None
dedupe_strings bool

Store repeated strings once in the workbook's shared-string table instead of inline, which can shrink the .xlsx substantially when a sheet has many repeated text values (categories, statuses, country codes). Off by default: it takes this sheet out of constant-memory mode, so the whole sheet is buffered in RAM and every string is hashed. Turn it on per sheet, for sheets whose text actually repeats, and measure.

False
header_row int

0-based row the header is written on; data follows it. Raise it to leave room for merged banner headers above.

0
merge_ranges Optional[List[Tuple]]

Merged cells, as (first_row, first_col, last_row, last_col, value[, format]) tuples — e.g. [(0, 1, 0, 2, "Gender", banner_fmt)] for a banner spanning two sub-columns. Ranges must sit strictly above header_row; anything overlapping the header or data raises, because rows already written cannot be merged after the fact.

None
row_heights Optional[Dict[int, float]]

{row_index: height} in points.

None
row_formats Optional[Dict[int, 'Format']]

{row_index: Format} applied to the whole row — the way to put a bottom border under the header or a top border above a totals row. A cell carrying its own format (a number format, a column format, a band) wins over the row's.

None
banded_rows Optional[str]

Background colour ("#F2F2F2" or a name) shaded onto every other data row, starting with the second. Applied per cell rather than per row, so columns with their own number format stay shaded too.

None
autofilter bool

Add Excel's filter dropdowns over the header row and its data. The range is computed from the rows actually written, so it follows header_row and needs no manual bounds.

False
url_columns Optional[Union[List[str], Dict[str, str]]]

Columns whose text cells become clickable links. A list names them and each cell shows the URL — ["homepage"]. A dict maps a link column to the column holding its display text — {"url": "product_name"} shows the product name and links to the URL, which is what a report usually wants. Accepts what Excel accepts: http(s)://, mailto:, and internal:Sheet2!A1 for a link to another sheet. A value Excel would reject (ordinary text, or a URL past its 2083-character limit) is written as plain text instead, so a stray non-link never aborts the export. An unknown display-text column warns and falls back to showing the URL.

None
totals_row Optional[Dict[str, str]]

{column_name: aggregate} written as Excel formulas in a row below the data — {"amount": "sum"} becomes =SUM(C2:C101). Valid aggregates: sum, average, count, min, max, product, stdev. A value starting with = is used as a formula instead, with {col} the column letter and {first}/{last} the data range::

totals_row={"margin": "=SUM({col}{first}:{col}{last})/2"}

Skipped entirely when there are no data rows, since the range would be empty. NOTE: the formulas carry no computed result, so readers that use cached values (pandas.read_excel, openpyxl with data_only=True) get None until Excel or LibreOffice opens the file and recalculates.

None
totals_label Optional[str]

Text for the first column of the totals row, e.g. "Total". Raises if the first column also has an aggregate.

None
totals_format Optional['Format']

:class:Format for the whole totals row — the usual bold plus a top border. Needed because the row index is not known ahead of time, so row_formats cannot reach it.

None
formula_columns Optional[Dict[str, str]]

{header: formula} — extra columns appended after the data, one formula per data row. {row} is replaced with that row's 1-based sheet row and {first} with the first data row::

formula_columns={"total": "=B{row}*C{row}"}

The formula text is passed through to Excel unchanged, so anything Excel accepts works: nested calls, SUMIFS, cross-sheet references, and modern functions like XLOOKUP or TEXTJOIN (which are rewritten with the _xlfn. prefix and dynamic-array metadata automatically). Structure is checked — unbalanced parentheses or quotes raise — but function names are not, so =NOTAFUNC(A1) reaches the file and shows #NAME?. There is no {last}: rows are still streaming when these are written, so the final row is unknown; use totals_row for whole-column formulas.

None
page_setup Optional[Dict[str, Any]]

Page and print settings as one mapping, because Excel has about twenty of them and a keyword each would double this signature. Keys: landscape, paper_size, margins (a dict of left/right/top/bottom/header/ footer; anything omitted keeps Excel's default), print_area as (first_row, first_col, last_row, last_col), repeat_rows and repeat_columns (an index or a (first, last) pair — this is what puts the header on every printed page), fit_to_pages as (width, height) with 0 letting that dimension run on, scale, center_horizontally, center_vertically, print_gridlines, print_headings, first_page_number, and header/footer using Excel's &-codes such as "&RPage &P of &N". An unknown key raises, as does setting scale and fit_to_pages together, which Excel cannot honour at once.

None
conditional_formats Optional[Dict[str, Any]]

Per-column conditional formatting, as {column: rule} or {column: [rule, rule]} when a column needs more than one. A rule is a dict with a type: cell (criteria ==/!=/>/>=/</<= with value, or between/not_between with min and max, plus a format), data_bar (optional color, bar_only), 2_color_scale and 3_color_scale (optional min_color, mid_color, max_color), text (contains/does_not_contain/begins_with/ ends_with with value and format), top (top/bottom/top_percent/bottom_percent with value, default top 10), average (above/below/equal_or_above/equal_or_below), and duplicate/unique.

Rules cover the column's data rows only — never the header — and the range follows the rows actually written, so no manual bounds. An unknown column warns and is skipped; an unknown type or criteria raises.

None
sheet_view Optional[Dict[str, Any]]

How the sheet presents on screen, as one mapping: tab_color, gridlines (on screen), zoom, right_to_left, hidden, selected. Separate from page_setup, which is about paper. An unknown key raises, as does hidden with selected — Excel rejects a workbook whose active sheet is hidden.

None
ignore_errors Optional[Union[List[str], Dict[str, str]]]

Suppress Excel's green error triangles on a column. A list of column names means number_stored_as_text — the reason anyone wants this, since an ID, SKU or postcode column is digits stored as text on purpose and Excel flags every cell of it. A dict maps a column to another error name instead — one per column, never a list, since Excel allows a single ignore rule per cell. Covers the data rows only; an unknown column warns and is skipped.

None
data_validations Optional[Dict[str, Dict[str, Any]]]

Per-column data validation, as {column: rule}. A rule is a dict with a type: list (values, a list of strings — the dropdown, and the reason most people want this; Excel caps the inline list at 255 characters including separators and a longer one raises), whole_number/decimal/text_length (criteria ==/!=/>/>=/</<= with value, or between/not_between with min and max; a fraction given to the two integer kinds raises rather than being truncated), custom (formula), or any.

Any rule also accepts input_title, input_message, error_title, error_message, error_style (stop, warning, information), ignore_blank and show_dropdown. Rules cover the data rows only, never the header; an unknown column warns and is skipped.

None
outline Optional[Dict[str, Any]]

Collapsible row and column groups — the +/- brackets in Excel's margin — as one mapping. rows takes a list of {"from": int, "to": int} by 0-based sheet row (matching row_heights), columns a list of {"from": name, "to": name} by header name, both with an optional collapsed. symbols_above and symbols_to_left choose which side the summary sits on.

NOTE: a row group takes this sheet out of constant-memory mode, the same trade-off as dedupe_strings. The constant-memory row writer emits hidden but not outlineLevel, so a collapsed group there would leave hidden rows with no bracket to reopen them — worse than not offering it. Column groups carry no such cost. An unknown column name warns and is skipped.

None
notes Optional[Dict[str, Any]]

Notes on header cells, as {column: text} — where to say what a column means without widening it or adding a legend sheet. The value may instead be a dict with text plus any of author, width, height, visible and background_color. An unknown column warns and is skipped.

None
images Optional[List[Dict[str, Any]]]

Images anchored to cells, as a list of dicts. Each needs path or data (raw bytes, for a logo already in memory) and takes row/col (0-based, default 0), scale or the per-axis scale_x/scale_y, fit_to_cell with keep_aspect_ratio, alt_text and url. Placed by index rather than by column name, since an image floats above the grid instead of belonging to a column. Identical images are stored once.

None
sparklines Optional[Dict[str, Dict[str, Any]]]

A one-cell chart per data row, as {column: rule}. The column is one left empty in the records; from and to name the span each row summarises::

rows = [{"q1": 1, "q2": 5, "q3": 3, "q4": 8, "trend": None}]
sparklines={"trend": {"from": "q1", "to": "q4"}}

Also takes type (line, column, win_lose), color, style and the toggles high_point, low_point, first_point, last_point, markers, negative_points, axis and right_to_left.

The target column must already exist: appending one would mean reaching into the header assembly and column accounting that formula_columns uses, in both row loops, for far more cost than the feature is worth. An unknown column warns and is skipped.

None
charts Optional[List[Dict[str, Any]]]

Charts anchored to a cell, as a list of dicts. Each needs a type and a series::

charts=[{"type": "column", "series": ["q1", "q2"],
         "categories": "region", "title": "Quarterly"}]

series is a list of column names, or of dicts with values and an optional name — left out, the series name links to that column's header cell so the legend follows the header. categories names the column used for axis labels.

Types: area, bar, column, line (each also with _stacked and _percent_stacked), pie, doughnut, radar, radar_with_markers, radar_filled, scatter, scatter_smooth, stock.

Also takes row/col, title, x_axis, y_axis, width, height, style and legend. Left unplaced, a chart lands one column clear of the data and level with the header rather than on top of the table. Series cover the data rows only. An unknown column warns and skips that chart, since a chart missing a series draws a misleading picture. A scatter chart is refused without categories — they are its x values rather than labels, so there is nothing to default them to.

None

Raises:

Type Description
ValueError

If the sheet name is invalid (validated on save), or a merge range overlaps the header/data rows.

save
save() -> None

Write all sheets to the target file or buffer.

Writes the format given as output_format, or the one implied by the target's extension: .csv → CSV, .tsv → TSV, anything else (including a buffer) → Excel.

Raises:

Type Description
ValueError

If no sheets have been added.

OSError

If there are filesystem errors while writing.

validate_sheet_name

validate_sheet_name(name: str) -> bool

Check whether name is a valid Excel sheet name.

Rules: ≤ 31 characters, no [ ] : * ? / \, not empty.

Examples:

>>> validate_sheet_name("Sheet1")
True
>>> validate_sheet_name("Sheet[1]")
False

write_csv

write_csv(
    records: SheetData,
    file_name: FileTarget,
    delimiter: Optional[str] = None,
    sanitize_formulas: bool = False,
    bom: bool = False,
    columns: Optional[List[str]] = None,
    header: bool = True,
    na_rep: Optional[str] = None,
    inf_value: Optional[str] = None,
) -> None

Write data to a CSV file.

Parameters:

Name Type Description Default
records SheetData

Data to write – a list of dicts, a generator of dicts, a pandas DataFrame, or a polars DataFrame.

required
file_name FileTarget

Destination file path or writable binary buffer.

required
delimiter Optional[str]

Column delimiter (default ","). Use "\t" for TSV.

None
sanitize_formulas bool

When True, string fields starting with = + - @ are prefixed with ' to neutralize CSV formula injection. Off by default (output stays byte-identical).

False
bom bool

Prefix the UTF-8 byte order mark. Excel on Windows reads a BOM-less UTF-8 file as the system code page, which turns non-ASCII text into mojibake; this is the fix. Off by default so output stays byte-identical for pipelines that parse it.

False
columns Optional[List[str]]

Select and order the output columns by name. A name that is not in the data raises ValueError — unlike the styling options, this one decides the shape of the file, so a silent drop would hand back something that looks complete. Works on every input type, and stays zero-copy on the Arrow path.

None
header bool

Write the header row. Set False to append to an existing file or to feed a reader that supplies its own names.

True
na_rep Optional[str]

Text written for a missing value — None, an Arrow null, or a float NaN, which are deliberately one knob: pandas turns NaN in a float column into an Arrow null, so a setting that caught only true NaN would do nothing on the most common input there is. Default None leaves the cell empty, as every earlier version did, which makes a missing value indistinguishable from a blank.

None
inf_value Optional[str]

Text written for inf; -inf gets the same text with a - in front, matching Excel's own INF/-INF.

None

Examples:

>>> write_csv([{"Name": "Alice", "Age": 30}], "out.csv")

write_worksheet

write_worksheet(
    records: SheetData,
    file_name: FileTarget,
    sheet_name: Optional[str] = None,
    password: Optional[str] = None,
    freeze_row: Optional[int] = None,
    freeze_col: Optional[int] = None,
    float_format: Optional[str] = None,
    datetime_format: Optional[str] = None,
    index_columns: Optional[List[str]] = None,
    autofit: bool = True,
    bold_headers: bool = False,
    column_width: Optional[float] = None,
    column_widths: Optional[ColumnWidths] = None,
    column_formats: Optional[ColumnFormats] = None,
    header_format: Optional[Format] = None,
    dedupe_strings: bool = False,
    header_row: int = 0,
    merge_ranges: Optional[List[MergeRange]] = None,
    row_heights: Optional[Dict[int, float]] = None,
    row_formats: Optional[Dict[int, Format]] = None,
    banded_rows: Optional[str] = None,
    autofilter: bool = False,
    url_columns: Optional[UrlColumns] = None,
    totals_row: Optional[Dict[str, str]] = None,
    totals_label: Optional[str] = None,
    totals_format: Optional[Format] = None,
    formula_columns: Optional[Dict[str, str]] = None,
    na_rep: Optional[str] = None,
    inf_value: Optional[str] = None,
    page_setup: Optional[PageSetup] = None,
    conditional_formats: Optional[
        ConditionalFormats
    ] = None,
    sheet_view: Optional[SheetView] = None,
    ignore_errors: Optional[IgnoreErrors] = None,
    data_validations: Optional[DataValidations] = None,
    outline: Optional[Outline] = None,
    notes: Optional[Notes] = None,
    images: Optional[Images] = None,
    sparklines: Optional[Sparklines] = None,
    charts: Optional[Charts] = None,
) -> None

Write data to a single worksheet in an Excel file.

Parameters:

Name Type Description Default
records SheetData

Data to write – a list of dicts, a generator of dicts, or a pandas DataFrame.

required
file_name FileTarget

Destination file path (*.xlsx) or a writable binary buffer such as io.BytesIO.

required
sheet_name Optional[str]

Worksheet name (default "Sheet1"). Must be ≤ 31 chars; cannot contain [ ] : * ? / \.

None
password Optional[str]

Optional password to protect the workbook.

None
freeze_row Optional[int]

Freeze panes above this row number.

None
freeze_col Optional[int]

Freeze panes to the left of this column number.

None
float_format Optional[str]

Excel number format for floats (e.g. "0.00").

None
index_columns Optional[List[str]]

Column names that should be rendered bold.

None
autofit bool

Automatically adjust column widths (default True).

True
column_width Optional[float]

Uniform width applied to every column.

None
column_widths Optional[ColumnWidths]

Per-column width — a dict keyed by header name or a positional list.

None
dedupe_strings bool

Store repeated strings once in the shared-string table instead of inline. Shrinks files with heavily repeated text, at the cost of buffering the sheet in memory (disables constant-memory mode). Off by default.

False
header_row int

0-based row the header is written on; data follows it.

0
merge_ranges Optional[List[MergeRange]]

(first_row, first_col, last_row, last_col, value[, format]) tuples. Must sit strictly above header_row.

None
row_heights Optional[Dict[int, float]]

{row_index: height} in points.

None
row_formats Optional[Dict[int, Format]]

{row_index: Format} applied to the whole row.

None
banded_rows Optional[str]

Background colour shaded onto every other data row.

None
autofilter bool

Add filter dropdowns over the header row and its data.

False
url_columns Optional[UrlColumns]

Columns whose text cells become clickable links. A list names them and the cell shows the URL; a dict maps each link column to the column holding its display text ({"url": "product_name"}). Values Excel rejects fall back to plain text.

None
totals_row Optional[Dict[str, str]]

{column_name: aggregate} written as formulas below the data. Valid: sum, average, count, min, max, product, stdev.

None
totals_label Optional[str]

Text for the first column of the totals row.

None
totals_format Optional[Format]

Format applied to the whole totals row.

None
formula_columns Optional[Dict[str, str]]

{header: formula} appended after the data, one formula per row. {row}/{first} are substituted.

None
na_rep Optional[str]

Text written for a missing value — None, an Arrow null, or a float NaN, which are deliberately one knob: pandas turns NaN in a float column into an Arrow null, so a setting that caught only true NaN would do nothing on the most common input there is. Default None leaves the cell empty, as every earlier version did, which makes a missing value indistinguishable from a blank.

None
inf_value Optional[str]

Text written for inf; -inf gets the same text with a - in front, matching Excel's own INF/-INF.

None
page_setup Optional[PageSetup]

Page and print settings, as one mapping — Excel has about twenty of them and a keyword each would double this signature. Keys: landscape, paper_size, margins (a dict of left/right/top/bottom/header/footer, any omitted one keeping Excel's default), print_area ((first_row, first_col, last_row, last_col)), repeat_rows and repeat_columns (an index or a (first, last) pair), fit_to_pages ((width, height); 0 lets that dimension run on), scale, center_horizontally, center_vertically, print_gridlines, print_headings, first_page_number, header and footer (Excel's &-codes, e.g. "&RPage &P of &N"). An unknown key raises, and so does setting scale together with fit_to_pages, which Excel cannot honour at once.

None
conditional_formats Optional[ConditionalFormats]

Per-column conditional formatting, as {column: rule} or {column: [rule, rule]}. A rule is a dict with a type:

  • cell — criteria (==, !=, >, >=, <, <=, between, not_between) plus value, or min and max for the two range criteria, and a format
  • data_bar — optional color and bar_only
  • 2_color_scale / 3_color_scale — optional min_color, mid_color, max_color
  • text — criteria (contains, does_not_contain, begins_with, ends_with), value, format
  • top — criteria (top, bottom, top_percent, bottom_percent, default top), value (default 10)
  • average — criteria (above, below, equal_or_above, equal_or_below)
  • duplicate / unique

Rules cover the column's data rows only, never the header, and the range follows the rows actually written. An unknown column warns and is skipped; an unknown type or criteria raises.

None
sheet_view Optional[SheetView]

How the sheet presents on screen, as one mapping: tab_color, gridlines (show them on screen), zoom, right_to_left, hidden, selected. Kept apart from page_setup, which is about paper. An unknown key raises, as does hidden together with selected — Excel rejects a workbook whose active sheet is hidden.

None
ignore_errors Optional[IgnoreErrors]

Suppress Excel's green error triangles on a column. A list of column names means number_stored_as_text, which is the reason anyone reaches for this: an ID, SKU or postcode column is digits stored as text on purpose. A dict maps a column to one error name instead — formula_error, formula_differs, formula_refers_to_empty_cells, formula_omits_cells, data_validation_error, two_digit_text_year, unlocked_cells_with_formula, inconsistent_column_formula. One name per column, never a list: Excel allows a single ignore rule per cell. Covers the data rows only, and an unknown column warns and is skipped.

None
data_validations Optional[DataValidations]

Per-column data validation, as {column: rule}. A rule is a dict with a type:

  • list — values, a list of strings; this is the dropdown, and the reason most people want the feature. Excel caps the inline list at 255 characters including separators, and a longer one raises rather than producing a file Excel refuses to open
  • whole_number / decimal / text_length — criteria (==, !=, >, >=, <, <=, between, not_between) with value, or min and max for the two range criteria. A fraction given to whole_number or text_length raises instead of being truncated
  • custom — formula
  • any — accepts anything, useful only to carry a message

Any rule also takes input_title, input_message, error_title, error_message, error_style (stop, warning, information), ignore_blank and show_dropdown. Rules cover the data rows only, never the header. An unknown column warns and is skipped; an unknown type or criteria raises.

None
outline Optional[Outline]

Collapsible row and column groups — the +/- brackets in Excel's margin — as one mapping:

  • rows — a list of {"from": int, "to": int} by 0-based sheet row, matching row_heights, plus optional collapsed
  • columns — a list of {"from": name, "to": name} by header name, plus optional collapsed
  • symbols_above / symbols_to_left — which side the summary row or column sits on

NOTE: asking for a row group takes the sheet out of constant-memory mode, the same trade-off as dedupe_strings. The constant-memory row writer emits hidden but not outlineLevel, so a collapsed group there would leave hidden rows with no bracket to reopen them. Column groups carry no such cost. An unknown column name warns and is skipped.

None
notes Optional[Notes]

Notes on header cells, as {column: text} — where you say what a column means without widening it or adding a legend sheet. The value may instead be a dict with text plus any of author, width, height, visible and background_color. An unknown column warns and is skipped.

None
images Optional[Images]

Images anchored to cells, as a list of dicts. Each needs path or data (raw bytes, for a logo already in memory), and takes row and col (0-based, default 0), scale or the per-axis scale_x/scale_y, fit_to_cell with keep_aspect_ratio, alt_text and url. Images are placed by index rather than by column name, since they float above the grid instead of belonging to a column. Identical images are stored once.

None
sparklines Optional[Sparklines]

A one-cell chart per data row, as {column: rule}. The column is one you left empty in the records, and from and to name the span each row summarises::

rows = [{"q1": 1, "q2": 5, "q3": 3, "q4": 8, "trend": None}]
sparklines={"trend": {"from": "q1", "to": "q4"}}

Also takes type (line, column, win_lose), color, style, and the toggles high_point, low_point, first_point, last_point, markers, negative_points, axis and right_to_left.

The target column has to exist already: appending one would mean reaching into the header assembly and column accounting that formula_columns uses, in both row loops, which is far more than the feature is worth. An unknown column warns and is skipped.

None
charts Optional[Charts]

Charts anchored to a cell, as a list of dicts. Each needs a type and a series::

charts=[{"type": "column", "series": ["q1", "q2"],
         "categories": "region", "title": "Quarterly"}]

series is a list of column names, or of dicts with values and an optional name — left out, the series name links to that column's header cell, so the legend follows the header. categories names the column used for the axis labels.

Types: area, bar, column, line (each also with _stacked and _percent_stacked), pie, doughnut, radar, radar_with_markers, radar_filled, scatter, scatter_smooth, stock.

Also takes row/col, title, x_axis, y_axis, width, height, style and legend. Left unplaced, a chart lands one column clear of the data and level with the header rather than on top of the table. Series cover the data rows only. An unknown column warns and skips that chart, since a chart missing a series draws a misleading picture. A scatter chart is refused without categories — they are its x values rather than labels, so there is nothing to default them to.

None

Raises:

Type Description
ValueError

Invalid sheet name or unsupported data type.

OSError

File system error while writing.

Examples:

>>> write_worksheet([{"Name": "Alice", "Age": 30}], "out.xlsx")

write_worksheets

write_worksheets(
    records_with_sheet_name: List[SheetEntry],
    file_name: FileTarget,
    password: Optional[str] = None,
    freeze_panes: Optional[FreezePanesConfig] = None,
    float_format: Optional[str] = None,
    datetime_format: Optional[str] = None,
    index_columns: Optional[List[str]] = None,
    autofit: bool = True,
    bold_headers: bool = False,
    column_width: Optional[Dict[str, float]] = None,
    column_widths: Optional[Dict[str, ColumnWidths]] = None,
    column_formats: Optional[
        Dict[str, ColumnFormats]
    ] = None,
    header_format: Optional[Dict[str, Format]] = None,
    dedupe_strings: Optional[Dict[str, bool]] = None,
    header_row: Optional[Dict[str, int]] = None,
    merge_ranges: Optional[
        Dict[str, List[MergeRange]]
    ] = None,
    row_heights: Optional[
        Dict[str, Dict[int, float]]
    ] = None,
    row_formats: Optional[
        Dict[str, Dict[int, Format]]
    ] = None,
    banded_rows: Optional[Dict[str, str]] = None,
    autofilter: Optional[Dict[str, bool]] = None,
    url_columns: Optional[Dict[str, UrlColumns]] = None,
    totals_row: Optional[Dict[str, Dict[str, str]]] = None,
    totals_label: Optional[Dict[str, str]] = None,
    totals_format: Optional[Dict[str, Format]] = None,
    formula_columns: Optional[
        Dict[str, Dict[str, str]]
    ] = None,
    na_rep: Optional[str] = None,
    inf_value: Optional[str] = None,
    page_setup: Optional[Dict[str, PageSetup]] = None,
    conditional_formats: Optional[
        Dict[str, ConditionalFormats]
    ] = None,
    sheet_view: Optional[Dict[str, SheetView]] = None,
    ignore_errors: Optional[Dict[str, IgnoreErrors]] = None,
    data_validations: Optional[
        Dict[str, DataValidations]
    ] = None,
    outline: Optional[Dict[str, Outline]] = None,
    notes: Optional[Dict[str, Notes]] = None,
    images: Optional[Dict[str, Images]] = None,
    sparklines: Optional[Dict[str, Sparklines]] = None,
    charts: Optional[Dict[str, Charts]] = None,
) -> None

Write data to multiple worksheets in an Excel file.

Parameters:

Name Type Description Default
records_with_sheet_name List[SheetEntry]

A list of (sheet_name, data) tuples.

required
file_name FileTarget

Destination file path or writable binary buffer.

required
password Optional[str]

Optional password to protect the workbook.

None
freeze_panes Optional[FreezePanesConfig]

Per-sheet and/or general freeze-pane config.

None
float_format Optional[str]

Excel number format for floats (e.g. "0.00").

None
index_columns Optional[List[str]]

Column names that should be rendered bold.

None
autofit bool

Automatically adjust column widths (default True).

True
column_width Optional[Dict[str, float]]

Uniform width per sheet — dict keyed by sheet name ("general" applies to all).

None
column_widths Optional[Dict[str, ColumnWidths]]

Per-column width per sheet — dict keyed by sheet name mapping to :data:ColumnWidths.

None
dedupe_strings Optional[Dict[str, bool]]

Per-sheet shared-string deduplication — dict keyed by sheet name ("general" applies to all). See :func:write_worksheet for the trade-off.

None
header_row Optional[Dict[str, int]]

Per-sheet header row index — dict keyed by sheet name.

None
merge_ranges Optional[Dict[str, List[MergeRange]]]

Per-sheet merged cells — dict keyed by sheet name.

None
row_heights Optional[Dict[str, Dict[int, float]]]

Per-sheet row heights — dict keyed by sheet name.

None
row_formats Optional[Dict[str, Dict[int, Format]]]

Per-sheet row formats — dict keyed by sheet name.

None
banded_rows Optional[Dict[str, str]]

Per-sheet alternating row colour — dict keyed by sheet name.

None
autofilter Optional[Dict[str, bool]]

Per-sheet filter dropdowns — dict keyed by sheet name.

None
url_columns Optional[Dict[str, UrlColumns]]

Per-sheet link columns — dict keyed by sheet name.

None
totals_row Optional[Dict[str, Dict[str, str]]]

Per-sheet totals formulas — dict keyed by sheet name.

None
totals_label Optional[Dict[str, str]]

Per-sheet totals label — dict keyed by sheet name.

None
totals_format Optional[Dict[str, Format]]

Per-sheet totals row format — dict keyed by sheet name.

None
formula_columns Optional[Dict[str, Dict[str, str]]]

Per-sheet computed columns — dict keyed by sheet name.

None
na_rep Optional[str]

Text written for a missing value — None, an Arrow null, or a float NaN, which are deliberately one knob: pandas turns NaN in a float column into an Arrow null, so a setting that caught only true NaN would do nothing on the most common input there is. Default None leaves the cell empty, as every earlier version did, which makes a missing value indistinguishable from a blank.

None
inf_value Optional[str]

Text written for inf; -inf gets the same text with a - in front, matching Excel's own INF/-INF.

None
page_setup Optional[Dict[str, PageSetup]]

Page and print settings, as one mapping — Excel has about twenty of them and a keyword each would double this signature. Keys: landscape, paper_size, margins (a dict of left/right/top/bottom/header/footer, any omitted one keeping Excel's default), print_area ((first_row, first_col, last_row, last_col)), repeat_rows and repeat_columns (an index or a (first, last) pair), fit_to_pages ((width, height); 0 lets that dimension run on), scale, center_horizontally, center_vertically, print_gridlines, print_headings, first_page_number, header and footer (Excel's &-codes, e.g. "&RPage &P of &N"). An unknown key raises, and so does setting scale together with fit_to_pages, which Excel cannot honour at once.

None
conditional_formats Optional[Dict[str, ConditionalFormats]]

Per-column conditional formatting, as {column: rule} or {column: [rule, rule]}. A rule is a dict with a type:

  • cell — criteria (==, !=, >, >=, <, <=, between, not_between) plus value, or min and max for the two range criteria, and a format
  • data_bar — optional color and bar_only
  • 2_color_scale / 3_color_scale — optional min_color, mid_color, max_color
  • text — criteria (contains, does_not_contain, begins_with, ends_with), value, format
  • top — criteria (top, bottom, top_percent, bottom_percent, default top), value (default 10)
  • average — criteria (above, below, equal_or_above, equal_or_below)
  • duplicate / unique

Rules cover the column's data rows only, never the header, and the range follows the rows actually written. An unknown column warns and is skipped; an unknown type or criteria raises.

None
sheet_view Optional[Dict[str, SheetView]]

How the sheet presents on screen, as one mapping: tab_color, gridlines (show them on screen), zoom, right_to_left, hidden, selected. Kept apart from page_setup, which is about paper. An unknown key raises, as does hidden together with selected — Excel rejects a workbook whose active sheet is hidden.

None
ignore_errors Optional[Dict[str, IgnoreErrors]]

Suppress Excel's green error triangles on a column. A list of column names means number_stored_as_text, which is the reason anyone reaches for this: an ID, SKU or postcode column is digits stored as text on purpose. A dict maps a column to one error name instead — formula_error, formula_differs, formula_refers_to_empty_cells, formula_omits_cells, data_validation_error, two_digit_text_year, unlocked_cells_with_formula, inconsistent_column_formula. One name per column, never a list: Excel allows a single ignore rule per cell. Covers the data rows only, and an unknown column warns and is skipped.

None
data_validations Optional[Dict[str, DataValidations]]

Per-column data validation, as {column: rule}. A rule is a dict with a type:

  • list — values, a list of strings; this is the dropdown, and the reason most people want the feature. Excel caps the inline list at 255 characters including separators, and a longer one raises rather than producing a file Excel refuses to open
  • whole_number / decimal / text_length — criteria (==, !=, >, >=, <, <=, between, not_between) with value, or min and max for the two range criteria. A fraction given to whole_number or text_length raises instead of being truncated
  • custom — formula
  • any — accepts anything, useful only to carry a message

Any rule also takes input_title, input_message, error_title, error_message, error_style (stop, warning, information), ignore_blank and show_dropdown. Rules cover the data rows only, never the header. An unknown column warns and is skipped; an unknown type or criteria raises.

None
outline Optional[Dict[str, Outline]]

Collapsible row and column groups — the +/- brackets in Excel's margin — as one mapping:

  • rows — a list of {"from": int, "to": int} by 0-based sheet row, matching row_heights, plus optional collapsed
  • columns — a list of {"from": name, "to": name} by header name, plus optional collapsed
  • symbols_above / symbols_to_left — which side the summary row or column sits on

NOTE: asking for a row group takes the sheet out of constant-memory mode, the same trade-off as dedupe_strings. The constant-memory row writer emits hidden but not outlineLevel, so a collapsed group there would leave hidden rows with no bracket to reopen them. Column groups carry no such cost. An unknown column name warns and is skipped.

None
notes Optional[Dict[str, Notes]]

Notes on header cells, as {column: text} — where you say what a column means without widening it or adding a legend sheet. The value may instead be a dict with text plus any of author, width, height, visible and background_color. An unknown column warns and is skipped.

None
images Optional[Dict[str, Images]]

Images anchored to cells, as a list of dicts. Each needs path or data (raw bytes, for a logo already in memory), and takes row and col (0-based, default 0), scale or the per-axis scale_x/scale_y, fit_to_cell with keep_aspect_ratio, alt_text and url. Images are placed by index rather than by column name, since they float above the grid instead of belonging to a column. Identical images are stored once.

None
sparklines Optional[Dict[str, Sparklines]]

A one-cell chart per data row, as {column: rule}. The column is one you left empty in the records, and from and to name the span each row summarises::

rows = [{"q1": 1, "q2": 5, "q3": 3, "q4": 8, "trend": None}]
sparklines={"trend": {"from": "q1", "to": "q4"}}

Also takes type (line, column, win_lose), color, style, and the toggles high_point, low_point, first_point, last_point, markers, negative_points, axis and right_to_left.

The target column has to exist already: appending one would mean reaching into the header assembly and column accounting that formula_columns uses, in both row loops, which is far more than the feature is worth. An unknown column warns and is skipped.

None
charts Optional[Dict[str, Charts]]

Charts anchored to a cell, as a list of dicts. Each needs a type and a series::

charts=[{"type": "column", "series": ["q1", "q2"],
         "categories": "region", "title": "Quarterly"}]

series is a list of column names, or of dicts with values and an optional name — left out, the series name links to that column's header cell, so the legend follows the header. categories names the column used for the axis labels.

Types: area, bar, column, line (each also with _stacked and _percent_stacked), pie, doughnut, radar, radar_with_markers, radar_filled, scatter, scatter_smooth, stock.

Also takes row/col, title, x_axis, y_axis, width, height, style and legend. Left unplaced, a chart lands one column clear of the data and level with the header rather than on top of the table. Series cover the data rows only. An unknown column warns and skips that chart, since a chart missing a series draws a misleading picture. A scatter chart is refused without categories — they are its x values rather than labels, so there is nothing to default them to.

None

Raises:

Type Description
ValueError

Invalid sheet name or unsupported data type.

OSError

File system error while writing.

Examples:

>>> write_worksheets(
...     [("Users", [{"Name": "Alice"}]), ("Items", [{"SKU": "A1"}])],
...     "multi.xlsx",
... )

get_version

get_version() -> str

Return the package version string.

get_name

get_name() -> str

Return the package name.

get_authors

get_authors() -> str

Return the package authors ('Name <email>' form).

get_description

get_description() -> str

Return the package description.

get_repository

get_repository() -> str

Return the repository URL.

get_homepage

get_homepage() -> str

Return the homepage URL.

get_license

get_license() -> str

Return the license identifier.