zarr v3 doesn't create a directory for a LocalStore if it doesn't exist. Should it?
In [3]: zarr.open_group(zarr.storage.LocalStore("/tmp/zarr-python-v3-not-a-directory", mode="w"))
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
Cell In[3], line 1
----> 1 zarr.open_group(zarr.storage.LocalStore("/tmp/zarr-python-v3-not-a-directory", mode="w"))
File ~/gh/zarr-developers/zarr-python/src/zarr/_compat.py:43, in _deprecate_positional_args.<locals>._inner_deprecate_positional_args.<locals>.inner_f(*args, **kwargs)
41 extra_args = len(args) - len(all_args)
42 if extra_args <= 0:
---> 43 return f(*args, **kwargs)
45 # extra_args > 0
46 args_msg = [
47 f"{name}={arg}"
48 for name, arg in zip(kwonly_args[:extra_args], args[-extra_args:], strict=False)
49 ]
File ~/gh/zarr-developers/zarr-python/src/zarr/api/synchronous.py:216, in open_group(store, mode, cache_attrs, synchronizer, path, chunk_store, storage_options, zarr_version, zarr_format, meta_array, attributes, use_consolidated)
199 @_deprecate_positional_args
200 def open_group(
201 store: StoreLike | None = None,
(...)
213 use_consolidated: bool | str | None = None,
214 ) -> Group:
215 return Group(
--> 216 sync(
217 async_api.open_group(
218 store=store,
219 mode=mode,
220 cache_attrs=cache_attrs,
221 synchronizer=synchronizer,
222 path=path,
223 chunk_store=chunk_store,
224 storage_options=storage_options,
225 zarr_version=zarr_version,
226 zarr_format=zarr_format,
227 meta_array=meta_array,
228 attributes=attributes,
229 use_consolidated=use_consolidated,
230 )
231 )
232 )
File ~/gh/zarr-developers/zarr-python/src/zarr/core/sync.py:91, in sync(coro, loop, timeout)
88 return_result = next(iter(finished)).result()
90 if isinstance(return_result, BaseException):
---> 91 raise return_result
92 else:
93 return return_result
File ~/gh/zarr-developers/zarr-python/src/zarr/core/sync.py:50, in _runner(coro)
45 """
46 Await a coroutine and return the result of running it. If awaiting the coroutine raises an
47 exception, the exception will be returned.
48 """
49 try:
---> 50 return await coro
51 except Exception as ex:
52 return ex
File ~/gh/zarr-developers/zarr-python/src/zarr/api/asynchronous.py:699, in open_group(store, mode, cache_attrs, synchronizer, path, chunk_store, storage_options, zarr_version, zarr_format, meta_array, attributes, use_consolidated)
696 if chunk_store is not None:
697 warnings.warn("chunk_store is not yet implemented", RuntimeWarning, stacklevel=2)
--> 699 store_path = await make_store_path(store, mode=mode, storage_options=storage_options)
700 if path is not None:
701 store_path = store_path / path
File ~/gh/zarr-developers/zarr-python/src/zarr/storage/common.py:99, in make_store_path(store_like, mode, storage_options)
97 if mode is not None and mode != store_like.mode.str:
98 store_like = store_like.with_mode(mode)
---> 99 await store_like._ensure_open()
100 result = StorePath(store_like)
101 elif store_like is None:
102 # mode = "w" is an exception to the default mode = 'r'
File ~/gh/zarr-developers/zarr-python/src/zarr/abc/store.py:80, in Store._ensure_open(self)
78 async def _ensure_open(self) -> None:
79 if not self._is_open:
---> 80 await self._open()
File ~/gh/zarr-developers/zarr-python/src/zarr/abc/store.py:73, in Store._open(self)
71 raise ValueError("store is already open")
72 if self.mode.str == "w":
---> 73 await self.clear()
74 elif self.mode.str == "w-" and not await self.empty():
75 raise FileExistsError("Store already exists")
File ~/gh/zarr-developers/zarr-python/src/zarr/storage/local.py:98, in LocalStore.clear(self)
96 async def clear(self) -> None:
97 self._check_writable()
---> 98 shutil.rmtree(self.root)
99 self.root.mkdir()
File ~/mambaforge/envs/python=3.12/lib/python3.12/shutil.py:759, in rmtree(path, ignore_errors, onerror, onexc, dir_fd)
757 try:
758 while stack:
--> 759 _rmtree_safe_fd(stack, onexc)
760 finally:
761 # Close any file descriptors still on the stack.
762 while stack:
File ~/mambaforge/envs/python=3.12/lib/python3.12/shutil.py:703, in _rmtree_safe_fd(stack, onexc)
701 except OSError as err:
702 err.filename = path
--> 703 onexc(func, path, err)
File ~/mambaforge/envs/python=3.12/lib/python3.12/shutil.py:669, in _rmtree_safe_fd(stack, onexc)
667 assert func is os.lstat
668 if orig_entry is None:
--> 669 orig_st = os.lstat(name, dir_fd=dirfd)
670 else:
671 orig_st = orig_entry.stat(follow_symlinks=False)
FileNotFoundError: [Errno 2] No such file or directory: PosixPath('/tmp/zarr-python-v3-not-a-directory')
In [2]: zarr.open_group("/tmp/zarr-python-v2-not-a-directory")
Out[2]: <zarr.hierarchy.Group '/'>
Zarr version
v3
Numcodecs version
na
Python Version
na
Operating System
na
Installation
na
Description
zarr v3 doesn't create a directory for a LocalStore if it doesn't exist. Should it?
Steps to reproduce
In [3]: zarr.open_group(zarr.storage.LocalStore("/tmp/zarr-python-v3-not-a-directory", mode="w")) --------------------------------------------------------------------------- FileNotFoundError Traceback (most recent call last) Cell In[3], line 1 ----> 1 zarr.open_group(zarr.storage.LocalStore("/tmp/zarr-python-v3-not-a-directory", mode="w")) File ~/gh/zarr-developers/zarr-python/src/zarr/_compat.py:43, in _deprecate_positional_args.<locals>._inner_deprecate_positional_args.<locals>.inner_f(*args, **kwargs) 41 extra_args = len(args) - len(all_args) 42 if extra_args <= 0: ---> 43 return f(*args, **kwargs) 45 # extra_args > 0 46 args_msg = [ 47 f"{name}={arg}" 48 for name, arg in zip(kwonly_args[:extra_args], args[-extra_args:], strict=False) 49 ] File ~/gh/zarr-developers/zarr-python/src/zarr/api/synchronous.py:216, in open_group(store, mode, cache_attrs, synchronizer, path, chunk_store, storage_options, zarr_version, zarr_format, meta_array, attributes, use_consolidated) 199 @_deprecate_positional_args 200 def open_group( 201 store: StoreLike | None = None, (...) 213 use_consolidated: bool | str | None = None, 214 ) -> Group: 215 return Group( --> 216 sync( 217 async_api.open_group( 218 store=store, 219 mode=mode, 220 cache_attrs=cache_attrs, 221 synchronizer=synchronizer, 222 path=path, 223 chunk_store=chunk_store, 224 storage_options=storage_options, 225 zarr_version=zarr_version, 226 zarr_format=zarr_format, 227 meta_array=meta_array, 228 attributes=attributes, 229 use_consolidated=use_consolidated, 230 ) 231 ) 232 ) File ~/gh/zarr-developers/zarr-python/src/zarr/core/sync.py:91, in sync(coro, loop, timeout) 88 return_result = next(iter(finished)).result() 90 if isinstance(return_result, BaseException): ---> 91 raise return_result 92 else: 93 return return_result File ~/gh/zarr-developers/zarr-python/src/zarr/core/sync.py:50, in _runner(coro) 45 """ 46 Await a coroutine and return the result of running it. If awaiting the coroutine raises an 47 exception, the exception will be returned. 48 """ 49 try: ---> 50 return await coro 51 except Exception as ex: 52 return ex File ~/gh/zarr-developers/zarr-python/src/zarr/api/asynchronous.py:699, in open_group(store, mode, cache_attrs, synchronizer, path, chunk_store, storage_options, zarr_version, zarr_format, meta_array, attributes, use_consolidated) 696 if chunk_store is not None: 697 warnings.warn("chunk_store is not yet implemented", RuntimeWarning, stacklevel=2) --> 699 store_path = await make_store_path(store, mode=mode, storage_options=storage_options) 700 if path is not None: 701 store_path = store_path / path File ~/gh/zarr-developers/zarr-python/src/zarr/storage/common.py:99, in make_store_path(store_like, mode, storage_options) 97 if mode is not None and mode != store_like.mode.str: 98 store_like = store_like.with_mode(mode) ---> 99 await store_like._ensure_open() 100 result = StorePath(store_like) 101 elif store_like is None: 102 # mode = "w" is an exception to the default mode = 'r' File ~/gh/zarr-developers/zarr-python/src/zarr/abc/store.py:80, in Store._ensure_open(self) 78 async def _ensure_open(self) -> None: 79 if not self._is_open: ---> 80 await self._open() File ~/gh/zarr-developers/zarr-python/src/zarr/abc/store.py:73, in Store._open(self) 71 raise ValueError("store is already open") 72 if self.mode.str == "w": ---> 73 await self.clear() 74 elif self.mode.str == "w-" and not await self.empty(): 75 raise FileExistsError("Store already exists") File ~/gh/zarr-developers/zarr-python/src/zarr/storage/local.py:98, in LocalStore.clear(self) 96 async def clear(self) -> None: 97 self._check_writable() ---> 98 shutil.rmtree(self.root) 99 self.root.mkdir() File ~/mambaforge/envs/python=3.12/lib/python3.12/shutil.py:759, in rmtree(path, ignore_errors, onerror, onexc, dir_fd) 757 try: 758 while stack: --> 759 _rmtree_safe_fd(stack, onexc) 760 finally: 761 # Close any file descriptors still on the stack. 762 while stack: File ~/mambaforge/envs/python=3.12/lib/python3.12/shutil.py:703, in _rmtree_safe_fd(stack, onexc) 701 except OSError as err: 702 err.filename = path --> 703 onexc(func, path, err) File ~/mambaforge/envs/python=3.12/lib/python3.12/shutil.py:669, in _rmtree_safe_fd(stack, onexc) 667 assert func is os.lstat 668 if orig_entry is None: --> 669 orig_st = os.lstat(name, dir_fd=dirfd) 670 else: 671 orig_st = orig_entry.stat(follow_symlinks=False) FileNotFoundError: [Errno 2] No such file or directory: PosixPath('/tmp/zarr-python-v3-not-a-directory')In zarr-python 2.x it created the directory:
Additional output
No response