Skip to content

Commit edf0d71

Browse files
authored
Merge pull request #196 from jakirkham/add_move
Add move
2 parents ff00eb6 + 62f6f34 commit edf0d71

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

docs/api/hierarchy.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,4 @@ Groups (``zarr.hierarchy``)
3636
.. automethod:: zeros_like
3737
.. automethod:: ones_like
3838
.. automethod:: full_like
39+
.. automethod:: move

zarr/hierarchy.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from zarr.attrs import Attributes
1111
from zarr.core import Array
1212
from zarr.storage import (contains_array, contains_group, init_group,
13-
DictStore, group_meta_key, attrs_key, listdir, rmdir)
13+
DictStore, group_meta_key, attrs_key, listdir, rename, rmdir)
1414
from zarr.creation import (array, create, empty, zeros, ones, full,
1515
empty_like, zeros_like, ones_like, full_like,
1616
normalize_store_arg)
@@ -81,6 +81,7 @@ class Group(MutableMapping):
8181
ones_like
8282
full_like
8383
info
84+
move
8485
8586
"""
8687

@@ -934,6 +935,37 @@ def _full_like_nosync(self, name, data, **kwargs):
934935
return full_like(data, store=self._store, path=path,
935936
chunk_store=self._chunk_store, **kwargs)
936937

938+
def _move_nosync(self, path, new_path):
939+
rename(self._store, path, new_path)
940+
if self._chunk_store is not None:
941+
rename(self._chunk_store, path, new_path)
942+
943+
def move(self, source, dest):
944+
"""Move contents from one path to another relative to the Group.
945+
946+
Parameters
947+
----------
948+
source : string
949+
Name or path to a Zarr object to move.
950+
dest : string
951+
New name or path of the Zarr object.
952+
"""
953+
954+
source = self._item_path(source)
955+
dest = self._item_path(dest)
956+
957+
# Check that source exists.
958+
if not (contains_array(self._store, source) or contains_group(self._store, source)):
959+
raise ValueError('The source, "%s", does not exist.' % source)
960+
if contains_array(self._store, dest) or contains_group(self._store, dest):
961+
raise ValueError('The dest, "%s", already exists.' % dest)
962+
963+
# Ensure groups needed for `dest` exist.
964+
if "/" in dest:
965+
self.require_group("/" + dest.rsplit("/", 1)[0])
966+
967+
self._write_op(self._move_nosync, source, dest)
968+
937969

938970
def _normalize_store_arg(store, clobber=False):
939971
return normalize_store_arg(store, clobber=clobber, default=DictStore)

zarr/tests/test_hierarchy.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,52 @@ def test_delitem(self):
685685
assert 'bar' not in g
686686
assert 'bar/baz' not in g
687687

688+
def test_move(self):
689+
g = self.create_group()
690+
691+
data = np.arange(100)
692+
g['boo'] = data
693+
694+
data = np.arange(100)
695+
g['foo'] = data
696+
697+
try:
698+
g.move('foo', 'bar')
699+
assert 'foo' not in g
700+
assert 'bar' in g
701+
assert_array_equal(data, g['bar'])
702+
703+
g.move('bar', 'foo/bar')
704+
assert 'bar' not in g
705+
assert 'foo' in g
706+
assert 'foo/bar' in g
707+
assert isinstance(g['foo'], Group)
708+
assert_array_equal(data, g['foo/bar'])
709+
710+
g.move('foo', 'foo2')
711+
assert 'foo' not in g
712+
assert 'foo/bar' not in g
713+
assert 'foo2' in g
714+
assert 'foo2/bar' in g
715+
assert isinstance(g['foo2'], Group)
716+
assert_array_equal(data, g['foo2/bar'])
717+
718+
g2 = g['foo2']
719+
g2.move('bar', '/bar')
720+
assert 'foo2' in g
721+
assert 'foo2/bar' not in g
722+
assert 'bar' in g
723+
assert isinstance(g['foo2'], Group)
724+
assert_array_equal(data, g['bar'])
725+
726+
with assert_raises(ValueError):
727+
g2.move('bar', 'bar2')
728+
729+
with assert_raises(ValueError):
730+
g.move('bar', 'boo')
731+
except NotImplementedError:
732+
pass
733+
688734
def test_array_creation(self):
689735
grp = self.create_group()
690736

0 commit comments

Comments
 (0)