Odio
A pure-Python library for the import / export of
ODF (.ods and .odt) documents. Licensed
under the MIT No Attribution Licence. Odio
supports ODF 1.1, 1.2 and 1.3.
Installation
- Set up a virtual environment:
python3 -m venv venv - Activate the virtual environment:
source venv/bin/activate - Install Odio with pip:
pip install odio
Examples
Create And Save A Spreadsheet
>>> from odio.v1_3 import create_spreadsheet, Cell, Formula, Table
>>> import datetime
>>>
>>>
>>> # Create the spreadsheet.
>>> sheet = create_spreadsheet()
>>>
>>> # Append a table (tab) to the spreadsheet
>>> table = sheet.append_table('Plan', values=[
... [
... "veni, vidi, vici", 0.3, 5, Formula('=B1 + C1'),
... datetime.datetime(2015, 6, 30, 16, 38),
... ],
... ]
... )
>>>
>>> with open('test.ods', 'wb') as f:
... sheet.save(f)
Parse a spreadsheet
>>> from odio import parse_document
>>>
>>>
>>> # Parse the document we just created.
>>> with open('test.ods', 'rb') as f:
... sheet = parse_document(f)
>>>
>>> table = sheet.tables[0]
>>> print(table.name)
Plan
>>> for row in table.rows:
... for cell in row.cells:
... print(cell.value)
veni, vidi, vici
0.3
5.0
=B1 + C1
2015-06-30 16:38:00
Create And Save A Text Document
>>> from odio.v1_3 import create_text, P, H, Span
>>>
>>>
>>> txt = create_text()
>>>
>>> txt.children.append(H("The Meditations"))
>>> txt.children.append(H("Book One"))
>>> txt.children.append(
... P(
... "From my grandfather Verus: the lessons of noble character ",
... "and even temper."
... )
... )
>>> txt.children.append(
... P(
... "From my father's reputation and my memory of "
... "him: modesty and manliness."
... )
... )
>>>
>>> with open('test.odt', 'wb') as f:
... txt.save(f)
Parse a text document
>>> from odio import parse_document
>>>
>>>
>>> # Parse the text document we just created.
>>> with open('test.odt', "rb") as f:
... txt = parse_document(f)
>>>
>>> # Find a child
>>> child = txt.children[2]
>>> print(child.tag_name)
text:p
>>>
>>> print(child)
<text:p>From my grandfather Verus: the lessons of noble character and even temper.</text:p>
Hyperlinks
In a text document:
>>> from odio.v1_3 import A, P, create_text
>>>
>>> txt = create_text()
>>> p = P(
... "The 12 books of ",
... A("The Meditations", href="https://en.wikipedia.org/wiki/Meditations"),
... " is written in Greek"
... )
>>> txt.children.append(p)
>>>
>>> print(txt.children[0].children[1].href)
https://en.wikipedia.org/wiki/Meditations
and within a cell of a spreadsheet:
>>> sheet = create_spreadsheet()
>>> row = [
... Cell(
... P(
... "The 12 books of ",
... A("The Meditations", href="https://en.wikipedia.org/wiki/Meditations"),
... " is written in Greek"
... )
... ),
... ]
>>> table = sheet.append_table('Book IX', values=[row])
>>>
>>> cell = table.rows[0].children[0]
>>> print(cell)
<table:table-cell><text:p>The 12 books of <text:a xlink:href="https://en.wikipedia.org/wiki/Meditations" xlink:type="simple">The Meditations</text:a> is written in Greek</text:p></table:table-cell>
>>> print(cell.children[0].children[1].href)
https://en.wikipedia.org/wiki/Meditations
Style
>>> from odio.v1_3 import create_text, P, H1, H2, Span
>>>
>>>
>>> txt = create_text()
>>>
>>> txt.children.append(H1("The Meditations", style_name='Title'))
>>> txt.children.append(H2("Book One", style_name='Heading 1'))
>>> txt.children.append(
... P(
... "From my grandfather ",
... Span("Verus", style_name='Strong Emphasis'),
... " I learned good morals and the government of my temper."
... )
... )
>>> txt.children.append(
... P(
... "From the reputation and remembrance of my father, "
... "modesty and a ", Span("manly", style_name='Emphasis'),
... " character."
... )
... )
>>>
>>> with open('test.odt', 'wb') as f:
... txt.save(f)
References
Validator
Regression Tests
- Install
tox:pip install tox - Run
tox:tox
Doing A Release Of Odio
Run tox make sure all tests pass, then update the release notes and then do:
git tag -a x.y.z -m "version x.y.z"rm -r distpython -m buildtwine upload dist/*
Release Notes
Version 0.0.27, 2025-08-06
- Should be at least one row in a table.
Version 0.0.26, 2025-07-31
- Update README with Codeberg homepage.
- Tidy up top-level
__init__.
Version 0.0.25, 2025-07-28 18:18
- Modify
sheet.append_tableto accept rows.
Version 0.0.24, 2025-07-28 18:00
- Add support for ODF 1.3
- Handle table cell dates that don't have a time.
Version 0.0.23, 2024-05-22
- When writing out to a spreadsheet, interpret a
decimal.Decimalas a number.
Version 0.0.22, 2021-02-08
- Substitute
<text:line-break/>for line breaks.
Version 0.0.21, 2021-02-05
- Finding text should never result in a
None.
Version 0.0.20, 2021-02-04
- Text should appear in the content of a
<text:p>element within a cell.
Version 0.0.19, 2021-02-04
- Where line breaks appear in a text element's content, they are now replaced by a
<text:line-break/>element. This means that line breaks appear in the spreadsheet, whereas before they didn't.
Version 0.0.18, 2019-11-29
- Performance improvement: rather than use the
xml.sax.saxutilsversions ofescapeandquoteattrI've copied them into the source of Odio, but removing the code for entities that aren't needed.
Version 0.0.17, 2018-08-19
- When parsing a spreadsheet cell of text type, if the value isn't contained in the attribute, recursively use the next nodes in the element contents.
Metadata
Release files for odio 0.0.27
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| odio-0.0.27.tar.gz | 122.7 kB | Without provenance | Details for odio-0.0.27.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| odio-0.0.27-py3-none-any.whl | Python 3 | none | any | Details for odio-0.0.27-py3-none-any.whl |
Total release size: 150.2 kB
Release files / odio-0.0.27.tar.gz
| Download URL | odio-0.0.27.tar.gz |
|---|---|
| Size | 122.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dab42e4a6d5a24ac7d10b18789d68ee3377a993ef643efaedff0d7892acb106e
|
|
BLAKE2b-256 checksum How to use checksums |
e286b29769bad0c6f6f7b0478235c55dd0fa344cb459651f5056c02ea925c4f3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.5
|
Release files / odio-0.0.27-py3-none-any.whl
| Download URL | odio-0.0.27-py3-none-any.whl |
|---|---|
| Size | 27.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f1a753e8bb1cb3bf46fbfca1aa2f99c78113b2933c804bc5254d4fbc917d79ef
|
|
BLAKE2b-256 checksum How to use checksums |
2e3e0a3792006981b50755506380ad78e2d8b6ed51bce6179bad87aca2710e24
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.5
|
Security for odio 0.0.27
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.