[h5py] 50/455: API changes and redesign for 0.2 mostly complete
Ghislain Vaillant
ghisvail-guest at moszumanska.debian.org
Thu Jul 2 18:19:16 UTC 2015
This is an automated email from the git hooks/post-receive script.
ghisvail-guest pushed a commit to annotated tag 1.3.0
in repository h5py.
commit 5cc9201de74f3c89fdfca1f3818eb06bf3989a7f
Author: andrewcollette <andrew.collette at gmail.com>
Date: Fri Jun 13 05:10:29 2008 +0000
API changes and redesign for 0.2 mostly complete
---
h5py/h5a.pyx | 8 +--
h5py/h5d.pyx | 10 +--
h5py/h5f.pyx | 4 +-
h5py/h5p.pyx | 4 +-
h5py/h5s.pyx | 9 +--
h5py/h5t.pyx | 131 +++++++++++++++++++++-----------------
h5py/h5z.pyx | 2 +-
h5py/highlevel.py | 146 ++++++++++++++++++++++---------------------
h5py/std_defs.pxi | 2 +
h5py/std_inline.pyx | 19 ------
h5py/tests/__init__.py | 6 +-
h5py/tests/test_h5a.py | 4 +-
h5py/tests/test_highlevel.py | 59 +++++++++++++++++
h5py/utils.pxd | 1 +
h5py/utils.pyx | 7 +++
setup.py | 2 +-
16 files changed, 241 insertions(+), 173 deletions(-)
diff --git a/h5py/h5a.pyx b/h5py/h5a.pyx
index b2afc0e..d69ed32 100644
--- a/h5py/h5a.pyx
+++ b/h5py/h5a.pyx
@@ -92,7 +92,7 @@ def read(hid_t attr_id, ndarray arr_obj):
space_id = 0
try:
- mtype_id = h5t.py_dtype_to_h5t(arr_obj.dtype)
+ mtype_id = h5t.py_translate_dtype(arr_obj.dtype)
space_id = H5Aget_space(attr_id)
check_numpy_write(arr_obj, space_id)
@@ -121,7 +121,7 @@ def write(hid_t attr_id, ndarray arr_obj):
space_id = 0
try:
- mtype_id = h5t.py_dtype_to_h5t(arr_obj.dtype)
+ mtype_id = h5t.py_translate_dtype(arr_obj.dtype)
space_id = H5Aget_space(attr_id)
check_numpy_read(arr_obj, space_id)
@@ -254,7 +254,7 @@ def py_create(hid_t loc_id, char* name, object dtype_in, object shape):
try:
sid = h5s.create_simple(shape)
- type_id = h5t.py_dtype_to_h5t(dtype_in)
+ type_id = h5t.py_translate_dtype(dtype_in)
return create(loc_id, name, type_id, sid)
@@ -294,7 +294,7 @@ def py_dtype(hid_t attr_id):
try:
type_id = H5Aget_type(attr_id)
- return h5t.py_h5t_to_dtype(type_id)
+ return h5t.py_translate_h5t(type_id)
finally:
if type_id:
PY_H5Tclose(type_id)
diff --git a/h5py/h5d.pyx b/h5py/h5d.pyx
index 92c55c6..8875d53 100644
--- a/h5py/h5d.pyx
+++ b/h5py/h5d.pyx
@@ -117,7 +117,7 @@ def read(hid_t dset_id, hid_t mspace_id, hid_t fspace_id, ndarray arr_obj,
mtype_id = 0
try:
- mtype_id = h5t.py_dtype_to_h5t(arr_obj.dtype)
+ mtype_id = h5t.py_translate_dtype(arr_obj.dtype)
check_numpy_write(arr_obj, -1)
H5Dread(dset_id, mtype_id, mspace_id, fspace_id, plist, PyArray_DATA(arr_obj))
@@ -143,7 +143,7 @@ def write(hid_t dset_id, hid_t mspace_id, hid_t fspace_id, ndarray arr_obj,
mtype_id = 0
try:
- mtype_id = h5t.py_dtype_to_h5t(arr_obj.dtype)
+ mtype_id = h5t.py_translate_dtype(arr_obj.dtype)
check_numpy_read(arr_obj, -1)
H5Dwrite(dset_id, mtype_id, mspace_id, fspace_id, plist, PyArray_DATA(arr_obj))
@@ -282,7 +282,7 @@ def py_create(hid_t parent_id, char* name, object data=None, object dtype=None,
else:
space_id = h5s.create_simple(shape)
- type_id = h5t.py_dtype_to_h5t(dtype)
+ type_id = h5t.py_translate_dtype(dtype)
if( chunks or compression or shuffle or fletcher32):
plist = h5p.create(H5P_DATASET_CREATE)
@@ -354,7 +354,7 @@ def py_read_slab(hid_t ds_id, object start, object count,
# Obtain the Numpy dtype of the array
if dtype is None:
type_id = H5Dget_type(ds_id)
- dtype = h5t.py_h5t_to_dtype(type_id)
+ dtype = h5t.py_translate_h5t(type_id)
file_space = H5Dget_space(ds_id)
space_type = H5Sget_simple_extent_type(file_space)
@@ -499,7 +499,7 @@ def py_dtype(hid_t dset_id):
try:
type_id = H5Dget_type(dset_id)
- return h5t.py_h5t_to_dtype(type_id)
+ return h5t.py_translate_h5t(type_id)
finally:
if type_id:
PY_H5Tclose(type_id)
diff --git a/h5py/h5f.pyx b/h5py/h5f.pyx
index 20e316c..b9ba0bd 100644
--- a/h5py/h5f.pyx
+++ b/h5py/h5f.pyx
@@ -16,7 +16,7 @@
# Pyrex compile-time imports
from h5p cimport H5P_DEFAULT
-from utils cimport emalloc, efree
+from utils cimport emalloc, efree, pybool
# Runtime imports
import h5
@@ -95,7 +95,7 @@ def is_hdf5(char* name):
Determine if a given file is an HDF5 file. Note this raises an
exception if the file doesn't exist.
"""
- return bool(H5Fis_hdf5(name))
+ return pybool(H5Fis_hdf5(name))
def reopen(hid_t file_id):
""" (INT file_id) => INT new_file_id
diff --git a/h5py/h5p.pyx b/h5py/h5p.pyx
index 20864bb..33bf204 100644
--- a/h5py/h5p.pyx
+++ b/h5py/h5p.pyx
@@ -20,7 +20,7 @@ from h5d cimport H5D_layout_t
from h5z cimport H5Z_filter_t
from utils cimport require_tuple, convert_dims, convert_tuple, \
- emalloc, efree
+ emalloc, efree, pybool
# Runtime imports
import h5
@@ -77,7 +77,7 @@ def equal(hid_t plist1, hid_t plist2):
Compare two existing property lists or classes for equality.
"""
- return bool(H5Pequal(plist1, plist2))
+ return pybool(H5Pequal(plist1, plist2))
# === File creation ===========================================================
diff --git a/h5py/h5s.pyx b/h5py/h5s.pyx
index 999a3cc..a5cb8d6 100644
--- a/h5py/h5s.pyx
+++ b/h5py/h5s.pyx
@@ -12,14 +12,11 @@
"""
Low-level interface to the "H5S" family of data-space functions.
-
- This module is incomplete; it currently only implements hyperslab and
- scalar operations.
"""
# Pyrex compile-time imports
from utils cimport require_tuple, require_list, convert_dims, convert_tuple, \
- emalloc, efree
+ emalloc, efree, pybool
# Runtime imports
import h5
@@ -118,7 +115,7 @@ def is_simple(hid_t space_id):
Determine if an existing dataspace is "simple" (including scalar
dataspaces). Currently all HDF5 dataspaces are simple.
"""
- return bool(H5Sis_simple(space_id))
+ return pybool(H5Sis_simple(space_id))
def offset_simple(hid_t space_id, object offset=None):
""" (INT space_id, TUPLE offset=None)
@@ -317,7 +314,7 @@ def select_valid(hid_t space_id):
Determine if the current selection falls within the dataspace extent.
"""
- return bool(H5Sselect_valid(space_id))
+ return pybool(H5Sselect_valid(space_id))
# === Point selection functions ===============================================
diff --git a/h5py/h5t.pyx b/h5py/h5t.pyx
index adea4d3..121a8ff 100644
--- a/h5py/h5t.pyx
+++ b/h5py/h5t.pyx
@@ -18,37 +18,49 @@
dtype objects. Constants are also defined in this module for a variety
of HDF5 native types and classes. Points of interest:
- (1) Enumerations
- There is no native Numpy or Python type for enumerations. Since an
- enumerated type is simply a mapping between string names and integer
- values, I have implemented enum support through dictionaries. An HDF5
- H5T_ENUM type is converted to the appropriate Numpy integer type (e.g.
- <u4, etc.), and a dictionary mapping names to values is also generated.
- Since dtype objects cannot be subclassed (why?) and have no provision
- for directly attached metadata, the dtype is given a single named field
- ("enum") and the dictionary stored in the metadata for that field. An
- example dtype declaration for this is:
+ 1. Translation
+
+ The functions py_translate_h5t and py_translate_dtype do the heavy
+ lifting required to go between HDF5 datatype objects and Numpy dtypes.
+
+ Since the HDF5 library can represent a greater range of types than
+ Numpy, the conversion is asymmetric. Attempting to convert an HDF5
+ type to a Numpy dtype will result in a dtype object which matches
+ as closely as possible. In contrast, converting from a Numpy dtype
+ to an HDF5 type will always result in a precise, byte-compatible
+ description of the Numpy data layout.
+
+ 2. Complex numbers
+
+ Since HDF5 has no native complex types, and the native Numpy
+ representation is a struct with two floating-point members, complex
+ numbers are saved as HDF5 compound objects.
+
+ These compound objects have exactly two fields, with IEEE 32- or 64-
+ bit format, and default names "r" and "i". Since other conventions
+ exist for field naming, and in fact may be essential for compatibility
+ with external tools, new names can be specified as arguments to
+ both py_translate_* functions.
+
+ 3. Enumerations
+
+ There is no native Numpy or Python type for enumerations. Since an
+ enumerated type is simply a mapping between string names and integer
+ values, I have implemented enum support through dictionaries.
+
+ An HDF5 H5T_ENUM type is converted to the appropriate Numpy integer
+ type (e.g. <u4, etc.), and a dictionary mapping names to values is also
+ generated. This dictionary is attached to the dtype object via the
+ functions py_enum_attach and py_enum_recover.
+
+ The exact dtype declaration is given below; howeve, the py_enum*
+ functions should encapsulate almost all meaningful operations.
enum_dict = {'RED': 0L, 'GREEN': 1L}
dtype( ('<i4', [ ( (enum_dict, 'enum'), '<i4' )] ) )
^ ^ ^ ^
(main type) (metadata) (field name) (field type)
-
- The functions py_attach_enum and py_recover_enum simplify the attachment
- and recovery of enumeration dictionaries from integer dtype objects.
-
- (2) Complex numbers
- Since HDF5 has no native complex types defined, and the native Numpy
- representation is a struct with two floating-point members, complex
- numbers are saved as HDF5 compound objects with IEEE 32/64 floating point
- and field names (by default) "r" and "i". Complex numbers can be auto-
- recovered from HDF5 objects provided they match this format and have
- compatible field names. Since other people may have named their fields
- e.g. "img" and "real", these names can be changed. The API functions
- py_dtype_to_h5t and py_h5t_to_dtype take arguments which specify these
- names.
-
"""
# Pyrex compile-time imports
@@ -57,7 +69,7 @@ from h5p cimport H5P_DEFAULT
from h5e cimport err_c, pause_errors, resume_errors
from numpy cimport dtype, ndarray
-from utils cimport emalloc, efree, \
+from utils cimport emalloc, efree, pybool, \
create_ieee_complex64, create_ieee_complex128, \
require_tuple, convert_dims, convert_tuple
@@ -209,7 +221,7 @@ def equal(hid_t typeid_1, hid_t typeid_2):
Test whether two identifiers point to the same datatype object.
Note this does NOT perform any kind of logical comparison.
"""
- return bool(H5Tequal(typeid_1, typeid_2))
+ return pybool(H5Tequal(typeid_1, typeid_2))
def lock(hid_t type_id):
""" (INT type_id)
@@ -262,7 +274,7 @@ def detect_class(hid_t type_id, int classtype):
Determine if a member of the given class exists in a compound
datatype. The search is recursive.
"""
- return bool(H5Tdetect_class(type_id, <H5T_class_t>classtype))
+ return pybool(H5Tdetect_class(type_id, <H5T_class_t>classtype))
def close(hid_t type_id, int force=1):
""" (INT type_id, BOOL force=True)
@@ -332,7 +344,7 @@ def is_variable_str(hid_t type_id):
Please note that reading/writing data in this format is impossible;
only fixed-length strings are currently supported.
"""
- return bool(H5Tis_variable_str(type_id))
+ return pybool(H5Tis_variable_str(type_id))
# === Compound datatype operations ============================================
@@ -640,15 +652,16 @@ def _validate_names(names):
raise ValueError("Compound names must be given as a tuple of strings.")
-def py_h5t_to_dtype(hid_t type_id, object byteorder=None,
+def py_translate_h5t(hid_t type_id, object byteorder=None,
object compound_names=None, object complex_names=None):
""" (INT type_id, STRING byteorder=None, TUPLE compound_names=None.
TUPLE complex_names=None)
=> DTYPE
Create a Numpy dtype object as similar as possible to the given HDF5
- datatype object. The result is not guaranteed to be memory-compatible
- with the original datatype object.
+ datatype object. The result is guaranteed to be logically compatible
+ with the original object, with no loss of precision, but may not
+ implement the same memory layout as the HDF5 type.
Optional arguments:
@@ -734,7 +747,7 @@ def py_h5t_to_dtype(hid_t type_id, object byteorder=None,
try:
tmp_name = get_member_name(type_id, i)
field_names.append(tmp_name)
- field_types.append(py_h5t_to_dtype(tmp_id, byteorder,
+ field_types.append(py_translate_h5t(tmp_id, byteorder,
None, complex_names))
finally:
PY_H5Tclose(tmp_id)
@@ -772,16 +785,16 @@ def py_h5t_to_dtype(hid_t type_id, object byteorder=None,
# enum field entry carrying a dictionary as metadata
super_tid = H5Tget_super(type_id)
try:
- edct = py_enum_to_dict(type_id)
+ edct = py_translate_enum(type_id)
# Superclass must be an integer, so only provide byteorder.
- typeobj = py_attach_enum(edct, py_h5t_to_dtype(super_tid, byteorder))
+ typeobj = py_enum_attach(edct, py_translate_h5t(super_tid, byteorder))
finally:
PY_H5Tclose(super_tid)
elif classtype == H5T_ARRAY:
super_tid = get_super(type_id)
try:
- base_dtype = py_h5t_to_dtype(super_tid, byteorder, compound_names, complex_names)
+ base_dtype = py_translate_h5t(super_tid, byteorder, compound_names, complex_names)
finally:
PY_H5Tclose(super_tid)
shape = get_array_dims(type_id)
@@ -794,7 +807,7 @@ def py_h5t_to_dtype(hid_t type_id, object byteorder=None,
return typeobj
-def py_dtype_to_h5t(dtype dtype_in not None, object complex_names=None):
+def py_translate_dtype(dtype dtype_in not None, object complex_names=None):
""" ( DTYPE dtype_in, TUPLE complex_names=None) => INT type_id
Given a Numpy dtype object, generate a byte-for-byte memory-compatible
@@ -838,14 +851,14 @@ def py_dtype_to_h5t(dtype dtype_in not None, object complex_names=None):
# Check for enumerated type first
if (kind == c'u' or kind == c'i') and len(names) == 1 and names[0] == 'enum':
basetype = _code_map[dtype_in.str]
- type_out = py_dict_to_enum(py_recover_enum(dtype_in), basetype)
+ type_out = py_translate_dict(py_enum_recover(dtype_in), basetype)
# Otherwise it's just a compound type
else:
type_out = create(H5T_COMPOUND, length)
for name in dtype_in.names:
dt, offset = dtype_in.fields[name]
- tmp = py_dtype_to_h5t(dt, complex_names)
+ tmp = py_translate_dtype(dt, complex_names)
try:
insert(type_out, name, offset, tmp)
finally:
@@ -875,7 +888,7 @@ def py_dtype_to_h5t(dtype dtype_in not None, object complex_names=None):
elif kind == c'V':
if dtype_in.subdtype:
- basetype = py_dtype_to_h5t(dtype_in.subdtype[0], complex_names)
+ basetype = py_translate_dtype(dtype_in.subdtype[0], complex_names)
try:
type_out = array_create(basetype, dtype_in.subdtype[1])
finally:
@@ -894,7 +907,7 @@ def py_dtype_to_h5t(dtype dtype_in not None, object complex_names=None):
return type_out
-def py_enum_to_dict(hid_t type_id):
+def py_translate_enum(hid_t type_id):
""" (INT type_id) => DICT enum
Produce a dictionary in the format [STRING] => LONG from
@@ -911,11 +924,11 @@ def py_enum_to_dict(hid_t type_id):
return dictout
-def py_dict_to_enum(object enumdict, hid_t basetype):
- """ (DICT enum, INT base_type_id) => INT new_type_id
+def py_translate_dict(object enumdict, hid_t basetype):
+ """ (DICT enumdict, INT basetype) => INT new_type_id
- Create a new HDF5 enumeration from a Python dictionary in the format
- [string name] => long value, and an HDF5 base type
+ Create a new HDF5 enumeration from a Python dictionary in the
+ format [string name] => long value, and an HDF5 base type.
"""
cdef hid_t type_id
type_id = enum_create(basetype)
@@ -924,18 +937,19 @@ def py_dict_to_enum(object enumdict, hid_t basetype):
return type_id
-def py_attach_enum(object enumdict, object basetype):
+def py_enum_attach(object enumdict, object base_dtype):
""" (DICT enum, DTYPE base_dtype) => DTYPE new_dtype
Convert a Python dictionary in the format [string] => integer to a
- Numpy dtype with associated enum dictionary.
+ Numpy dtype with associated enum dictionary. Returns a new
+ dtype object; does not mutate the original.
"""
- return dtype( (basetype, [( (enumdict, 'enum'), basetype )] ) )
+ return dtype( (base_dtype, [( (enumdict, 'enum'), base_dtype )] ) )
-def py_recover_enum(dtype dtype_in):
+def py_enum_recover(dtype dtype_in):
""" (DTYPE dtype_with_enum) => DICT enum
- Extract the enum dictionary from a Numpy dtype object
+ Get the enum dictionary from a Numpy dtype object.
"""
cdef object names
names = dtype_in.names
@@ -949,8 +963,8 @@ def py_recover_enum(dtype dtype_in):
def py_list_compound_names(hid_t type_in):
""" (INT type_id) => LIST compound_names
- Obtain a Python list of member names for a compound or enumeration
- type.
+ Obtain a Python list of member names for a compound or
+ enumeration type.
"""
cdef int nmem
cdef int i
@@ -968,21 +982,22 @@ def py_can_convert_dtype(object dt, object complex_names=None):
Test whether the given Numpy dtype can be converted to the appropriate
memory-compatible HDF5 datatype. complex_names works as in the
- function h5t.py_dtype_to_h5t.
+ function h5t.py_translate_dtype.
"""
cdef hid_t tid
tid = 0
- can_convert = False
+
+ retval = None
try:
- tid = py_dtype_to_h5t(dt, complex_names)
- can_convert = True
+ tid = py_translate_dtype(dt, complex_names)
+ retval = True
except ValueError:
- pass
+ retval = False
if tid:
PY_H5Tclose(tid)
- return can_convert
+ return retval
PY_SIGN = DDict({H5T_SGN_NONE: "UNSIGNED", H5T_SGN_2: "SIGNED"})
diff --git a/h5py/h5z.pyx b/h5py/h5z.pyx
index fb29c01..18365fb 100644
--- a/h5py/h5z.pyx
+++ b/h5py/h5z.pyx
@@ -15,7 +15,7 @@
Filter API and constants
"""
# Pyrex compile-time imports
-include "std_inline.pyx"
+from utils cimport pybool
# Runtime imports
import h5
diff --git a/h5py/highlevel.py b/h5py/highlevel.py
index 09e8c2a..4f862b1 100644
--- a/h5py/highlevel.py
+++ b/h5py/highlevel.py
@@ -56,7 +56,7 @@ import h5d
import h5t
import h5a
import h5p
-from errors import H5Error
+from h5e import H5Error
# === Main classes (Dataset/Group/File) =======================================
@@ -78,7 +78,8 @@ class Dataset(object):
dtype A Numpy dtype representing the array data-type.
Writable properties:
- cnames: HDF5 compound names used for complex I/O
+ cnames: HDF5 compound names used for complex I/O. This can be
+ None, (), or a 2-tuple with ("realname", "imgname").
"""
# --- Properties (Dataset) ------------------------------------------------
@@ -110,24 +111,25 @@ class Dataset(object):
# --- Public interface (Dataset) ------------------------------------------
- def __init__(self, group, name, create=False,
+ def __init__(self, group, name,
data=None, dtype=None, shape=None,
chunks=None, compression=None, shuffle=False, fletcher32=False):
""" Create a new Dataset object. There are two modes of operation:
1. Open an existing dataset
- If "create" is false, open an existing dataset. An exception
- will be raised if it doesn't exist.
+ If you only supply the required parameters "group" and "name",
+ the object will attempt to open an existing HDF5 dataset.
2. Create a dataset
- If "create" is True, create a new dataset. You must supply
- *either* "data", which must be a Numpy array from which the
- shape, dtype and initial contents will be determined, or *both*
- "dtype" (Numpy dtype object) and "shape" (tuple of dimensions).
- Chunks/compression/shuffle/fletcher32 can also be specified.
+ You can supply either:
+ - Keyword "data"; a Numpy array from which the shape, dtype and
+ initial contents will be determined.
+ - Both "dtype" (Numpy dtype object) and "shape" (tuple of
+ dimensions).
- Creating a dataset will fail if another of the same name
- already exists.
+ Creating a dataset will fail if another of the same name already
+ exists. Also, chunks/compression/shuffle/fletcher32 may only be
+ specified when creating a dataset.
Creation keywords (* is default):
@@ -136,13 +138,13 @@ class Dataset(object):
shuffle: Use the shuffle filter? (requires compression) T/F*
fletcher32: Enable Fletcher32 error detection? T/F*
"""
- if create:
- self.id = h5d.py_create(group.id, name, data, shape,
- chunks, compression, shuffle, fletcher32)
- else:
+ if data is None and dtype is None and shape is None:
if any((data,dtype,shape,chunks,compression,shuffle,fletcher32)):
raise ValueError('You cannot specify keywords when opening a dataset.')
self.id = h5d.open(group.id, name)
+ else:
+ self.id = h5d.py_create(group.id, name, data, shape,
+ chunks, compression, shuffle, fletcher32)
self._attrs = AttributeManager(self)
self._byteorder = None
@@ -158,24 +160,27 @@ class Dataset(object):
ds[:] => All elements, regardless of dimension.
ds[0:3, 1:4, "a", "b"] => (3 x 3) slice, only including compound
- elements "a" and "b".
+ elements "a" and "b", in that order.
"""
start, count, stride, names = slicer(self.shape, args)
if names is not None and self.dtype.names is None:
- raise ValueError('This dataset has no named fields (requested "%s")' % ", ".join(names))
-
+ raise ValueError('This dataset has no named fields.')
tid = 0
try:
tid = h5d.get_type(self.id)
- dt = h5t.py_h5t_to_dtype(tid, byteorder=self._byteorder,
+ dt = h5t.py_translate_h5t(tid, byteorder=self._byteorder,
compound_names=names,
complex_names=self._cnames)
finally:
if tid != 0:
- h5t.close(tid, force=True)
+ h5t.close(tid)
- return h5d.py_read_slab(self.id, start, count, stride, dtype=dt)
+ arr = h5d.py_read_slab(self.id, start, count, stride, dtype=dt)
+ if names is not None and len(names) == 1:
+ # Match Numpy convention for recarray indexing
+ return arr[names[0]]
+ return arr
def __setitem__(self, args):
""" Write to the underlying array from an existing Numpy array. The
@@ -191,17 +196,15 @@ class Dataset(object):
h5d.py_write_slab(self.id, args[-1], start, stride)
def close(self):
- """ Force the HDF5 library to close and free this object. You
- shouldn't need to do this in normal operation; HDF5 objects are
- automatically closed when their Python counterparts are deallocated.
+ """ Force the HDF5 library to close and free this object. This
+ will be called automatically when the object is garbage collected,
+ if it hasn't already.
"""
h5d.close(self.id)
def __del__(self):
- try:
+ if h5i.get_type(self.id) == h5i.DATASET:
h5d.close(self.id)
- except H5Error:
- pass
def __str__(self):
return 'Dataset: '+str(self.shape)+' '+repr(self.dtype)
@@ -224,7 +227,7 @@ class Group(object):
the special case of a scalar dataset, a Numpy array scalar is
returned.
- - Setting items: See the __setitem__ docstring; the rules are:
+ - Setting items:
1. Existing Group or Dataset: create a hard link in this group
2. Numpy array: create a new dataset here, overwriting any old one
3. Anything else: try to create a Numpy array. Also works with
@@ -238,6 +241,9 @@ class Group(object):
- len(obj) returns the number of group members
"""
+ #: Provides access to HDF5 attributes. See AttributeManager docstring.
+ attrs = property(lambda self: self._attrs)
+
# --- Public interface (Group) --------------------------------------------
def __init__(self, parent_object, name, create=False):
@@ -247,14 +253,13 @@ class Group(object):
raising an exception if it doesn't exist. If "create" is True,
create a new HDF5 group and link it into the parent group.
"""
- self.id = 0
if create:
self.id = h5g.create(parent_object.id, name)
else:
self.id = h5g.open(parent_object.id, name)
#: Group attribute access (dictionary-style)
- self.attrs = AttributeManager(self)
+ self._attrs = AttributeManager(self)
def __delitem__(self, name):
""" Unlink a member from the HDF5 group.
@@ -276,20 +281,15 @@ class Group(object):
if isinstance(obj, Group) or isinstance(obj, Dataset):
h5g.link(self.id, name, h5i.get_name(obj.id), link_type=h5g.LINK_HARD)
- elif isinstance(obj, numpy.ndarray):
+ else:
+ if not isinstance(obj, numpy.ndarray):
+ obj = numpy.array(obj)
if h5t.py_can_convert_dtype(obj.dtype):
- dset = Dataset(self, name, data=obj, create=True)
+ dset = Dataset(self, name, data=obj)
dset.close()
else:
raise ValueError("Don't know how to store data of this type in a dataset: " + repr(obj.dtype))
- else:
- arr = numpy.array(obj)
- if h5t.py_can_convert_dtype(arr.dtype):
- dset = Dataset(self, name, data=arr, create=True)
- dset.close()
- else:
- raise ValueError("Don't know how to store data of this type in a dataset: " + repr(arr.dtype))
def __getitem__(self, name):
""" Retrive the Group or Dataset object. If the Dataset is scalar,
@@ -326,10 +326,8 @@ class Group(object):
h5g.close(self.id)
def __del__(self):
- try:
+ if h5i.get_type(self.id) == h5i.GROUP:
h5g.close(self.id)
- except H5Error:
- pass
def __str__(self):
return 'Group (%d members): ' % self.nmembers + ', '.join(['"%s"' % name for name in self])
@@ -341,13 +339,16 @@ class File(Group):
""" Represents an HDF5 file on disk.
+ Created with standard Python syntax File(name, mode), where mode may be
+ one of r, r+, w, w+, a.
+
File objects inherit from Group objects; Group-like methods all
operate on the HDF5 root group ('/'). Like Python file objects, you
must close the file ("obj.close()") when you're done with it.
"""
_modes = ('r','r+','w','w+','a')
-
+
# --- Public interface (File) ---------------------------------------------
def __init__(self, name, mode, noclobber=False):
@@ -366,20 +367,23 @@ class File(Group):
if not mode in self._modes:
raise ValueError("Invalid mode; must be one of %s" % ', '.join(self._modes))
- plist = h5p.create(h5p.CLASS_FILE_ACCESS)
+ plist = h5p.create(h5p.FILE_ACCESS)
try:
h5p.set_fclose_degree(plist, h5f.CLOSE_STRONG)
if mode == 'r':
- self.id = h5f.open(name, h5f.ACC_RDONLY, access_id=plist)
+ self.fid = h5f.open(name, h5f.ACC_RDONLY, access_id=plist)
elif 'r' in mode or 'a' in mode:
- self.id = h5f.open(name, h5f.ACC_RDWR, access_id=plist)
+ self.fid = h5f.open(name, h5f.ACC_RDWR, access_id=plist)
elif noclobber:
- self.id = h5f.create(name, h5f.ACC_EXCL, access_id=plist)
+ self.fid = h5f.create(name, h5f.ACC_EXCL, access_id=plist)
else:
- self.id = h5f.create(name, h5f.ACC_TRUNC, access_id=plist)
+ self.fid = h5f.create(name, h5f.ACC_TRUNC, access_id=plist)
finally:
h5p.close(plist)
+ self.id = self.fid # So the Group constructor can find it.
+ Group.__init__(self, self, '/')
+
# For __str__ and __repr__
self.filename = name
self.mode = mode
@@ -389,12 +393,16 @@ class File(Group):
""" Close this HDF5 object. Note that any further access to objects
defined in this file will raise an exception.
"""
- h5f.close(self.id)
+ if h5i.get_type(self.fid) != h5i.FILE:
+ raise IOError("File is already closed.")
+
+ Group.close(self)
+ h5f.close(self.fid)
def flush(self):
""" Instruct the HDF5 library to flush disk buffers for this file.
"""
- h5f.flush(self.id)
+ h5f.flush(self.fid)
def __del__(self):
""" This docstring is here to remind you that THE HDF5 FILE IS NOT
@@ -453,7 +461,8 @@ class AttributeManager(object):
return h5a.get_num_attrs(self.id)
def __iter__(self):
- return h5a.py_listattrs(self.id)
+ for name in h5a.py_listattrs(self.id):
+ yield name
def iteritems(self):
for name in self:
@@ -467,19 +476,19 @@ class NamedType(object):
""" Represents a named datatype, stored in a file.
HDF5 datatypes are typically represented by their Numpy dtype
- equivalents; this class exists mainly to provide access to attributes
+ equivalents; this class exists only to provide access to attributes
stored on HDF5 named types. Properties:
dtype: Equivalent Numpy dtype for this HDF5 type
attrs: AttributeManager instance for attribute access
- Mutating the returned dtype object has no effect on the underlying
- HDF5 datatype.
+ Like dtype objects, these are immutable; the worst you can do it
+ unlink them from their parent group.
"""
def _get_dtype(self):
if self._dtype is None:
- self._dtype = h5t.py_h5t_to_dtype(self.id)
+ self._dtype = h5t.py_translate_h5t(self.id)
return self._dtype
dtype = property(_get_dtype)
@@ -499,7 +508,7 @@ class NamedType(object):
if dtype is not None:
dtype = numpy.dtype(dtype)
- tid = h5t.py_dtype_to_h5t(dtype)
+ tid = h5t.py_translate_dtype(dtype)
try:
h5t.commit(group.id, name, tid)
finally:
@@ -509,18 +518,16 @@ class NamedType(object):
self.attrs = AttributeManager(self)
def close(self):
- """ Force the library to close this object. Not ordinarily required.
+ """ Force the library to close this object. It will still exist
+ in the file.
"""
if self.id is not None:
h5t.close(self.id)
+ self.id = None
def __del__(self):
if self.id is not None:
- try:
- h5t.close(self.id)
- except H5Error:
- pass
-
+ h5t.close(self.id)
# === Browsing and interactivity ==============================================
@@ -614,7 +621,7 @@ class _H5Cmd(cmd.Cmd):
for name in self.group:
outstring = name
type_code = h5g.get_objinfo(self.group.id, name).type
- if type_code == h5g.OBJ_GROUP:
+ if type_code == h5g.GROUP:
outstring += "/"
if extended:
@@ -664,7 +671,7 @@ class _H5Cmd(cmd.Cmd):
def complete_cd(self, text, line, begidx, endidx):
return [x for x in self.group if x.find(text)==0 \
- and h5g.get_objinfo(self.group.id,x).type == h5g.OBJ_GROUP]
+ and h5g.get_objinfo(self.group.id,x).type == h5g.GROUP]
def help_cd(self):
print ""
@@ -706,16 +713,16 @@ def _open_arbitrary(group_obj, name):
"""
info = h5g.get_objinfo(group_obj.id, name)
- if info.type == h5g.OBJ_GROUP: # group
+ if info.type == h5g.GROUP: # group
return Group(group_obj, name)
- elif info.type == h5g.OBJ_DATASET: # dataset
+ elif info.type == h5g.DATASET: # dataset
return Dataset(group_obj, name)
- elif info.type == h5g.OBJ_DATATYPE: # named type
+ elif info.type == h5g.DATATYPE: # named type
return NamedDatatype(group_obj, name)
- raise NotImplementedError('Object type "%s" unsupported by the high-level interface.' % h5g.OBJ_MAPPER[info.type])
+ raise NotImplementedError('Object type "%s" unsupported by the high-level interface.' % h5g.PY_TYPE[info.type])
def slicer(shape, args):
""" Processes arguments to __getitem__ methods.
@@ -815,7 +822,6 @@ def slicer(shape, args):
start.append(ss)
stride.append(st)
count.append(cc)
- slices.append(arg)
return (tuple(start), tuple(count), tuple(stride), names)
diff --git a/h5py/std_defs.pxi b/h5py/std_defs.pxi
index 13aeb16..1dd4ab5 100644
--- a/h5py/std_defs.pxi
+++ b/h5py/std_defs.pxi
@@ -12,6 +12,8 @@
# "Boilerplate" includes which are so common I don't want to repeat them
# in every file. These include all basic HDF5 and C typedefs.
+# This file is designed to be included in *.pxd files; only definitions
+# are allowed.
from h5 cimport hid_t, hbool_t, herr_t, htri_t, hsize_t, \
hssize_t, haddr_t, hvl_t
diff --git a/h5py/std_inline.pyx b/h5py/std_inline.pyx
deleted file mode 100644
index 375288f..0000000
--- a/h5py/std_inline.pyx
+++ /dev/null
@@ -1,19 +0,0 @@
-#+
-#
-# This file is part of h5py, a low-level Python interface to the HDF5 library.
-#
-# Copyright (C) 2008 Andrew Collette
-# http://h5py.alfven.org
-# License: BSD (See LICENSE.txt for full license)
-#
-# $Date$
-#
-#-
-
-# Simple defs which aren't worth putting in their own module.
-
-cdef object pybool(long val):
- # It seems Pyrex's bool() actually returns some sort of int.
- if val:
- return True
- return False
diff --git a/h5py/tests/__init__.py b/h5py/tests/__init__.py
index 0b2c914..f7f5501 100644
--- a/h5py/tests/__init__.py
+++ b/h5py/tests/__init__.py
@@ -13,13 +13,13 @@
import unittest
import sys
import test_h5a, test_h5f, test_h5i, test_h5d, \
- test_h5g, test_h5, test_h5s, test_h5p
+ test_h5g, test_h5, test_h5s, test_h5p, test_highlevel
-from h5py import h5a, h5f, h5g, h5d, h5s, h5i, h5z, h5p#, highlevel
+from h5py import h5a, h5f, h5g, h5d, h5s, h5i, h5z, h5p, highlevel
TEST_CASES = (test_h5a.TestH5A, test_h5f.TestH5F, test_h5g.TestH5G,
test_h5i.TestH5I, test_h5d.TestH5D, test_h5.TestH5,
- test_h5s.TestH5S, test_h5p.TestH5P)
+ test_h5s.TestH5S, test_h5p.TestH5P, test_highlevel.TestHighlevel)
def buildsuite(cases):
diff --git a/h5py/tests/test_h5a.py b/h5py/tests/test_h5a.py
index ba7c1d8..e8beb4e 100644
--- a/h5py/tests/test_h5a.py
+++ b/h5py/tests/test_h5a.py
@@ -54,7 +54,7 @@ class TestH5A(unittest.TestCase):
arr_fail = ones((15,15), dtype=dt)
sid = h5s.create(h5s.SCALAR)
- tid = h5t.py_dtype_to_h5t(dt)
+ tid = h5t.py_translate_dtype(dt)
aid = h5a.create(obj, name, tid, sid)
self.assert_(self.is_attr(aid))
@@ -163,7 +163,7 @@ class TestH5A(unittest.TestCase):
for name, (value, dt, shape) in ATTRIBUTES.iteritems():
aid = h5a.open_name(self.obj, name)
tid = h5a.get_type(aid)
- supposed_dtype = h5t.py_h5t_to_dtype(tid)
+ supposed_dtype = h5t.py_translate_h5t(tid)
self.assertEqual(supposed_dtype, dt)
h5t.close(tid)
h5a.close(aid)
diff --git a/h5py/tests/test_highlevel.py b/h5py/tests/test_highlevel.py
new file mode 100644
index 0000000..e4c0996
--- /dev/null
+++ b/h5py/tests/test_highlevel.py
@@ -0,0 +1,59 @@
+#+
+#
+# This file is part of h5py, a low-level Python interface to the HDF5 library.
+#
+# Copyright (C) 2008 Andrew Collette
+# http://h5py.alfven.org
+# License: BSD (See LICENSE.txt for full license)
+#
+# $Date$
+#
+#-
+
+import unittest
+import os
+from numpy import all
+
+import h5py
+from h5py.highlevel import *
+
+# --- Description of the PyTables test file smpl_compound_chunked -------------
+
+HDFNAME2 = os.path.join(os.path.dirname(h5py.__file__), 'tests/data/smpl_compound_chunked.hdf5')
+DTYPE = numpy.dtype([('a_name','>i4'),
+ ('c_name','|S6'),
+ ('d_name', numpy.dtype( ('>i2', (5,10)) )),
+ ('e_name', '>f4'),
+ ('f_name', numpy.dtype( ('>f8', (10,)) )),
+ ('g_name', '<u1')])
+SHAPE = (6,)
+
+basearray = numpy.ndarray(SHAPE, dtype=DTYPE)
+for i in range(SHAPE[0]):
+ basearray[i]["a_name"] = i,
+ basearray[i]["c_name"] = "Hello!"
+ basearray[i]["d_name"][:] = numpy.sum(numpy.indices((5,10)),0) + i # [:] REQUIRED for some stupid reason
+ basearray[i]["e_name"] = 0.96*i
+ basearray[i]["f_name"][:] = numpy.array((1024.9637*i,)*10)
+ basearray[i]["g_name"] = 109
+
+names = ("a_name","c_name","d_name","e_name","f_name","g_name")
+
+class TestHighlevel(unittest.TestCase):
+
+
+ def test_ds(self):
+ myfile = File(HDFNAME2,'r')
+ try:
+ ds = myfile["CompoundChunked"]
+ for i in range(6):
+ self.assert_(all(ds[i]==basearray[i]), "%d"%i)
+ for name in names:
+ self.assert_(all(ds[name]==basearray[name]))
+ finally:
+ myfile.close()
+
+
+
+
+
diff --git a/h5py/utils.pxd b/h5py/utils.pxd
index 7a88189..96bd74e 100644
--- a/h5py/utils.pxd
+++ b/h5py/utils.pxd
@@ -36,4 +36,5 @@ cdef extern from "utils_low.h":
cdef int require_tuple(object tpl, int none_allowed, int size, char* name) except -1
cdef int require_list(object lst, int none_allowed, int size, char* name) except -1
+cdef object pybool(long long val)
diff --git a/h5py/utils.pyx b/h5py/utils.pyx
index 38c2da7..02a54a1 100644
--- a/h5py/utils.pyx
+++ b/h5py/utils.pyx
@@ -50,6 +50,13 @@ cdef int require_list(object lst, int none_allowed, int size, char* name) except
PyErr_SetString(ValueError, msg)
return -1
+cdef object pybool(long long val):
+ # It seems Pyrex's bool() actually returns some sort of int.
+ # This is OK for C, but ugly in Python.
+ if val:
+ return True
+ return False
+
diff --git a/setup.py b/setup.py
index 39bfbe7..81e7c76 100644
--- a/setup.py
+++ b/setup.py
@@ -205,7 +205,7 @@ pyx_library_dirs = ['/usr/lib', '/usr/local/lib']
pyx_library_dirs.extend(custom_library_dirs)
# Additional compiler flags for Pyrex code
-pyx_extra_args = ['-Wno-unused', '-DH5_USE_16_API']
+pyx_extra_args = ['-Wno-unused', '-Wno-uninitialized', '-DH5_USE_16_API']
extra_link_args = []
extra_compile_args = pyx_extra_args
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/h5py.git
More information about the debian-science-commits
mailing list