Skip to content

Commit ce04aaa

Browse files
authored
Pathlib support (#768)
* Tests for pathlib use * Allow pathlib use in convenience and filesystem stores * Rename Path newtype to PathType With the use of pathlib.Path in the library, this could get confusing. * Use os.PathLike instead of Path for type checks * Document PathLike usage in convenience * Revert "Document PathLike usage in convenience" This reverts commit 7292604. * Revert "Rename Path newtype to PathType" This reverts commit 515951c. * Use pathlib.Path explicitly This makes a more obvious contrast opposed to zarr's built-in `Path` type annotation (for internal keys).
1 parent 9ccc16e commit ce04aaa

File tree

5 files changed

+29
-5
lines changed

5 files changed

+29
-5
lines changed

Diff for: zarr/convenience.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Convenience functions for storing and loading data."""
22
import io
33
import itertools
4+
import os
45
import re
56
from collections.abc import Mapping
67

@@ -100,6 +101,10 @@ def open(store=None, mode='a', **kwargs):
100101
raise PathNotFoundError(path)
101102

102103

104+
def _might_close(path):
105+
return isinstance(path, (str, os.PathLike))
106+
107+
103108
def save_array(store, arr, **kwargs):
104109
"""Convenience function to save a NumPy array to the local file system, following a
105110
similar API to the NumPy save() function.
@@ -131,7 +136,7 @@ def save_array(store, arr, **kwargs):
131136
array([ 0, 1, 2, ..., 9997, 9998, 9999])
132137
133138
"""
134-
may_need_closing = isinstance(store, str)
139+
may_need_closing = _might_close(store)
135140
store = normalize_store_arg(store, clobber=True)
136141
try:
137142
_create_array(arr, store=store, overwrite=True, **kwargs)
@@ -202,7 +207,7 @@ def save_group(store, *args, **kwargs):
202207
if len(args) == 0 and len(kwargs) == 0:
203208
raise ValueError('at least one array must be provided')
204209
# handle polymorphic store arg
205-
may_need_closing = isinstance(store, str)
210+
may_need_closing = _might_close(store)
206211
store = normalize_store_arg(store, clobber=True)
207212
try:
208213
grp = _create_group(store, overwrite=True)

Diff for: zarr/creation.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
from warnings import warn
23

34
import numpy as np
@@ -148,7 +149,9 @@ def create(shape, chunks=True, dtype=None, compressor='default',
148149
def normalize_store_arg(store, clobber=False, storage_options=None, mode='w'):
149150
if store is None:
150151
return dict()
151-
elif isinstance(store, str):
152+
if isinstance(store, os.PathLike):
153+
store = os.fspath(store)
154+
if isinstance(store, str):
152155
mode = mode if clobber else "r"
153156
if "://" in store or "::" in store:
154157
return FSStore(store, mode=mode, **(storage_options or {}))

Diff for: zarr/tests/conftest.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import pathlib
2+
3+
import pytest
4+
5+
6+
@pytest.fixture(params=[str, pathlib.Path])
7+
def path_type(request):
8+
return request.param

Diff for: zarr/tests/test_convenience.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,11 @@
2727
atexit_rmtree, getsize)
2828

2929

30-
def test_open_array():
30+
def test_open_array(path_type):
3131

3232
store = tempfile.mkdtemp()
3333
atexit.register(atexit_rmtree, store)
34+
store = path_type(store)
3435

3536
# open array, create if doesn't exist
3637
z = open(store, mode='a', shape=100)
@@ -53,10 +54,11 @@ def test_open_array():
5354
open('doesnotexist', mode='r')
5455

5556

56-
def test_open_group():
57+
def test_open_group(path_type):
5758

5859
store = tempfile.mkdtemp()
5960
atexit.register(atexit_rmtree, store)
61+
store = path_type(store)
6062

6163
# open group, create if doesn't exist
6264
g = open(store, mode='a')

Diff for: zarr/tests/test_storage.py

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import atexit
33
import json
44
import os
5+
import pathlib
56
import sys
67
import pickle
78
import shutil
@@ -836,6 +837,11 @@ def test_filesystem_path(self):
836837
with pytest.raises(ValueError):
837838
DirectoryStore(f.name)
838839

840+
def test_init_pathlib(self):
841+
path = tempfile.mkdtemp()
842+
atexit.register(atexit_rmtree, path)
843+
DirectoryStore(pathlib.Path(path))
844+
839845
def test_pickle_ext(self):
840846
store = self.create_store()
841847
store2 = pickle.loads(pickle.dumps(store))

0 commit comments

Comments
 (0)