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

Uploaded CPython 3.10+Windows x86-64

rustypyxl-0.7.1-cp310-abi3-musllinux_1_2_x86_64.whl (4.4 MB view details)

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

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

Uploaded CPython 3.10+musllinux: musl 1.2+ ARM64

rustypyxl-0.7.1-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.1-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.1-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.1.tar.gz.

File metadata

  • Download URL: rustypyxl-0.7.1.tar.gz
  • Upload date:
  • Size: 266.2 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.1.tar.gz
Algorithm Hash digest
SHA256 2687ce02a030f156490f43c36517d73fc71ea8ebb221cd0fe5fbd0b02920ae54
MD5 ff3640ed05c08f088ac6166f28817c11
BLAKE2b-256 d733d8d06c27ec427ab3809f5b883cf5e0fd42b0dcc54741fc42f31d08027337

See more details on using hashes here.

Provenance

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

File metadata

  • Download URL: rustypyxl-0.7.1-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.1-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 10ff0ffbae42383431607e10449090ba1b3b041a32fdf48daa74778a50060a71
MD5 165ed73ad96b54e1ebcd8a4145065362
BLAKE2b-256 e982dc6be7357e2455955963cb2b78cf942f6e1fc07f98722c981c59cdfb6d3d

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for rustypyxl-0.7.1-cp310-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 914e5988d37d69d5209a5766500391ed748ecab0d73fddd4696c5b422280c38c
MD5 d03e51ae21de8963ac8c2666abfe09dd
BLAKE2b-256 82bad23137a190c8e6b7ebaa41795703160da926e84ebad66e195cab5d93338f

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for rustypyxl-0.7.1-cp310-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 14cee5a441878304c48fcef323bf86b8c6f070a4ec963eba0c8af16d7eeac2c5
MD5 dc847da0437a4b0aab978e9d026df6a1
BLAKE2b-256 060a2ed25a6fdd08f2e7dd5235cbb9cfbb13a788fbeb45b1930a0d150ec041e7

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for rustypyxl-0.7.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 06ae282804095d952ddd8e8c65856bd058bdc2facbbbb5ab27ea85a8e6eb0487
MD5 9413ca16fafe87033e4873a12a9ca049
BLAKE2b-256 26d0bca020ae7d078d1a2207a3f68f9d85c9b32650f03f05ce40251e7bead763

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for rustypyxl-0.7.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 5ed745fe531e49467bc6113ea11a04326338389e33d7c2907e22916748bc5c06
MD5 0016f2a949359797eeb5b9816665431c
BLAKE2b-256 83d7109e09dca6b05ec576cffad6e04254e7ce5b8e86e7c3876569d15f2839e9

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for rustypyxl-0.7.1-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 b934e679a2643eec2cb8966c2e897cfc90e5b65cd51a68fc9bf454aba57962c1
MD5 fc9003e9a9d261c3dc66651c88ab9ae6
BLAKE2b-256 7067f1e38224bac96cfcf3eeb7a02a69abfa0f86cd83eb555c896fa485c13de1

See more details on using hashes here.

Provenance

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

This release

0.7.1 This release

7 files

0.7.0

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