def copy(self, source, dest, name=None): """ Copy an object or group. The source can be a path, Group, Dataset, or Datatype object. The destination can be either a path or a Group object. The source and destinations need not be in the same file. If the source is a Group object, all objects contained in that group will be copied recursively. When the destination is a Group object, by default the target will be created in that group with its current name (basename of obj.name). You can override that by setting "name" to a string. Example: >>> f = File('myfile.hdf5') >>> f.listnames() ['MyGroup'] >>> f.copy('MyGroup', 'MyCopy') >>> f.listnames() ['MyGroup', 'MyCopy'] """ if isinstance(source, HLObject): source_path = '.' else: # Interpret source as a path relative to this group source_path = source source = self if isinstance(dest, Group): if name is not None: dest_path = name else: # copy source into dest group: dest_name/source_name dest_path = pp.basename(h5i.get_name(source[source_path].id)) elif isinstance(dest, HLObject): raise TypeError("Destination must be path or Group object") else: # Interpret destination as a path relative to this group dest_path = dest dest = self h5o.copy(source.id, self._e(source_path), dest.id, self._e(dest_path))
def copy(self, source, dest, name=None, shallow=False, expand_soft=False, expand_external=False, expand_refs=False, without_attrs=False): """Copy an object or group. The source can be a path, Group, Dataset, or Datatype object. The destination can be either a path or a Group object. The source and destinations need not be in the same file. If the source is a Group object, all objects contained in that group will be copied recursively. When the destination is a Group object, by default the target will be created in that group with its current name (basename of obj.name). You can override that by setting "name" to a string. There are various options which all default to "False": - shallow: copy only immediate members of a group. - expand_soft: expand soft links into new objects. - expand_external: expand external links into new objects. - expand_refs: copy objects that are pointed to by references. - without_attrs: copy object without copying attributes. Example: >>> f = File('myfile.hdf5') >>> f.listnames() ['MyGroup'] >>> f.copy('MyGroup', 'MyCopy') >>> f.listnames() ['MyGroup', 'MyCopy'] """ if isinstance(source, HLObject): source_path = '.' else: # Interpret source as a path relative to this group source_path = source source = self if isinstance(dest, Group): if name is not None: dest_path = name else: # copy source into dest group: dest_name/source_name dest_path = pp.basename(h5i.get_name(source[source_path].id)) elif isinstance(dest, HLObject): raise TypeError("Destination must be path or Group object") else: # Interpret destination as a path relative to this group dest_path = dest dest = self flags = 0 if shallow: flags |= h5o.COPY_SHALLOW_HIERARCHY_FLAG if expand_soft: flags |= h5o.COPY_EXPAND_SOFT_LINK_FLAG if expand_external: flags |= h5o.COPY_EXPAND_EXT_LINK_FLAG if expand_refs: flags |= h5o.COPY_EXPAND_REFERENCE_FLAG if without_attrs: flags |= h5o.COPY_WITHOUT_ATTR_FLAG if flags: copypl = h5p.create(h5p.OBJECT_COPY) copypl.set_copy_object(flags) else: copypl = None h5o.copy(source.id, self._e(source_path), dest.id, self._e(dest_path), copypl, base.dlcpl)
def name(self): """ Return the full name of this object. None if anonymous. """ return self._d(h5i.get_name(self.id))
def swap(old, new): """ Swap every dataset in old with the corresponding one in new Datasets in old that aren't in new are ignored. """ move_names = [] def _move(name, object): if isinstance(object, Dataset): if name in new: move_names.append(name) old.visititems(_move) for name in move_names: if new[name].is_virtual: # We cannot simply move virtual datasets, because they will still # point to the old raw_data location. So instead, we have to # recreate them, pointing to the new raw_data. oldd = old[name] newd = new[name] def _normalize(path): return path if path.endswith('/') else path + '/' def _replace_prefix(path, name1, name2): """Replace the prefix name1 with name2 in path""" name1 = _normalize(name1) name2 = _normalize(name2) return name2 + path[len(name1):] def _new_vds_layout(d, name1, name2): """Recreate a VirtualLayout for d, replacing name1 with name2 in the source dset name""" virtual_sources = d.virtual_sources() layout = VirtualLayout(d.shape, dtype=d.dtype) for vmap in virtual_sources: vspace, fname, dset_name, src_space = vmap assert dset_name.startswith(name1) dset_name = _replace_prefix(dset_name, name1, name2) fname = fname.encode('utf-8') new_vmap = VDSmap(vspace, fname, dset_name, src_space) # h5py 3.3 changed the VirtualLayout code. See # https://github.com/h5py/h5py/pull/1905. if hasattr(layout, 'sources'): layout.sources.append(new_vmap) else: layout.dcpl.set_virtual(vspace, fname, dset_name.encode('utf-8'), src_space) return layout old_layout = _new_vds_layout(oldd, old.name, new.name) new_layout = _new_vds_layout(newd, new.name, old.name) old_fillvalue = old[name].fillvalue new_fillvalue = new[name].fillvalue old_attrs = dict(old[name].attrs) new_attrs = dict(new[name].attrs) del old[name] old.create_virtual_dataset(name, new_layout, fillvalue=new_fillvalue) for k, v in new_attrs.items(): if isinstance(v, str) and v.startswith(new.name): v = _replace_prefix(v, new.name, old.name) old[name].attrs[k] = v del new[name] new.create_virtual_dataset(name, old_layout, fillvalue=old_fillvalue) for k, v in old_attrs.items(): if isinstance(v, str) and v.startswith(old.name): v = _replace_prefix(v, old.name, new.name) new[name].attrs[k] = v else: # Invalidate any InMemoryGroups that point to these groups delete = [] for bind in _groups: if get_name(bind) and ( get_name(bind).startswith(get_name(old.id)) or get_name(bind).startswith(get_name(new.id))): delete.append(bind) for d in delete: del _groups[d] old.move(name, pp.join(new.name, name + '__tmp')) new.move(name, pp.join(old.name, name)) new.move(name + '__tmp', name)