feat(python): ship the libmagic database inside the wheel - #623
Merged
Conversation
`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
enabled auto-merge (squash)
July 26, 2026 16:13
There was a problem hiding this comment.
💡 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".
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
disabled auto-merge
July 26, 2026 16:24
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 Generated with Claude Code
Wheel builds disabled libmagic on the premise recorded in
pyproject.toml:That premise doesn't hold up:
BUILD_SHARED_LIBS=OFF, so libmagic and its zlib/xz/bzip2 dependencies link intopyodr/_core.<abi>.so. Nothing forauditwheelto vendor.magic.mgcis 8.5 MB raw but deflates to ~0.4 MB, and wheels are zip-deflated.python/CMakeLists.txtalready installs the whole build data directory aspyodr/data, soODR_BUNDLE_ASSETS=ONis 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 — andpyodr/__init__.pyonly 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 onisfilerather thanisdir.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.pyodr.mimetype("x.odt")application/zipapplication/vnd.oasis.opendocument.textVerification
Built a real wheel and installed it into a fresh venv:
pyodr/data/magic.mgcpresent in the wheel: 8,513,392 raw → 443,589 compressed; wheel total 3.29 MB compressed / 18.2 MB installed.build_test.ymlpath,PYTHONPATH=build/python): 33 passed —pyodr_packagealready mirrors the data directory, so the database resolves there too.magic.mgcremoved 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.ymldrops-o '&:with_libmagic=False'(conan already defaults it on) and adds-o '&:bundle_assets=True', which is what bridgesLIBMAGIC_DATABASE_PATHfrom the dependency runenv into the build.libmagic.cpp:35already falls back to the system database, andmagic.cpp:101then falls back to odr's own sniffing.