feat: Support Python 3.14. - #131
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (19)
🚧 Files skipped from review as they are similar to previous changes (19)
📝 WalkthroughWalkthroughThe change adds Python 3.14 support across packaging, CI, documentation, and development tooling. It adds optional dependency diagnostics, handles Zarr constraints, and centralizes extended-attribute reads through an internal wrapper. ChangesPython 3.14 and dependency support
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Caller
participant multistorageclient.__getattr__
participant OptionalDependency
participant PackageMetadata
Caller->>multistorageclient.__getattr__: request contrib module
multistorageclient.__getattr__->>OptionalDependency: import contrib dependency
OptionalDependency-->>multistorageclient.__getattr__: module or ImportError
multistorageclient.__getattr__->>PackageMetadata: inspect installed version
PackageMetadata-->>multistorageclient.__getattr__: version or metadata failure
multistorageclient.__getattr__-->>Caller: module or chained guidance error
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@multi-storage-client/src/multistorageclient/_xattr.py`:
- Around line 19-23: Correct the description around the xattr wrapper behavior:
state that xattr.xattr.get’s implicit _SENTINEL_MISSING widens the static return
type, while module-level xattr.getxattr calls that omit default still raise
OSError for missing attributes. Preserve the existing explanation that the
wrapper restores the bytes contract for callers.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: caec3020-10d7-4e43-bdca-c14c88be112a
⛔ Files ignored due to path filters (1)
uv.lockis excluded by!**/*.lock
📒 Files selected for processing (19)
.github/workflows/.beta.yml.github/workflows/.source.yml.gitlab/pipelines/.beta.yml.gitlab/pipelines/.source.yml.release_notes/.unreleased.mdmulti-storage-client-docs/src/user_guide/installation.rstmulti-storage-client/pyproject.tomlmulti-storage-client/src/multistorageclient/__init__.pymulti-storage-client/src/multistorageclient/_xattr.pymulti-storage-client/src/multistorageclient/cache.pymulti-storage-client/src/multistorageclient/contrib/zarr.pymulti-storage-client/src/multistorageclient/providers/posix_file.pymulti-storage-client/tests/test_multistorageclient/unit/contrib/test_xarray.pymulti-storage-client/tests/test_multistorageclient/unit/contrib/test_zarr.pymulti-storage-client/tests/test_multistorageclient/unit/sync/test_worker.pymulti-storage-client/tests/test_multistorageclient/unit/test_cache.pymulti-storage-client/tests/test_multistorageclient/unit/test_lazy_import.pymulti-storage-client/tests/test_multistorageclient/unit/test_partial_file_caching.pynix/overlays/development/multi-storage-client/devShells/python3.14.nix
| # PyYAML 6.0.3 and xattr 1.3.0 are the first releases with Python 3.14 wheels, and | ||
| # neither older floor builds from its sdist on 3.14. The bumps are scoped to 3.14 so | ||
| # older interpreters keep their existing floors: raising them there would force an | ||
| # upgrade on downstream pins for no reason, and xattr 1.3.0 ships no PyPy wheels. | ||
| "pyyaml>=6.0.1,<7; python_version<'3.14'", | ||
| "pyyaml>=6.0.3,<7; python_version>='3.14'", | ||
| "opentelemetry-api>=1.24,<2", | ||
| "xattr>=1.1.4,<2", | ||
| "xattr>=1.1.4,<2; python_version<'3.14'", | ||
| "xattr>=1.3.0,<2; python_version>='3.14'", |
There was a problem hiding this comment.
I don't see a good reason to not just use pyyaml>=6.0.3,<7 and xattr>=1.3.0,<2 for all Python versions. The less conditionals we have the better.
| # 2.182 is the first release pinning crc32c 2.8.0, which has Python 3.14 wheels. | ||
| "oci>=2.181,<3; python_version<'3.14'", | ||
| "oci>=2.182,<3; python_version>='3.14'" |
There was a problem hiding this comment.
Ditto for oci>=2.182,<3.
Adds Python 3.14 to the supported matrix without waiting on the Zarr 3.x migration. Zarr 2.x cannot run on Python 3.14: zarr 2.18.7 caps numcodecs <0.16, but numcodecs only ships Python 3.14 wheels from 0.16.4 on, and forcing 0.16.x breaks Zarr 2.x at import (numcodecs.blosc.cbuffer_sizes was removed). Zarr 3.x does support Python 3.14 but is a breaking API change (no zarr.storage.BaseStore, async store ABC) and requires Python 3.11+, rising to 3.12+ in recent releases, so it cannot cover our Python 3.10 support either. Rather than maintain parallel Zarr 2.x/3.x store implementations for the few months until Python 3.10 EOL (October 2026), the zarr extra is gated off on Python 3.14 and everything else ships now. Dependency floors are raised only where Python 3.14 needs them, using markers so Python 3.10-3.13 consumers keep their existing floors. pyyaml 6.0.3, xattr 1.3.0, numpy 2.3.2 and oci 2.182 (2.181 pins crc32c 2.7.1) are each the first release carrying cp314 wheels, and neither pyyaml 6.0.1 nor xattr 1.1.4 builds from its sdist on 3.14. Scoping the bumps avoids forcing an upgrade on downstream pins for a constraint their interpreter doesn't have, and keeps the PyPy wheels that xattr dropped in 1.3.0. Because a marker-gated extra resolves empty rather than failing, `pip install "multi-storage-client[zarr]"` succeeds but the zarr extra contributes nothing on Python 3.14. The contrib __getattr__ now translates an unusable optional dependency into a message naming the package and the extra. It catches ImportError rather than ModuleNotFoundError, because an installed Zarr 3.x fails on a missing name (zarr.storage.BaseStore) rather than a missing module, and it resolves the Zarr cases from the attribute being imported rather than from the raised error, because contrib.zarr imports numpy before zarr and would otherwise name the wrong package on 3.14. Unrecognized ImportErrors propagate untouched so unrelated failures aren't masked. This also fixes a pre-existing papercut on every Python version: installing the xarray extra without the zarr extra previously surfaced a bare "No module named 'zarr'". xattr 1.3.0 gave xattr.xattr.get a sentinel default of object(), widening the inferred return type of the module-level getxattr from bytes to object and failing pyright at every .decode() call site on every Python version. multistorageclient._xattr restores the bytes contract in one place. contrib/zarr.py's zarr imports carry reportMissingImports suppressions so pyright also passes in a Python 3.14 environment, where the extra installs nothing; they are inert wherever Zarr is installed. Verified: full unit suite passes on Python 3.14 (1072 passed, 5 skipped) and Python 3.10 (1074 passed, 3 skipped); the difference is the two zarr-dependent contrib tests skipping. `uv sync --all-extras --locked` succeeds on Python 3.14 and maturin produces a cp314 wheel. `ruff check`, `ruff format --check` and `uv run pyright` are clean, the last both with and without Zarr installed. pyyaml 6.0.1 and xattr 1.1.4 were confirmed to fail their sdist builds on 3.14 and to install cleanly on 3.10, and the Zarr 3 path was exercised against a package exposing zarr.storage without BaseStore. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1e2f895 to
45cbf0d
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
Adds Python 3.14 to the supported matrix without waiting on the Zarr 3.x migration.
Zarr 2.x cannot run on Python 3.14: zarr 2.18.7 caps numcodecs <0.16, but numcodecs only ships Python 3.14 wheels from 0.16.4 on, and forcing 0.16.x breaks Zarr 2.x at import (numcodecs.blosc.cbuffer_sizes was removed). Zarr 3.x does support Python 3.14 but is a breaking API change (no zarr.storage.BaseStore, async store ABC) and requires Python 3.11+, rising to 3.12+ in recent releases, so it cannot cover our Python 3.10 support either. Rather than maintain parallel Zarr 2.x/3.x store implementations for the few months until Python 3.10 EOL (October 2026), the zarr extra is gated off on Python 3.14 and everything else ships now.
Dependency floors are raised only where Python 3.14 needs them, using markers so Python 3.10-3.13 consumers keep their existing floors. pyyaml 6.0.3, xattr 1.3.0, numpy 2.3.2 and oci 2.182 (2.181 pins crc32c 2.7.1) are each the first release carrying cp314 wheels, and neither pyyaml 6.0.1 nor xattr 1.1.4 builds from its sdist on 3.14. Scoping the bumps avoids forcing an upgrade on downstream pins for a constraint their interpreter doesn't have, and keeps the PyPy wheels that xattr dropped in 1.3.0.
Because a marker-gated extra resolves empty rather than failing,
pip install "multi-storage-client[zarr]"succeeds but the zarr extra contributes nothing on Python 3.14. The contrib getattr now translates an unusable optional dependency into a message naming the package and the extra. It catches ImportError rather than ModuleNotFoundError, because an installed Zarr 3.x fails on a missing name (zarr.storage.BaseStore) rather than a missing module, and it resolves the Zarr cases from the attribute being imported rather than from the raised error, because contrib.zarr imports numpy before zarr and would otherwise name the wrong package on 3.14. Unrecognized ImportErrors propagate untouched so unrelated failures aren't masked. This also fixes a pre-existing papercut on every Python version: installing the xarray extra without the zarr extra previously surfaced a bare "No module named 'zarr'".xattr 1.3.0 gave xattr.xattr.get a sentinel default of object(), widening the inferred return type of the module-level getxattr from bytes to object and failing pyright at every .decode() call site on every Python version. multistorageclient._xattr restores the bytes contract in one place. contrib/zarr.py's zarr imports carry reportMissingImports suppressions so pyright also passes in a Python 3.14 environment, where the extra installs nothing; they are inert wherever Zarr is installed.
Verified: full unit suite passes on Python 3.14 (1072 passed, 5 skipped) and Python 3.10 (1074 passed, 3 skipped); the difference is the two zarr-dependent contrib tests skipping.
uv sync --all-extras --lockedsucceeds on Python 3.14 and maturin produces a cp314 wheel.ruff check,ruff format --checkanduv run pyrightare clean, the last both with and without Zarr installed. pyyaml 6.0.1 and xattr 1.1.4 were confirmed to fail their sdist builds on 3.14 and to install cleanly on 3.10, and the Zarr 3 path was exercised against a package exposing zarr.storage without BaseStore.Description
Change description.
{Relates to/Closes} {Task ID}.
Checklist
.release_notes/.unreleased.mdmulti-storage-client/pyproject.toml.release_notes/.unreleased.md.release_notes/{bumped package version}.mdfile.Summary by CodeRabbit