Repository navigation
Split into tensorcodec (pure Python) and tensorcodec-av; BMP; OpenCV >=4.12 - #14
Merged
Merged
Conversation
Image codecs only need OpenCV, but importing tensorcodec.decoders loaded the Rust extension, so they were unusable where no native wheel exists. VideoDecoder/AudioDecoder now import it on construction and raise a clear ImportError when it is missing. scripts/build_pure_wheel.py builds a py3-none-any wheel with the same [project] metadata; CI builds it, tests it on Windows, Intel macOS and Linux, and publish uploads it with the native wheels. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YAijSnAE4aAjuS1EcCTwqS
OpenCV decodes BMP losslessly. Alpha follows Pillow: only 32-bit BI_BITFIELDS with a nonzero alpha mask keeps it, since OpenCV otherwise returns the padding byte as a fourth channel. TIFF stays unsupported because OpenCV premultiplies unassociated alpha and drops gray+alpha. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YAijSnAE4aAjuS1EcCTwqS
FFmpeg's glob pattern type is unavailable on Windows, so the animated GIF fixture uses a numbered sequence. Homebrew's FFmpeg has no libaom, so the fallback jobs use the conda-forge FFmpeg the other workflows already pin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YAijSnAE4aAjuS1EcCTwqS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YAijSnAE4aAjuS1EcCTwqS
The Windows opencv-python-headless 4.14 wheel cannot decode AVIF; the dispatch test now checks the explicit error there instead of failing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YAijSnAE4aAjuS1EcCTwqS
Replaces the copy-and-rebuild fallback wheel. tensorcodec is built by hatchling as a py3-none-any wheel with the Python API and image codecs. native/ is the maturin project for tensorcodec-native, which contains only the FFmpeg extension (import tensorcodec_native) and the bundled-library notices. tensorcodec pins tensorcodec-native to its own version behind a marker matching the native wheel tags, plus a `native` extra; the version test and a runtime check reject skew. Publish uploads tensorcodec-native before tensorcodec. The OpenCV bound is now measured: the image suite, including TorchCodec comparisons, passes with 4.12, 4.13 and 5.0; 4.10/4.11 wheels lack the GIF and AVIF decoders. The extra becomes >=4.12 without the <5 cap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YAijSnAE4aAjuS1EcCTwqS
0.2.0 is an existing single-package release: reusing it would collide with its sdist and leave installed 0.2.0 environments un-upgraded. The version test also checks Cargo.lock and skips native checks in the tensorcodec sdist, which does not contain native/. README notes the --no-deps route for Linux environments the marker cannot exclude (musl, free-threaded). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YAijSnAE4aAjuS1EcCTwqS
pip's vendored packaging 22-25 raises InvalidVersion when comparing platform_release on Linux kernels such as 6.8.0-azure, which would break installs on supported Linux. macOS arm64 older than 14 now tries the native sdist, as it did before the split. The tensorcodec sdist includes native/ so its uv source and version tests work from the archive. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YAijSnAE4aAjuS1EcCTwqS
Where the marker applies it is a no-op; elsewhere it only triggers the same source build as requesting tensorcodec-native directly, while suggesting that it enables video on Windows. The docs now say to install tensorcodec-native==<same version> explicitly to build from source. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YAijSnAE4aAjuS1EcCTwqS
build-python.yml builds and tests tensorcodec (artifact dist-python); build-native.yml builds and validates the manylinux x86_64/aarch64 and macOS arm64 wheels and the sdist of tensorcodec-native (dist-native-*). CI now runs the Linux release builds too: on every push and on PRs touching what they build or validate. publish.yml calls both, checks the release set (one version, six files) and uploads native first. The duplicated sdist steps and source.yml are gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YAijSnAE4aAjuS1EcCTwqS
The compiled distribution is the audio/video codec implementation; images live in tensorcodec. Renamed consistently: PyPI name, import package tensorcodec_av with extension module _av, Cargo package and lib, the native/ directory (now av/), the pin, ImportError messages, tests, workflows (build-av.yml, dist-av-* artifacts, av jobs) and docs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YAijSnAE4aAjuS1EcCTwqS
Docs keep only what users and maintainers need; releasing.md is reduced to the two-package release steps and the recovery step. Workflows drop the path filter (CI always runs build-av.yml), the publish release-set check (needs already require every artifact), the single-entry macOS matrix and redundant checks. Tests merge overlapping cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YAijSnAE4aAjuS1EcCTwqS
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.
Image codecs only need OpenCV, but
tensorcodec0.2.0 was one maturin package. Its import loaded the Rust extension, and installing on Windows or Intel macOS fell back to an sdist that needs Rust and FFmpeg. This PR splits the project into two distributions, the way pydantic and pydantic-core are split. It also adds BMP todecode_imageand replaces the OpenCV bound with a measured one. Versions go to 0.3.0, since 0.2.0 is already published as a single package. Nothing is released by this PR.Size: +829/−309 across 40 files. Most of it is moved workflow steps, the copied
av/LICENSE(+204) and tests; the runtime code change is about 50 lines.Packaging split
tensorcodec(rootpyproject.toml)import tensorcodec)py3-none-anywheel, sdistApache-2.0,LICENSEonly,OS Independenttensorcodec-av(av/pyproject.toml, new)import tensorcodec_av)Apache-2.0 AND LGPL-3.0-or-later AND BSD-2-Clause; the FFmpeg/dav1d/OpenSSL notices moved toav/licenses/tensorcodec-av(the audio/video decoders; images live intensorcodec) is unregistered on PyPI as of 2026-10-05. The Rust package lives inav/; the extension module istensorcodec_av._av.Dependency.
tensorcodecrequirestensorcodec-av==<same version>behind the markerplatform_python_implementation == 'CPython' and ((sys_platform == 'linux' and platform_machine in {x86_64, aarch64}) or (sys_platform == 'darwin' and platform_machine == 'arm64')).pip install tensorcodecbehaves as before wheretensorcodec-avwheels exist.nativeextra. Where the marker applies it would do nothing; elsewhere it would only trigger the same source build as installingtensorcodec-avdirectly. The docs say to installtensorcodec-av==<same version>explicitly to build it from source (needs Rust and FFmpeg 7).platform_release. pip's vendored packaging 22–25 raisesInvalidVersionon Linux kernel strings like6.8.0-azure; I verified this with packaging 22.0/23.2/24.2/25.0, and a test guards it.Lazy import and skew check.
VideoDecoderandAudioDecoderimporttensorcodec_avwhen constructed.ImportErrorthat explains which platforms havetensorcodec-avwheels.__version__(CARGO_PKG_VERSION). Atensorcodec-avwhose version differs fromtensorcodecis rejected with an explicit message.Lockstep.
tests/test_versions.py(runs in every CI and release job) requirespyproject.toml, the pin,av/Cargo.toml(thetensorcodec-avversion source),av/Cargo.lockandtensorcodec.__version__to agree. It also checks thatav/LICENSEequalsLICENSEand that the marker matches the published wheel platforms.Workflows: one reusable workflow per distribution. CI and the release call the same two workflows:
build-python.yml(renamed frompure-python-wheel.yml)build:tensorcodecwheel and sdist,python -m build+twine check --strict.test-without-av: installstensorcodec[images]with--no-indexon windows-2025 (Python 3.12, latest OpenCV = 5.0) and macos-15-intel (Python 3.10, OpenCV 4.12.0.88, the lower bound), then runs the image, encoder, optional-native and version testsdist-pythonbuild-av.yml(replacesmacos-wheels.ymland the inline Linux jobs inpublish.yml)linux(x86_64, aarch64): manylinux2014 via maturin-action with the existing native-deps cache, size check, glibc 2.17 Python 3.10/3.13 runtime check, contract and--compareoracle tests.macos(arm64): build, delocate, full pytest, clean 3.10/3.13 venvs.sdist. The wheel jobs validate against thedist-pythonwheel, so callers runbuild-python.ymlfirstdist-av-linux-{x86_64,aarch64},dist-av-macos-arm64,dist-av-sdist,wheel-size-linux-*ci.ymlpython→av, plustest(development build against conda-forge FFmpeg, Clippy, contract and--compare)publish.ymlpython→av→publish(tensorcodec-avfirst, so the exact pin never points at a missing release, thentensorcodec) →update-size-docs(now measurestensorcodec-av)ci.ymlrunsavon every push and PR, so a release commit has already passed the same Linux and macOS release builds.source.ymlis removed:publish.yml --field publish=falseproduces the same artifacts.Removed.
scripts/build_pure_wheel.py.Docs. README,
docs/releasing.md(two-project release, pending trusted publisher fortensorcodec-av, version-bump steps, recovery if the second upload fails),docs/system_ffmpeg.md,docs/images.mdanddocs/package_size.md.Upgrade path: installing the 0.3.0
tensorcodecwheel over the published 0.2.0 removestensorcodec/_native.abi3.soandtensorcodec.libs(checked locally). On marker platforms, the dependency then installstensorcodec-av.Known limitation (deliberate): environment markers cannot detect musl, free-threaded CPython or macOS older than 14. On those platforms installers still try
tensorcodec-avand fall back to its sdist, which is what happened before the split. The README documentspip install --no-deps tensorcodec numpyfor image-only use there. The adversarial review flags this; avoiding it would require making native opt-in everywhere, which changespip install tensorcodecon the supported platforms.BMP
decode_imagedetectsBMand decodes throughcv2.imdecode, losslessly.BI_BITFIELDSfiles with a nonzero alpha mask keep it.decode_bmp, matching TorchCodec's function set.OpenCV bound:
>=4.12, no upper capImage decoder/encoder/optional-AV tests (152 with TorchCodec 0.17.0
--compare). One throwaway venv per version; Linux, Python 3.12, PyPIopencv-python-headless.OpenCV could not decode)GIF: NOandAVIF: NOincv2.getBuildInformation(). 4.12 reports both as YES._opencv.py, theimagesextra and the dev group now use>=4.12, without the<5cap. The reason is recorded at the check and indocs/images.md.Validation
a9f9e1b, all green), including the Linux release builds:av / linuxx86_64 and aarch64: cache hit,tensorcodec_av-0.3.0wheel built, glibc 2.17 runtime checks, 67 contract and 462--comparetests passed.av / macosarm64: 316 passed.av / sdist,python / build, andpython / test-without-avon Windows and Intel macOS.test.tensorcodecwheel and sdist: the wheel has only Python files andLICENSE. A wheel rebuilt from the sdist works, and the version tests pass in the extracted sdist.tensorcodec-avsdist via maturin contains only the Rust sources and the notices.--compare.review --scope branch, final state after the trim): no actionable regressions. Earlier rounds found the reuse of version 0.2.0, theplatform_releasemarker crash and the sdist missingnative/; all three are fixed.Release steps (not done here)
tensorcodec-avas a pending trusted publisher (same repository,publish.yml, environmentpypi).main. A--field publish=falsedry run is possible first.pip install tensorcodec==0.3.0pullstensorcodec-av==0.3.0on Linux and macOS arm64, and installs pure Python on Windows.🤖 Generated with Claude Code
https://claude.ai/code/session_01YAijSnAE4aAjuS1EcCTwqS