Multi-Storage Client (MSC)
This release adds Python 3.14 support to Multi-Storage Client, including Python 3.14 in the tested build matrix and published package metadata.
Breaking Changes
- Removed the
msc.zarrandmsc.xarrayadapters, theirmultistorageclient.contribmodules, and the correspondingzarrandxarrayoptional extras. Installmulti-storage-client[fsspec]and use the libraries' native fsspec support instead, such aszarr.open("msc://...")orxarray.open_zarr("msc://...").
New Features
- Added Python 3.14 support.
- Add OpenTelemetry metrics for POSIX file descriptor usage:
multistorageclient.file_descriptor.opentracks file descriptors held byPosixFile, andmultistorageclient.file_descriptor.durationrecords how long each descriptor remains open. - Add strict handling for POSIX symlinks that target paths outside the configured base path.
Performance Improvements
- Cache the resolved POSIX base path when evaluating symlinks to avoid repeated
realpathsystem calls.
Bug Fixes
ObjectFilereads no longer block indefinitely when opening a missing cached object or when a background download fails before creating the local file. Waiting callers now wake and receive the download error.PosixFile.readall()no longer emits READ metrics twice (once for itself and once for the instrumentedread()it delegated to).- Sort and de-duplicate
source_filesinsync_frombefore merging against the target listing; an unsorted list previously caused up-to-date target files to be deleted and re-copied. info("")on a POSIX profile now reports the modification time of the profile'sbase_pathinstead of the process working directory.- OCI listings now strip the bucket from
start_after/end_atlike every other provider; with abase_paththat includes the bucket,end_atpreviously filtered out every object andstart_afterwas ignored. copy.deepcopyof the immutable config dictionary now converts frozen tuples back to lists, somsc config validateno longer emits!!python/tupletags thatyaml.safe_loadrejects.- Azure batch-delete failures now include the response body in the raised error instead of a bound-method repr.
- Declare the record method explicitly on the cross-process
Counter/Gaugetelemetry proxies (derived from each instrument class's public methods). Proxy generation no longer depends on the installed OpenTelemetry's instrument shape, fixingAttributeError: 'AutoProxy[opentelemetry.metrics.Counter]' object has no attribute 'add'under OpenTelemetry version skew. MultiStoragePath.read_text()now honors itserrorsargument ("ignore","replace", ...) instead of always decoding strictly.RustClient.download_multipart_to_bytesnow returnsb""for zero-byte objects and empty ranges instead of failing with an integer underflow / invalid range error.ObjectFile.fileno()on in-memory files now returns one stable temporary descriptor instead of allocating a new one on every call (which leaked a descriptor per call untilclose()), andclose()releases tracked descriptors and the append-mode staging file even when the upload fails.msc lsnow shows the size of files whose provider reports no modification time (for example HuggingFace or AIStore); the size column was previously blanked for every row without a date.- Percent-encode the container and blob path in Azure presigned (SAS) URLs; blob names containing spaces,
#,+or%previously produced URLs that were truncated or rejected. - Azure downloads of large objects into a
StringIOnow decode the staged content as UTF-8 regardless of the host locale, matching the small-object path and the upload encoding. - Rust recursive listing now reports a failed listing task as a regular storage error instead of a Rust panic that bypasses MSC's exception translation.
- Numeric literals in object attribute filters now compare correctly with string-valued metadata for equality and inequality operations.
Multi-Storage File System (MSFS)
MSFS is planned to move to a separate repository and adopt an independent release process.