Skip to main content

odsslicer

CI PyPI

Python reader and writer for .ods files (OpenDocument Spreadsheet — LibreOffice / OpenOffice Calc), with a numpy-inspired indexing API:

from odsslicer import ODSReader

table = ODSReader("workbook.ods")
sheet = table.sheet("Sheet1")

sheet["A1"].value          # typed value: str / float / bool / date / time / None
sheet["A1:B3"].to_numpy()  # any block as a numpy array
sheet[:, 0]                 # entire column A

sheet["C1"].formula = "SUM(A1:A10)"
sheet["C1"].style.bold = True
table.save("out.ods")                     # add recalculate=True to have LibreOffice compute formulas/pivots

odsslicer works directly on the ODF XML (via BeautifulSoup/lxml), so it preserves what other tools tend to drop — cell formats (currency, percentage, date, time), formulas, merged and repeated cells, styles, comments — and writes them back faithfully. It has no calculation engine of its own: like ODF itself, it describes what to compute — and can hand the file to a local LibreOffice (save(..., recalculate=True)) to compute formulas and pivot tables for you.

Full documentation with an example for every feature: DOCS.md.

Installation

pip install odsslicer

Requires Python ≥ 3.10. Dependencies (beautifulsoup4, lxml, numpy) are installed automatically. For local development:

git clone https://github.com/antnardo/odsslicer.git
cd odsslicer
pip install -e ".[test]"

What it does

Each line links to the detailed section (with examples) in DOCS.md.

Area Feature Example
Reading numpy-style indexing — addresses, slices, out-of-range returns empty cells sheet["A1"], sheet[0, 0], sheet["A1:B3"], sheet[:, 0]
Typed cells — value, displayed text, format, address cell.value, cell.text, cell.format
Arrays — to_list(), to_numpy(), numpy-like shapes sheet["A1:B3"].to_numpy()
Writing Values of every ODF type, then save() sheet["A1"].value = 42.5
Ranges at once — broadcast or element-wise sheet["A1:C1"].value = [1, 2, 3]
Auto-unrolling of repeated/merged cells on first write transparent
Auto-growth when writing past the sheet's extent sheet["Z100"].value = 1
Displayed text inferred from the document's own formats "50,00 %", "05/01/30"
Files & sheets New file from scratch ODSReader.new()
Add / rename / reorder / delete sheets — renaming fixes cross-sheet formulas table.rename_sheet("Sheet1", "Q4")
Structure Insert rows/columns — formula references and merges follow sheet.insert_rows(2, 5)
Delete rows/columns — formula references follow, batchable sheet.delete_rows([3, 7, 20])
Copy cells/ranges — value + formula + style, overlap-safe sheet.copy("A1:B2", "D5")
Sort a range — stable, None last, formulas follow their row sheet.sort("A2:C10", by=1)
Merge / unmerge + read merge state sheet.merge("A1:C2"), cell.merge_range
Formulas Write in ordinary syntax, translated to ODF's cell.formula = "IF(A1>0,1,-1)"
Read back in ordinary syntax cell.formula_friendly
Fill across a range like a fill handle cell.fill_formula("B3:B10")
{r}/{c} templates for per-cell patterns sheet["A2:A10"].formula = "$A{r-1}+1"
Pivot tables — definition written, computed by the spreadsheet sheet.create_pivot_table(...)
Recalculate with LibreOffice — formulas + pivot refresh, headless, no UNO needed table.save("out.ods", recalculate=True)
Styles Read and write cell styles — font, colors, alignment, borders, rotation, wrap… cell.style.bold = True
Copy a style in one shot b.style = a.style
Number formats — read, assign, or create from scratch NumberFormat.create(table, "currency", ...)
Conditional formats (e.g. negatives in red) fmt.add_condition("value()<0", red)
Row / column / sheet styles — height, width, visibility, tab color sheet.column_style(0).width = "5cm"
Annotations Comments — text, author, date, visibility cell.comment = "Check this"
Hyperlinks cell.hyperlink = "https://…"
Document Properties — title, author, keywords, typed custom properties table.properties.title = "Q4"

See Known limitations for what's deliberately out of scope (no calculation engine, no charts/images, no partial rich text…).

Are there already equivalent PyPI modules?

Package Read/Write Latest release Notes
odfpy Low-level R/W 1.4.1 — Jan 2020 Dormant, but still the brick pandas uses internally
odfdo Full R/W 3.24 — Aug 2026 Actively maintained modern fork of odfpy; generic DOM-like API for all ODF document types
pyexcel-ods3 R/W 0.6.1 — Jan 2022 Inactive; values only, no styles/formulas
ezodf R/W 0.3.2 — Dec 2015 Abandoned
pandas (engine="odf") Read (via odfpy) follows pandas Convenient for data frames; loses formulas and fine-grained formats
python-calamine Read-only (Rust), fast 0.8 — Jul 2026 The best option for fast pure reading
pandas-ods-reader Read-only → DataFrame 1.0.2 — May 2025 Maintained, limited scope

(Versions and dates as of August 2026.)

Where odsslicer sits: a spreadsheet-shaped API (sheet["A1:B3"], numpy arrays, fill handles, copy/sort/merge) rather than a generic ODF DOM, with read and write of the things data-oriented tools usually lose — formats, formulas (in ordinary syntax), styles, merged cells, comments, pivot definitions — and every write verified against a real LibreOffice. If you only need to read values fast, use python-calamine; if you need to manipulate arbitrary ODF documents (text, presentations) at the XML level, use odfdo.

Tests

pip install -e ".[test]"
pytest

The main suite (tests/test_odsslicer.py) covers every feature above plus regression tests for the bugs fixed along the way; it runs on every push/PR via GitHub Actions across Python 3.10 to 3.13.

tests/test_wild_files.py confronts the API with real-world files written by other generators — Excel 16, a 2012-era LibreOffice 3.5, recent LibreOffice on Linux and Windows, a Google Sheets export (see tests/wild/README.md for provenance) — reading, writing and round-tripping each one.

tests/test_libreoffice_consistency.py is an opt-in suite that hands files odsslicer wrote to a real, local LibreOffice (soffice --headless --convert-to fods) and inspects what LibreOffice itself made of them — the strongest available signal that a write is genuinely valid ODF, not just something our own reader happens to parse back. It skips automatically if no soffice/libreoffice binary is on PATH.

Versions

Version numbers are derived automatically from git tags (via setuptools-scm) and follow Semantic Versioning — while the major version stays 0, the API can still change between minor versions. See CHANGELOG.md (and the Releases page) for what changed in each version.

License

MIT — reuse with essentially no restriction, just keep the copyright notice.

Project name

odsslicer, to reflect the module's real differentiator — numpy-style indexing/slicing by cell address — rather than a generic "ods reader".

Release files for odsslicer 0.12.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for odsslicer 0.12.1
File Size Uploaded
odsslicer-0.12.1.tar.gz 4.5 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for odsslicer 0.12.1
File Interpreter ABI Platform
odsslicer-0.12.1-py3-none-any.whl Python 3 none any Details

Total release size: 4.6 MB

Release files / odsslicer-0.12.1.tar.gz

Download URL odsslicer-0.12.1.tar.gz
Size 4.5 MB
Tags Source
SHA-256 checksum
How to use checksums
2a582cf8f4987cf486cb093c2947c3ecb39cc846a78b77d2bcabc67fd07b8b7a
BLAKE2b-256 checksum
How to use checksums
941bad5b4e0284930287834d2745748f07bbf7eeb2dacf5546c10f7c4d89f603
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.

Transparency log

Release files / odsslicer-0.12.1-py3-none-any.whl

Download URL odsslicer-0.12.1-py3-none-any.whl
Size 72.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7b8ccfe6c2c8419281f3994fd2cb1bcaa2c732a4457ab6b3abc737c6b71b3729
BLAKE2b-256 checksum
How to use checksums
904727d1326557cc6210490c497ed11a3cbc9931a31fb2f53f417d81eca46ba0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.

Transparency log

Release history Release notifications | RSS feed

0.13.2

2 release files

0.13.1

2 release files

0.13.0

2 release files

0.12.3

2 release files

0.12.2

2 release files

This release

0.12.1 This release

2 release files

0.12.0

2 release files

0.11.1

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.1

2 release files

0.9.0

1 release file

0.1.0

1 release file

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