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.7.0.tar.gz (260.6 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.7.0-cp310-abi3-win_amd64.whl (4.0 MB view details)

Uploaded CPython 3.10+Windows x86-64

rustypyxl-0.7.0-cp310-abi3-musllinux_1_2_x86_64.whl (4.3 MB view details)

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

rustypyxl-0.7.0-cp310-abi3-musllinux_1_2_aarch64.whl (4.1 MB view details)

Uploaded CPython 3.10+musllinux: musl 1.2+ ARM64

rustypyxl-0.7.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.1 MB view details)

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

rustypyxl-0.7.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.9 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ ARM64

rustypyxl-0.7.0-cp310-abi3-macosx_11_0_arm64.whl (3.7 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

File details

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

File metadata

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

File hashes

Hashes for rustypyxl-0.7.0.tar.gz
Algorithm Hash digest
SHA256 6da68726a7427517cc0d7288be9329ca72e62db6682bc7772c55c74daaccf64f
MD5 23b00fb2066e6816b112cf5dd44f6fe1
BLAKE2b-256 d569b46c427c9074157311c9bf41fed785d87eb2f87e01be833eaab557b81577

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustypyxl-0.7.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.7.0-cp310-abi3-win_amd64.whl.

File metadata

  • Download URL: rustypyxl-0.7.0-cp310-abi3-win_amd64.whl
  • Upload date:
  • Size: 4.0 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.7.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 ab0218a3e429f9460c79afcdb3c862010bb7287eea2bac8ccff27b15d0060b63
MD5 555ec31e354c6200add471ac94808ecc
BLAKE2b-256 2664e730cab07ff752d146c8ef011c5789c3de112382e643aef3a730e9874f07

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustypyxl-0.7.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.7.0-cp310-abi3-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for rustypyxl-0.7.0-cp310-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 fc9b99651d959eb8ee2134b42ad8721f5a0a2d29c6f91deceb996e25216301da
MD5 d3265804d64a23e2fd1257c2790a7ad4
BLAKE2b-256 bc62a22440952ee99e1deb09c057c2f15bd93162697eafeccf15c2bd5218d11a

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustypyxl-0.7.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.7.0-cp310-abi3-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for rustypyxl-0.7.0-cp310-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 4752943cf75f686dee70f8466ecf360f3364e4cd776ab3c7448720a2fd1653ab
MD5 dc777d3cd3784c8ecdf6bf56cdab6ce6
BLAKE2b-256 bbbe93264d84dd77c4968fdf024ed220109a5b4642761c37ebb77c4bea62ef16

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustypyxl-0.7.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.7.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for rustypyxl-0.7.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5f6d1145162e2733e44c9faa6904f894458f80f1be9116177232c18cf1dd9b31
MD5 201626764f5040bf75ec86d33dee6b85
BLAKE2b-256 902fcba86ceca1cf09091ac88370efa2d09984d1a26ad92f1a83ba1e2bdcb842

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustypyxl-0.7.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.7.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for rustypyxl-0.7.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 e87a2b893e7b780dfab52d980d5bcfc1c38e0cd6fe5170d347f0c5062f18e74c
MD5 384d150585cbed93b9d4a81d98cc0fcc
BLAKE2b-256 f3bab256c61b47c22be6266d06b79f74c19c5e5561ca05b2766b98fe033f94e7

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustypyxl-0.7.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.7.0-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for rustypyxl-0.7.0-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 207b18d3f23fe98d147a10b7f1c6daddc42e1e2921056677135d733270453fee
MD5 5fdf7739c597cf7fe734f428d20a5d60
BLAKE2b-256 34b24bb8c1eb441a4973ffad8188932a9f5fe1f360567747ef78daa42c6b70cd

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustypyxl-0.7.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

This release

0.7.0 This release

7 files

0.6.0

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