Skip to content

feat(python): ship the libmagic database inside the wheel - #623

Merged
andiwand merged 2 commits into
mainfrom
feat/ship-libmagic-database-in-wheel
Jul 26, 2026
Merged

feat(python): ship the libmagic database inside the wheel#623
andiwand merged 2 commits into
mainfrom
feat/ship-libmagic-database-in-wheel

Conversation

@andiwand

Copy link
Copy Markdown
Member

🤖 Generated with Claude Code

Wheel builds disabled libmagic on the premise recorded in pyproject.toml:

# Keep wheels self-contained: skip the components whose runtime data cannot be
# bundled into the package.
ODR_WITH_LIBMAGIC = "OFF"

That premise doesn't hold up:

  • Not a linking problem. Wheels build with BUILD_SHARED_LIBS=OFF, so libmagic and its zlib/xz/bzip2 dependencies link into pyodr/_core.<abi>.so. Nothing for auditwheel to vendor.
  • Not a size problem. magic.mgc is 8.5 MB raw but deflates to ~0.4 MB, and wheels are zip-deflated.
  • Not a packaging problem. python/CMakeLists.txt already installs the whole build data directory as pyodr/data, so ODR_BUNDLE_ASSETS=ON is enough to put the database there.

What was actually missing is the runtime fix-up. The compiled-in default from project_info::libmagic_database_path() is the relative string "share/magic.mgc" — meaningless inside a site-packages install — and pyodr/__init__.py only ever repointed the core data path. This gives the database the same three-step resolution already used there (already-configured path → ODR_LIBMAGIC_DATABASE_PATH → bundled copy), keyed on isfile rather than isdir.

What this buys

odr::mimetype() is the only consumer of libmagic (src/odr/internal/magic.cpp:99); the decode pipeline uses odr's own sniffing regardless. So the effect is precise: MIME detection stops bottoming out at the container type.

before after
pyodr.mimetype("x.odt") application/zip application/vnd.oasis.opendocument.text

Verification

Built a real wheel and installed it into a fresh venv:

magic db: .../site-packages/pyodr/data/magic.mgc
isfile  : True
33 passed
  • pyodr/data/magic.mgc present in the wheel: 8,513,392 raw → 443,589 compressed; wheel total 3.29 MB compressed / 18.2 MB installed.
  • In-tree build (the build_test.yml path, PYTHONPATH=build/python): 33 passed — pyodr_package already mirrors the data directory, so the database resolves there too.
  • With magic.mgc removed from the staged tree: 32 passed, 1 skipped — the new test degrades to a skip rather than a failure, so builds without a database stay green.

Notes

  • python.yml drops -o '&:with_libmagic=False' (conan already defaults it on) and adds -o '&:bundle_assets=True', which is what bridges LIBMAGIC_DATABASE_PATH from the dependency runenv into the build.
  • pdf2htmlEX and wvWare stay off — their runtime data genuinely is a different story.
  • Nothing missing is fatal: libmagic.cpp:35 already falls back to the system database, and magic.cpp:101 then falls back to odr's own sniffing.

`pyproject.toml` disabled libmagic for wheel builds on the premise that its
runtime data "cannot be bundled into the package". That was never true:

- the wheel links statically (`BUILD_SHARED_LIBS=OFF`), so libmagic and its
  zlib/xz/bzip2 dependencies end up inside `_core.<abi>.so` with nothing for
  auditwheel to vendor;
- `magic.mgc` is 8.5 MB raw but deflates to ~0.4 MB, and wheels are
  zip-deflated;
- `python/CMakeLists.txt` already installs the whole build data directory as
  `pyodr/data`, so `ODR_BUNDLE_ASSETS=ON` is enough to place the database
  there.

What was actually missing is the runtime fix-up. The compiled-in default from
`project_info::libmagic_database_path()` is the relative string
`"share/magic.mgc"`, meaningless inside a site-packages install, and
`pyodr/__init__.py` only ever repointed the core data path. Give the database
the same three-step resolution (configured path, then
`ODR_LIBMAGIC_DATABASE_PATH`, then the bundled copy), keyed on `isfile` rather
than `isdir`.

Verified against an installed wheel: `libmagic_database_path()` resolves inside
site-packages and `pyodr.mimetype()` on a minimal `.odt` returns
`application/vnd.oasis.opendocument.text` instead of the `application/zip` that
odr's own 12-byte sniffing yields. The wheel grew by 444 KB compressed.

The new test skips when the build has no database, so in-tree runs without
bundled assets stay green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YU1LRdUxTFmM5m5eCgb5Lb
@andiwand
andiwand enabled auto-merge (squash) July 26, 2026 16:13

@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: 53f65a9744

ℹ️ 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/pyodr/__init__.py Outdated
The compiled-in defaults from `project_info` are install-relative guesses
("share", "share/magic.mgc"). Testing them with `isdir`/`isfile` resolved
them against the process working directory, so launching from a directory
that happens to contain a `share/` tree made initialization return early
and silently ignore the assets shipped in the package.

Only an absolute path that exists now counts as already configured;
anything else falls through to the environment variable and then to the
bundled copy, as intended.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DBknDRREKdLmcBKaGgBm4t
@andiwand
andiwand disabled auto-merge July 26, 2026 16:24
@andiwand
andiwand merged commit d39e91a into main Jul 26, 2026
13 of 14 checks passed
@andiwand
andiwand deleted the feat/ship-libmagic-database-in-wheel branch July 26, 2026 16:24
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