diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 3a382d5..6081f94 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v3 diff --git a/pyfive/dataobjects.py b/pyfive/dataobjects.py index a2fe60b..0730e12 100644 --- a/pyfive/dataobjects.py +++ b/pyfive/dataobjects.py @@ -20,6 +20,9 @@ from .misc_low_level import Heap, SymbolTable, GlobalHeap, FractalHeap from .indexing import OrthogonalIndexer, ZarrArrayStub +# these constants happen to have the same value... +UNLIMITED_SIZE = UNDEFINED_ADDRESS + class DataObjects(object): """ @@ -182,7 +185,7 @@ def unpack_attribute(self, offset): offset += _padded_size(attr_dict['datatype_size'], padding_multiple) # read in the dataspace information - shape = determine_data_shape(self.msg_data, offset) + shape, maxshape = determine_data_shape(self.msg_data, offset) items = int(np.product(shape)) offset += _padded_size(attr_dict['dataspace_size'], padding_multiple) @@ -248,7 +251,16 @@ def shape(self): """ Shape of the dataset. """ msg = self.find_msg_type(DATASPACE_MSG_TYPE)[0] msg_offset = msg['offset_to_message'] - return determine_data_shape(self.msg_data, msg_offset) + shape, maxshape = determine_data_shape(self.msg_data, msg_offset) + return shape + + @property + def maxshape(self): + """ Maximum Shape of the dataset. (None for unlimited dimension) """ + msg = self.find_msg_type(DATASPACE_MSG_TYPE)[0] + msg_offset = msg['offset_to_message'] + shape, maxshape = determine_data_shape(self.msg_data, msg_offset) + return maxshape @property def fillvalue(self): @@ -779,9 +791,15 @@ def determine_data_shape(buf, offset): ndims = header['dimensionality'] dim_sizes = struct.unpack_from('<' + 'Q' * ndims, buf, offset) + offset += 8 * ndims # Dimension maximum size follows if header['flags'] bit 0 set + if header['flags'] & 2**0: + maxshape = struct.unpack_from('<' + 'Q' * ndims, buf, offset) + maxshape = tuple((None if d == UNLIMITED_SIZE else d) for d in maxshape) + else: + maxshape = dim_sizes # Permutation index follows if header['flags'] bit 1 set - return dim_sizes + return dim_sizes, maxshape # HDF5 Structures diff --git a/pyfive/high_level.py b/pyfive/high_level.py index e13bdc9..6614f3a 100644 --- a/pyfive/high_level.py +++ b/pyfive/high_level.py @@ -310,6 +310,11 @@ def shape(self): """ shape attribute. """ return self._dataobjects.shape + @property + def maxshape(self): + """ maxshape attribute. (None for unlimited dimensions) """ + return self._dataobjects.maxshape + @property def ndim(self): """ number of dimensions. """