Skip to content

feat(python): integrate pyodr bindings from OpenDocument.py#616

Merged
andiwand merged 4 commits into
mainfrom
python-bindings
Jul 25, 2026
Merged

feat(python): integrate pyodr bindings from OpenDocument.py#616
andiwand merged 4 commits into
mainfrom
python-bindings

Conversation

@andiwand

@andiwand andiwand commented Jul 25, 2026

Copy link
Copy Markdown
Member

🤖 Generated with Claude Code

Integrates the Python bindings from OpenDocument.py into the main repo as a new root python/ folder, so the old repo can be archived.

Bindings

The old bindings targeted odrcore 4.1.1, so they were rewritten from scratch against the current public API (public headers only, no internals):

  • odr.hpp free functions: open (all overloads), list_file_types, mimetype, type/category/engine mappings, version info
  • the full DecodedFile family incl. FontFile, DecoderEngine, DecodePreference, encryption/decrypt
  • Document + complete typed element tree with Python iteration; everything returning an Element carries py::keep_alive so handles keep the originating Document alive
  • all style structs, Measure/DynamicUnit, Color, PageLayout
  • the HtmlService/HtmlView/bring_offline pipeline incl. HtmlConfig (all fields, resource_locator callables work), HtmlResource. Views returned by list_views pin their service Python object, so translate(...).list_views()[0] cannot dangle
  • Filesystem/FileWalker/Archive, GlobalParams, typed exceptions (FileNotFound maps to Python's FileNotFoundError)
  • HttpServer, gated by the central ODR_WITH_HTTP_SERVER option; listen/stop release the GIL. pyodr.has_http_server reports availability

The pyodr package ships a CLI: pyodr <file> renders and opens a document, pyodr <file> --serve hosts it over HTTP.

Build integration

  • CMake: new ODR_PYTHON option (default OFF) includes python/CMakeLists.txt, which also configures standalone against an installed odrcore. Install of the CLI targets is now conditional on ODR_CLI (was unconditional and broke ODR_CLI=OFF builds).
  • Conan: new with_python option (default False) requires pybind11/2.13.6 and wires ODR_PYTHON through the toolchain.
  • Packaging: root pyproject.toml (scikit-build-core); wheels bundle the odr.js/css assets under pyodr/data and pyodr auto-configures GlobalParams on import (env var ODR_CORE_DATA_PATH also honored).

Tests

Hermetic pytest suite (32 tests) — inputs generated inline (txt/csv/json, a zip-built minimal ODT): detection/open, text extraction, document element walk + navigation, HTML translation via bring_offline, view lifetime, and a live HTTP server round-trip. Also registered as a CTest test (pyodr_pytest) when ODR_TEST is on.

CI (migrated from OpenDocument.py's format/pip/wheels workflows)

.github/workflows/python.yml:

  • format: black --check python
  • build-test: conan build with with_python=True + pytest on ubuntu-24.04/macos-26, reusing the existing conan profiles and caches
  • wheels: per-OS wheel builds, smoke-tested by installing the wheel and re-running pytest; wheels build without pdf2htmlEX/wvWare/libmagic since their runtime data cannot ship inside a wheel
  • sdist + publish: releases attach the wheels and sdist as GitHub release assets. Nothing goes to PyPI yet — pip cannot build the sdist in an isolated backend (the build needs the conan-generated toolchain plus the conan-odr-index recipes, which the sdist excludes), and the Linux wheels are not manylinux-audited. PyPI publishing via cibuildwheel+conan is a follow-up.

Core fix

TextFile::text() was an unimplemented stub (return ""; // TODO) — now reads the underlying stream.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: badb623522

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread python/src/bind_html.cpp Outdated
Comment thread .github/workflows/python.yml Outdated
andiwand and others added 4 commits July 25, 2026 23:03
Bring the Python bindings into the main repo as a new root `python/`
folder, replacing the separate OpenDocument.py repository:

- pybind11 bindings rewritten against the current public API: odr free
  functions, the DecodedFile family, Document + full typed element tree
  (with keep_alive chains and Python iteration), styles, the
  HtmlService/HtmlView pipeline (views returned by list_views pin their
  service so they cannot dangle), Filesystem/Archive, GlobalParams,
  typed exceptions, and the HTTP server (gated by ODR_WITH_HTTP_SERVER)
- `pyodr` package with a CLI (`pyodr <file>`, `--serve` to host over
  HTTP) and automatic data-asset discovery
- hermetic pytest suite (inline-generated txt/csv/json/minimal ODT),
  including a live HTTP server round-trip
- CMake: new ODR_PYTHON option includes python/CMakeLists.txt; install
  of CLI targets now conditional on ODR_CLI
- conan: new with_python option requires pybind11 and wires ODR_PYTHON
- packaging: root pyproject.toml (scikit-build-core); wheels bundle the
  odr.js/css assets under pyodr/data
- CI: python.yml with black check, conan build + pytest (ubuntu/macos),
  wheel + sdist builds; releases attach wheels and sdist as GitHub
  release assets (nothing goes to PyPI yet — pip cannot build the sdist
  in an isolated backend and Linux wheels are not manylinux-audited;
  cibuildwheel+conan wiring is a follow-up)
- core fix: implement TextFile::text() (was a TODO stub)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gffw8AurchbpS1rL3kWwBd
Replace the ODR_WITH_HTTP_SERVER ifdef in bind_http_server.cpp with a
stub source file chosen in CMake, matching how the CLI handles the
option; the compile definition is no longer needed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gffw8AurchbpS1rL3kWwBd
CI's conan install rejects the new pybind11/2.13.6 requirement because
the lockfile was not regenerated when the dependency was added.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gffw8AurchbpS1rL3kWwBd
Drop the hardcoded pyproject version: setuptools-scm derives it from git
tags via scikit-build-core dynamic metadata, matching how the conan
package version is stamped from the release tag. The wheels/sdist jobs
fetch full history so the tags are available.

Publish wheels and the sdist to PyPI via trusted publishing on release,
like the original OpenDocument.py repo did. Linux wheels are grafted
onto a manylinux tag with auditwheel first since PyPI rejects plain
linux_* platform tags.

Also install ccache in the wheels job: the conan profiles use it as
compiler launcher, so conan source builds fail without it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gffw8AurchbpS1rL3kWwBd
@andiwand
andiwand enabled auto-merge (squash) July 25, 2026 21:05
@andiwand
andiwand merged commit 133059a into main Jul 25, 2026
19 checks passed
@andiwand
andiwand deleted the python-bindings branch July 25, 2026 21:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant