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 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.11.0

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.11.0
File Size Uploaded
odsslicer-0.11.0.tar.gz 4.5 MB Details

Built distribution (wheel)

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

Total release size: 4.6 MB

Release files / odsslicer-0.11.0.tar.gz

Download URL odsslicer-0.11.0.tar.gz
Size 4.5 MB
Tags Source
SHA-256 checksum
How to use checksums
ef1bd99aa6b3c87ff2ed74bcddca6f2f33aa7b74889307b732d0d9c1396818cd
BLAKE2b-256 checksum
How to use checksums
3eb3ff122bf44d37e58facb649f086793eeeb44fcc6c46585399eda7a15a8b6b
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 Aug 26, 2026.

Transparency log

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

Download URL odsslicer-0.11.0-py3-none-any.whl
Size 68.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
08bc7c945498c5176cbd8e6e8a68232676056b8d189b3d5c372806388ddfb0ad
BLAKE2b-256 checksum
How to use checksums
abe8416d146f59aa6f504b82f4efa15b4cff03cc14b6771ce4a90c4f79f46843
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 Aug 26, 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

0.12.1

2 release files

0.12.0

2 release files

0.11.1

2 release files

This release

0.11.0 This release

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