Skip to content

LocalStore listing lists .partial temp files #4161

Description

@omar-merhebi

Zarr version

3.2.2.dev112+g50b7e016

Numcodecs version

0.16.5

Python Version

3.12

Operating System

Linux (RHEL 9)

Installation

editable install from source (uv pip install -e .) on a main checkout inside a venv

Description

When LocalStore writes zarr arrays and metadata, it initially writes to a temporary .partial file (full: <stem>.<uuid>.partial) and then it renames it into place when the write is complete. LocalStore.list(), LocalStore.list_prefix(), and LocalStore.list_dir() include these temporary files. So, when a process is writing to a store while another process reads it, those .partial files get listed as if they were real zarr store keys and they also cause a ZarrUserWarning when the group is iterated via Group.members(). When writing arrays concurrently, this clogs up the logs/output with many warnings like this:

ZarrUserWarning: Object at zarr.16442ffbc9dc4bffaae221fef349d64a.partial is not recognized as a component of a Zarr hierarchy.

I've been suppressing these manually. Working on a fix to filter the .partial temps in the listing methods. Happy to PR or take another direction if you prefer!

Steps to reproduce

# /// script
# requires-python = ">=3.12"
# dependencies = [
#   "zarr@git+https://github.com/zarr-developers/zarr-python.git@main",
# ]
# ///
#
# This script automatically imports the development branch of zarr to check for issues

import zarr

import asyncio
import tempfile
import warnings
from pathlib import Path

from zarr.storage import LocalStore
from zarr.storage._local import (
    _atomic_write,
)


async def main() -> None:
    root = Path(tempfile.mkdtemp())
    store = LocalStore(root)
    group = zarr.open_group(store=store, mode="w")
    group.create_array("a", shape=(1,), dtype="int32")

    # Begin writing a zarr array and then list the store
    # before the .partial file is renamed.
    with _atomic_write(root / "zarr.json", "wb") as f:
        f.write(b'{"zarr_format": 3, "node_type": "group"}')

        print("list() ->", sorted([k async for k in store.list()]))

        # This should result in the ZarrUserWarning
        with warnings.catch_warnings(record=True) as caught:
            warnings.simplefilter("always")
            list(group.members())
        for w in caught:
            print(f"{w.category.__name__}: {w.message}")


asyncio.run(main())

zarr.print_debug_info()

Additional output

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugPotential issues with the zarr-python library

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions