dims.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. # This file is part of h5py, a Python interface to the HDF5 library.
  2. #
  3. # http://www.h5py.org
  4. #
  5. # Copyright 2008-2013 Andrew Collette and contributors
  6. #
  7. # License: Standard 3-clause BSD; see "license.txt" for full license terms
  8. # and contributor agreement.
  9. """
  10. Implements support for HDF5 dimension scales.
  11. """
  12. import warnings
  13. from .. import h5ds
  14. from ..h5py_warnings import H5pyDeprecationWarning
  15. from . import base
  16. from .base import phil, with_phil
  17. from .dataset import Dataset
  18. class DimensionProxy(base.CommonStateObject):
  19. """
  20. Represents an HDF5 "dimension".
  21. """
  22. @property
  23. @with_phil
  24. def label(self):
  25. """ Get or set the dimension scale label """
  26. #return h5ds.get_label(self._id, self._dimension)
  27. # Produces a segfault for a non-existent label (Fixed in hdf5-1.8.8).
  28. # Here is a workaround:
  29. try:
  30. dset = Dataset(self._id)
  31. return dset.attrs['DIMENSION_LABELS'][self._dimension]
  32. except (KeyError, IndexError):
  33. return ''
  34. @label.setter
  35. @with_phil
  36. def label(self, val):
  37. # pylint: disable=missing-docstring
  38. h5ds.set_label(self._id, self._dimension, self._e(val))
  39. @with_phil
  40. def __init__(self, id_, dimension):
  41. self._id = id_
  42. self._dimension = dimension
  43. @with_phil
  44. def __hash__(self):
  45. return hash((type(self), self._id, self._dimension))
  46. @with_phil
  47. def __eq__(self, other):
  48. return hash(self) == hash(other)
  49. @with_phil
  50. def __iter__(self):
  51. for k in self.keys():
  52. yield k
  53. @with_phil
  54. def __len__(self):
  55. return h5ds.get_num_scales(self._id, self._dimension)
  56. @with_phil
  57. def __getitem__(self, item):
  58. if isinstance(item, int):
  59. scales = []
  60. h5ds.iterate(self._id, self._dimension, scales.append, 0)
  61. return Dataset(scales[item])
  62. else:
  63. def f(dsid):
  64. """ Iterate over scales to find a matching name """
  65. if h5ds.get_scale_name(dsid) == self._e(item):
  66. return dsid
  67. res = h5ds.iterate(self._id, self._dimension, f, 0)
  68. if res is None:
  69. raise KeyError(item)
  70. return Dataset(res)
  71. def attach_scale(self, dset):
  72. """ Attach a scale to this dimension.
  73. Provide the Dataset of the scale you would like to attach.
  74. """
  75. with phil:
  76. h5ds.attach_scale(self._id, dset.id, self._dimension)
  77. def detach_scale(self, dset):
  78. """ Remove a scale from this dimension.
  79. Provide the Dataset of the scale you would like to remove.
  80. """
  81. with phil:
  82. h5ds.detach_scale(self._id, dset.id, self._dimension)
  83. def items(self):
  84. """ Get a list of (name, Dataset) pairs with all scales on this
  85. dimension.
  86. """
  87. with phil:
  88. scales = []
  89. # H5DSiterate raises an error if there are no dimension scales,
  90. # rather than iterating 0 times. See #483.
  91. if len(self) > 0:
  92. h5ds.iterate(self._id, self._dimension, scales.append, 0)
  93. return [
  94. (self._d(h5ds.get_scale_name(x)), Dataset(x))
  95. for x in scales
  96. ]
  97. def keys(self):
  98. """ Get a list of names for the scales on this dimension. """
  99. with phil:
  100. return [key for (key, _) in self.items()]
  101. def values(self):
  102. """ Get a list of Dataset for scales on this dimension. """
  103. with phil:
  104. return [val for (_, val) in self.items()]
  105. @with_phil
  106. def __repr__(self):
  107. if not self._id:
  108. return "<Dimension of closed HDF5 dataset>"
  109. return ('<"%s" dimension %d of HDF5 dataset at %s>'
  110. % (self.label, self._dimension, id(self._id)))
  111. class DimensionManager(base.CommonStateObject):
  112. """
  113. Represents a collection of dimension associated with a dataset.
  114. Like AttributeManager, an instance of this class is returned when
  115. accessing the ".dims" property on a Dataset.
  116. """
  117. @with_phil
  118. def __init__(self, parent):
  119. """ Private constructor.
  120. """
  121. self._id = parent.id
  122. @with_phil
  123. def __getitem__(self, index):
  124. """ Return a Dimension object
  125. """
  126. if index > len(self) - 1:
  127. raise IndexError('Index out of range')
  128. return DimensionProxy(self._id, index)
  129. @with_phil
  130. def __len__(self):
  131. """ Number of dimensions associated with the dataset. """
  132. return len(Dataset(self._id).shape)
  133. @with_phil
  134. def __iter__(self):
  135. """ Iterate over the dimensions. """
  136. for i in range(len(self)):
  137. yield self[i]
  138. @with_phil
  139. def __repr__(self):
  140. if not self._id:
  141. return "<Dimensions of closed HDF5 dataset>"
  142. return "<Dimensions of HDF5 object at %s>" % id(self._id)
  143. def create_scale(self, dset, name=''):
  144. """ Create a new dimension, from an initial scale.
  145. Provide the dataset and a name for the scale.
  146. """
  147. warnings.warn("other_ds.dims.create_scale(ds, name) is deprecated. "
  148. "Use ds.make_scale(name) instead.",
  149. H5pyDeprecationWarning, stacklevel=2,
  150. )
  151. dset.make_scale(name)