Skip to main content

rustypyxl

Quality Gate Status Maintainability Rating Security Rating Known Vulnerabilities

A Rust-powered Excel (XLSX) library for Python with an openpyxl-compatible API.

It is also a standalone Rust crate: the same library is published on crates.io as rustypyxl for use directly from Rust, with no Python involved. See Using from Rust.

Installation

pip install rustypyxl

Using from Rust

The core is a normal Rust library -- the Python package is a thin binding over it.

[dependencies]
rustypyxl = "0.6"
use rustypyxl::{Workbook, CellValue};

let mut wb = Workbook::new();
wb.create_sheet(Some("Data".to_string())).unwrap();
wb.set_cell_value_in_sheet("Data", 1, 1, CellValue::from("Hello")).unwrap();
wb.save("output.xlsx").unwrap();

Usage

import rustypyxl

# Create or load a workbook
wb = rustypyxl.Workbook()
ws = wb.create_sheet('Sheet1')          # or: wb = rustypyxl.load_workbook('input.xlsx'); ws = wb.active

# openpyxl-style cell access
ws['A1'] = 'Hello'
ws['A2'] = 42.5
ws['A3'] = '=SUM(A1:A2)'
ws.cell(row=4, column=1).value = 'world'
print(ws['A1'].value)                   # -> "Hello"

# Append rows, merge, freeze, rename
ws.append(['Name', 'Age', 'Score'])
ws.merge_cells('A1:C1')
ws.freeze_panes = 'A2'
ws.title = 'Data'

# Iterate
for row in ws.iter_rows(values_only=True):
    print(row)

wb.save('output.xlsx')

Bulk API (fastest for large grids)

When writing or reading many rows at once, the workbook-level bulk methods avoid per-cell Python overhead:

wb.write_rows('Data', [
    ['Name', 'Age', 'Score'],
    ['Alice', 30, 95.5],
    ['Bob', 25, 87.3],
])
data = wb.read_rows('Data', min_row=1, max_row=100)

Features

  • openpyxl-compatible API: Familiar patterns (ws['A1'], ws.cell(), ws.append(), iter_rows()) for easy migration
  • Read and write support: Full round-trip capability
  • Cell values: Strings, numbers, booleans, dates, formulas
  • Formatting: Fonts (incl. underline styles), alignment, fills, borders, number formats
  • Workbook features: Hyperlinks, comments, named ranges, merged cells, freeze panes
  • Sheet protection: Cell locking and worksheet protection

Not yet supported through the Python API: inserting/deleting rows and columns, charts, and images.

  • Parquet import/export: Direct Parquet ↔ Excel conversion (bypasses Python FFI)
  • S3 support: Works with boto3 via bytes I/O
  • Bytes I/O: Load from bytes or file-like objects, save to bytes
  • Configurable compression: Trade off speed vs file size

Parquet Import

Import large Parquet files directly into Excel worksheets. Data flows from Parquet → Rust → Excel without crossing the Python FFI boundary, making it very fast for large datasets.

import rustypyxl

wb = rustypyxl.Workbook()
wb.create_sheet("Data")

# Import parquet file into sheet
result = wb.insert_from_parquet(
    sheet_name="Data",
    path="large_dataset.parquet",
    start_row=1,
    start_col=1,
    include_headers=True,
    column_renames={"old_name": "new_name"},  # optional
    columns=["col1", "col2", "col3"],  # optional: select specific columns
)

print(f"Imported {result['rows_imported']} rows")
print(f"Data range: {result['range']}")

wb.save("output.xlsx")

Performance: ~4 seconds for 1M rows × 20 columns on M1 MacBook Pro.

Parquet Export

Export worksheet data to Parquet format with automatic type inference:

import rustypyxl

wb = rustypyxl.load_workbook("data.xlsx")

# Export entire sheet
result = wb.export_to_parquet(
    sheet_name="Sheet1",
    path="output.parquet",
    has_headers=True,              # first row contains headers
    compression="snappy",          # snappy, zstd, gzip, lz4, none
    column_renames={"old": "new"}, # optional: rename columns
    column_types={"date_col": "datetime"},  # optional: force column types
)

print(f"Exported {result['rows_exported']} rows")
print(f"File size: {result['file_size']} bytes")

# Export specific range
result = wb.export_range_to_parquet(
    sheet_name="Sheet1",
    path="subset.parquet",
    min_row=1, min_col=1,
    max_row=1000, max_col=5,
)

Supported column type hints: string, float64, int64, boolean, date, datetime, auto.

Loading from Bytes or File-like Objects

Load workbooks from in-memory bytes or file-like objects:

import rustypyxl
import io

# From bytes
with open("file.xlsx", "rb") as f:
    data = f.read()
wb = rustypyxl.load_workbook(data)

# From file-like object (e.g., BytesIO, HTTP response)
wb = rustypyxl.load_workbook(io.BytesIO(data))

# Save to bytes (for HTTP responses, S3, etc.)
output_bytes = wb.save_to_bytes()

S3 Support

Use save_to_bytes() and load_workbook(bytes) with boto3 for S3 integration:

import boto3
import rustypyxl

s3 = boto3.client("s3")

# Load from S3
response = s3.get_object(Bucket="my-bucket", Key="path/to/file.xlsx")
wb = rustypyxl.load_workbook(response["Body"].read())

# Save to S3
data = wb.save_to_bytes()
s3.put_object(Bucket="my-bucket", Key="path/to/output.xlsx", Body=data)

This works with any S3-compatible service and uses boto3's credential handling (IAM roles, environment variables, etc.).

Streaming Writes (Low Memory)

For very large files, use WriteOnlyWorkbook which streams rows directly to disk:

import rustypyxl

wb = rustypyxl.WriteOnlyWorkbook("large_output.xlsx")
wb.create_sheet("Data")

for i in range(1_000_000):
    wb.append_row([f"Row {i}", i, i * 1.5, i % 2 == 0])

wb.close()  # Must call close() to finalize the file

This uses minimal memory regardless of file size, similar to openpyxl's write_only=True mode.

Benchmarks

Apple Silicon, openpyxl 3.1.5. Times are the minimum wall-clock over several runs (the fastest run is the one least disturbed by other processes), measured on an otherwise-idle machine. Your results will vary with data and hardware.

Write Performance (1M rows × 20 columns, mixed data)

Method Time vs openpyxl
rustypyxl WriteOnlyWorkbook (streaming) ~4s ~27x
rustypyxl write_rows (build in memory, then save) ~29s ~4x
openpyxl (write_only) ~112s

The streaming path is the one to use for large writes: it serializes rows straight to disk and never holds the sheet in memory. write_rows is slower at this scale because all 20M cell values cross the Python/Rust boundary and the whole workbook is built in memory first; it is convenient for moderate sheets, not the throughput path. (Loading straight from Parquet with insert_from_parquet avoids the boundary entirely -- see the Parquet section.)

Read Performance (min wall time)

Dataset rustypyxl calamine openpyxl
10k × 20 (numeric) 0.09s 0.10s 0.73s
10k × 20 (strings) 0.11s 0.11s 1.55s
100k × 20 (numeric) 1.02s 1.01s 7.16s
100k × 20 (mixed) 1.25s 1.16s 11.9s

rustypyxl and calamine (a read-only Rust reader, via python-calamine) are within noise of each other, both roughly 5-10x faster than openpyxl's read-only mode.

Memory Usage (Read)

Dataset rustypyxl calamine openpyxl
10k × 20 29 MB 9 MB 11 MB
50k × 20 62 MB 48 MB 53 MB
100k × 20 103 MB 95 MB 106 MB

rustypyxl keeps the whole workbook resident (like openpyxl's default mode), so its read footprint is comparable to openpyxl and above calamine's streaming reader. For low-memory reads of very large files, the trade-off is CPU vs RAM.

Memory Usage (Write)

Dataset rustypyxl (write_rows) WriteOnlyWorkbook openpyxl (write_only)
10k × 20 10 MB ~0 MB 0.4 MB
50k × 20 50 MB ~0 MB 0.4 MB
100k × 20 99 MB ~0 MB 0.4 MB

WriteOnlyWorkbook streams rows directly to disk, so its memory stays flat regardless of file size -- the same idea as openpyxl's write_only mode.

Building from Source

# Install Rust and maturin
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
pip install maturin

# Build
maturin develop --release

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rustypyxl-0.6.0.tar.gz (171.4 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

rustypyxl-0.6.0-cp310-abi3-win_amd64.whl (3.8 MB view details)

Uploaded CPython 3.10+Windows x86-64

rustypyxl-0.6.0-cp310-abi3-musllinux_1_2_x86_64.whl (4.1 MB view details)

Uploaded CPython 3.10+musllinux: musl 1.2+ x86-64

rustypyxl-0.6.0-cp310-abi3-musllinux_1_2_aarch64.whl (3.9 MB view details)

Uploaded CPython 3.10+musllinux: musl 1.2+ ARM64

rustypyxl-0.6.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.8 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ x86-64

rustypyxl-0.6.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.7 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ ARM64

rustypyxl-0.6.0-cp310-abi3-macosx_11_0_arm64.whl (3.4 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

File details

Details for the file rustypyxl-0.6.0.tar.gz.

File metadata

  • Download URL: rustypyxl-0.6.0.tar.gz
  • Upload date:
  • Size: 171.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rustypyxl-0.6.0.tar.gz
Algorithm Hash digest
SHA256 6a52178daf084e9a0918fd942fe4e7299638f1acc07a9f2a9dc7add1bc03df36
MD5 b1b1efaa9eeae47ee0282427fc5b3596
BLAKE2b-256 7ad67f86f184d9e43163a6532db1913e03e7551967ca3c7e4afbff2202ea8ba4

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustypyxl-0.6.0.tar.gz:

Publisher: publish.yml on freeeve/rustypyxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rustypyxl-0.6.0-cp310-abi3-win_amd64.whl.

File metadata

  • Download URL: rustypyxl-0.6.0-cp310-abi3-win_amd64.whl
  • Upload date:
  • Size: 3.8 MB
  • Tags: CPython 3.10+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rustypyxl-0.6.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 ef9bc47c322a34fe35fa63ff096ad164f2ede42d18b8962419569697bb6d900f
MD5 3892f8702f97737d9953dad551eea9b2
BLAKE2b-256 24ef1d7c9c33e8bb8a82d49d1273396f11d1ac09b921ed3ab945991d6a9c6eea

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustypyxl-0.6.0-cp310-abi3-win_amd64.whl:

Publisher: publish.yml on freeeve/rustypyxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rustypyxl-0.6.0-cp310-abi3-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for rustypyxl-0.6.0-cp310-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 59facd049c6811dd4252399f42486ee8a61ff9275d8948c1d080b7a0721a6b95
MD5 0eb7960d844e5fcc50f2a66cd290c78f
BLAKE2b-256 5209a05a524e367ff08396b9c46929c5c326af6ef97a56852768eacab95edcdd

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustypyxl-0.6.0-cp310-abi3-musllinux_1_2_x86_64.whl:

Publisher: publish.yml on freeeve/rustypyxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rustypyxl-0.6.0-cp310-abi3-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for rustypyxl-0.6.0-cp310-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 cf857544dd3eeb1d03a6e3cfb62f64714057b74348c9766249b58f89ed66b066
MD5 a34f3856425431c8b4842e06e449be27
BLAKE2b-256 4069b1c19d8ad5d221488d39774bf1254b3c7803b82b5710baa1b8590caa92b7

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustypyxl-0.6.0-cp310-abi3-musllinux_1_2_aarch64.whl:

Publisher: publish.yml on freeeve/rustypyxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rustypyxl-0.6.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for rustypyxl-0.6.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 fdda6105c590799fff045dfc1334a90488282c37a61111eec07b90ae5a5b343f
MD5 cb0361adc058e04676b7a2404160ae95
BLAKE2b-256 266e4619b00ae40d10143bbb4abac60a511472f8a75ee17c624ee969f8c57e9a

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustypyxl-0.6.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: publish.yml on freeeve/rustypyxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rustypyxl-0.6.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for rustypyxl-0.6.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 1560fc39a76ac9c9df0837b3871c6b7a99efe04a28cdc632c66d0251fb93e390
MD5 70772e0d6916bac773d4d06ec30960a1
BLAKE2b-256 d261886eeec7b0600e0e1ac627d50d1ea782524aed6c4bedf1beb39ff1821918

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustypyxl-0.6.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: publish.yml on freeeve/rustypyxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rustypyxl-0.6.0-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for rustypyxl-0.6.0-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c0ce4b5d16be056ae8fd568822837512e8ea2a1b1ab1cd52908595097cf3cc26
MD5 3e745c04472d3a77024a258a49c4f5a1
BLAKE2b-256 d9c8fd613f4277622d9885dcda565be595de148b231af3322eba795122ce04df

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustypyxl-0.6.0-cp310-abi3-macosx_11_0_arm64.whl:

Publisher: publish.yml on freeeve/rustypyxl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.7.1

7 files

0.7.0

7 files

This release

0.6.0 This release

7 files

0.5.0

16 files

0.4.0

16 files

0.3.1

15 files

0.3.0

15 files

0.1.1

15 files

0.1.0

16 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page