[h5py] 73/455: Minor fixes

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Thu Jul 2 18:19:19 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 79874575ac733928d9ab8e79580b0a7ac1a76519
Author: andrewcollette <andrew.collette at gmail.com>
Date:   Wed Jul 9 22:58:16 2008 +0000

    Minor fixes
---
 MANIFEST.in            |  2 +-
 README.txt             |  4 +++
 h5py/h5a.pyx           | 21 ++++++++++++-
 h5py/h5t.pyx           |  5 +++
 h5py/highlevel.py      | 82 +++++++++++++++++++++++++++++++++++++-------------
 h5py/tests/test_h5a.py |  4 +++
 setup.py               | 52 ++++++++++++++++----------------
 7 files changed, 121 insertions(+), 49 deletions(-)

diff --git a/MANIFEST.in b/MANIFEST.in
index 13a5cf4..859cf56 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -3,7 +3,7 @@ include LICENSE.txt
 include README.txt
 include VERSION.txt
 include docs.cfg
-recursive-include h5py *.py *.pyx *.pxd *.h *.c *.hdf5
+recursive-include h5py *.py *.pyx *.pxd *.pxi *.h *.c *.hdf5
 recursive-include licenses *
 recursive-include docs *
 
diff --git a/README.txt b/README.txt
index 623a3ca..65ff137 100644
--- a/README.txt
+++ b/README.txt
@@ -7,6 +7,10 @@ Copyright (c) 2008 Andrew Collette
 
 Version 0.2.0
 
+* `Introduction`_
+* `Features`_
+* `Installation`_
+
 Introduction
 ============
 
diff --git a/h5py/h5a.pyx b/h5py/h5a.pyx
index 2d03d75..58d1e47 100644
--- a/h5py/h5a.pyx
+++ b/h5py/h5a.pyx
@@ -21,7 +21,7 @@ from h5s cimport SpaceID, H5Sclose
 
 from numpy cimport import_array, ndarray, PyArray_DATA
 from utils cimport  check_numpy_read, check_numpy_write, \
-                    emalloc, efree
+                    emalloc, efree, pybool
 
 # Runtime imports
 import h5
@@ -132,6 +132,25 @@ def py_listattrs(ObjectID loc not None):
     H5Aiterate(loc.id, &i, <H5A_operator_t>list_cb, retlist)
     return retlist
 
+cdef herr_t cb_exist(hid_t loc_id, char* attr_name, object ref_name):
+
+    if ref_name == attr_name:
+        return 1
+    return 0
+
+def py_exists(ObjectID loc not None, object ref_name):
+    """ (ObjectID loc, STRING ref_name)
+
+        Determine if an attribute named "ref_name" is attached to this object.
+    """
+    cdef unsigned int i
+    cdef herr_t retval
+    i=0
+
+    retval = H5Aiterate(loc.id, &i, <H5A_operator_t>cb_exist, ref_name)
+    
+    return pybool(retval)
+        
 # === Attribute class & methods ===============================================
 
 cdef class AttrID(ObjectID):
diff --git a/h5py/h5t.pyx b/h5py/h5t.pyx
index 6bfcde3..c79b1fb 100644
--- a/h5py/h5t.pyx
+++ b/h5py/h5t.pyx
@@ -48,6 +48,11 @@
         calls, which are presented as methods of class TypeEnumID.
         Additionally, the py_create function allows you to create HDF5
         enumerated types by passing in a dictionary along with a Numpy dtype.
+
+    4. Variable-length types
+
+        VLEN types, including VLEN strings, are not currently supported.
+        This may eventually change.
 """
 
 include "conditions.pxi"
diff --git a/h5py/highlevel.py b/h5py/highlevel.py
index f4e9da8..b44fa49 100644
--- a/h5py/highlevel.py
+++ b/h5py/highlevel.py
@@ -90,13 +90,13 @@ class Group(HLObject):
 
         The len() of a group is the number of members, and iterating over a
         group yields the names of its members, in arbitary library-defined
-        order.
+        order.  They also support the __contains__ syntax ("if name in group").
 
         Subgroups and datasets can be created via the convenience functions
         create_group and create_dataset, as well as by calling the appropriate
         class constructor.
 
-        Group attributes are accessed via Group.attrs; see the docstring for
+        Group attributes are accessed via group.attrs; see the docstring for
         the AttributeManager class.
     """
 
@@ -133,6 +133,15 @@ class Group(HLObject):
                 Attempt to convert it to an ndarray and store it.  Scalar
                 values are stored as scalar datasets. Raise ValueError if we
                 can't understand the resulting array dtype.
+            
+            If a group member of the same name already exists, the assignment
+            will fail.  You can check by using the Python __contains__ syntax:
+
+                if "name" in grp:
+                    del grp["name"]
+                grp["name"] = <whatever>
+
+            This limitation is intentional, and may be lifted in the future.
         """
         if isinstance(obj, Group) or isinstance(obj, Dataset) or isinstance(obj, Datatype):
             self.id.link(name, h5i.get_name(obj.id), link_type=h5g.LINK_HARD)
@@ -170,17 +179,19 @@ class Group(HLObject):
         self.id.unlink(name)
 
     def __len__(self):
+        """ Number of members attached to this group """
         return self.id.get_num_objs()
 
+    def __contains__(self, name):
+        """ Test if a member name exists """
+        return self.id.py_exists(name)
+
     def __iter__(self):
+        """ Iterate over member names """
         return self.id.py_iter()
 
-    def __str__(self):
-        if self.id._valid:
-            return 'Group "%s" (%d members)' % (hbasename(self.name), len(self))
-        return "Closed group"
-
     def iteritems(self):
+        """ Iterate over the group members as (name, value) pairs """
         for name in self:
             yield (name, self[name])
 
@@ -224,6 +235,12 @@ class Group(HLObject):
             outstr += '\nComment:\n'+cmnt
         return outstr
         
+    def __str__(self):
+        if self.id._valid:
+            return 'Group "%s" (%d members)' % (hbasename(self.name), len(self))
+        return "Closed group"
+
+
 class File(Group):
 
     """ Represents an HDF5 file on disk.
@@ -373,7 +390,7 @@ class Dataset(HLObject):
     def __init__(self, group, name,
                     data=None, dtype=None, shape=None, 
                     chunks=None, compression=None, shuffle=False, fletcher32=False):
-        """ Create a Dataset object.  You might find it easier to use the
+        """ Construct a Dataset object.  You might find it easier to use the
             Group methods: Group["name"] or Group.create_dataset().
 
             There are two modes of operation for this constructor:
@@ -383,7 +400,7 @@ class Dataset(HLObject):
                 the object will attempt to open an existing HDF5 dataset.
 
             2.  Create a dataset
-                You can supply either:
+                You supply "group", "name" and 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 
@@ -433,12 +450,12 @@ class Dataset(HLObject):
         self._attrs = AttributeManager(self)
 
     def __getitem__(self, args):
-        """ Read a slice from the underlying HDF5 array.  Takes slices and
+        """ Read a slice from the HDF5 dataset.  Takes slices and
             recarray-style field names (more than one is allowed!) in any
             order.
 
             For a compound dataset ds, with shape (10,10,5) and fields "a", "b" 
-            and "c", the following are all legal subscripts:
+            and "c", the following are all legal syntax:
 
             ds[1,2,3]
             ds[1,2,:]
@@ -446,7 +463,7 @@ class Dataset(HLObject):
             ds[1]
             ds[:]
             ds[1,2,3,"a"]
-            ds[0:5:2, 0:6:3, 0:2, "a", "b"]
+            ds[0:5:2, ..., 0:2, "a", "b"]
         """
         start, count, stride, names = slicer(self.shape, args)
 
@@ -496,10 +513,9 @@ class Dataset(HLObject):
         return arr
 
     def __setitem__(self, args):
-        """ Write to the underlying array from an existing Numpy array.  The
-            shape of the Numpy array must match the shape of the selection,
-            and the Numpy array's datatype must be convertible to the HDF5
-            array's datatype.
+        """ Write to the HDF5 dataset from an Numpy array.  The shape of the
+            Numpy array must match the shape of the selection, and the Numpy
+            array's datatype must be convertible to the HDF5 datatype.
         """
         val = args[-1]
         args = args[0:-1]
@@ -539,7 +555,13 @@ class AttributeManager(object):
         array.  Non-scalar data is always returned as an ndarray.
 
         The len() of this object is the number of attributes; iterating over
-        it yields the attribute names.
+        it yields the attribute names.  They also support the __contains__
+        syntax ("if name in obj.attrs...").
+
+        Unlike groups, writing to an attribute will overwrite an existing
+        attribute of the same name.  This is not a transacted operation; you
+        can lose data if you try to assign an object which h5py doesn't
+        understand.
     """
 
     def __init__(self, parent):
@@ -548,6 +570,10 @@ class AttributeManager(object):
         self.id = parent.id
 
     def __getitem__(self, name):
+        """ Read the value of an attribute.  If the attribute is scalar, it
+            will be returned as a Numpy scalar.  Otherwise, it will be returned
+            as a Numpy ndarray.
+        """
         attr = h5a.open_name(self.id, name)
 
         arr = numpy.ndarray(attr.shape, dtype=attr.dtype)
@@ -558,34 +584,48 @@ class AttributeManager(object):
         return arr
 
     def __setitem__(self, name, value):
+        """ Set the value of an attribute, overwriting any previous value.
+            The value you provide must be convertible to a Numpy array or
+            scalar.  If it's not, the action is aborted with no data loss.
+
+            Any existing value is destroyed just before the call to h5a.create.
+            If the creation fails, the data is not recoverable.
+        """
         if not isinstance(value, numpy.ndarray):
             value = numpy.array(value)
 
         space = h5s.create_simple(value.shape)
         htype = h5t.py_create(value.dtype)
 
-        # TODO: some kind of transaction safeguard here
-        try:
+        # TODO: some kind of transactions safeguard
+        if name in self:
             h5a.delete(self.id, name)
-        except H5Error:
-            pass
+
         attr = h5a.create(self.id, name, htype, space)
         attr.write(value)
 
     def __delitem__(self, name):
+        """ Delete an attribute (which must already exist). """
         h5a.delete(self.id, name)
 
     def __len__(self):
+        """ Number of attributes attached to the object. """
         return h5a.get_num_attrs(self.id)
 
     def __iter__(self):
+        """ Iterate over the names of attributes. """
         for name in h5a.py_listattrs(self.id):
             yield name
 
     def iteritems(self):
+        """ Iterate over (name, value) tuples. """
         for name in self:
             yield (name, self[name])
 
+    def __contains__(self, name):
+        """ Determine if an attribute exists, by name. """
+        return h5a.py_exists(self.id, name)
+
     def __str__(self):
         if self.id._valid:
             rstr = 'Attributes of "%s": ' % hbasename(h5i.get_name(self.id))
diff --git a/h5py/tests/test_h5a.py b/h5py/tests/test_h5a.py
index 28dd6c0..94df76e 100644
--- a/h5py/tests/test_h5a.py
+++ b/h5py/tests/test_h5a.py
@@ -197,6 +197,10 @@ class TestH5A(unittest.TestCase):
 
         self.assertEqual(attrlist, ATTRIBUTES_ORDER)
 
+    def test_py_exists(self):
+
+        self.assert_(h5a.py_exists(self.obj, ATTRIBUTES_ORDER[0]))
+        self.assert_(not h5a.py_exists(self.obj, "Something else"))
 
 
 
diff --git a/setup.py b/setup.py
index 8ec510c..52bd43c 100644
--- a/setup.py
+++ b/setup.py
@@ -82,10 +82,10 @@ def warn(instring):
 
 # === Parse command line arguments ============================================
 
-ENABLE_PYREX = False
-PYREX_ONLY = False
-PYREX_FORCE = False
-PYREX_FORCE_OFF = False
+ENABLE_PYREX = False        # Flag: Pyrex must be run
+PYREX_ONLY = False          # Flag: Run Pyrex, but don't perform build
+PYREX_FORCE = False         # Flag: Disable Pyrex timestamp checking
+PYREX_FORCE_OFF = False     # Flag: Don't run Pyrex, no matter what
 
 API_VERS = (1,6)
 DEBUG_LEVEL = 0
@@ -106,6 +106,7 @@ for arg in sys.argv[:]:
         PYREX_FORCE_OFF = True
         sys.argv.remove(arg)
     elif arg.find('--api=') == 0:
+        ENABLE_PYREX=True
         api = arg[6:]
         if api == '16':
             API_VERS = (1,6)
@@ -113,6 +114,7 @@ for arg in sys.argv[:]:
             fatal('Unrecognized API version "%s" (only "16" currently allowed)' % api)
         sys.argv.remove(arg)
     elif arg.find('--debug=') == 0:
+        ENABLE_PYREX=True
         DEBUG_LEVEL = int(arg[8:])
         sys.argv.remove(arg)
 
@@ -177,40 +179,38 @@ extra_compile_args = pyx_extra_args
 # Pyrex source files (without extension)
 pyrex_sources = [os.path.join(pyx_src_path, x) for x in pyx_modules]
 
-# Check if the conditions.pxi file is up-to-date
-cond_path = os.path.join(pyx_src_path, 'conditions.pxi')
-cond = \
-"""
-%s
-
-DEF H5PY_API_MAJ = %d
-DEF H5PY_API_MIN = %d
-DEF H5PY_DEBUG = %d
-DEF H5PY_API = "%d.%d"
-""" % (AUTO_HDR, API_VERS[0], API_VERS[1], DEBUG_LEVEL,API_VERS[0], API_VERS[1])
-
-try:
-    cond_file = open(cond_path,'r')
-    cond_present = cond_file.read()
-    cond_file.close()
-    if cond_present != cond:
-        ENABLE_PYREX = True
-except IOError:
-    ENABLE_PYREX = True
-    cond_present = ""
-
 # If for some reason the .c files are missing, Pyrex is required.
 if not all([os.path.exists(x+'.c') for x in pyrex_sources]):
     ENABLE_PYREX = True
 
 if ENABLE_PYREX and not PYREX_FORCE_OFF:
     print "Running Pyrex..."
+
     try:
         from Pyrex.Compiler.Main import Version
 
         if Version.version >= MIN_PYREX:
             from Pyrex.Compiler.Main import compile_multiple, CompilationOptions
 
+            # Check if the conditions.pxi file is up-to-date
+            cond_path = os.path.join(pyx_src_path, 'conditions.pxi')
+            cond = \
+"""
+%s
+
+DEF H5PY_API_MAJ = %d
+DEF H5PY_API_MIN = %d
+DEF H5PY_DEBUG = %d
+DEF H5PY_API = "%d.%d"
+""" % (AUTO_HDR, API_VERS[0], API_VERS[1], DEBUG_LEVEL,API_VERS[0], API_VERS[1])
+
+            try:
+                cond_file = open(cond_path,'r')
+                cond_present = cond_file.read()
+                cond_file.close()
+            except IOError:
+                cond_present = ""
+
             # If we regenerate the file every time, Pyrex's timestamp checking
             # is useless.  So only replace it if it's out of date.
             if cond_present != cond:

-- 
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