summaryrefslogtreecommitdiff
path: root/silx/gui/hdf5/_utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'silx/gui/hdf5/_utils.py')
-rw-r--r--silx/gui/hdf5/_utils.py184
1 files changed, 163 insertions, 21 deletions
diff --git a/silx/gui/hdf5/_utils.py b/silx/gui/hdf5/_utils.py
index af9c79f..048aa20 100644
--- a/silx/gui/hdf5/_utils.py
+++ b/silx/gui/hdf5/_utils.py
@@ -28,11 +28,10 @@ package `silx.gui.hdf5` package.
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "26/04/2017"
+__date__ = "29/09/2017"
import logging
-import numpy
from .. import qt
import silx.io.utils
from silx.utils.html import escape
@@ -138,10 +137,61 @@ class H5Node(object):
:param Hdf5Item h5py_item: An Hdf5Item
"""
self.__h5py_object = h5py_item.obj
+ self.__h5py_target = None
self.__h5py_item = h5py_item
def __getattr__(self, name):
- return object.__getattribute__(self.__h5py_object, name)
+ if hasattr(self.__h5py_object, name):
+ attr = getattr(self.__h5py_object, name)
+ return attr
+ raise AttributeError("H5Node has no attribute %s" % name)
+
+ def __get_target(self, obj):
+ """
+ Return the actual physical target of the provided object.
+
+ Objects can contains links in the middle of the path, this function
+ check each groups and remove this prefix in case of the link by the
+ link of the path.
+
+ :param obj: A valid h5py object (File, group or dataset)
+ :type obj: h5py.Dataset or h5py.Group or h5py.File
+ :rtype: h5py.Dataset or h5py.Group or h5py.File
+ """
+ elements = obj.name.split("/")
+ if obj.name == "/":
+ return obj
+ elif obj.name.startswith("/"):
+ elements.pop(0)
+ path = ""
+ while len(elements) > 0:
+ e = elements.pop(0)
+ path = path + "/" + e
+ link = obj.parent.get(path, getlink=True)
+
+ if isinstance(link, h5py.ExternalLink):
+ subpath = "/".join(elements)
+ external_obj = obj.parent.get(self.basename + "/" + subpath)
+ return self.__get_target(external_obj)
+ elif silx.io.utils.is_softlink(link):
+ # Restart from this stat
+ path = ""
+ root_elements = link.path.split("/")
+ if link.path == "/":
+ root_elements = []
+ elif link.path.startswith("/"):
+ root_elements.pop(0)
+ for name in reversed(root_elements):
+ elements.insert(0, name)
+
+ return obj.file[path]
+
+ @property
+ def h5py_target(self):
+ if self.__h5py_target is not None:
+ return self.__h5py_target
+ self.__h5py_target = self.__get_target(self.__h5py_object)
+ return self.__h5py_target
@property
def h5py_object(self):
@@ -170,8 +220,18 @@ class H5Node(object):
return self.__h5py_object.name.split("/")[-1]
@property
+ def is_broken(self):
+ """Returns true if the node is a broken link.
+
+ :rtype: bool
+ """
+ if self.__h5py_item is None:
+ raise RuntimeError("h5py_item is not defined")
+ return self.__h5py_item.isBrokenObj()
+
+ @property
def local_name(self):
- """Returns the local path of this h5py node.
+ """Returns the path from the master file root to this node.
For links, this path is not equal to the h5py one.
@@ -183,34 +243,46 @@ class H5Node(object):
result = []
item = self.__h5py_item
while item is not None:
- if issubclass(item.h5pyClass, h5py.File):
+ # stop before the root item (item without parent)
+ if item.parent.parent is None:
+ name = item.obj.name
+ if name != "/":
+ result.append(item.obj.name)
break
- result.append(item.basename)
+ else:
+ result.append(item.basename)
item = item.parent
if item is None:
raise RuntimeError("The item does not have parent holding h5py.File")
if result == []:
return "/"
- result.append("")
+ if not result[-1].startswith("/"):
+ result.append("")
result.reverse()
- return "/".join(result)
+ name = "/".join(result)
+ return name
- def __file_item(self):
- """Returns the parent item holding the :class:`h5py.File` object
+ def __get_local_file(self):
+ """Returns the file of the root of this tree
:rtype: h5py.File
- :raises RuntimeException: If no file are found
"""
item = self.__h5py_item
- while item is not None:
- if issubclass(item.h5pyClass, h5py.File):
- return item
+ while item.parent.parent is not None:
+ class_ = item.h5pyClass
+ if class_ is not None and issubclass(class_, h5py.File):
+ break
item = item.parent
- raise RuntimeError("The item does not have parent holding h5py.File")
+
+ class_ = item.h5pyClass
+ if class_ is not None and issubclass(class_, h5py.File):
+ return item.obj
+ else:
+ return item.obj.file
@property
def local_file(self):
- """Returns the local :class:`h5py.File` object.
+ """Returns the master file in which is this node.
For path containing external links, this file is not equal to the h5py
one.
@@ -218,12 +290,11 @@ class H5Node(object):
:rtype: h5py.File
:raises RuntimeException: If no file are found
"""
- item = self.__file_item()
- return item.obj
+ return self.__get_local_file()
@property
def local_filename(self):
- """Returns the local filename of the h5py node.
+ """Returns the filename from the master file of this node.
For path containing external links, this path is not equal to the
filename provided by h5py.
@@ -235,13 +306,84 @@ class H5Node(object):
@property
def local_basename(self):
- """Returns the local filename of the h5py node.
+ """Returns the basename from the master file root to this node.
For path containing links, this basename can be different than the
basename provided by h5py.
:rtype: str
"""
- if issubclass(self.__h5py_item.h5pyClass, h5py.File):
+ class_ = self.__h5py_item.h5pyClass
+ if class_ is not None and issubclass(class_, h5py.File):
return ""
return self.__h5py_item.basename
+
+ @property
+ def physical_file(self):
+ """Returns the physical file in which is this node.
+
+ .. versionadded:: 0.6
+
+ :rtype: h5py.File
+ :raises RuntimeError: If no file are found
+ """
+ if isinstance(self.__h5py_object, h5py.ExternalLink):
+ # It means the link is broken
+ raise RuntimeError("No file node found")
+ if isinstance(self.__h5py_object, h5py.SoftLink):
+ # It means the link is broken
+ return self.local_file
+
+ physical_obj = self.h5py_target
+ return physical_obj.file
+
+ @property
+ def physical_name(self):
+ """Returns the path from the location this h5py node is physically
+ stored.
+
+ For broken links, this filename can be different from the
+ filename provided by h5py.
+
+ :rtype: str
+ """
+ if isinstance(self.__h5py_object, h5py.ExternalLink):
+ # It means the link is broken
+ return self.__h5py_object.path
+ if isinstance(self.__h5py_object, h5py.SoftLink):
+ # It means the link is broken
+ return self.__h5py_object.path
+
+ physical_obj = self.h5py_target
+ return physical_obj.name
+
+ @property
+ def physical_filename(self):
+ """Returns the filename from the location this h5py node is physically
+ stored.
+
+ For broken links, this filename can be different from the
+ filename provided by h5py.
+
+ :rtype: str
+ """
+ if isinstance(self.__h5py_object, h5py.ExternalLink):
+ # It means the link is broken
+ return self.__h5py_object.filename
+ if isinstance(self.__h5py_object, h5py.SoftLink):
+ # It means the link is broken
+ return self.local_file.filename
+
+ return self.physical_file.filename
+
+ @property
+ def physical_basename(self):
+ """Returns the basename from the location this h5py node is physically
+ stored.
+
+ For broken links, this basename can be different from the
+ basename provided by h5py.
+
+ :rtype: str
+ """
+ return self.physical_name.split("/")[-1]