Changeset 1252


Ignore:
Timestamp:
Mar 21, 2013 1:28:00 PM (9 years ago)
Author:
jemian
Message:

improve the test for a valid NeXus? data file, refactor, better tests for group, dataset, and externallink

Location:
hdf5_examine/src/Hdf5Examine
Files:
1 deleted
1 edited

Legend:

Unmodified
Added
Removed
  • hdf5_examine/src/Hdf5Examine/h5toText.py

    r1251 r1252  
    3131        mc.report()
    3232    '''
    33     filename = None
    3433    requested_filename = None
    3534    isNeXus = False
    3635    array_items_shown = 5
    3736
    38     def __init__(self, filename, makeReport = False):
     37    def __init__(self, filename):
    3938        ''' Constructor '''
    4039        self.requested_filename = filename
     40        self.filename = None
    4141        if os.path.exists(filename):
    4242            self.filename = filename
    43             self.isNeXus = self.testIsNeXus()
    44             if makeReport:
    45                 self.report()
     43            self.isNeXus = self._testIsNeXus()
    4644
    4745    def report(self):
    4846        ''' reporter '''
    49         if self.filename == None: return None
     47        if self.filename is None: return None
    5048        f = h5py.File(self.filename, 'r')
    5149        txt = self.filename
    5250        if self.isNeXus:
    5351            txt += " : NeXus data file"
    54         structure = self.showGroup(f, txt, indentation = "")
     52        structure = self._renderGroup(f, txt, indentation = "")
    5553        f.close()
    5654        return structure
    5755
    58     def testIsNeXus(self):
     56    def _testIsNeXus(self):
    5957        '''
    6058        test if the selected HDF5 file is a NeXus file
    6159       
    62         At this time, the code only tests for the existence of
    63         the NXentry group.  The tests should be extended to require
    64         a NXdata group and a single dataset containing signal=1 attribute.
     60        Tests for the existence of any NXentry group
     61        containing any NXdata group containing a single dataset
     62        with signal=1 attribute (allows either integer or text representation).
     63        This is the minimum requirement for a NeXus data file.
    6564        '''
    6665        result = False
    6766        try:
    6867            f = h5py.File(self.filename, 'r')
    69             for value in f.itervalues():
    70                 #print str(type(value))
    71                 if '.Group' not in str(type(value)):
    72                     continue
    73                 #print value.attrs.keys()
    74                 if 'NX_class' not in value.attrs:
    75                     continue
    76                 v = value.attrs['NX_class']
    77                 #print type(v), v, type("a string")
    78                 possible_types = ["<type 'numpy.string_'>", ]
    79                 possible_types.append("<type 'str'>")
    80                 if str(type(v)) not in possible_types:
    81                     continue
    82                 if str(v) == str('NXentry'):
    83                     # TODO: apply more tests
    84                     #    for group NXdata
    85                     #    and signal=1 attribute on only one dataset
    86                     result = True
    87                     break
     68            # verify this NeXus classpath exists:
     69            #  /NXentry/NXdata/dataset/@signal=1
     70            for node0 in f:
     71                # the_type = str(type(value))
     72                if self._testIsNeXusGroup(node0, 'NXentry'):
     73                    for node1 in node0:
     74                        if self._testIsNeXusGroup(node1, 'NXdata'):
     75                            # ensure only one dataset has signal=1 attribute
     76                            signal1_count = 0
     77                            for node2 in node1:
     78                                if self._testIsNeXusDataset(node2):
     79                                    if 'signal' in node2.attrs:
     80                                        if str(node2.attrs['signal']) == '1':
     81                                            signal1_count += 1
     82                            if signal1_count == 1:
     83                                result = True
     84                                break
    8885            f.close()
    8986        except:
     
    9188        return result
    9289
    93     def showGroup(self, obj, name, indentation = "  "):
    94         '''print the contents of the group'''
     90    def _testIsNeXusGroup(self, obj, NXtype):
     91        '''
     92        Is the h5py object "obj" a NeXus NXtype group?
     93        '''
     94        result = False
     95        if isinstance(obj, h5py.Group):
     96            if 'NX_class' in obj.attrs:
     97                if str(obj.attrs['NX_class']) == str(NXtype):
     98                    result = True
     99        return result
     100
     101    def _testIsNeXusDataset(self, obj):
     102        '''
     103        Is the h5py object "obj" a NeXus dataset?
     104        '''
     105        return isinstance(obj, h5py.Dataset)
     106
     107    def _renderGroup(self, obj, name, indentation = "  "):
     108        '''return a [formatted_string] with the contents of the group'''
    95109        s = []
    96110        nxclass = ""
     
    99113            nxclass = ":" + str(class_attr)
    100114        s += [ indentation + name + nxclass ]
    101         s += self.showAttributes(obj, indentation)
     115        s += self._renderAttributes(obj, indentation)
    102116        # show datasets and links next
    103117        groups = []
    104118        for itemname in sorted(obj):
    105119            linkref = obj.get(itemname, getlink=True)
    106             if '.ExternalLink' in str(type(linkref)):
     120            if isinstance(linkref, h5py.ExternalLink):
    107121                # if the external file is not present, cannot know if
    108122                # link target is a dataset or a group or another link
     
    115129                    groups.append(value)
    116130                elif '.Dataset' in str(classref):
    117                     s += self.showDataset(value, itemname, indentation+"  ")
     131                    s += self._renderDataset(value, itemname, indentation+"  ")
    118132                else:
    119133                    msg = "unidentified %s: %s, %s", itemname, repr(classref), repr(linkref)
     
    122136        for value in groups:
    123137            itemname = value.name.split("/")[-1]
    124             s += self.showGroup(value, itemname, indentation+"  ")
     138            s += self._renderGroup(value, itemname, indentation+"  ")
    125139       
    126140        return s
    127141
    128     def showAttributes(self, obj, indentation = "  "):
    129         '''print any attributes'''
     142    def _renderAttributes(self, obj, indentation = "  "):
     143        '''return a [formatted_string] with any attributes'''
    130144        s = []
    131145        for name, value in obj.attrs.iteritems():
     
    133147        return s
    134148
    135     def showDataset(self, dset, name, indentation = "  "):
    136         '''print the contents and structure of a dataset'''
     149    def _renderDataset(self, dset, name, indentation = "  "):
     150        '''return a [formatted_string] with the contents and structure of a dataset'''
    137151        shape = dset.shape
    138152        # dset.dtype.kind == 'S', nchar = dset.dtype.itemsize
     
    142156                    return ["%s%s --> %s" % (indentation, name,
    143157                                           dset.attrs['target'])]
    144         txType = self.getType(dset)
    145         txShape = self.getShape(dset)
     158        txType = self._renderDsType(dset)
     159        txShape = self._renderDsShape(dset)
    146160        s = []
    147161        if dset.dtype.kind == 'S':
    148162            value = " = %s" % str(dset.value)
    149163            s += [ "%s%s:%s%s" % (indentation, name, txType, value) ]
    150             s += self.showAttributes(dset, indentation)
     164            s += self._renderAttributes(dset, indentation)
    151165            # dset.dtype.kind == 'S', nchar = dset.dtype.itemsize
    152166        elif shape == (1,):
     
    154168            s += [ "%s%s:%s%s%s" % (indentation, name, txType,
    155169                                   txShape, value) ]
    156             s += self.showAttributes(dset, indentation)
     170            s += self._renderAttributes(dset, indentation)
    157171        else:
    158172            s += [ "%s%s:%s%s = __array" % (indentation, name,
    159173                                       txType, txShape) ]
    160174            # show these before __array
    161             s += self.showAttributes(dset, indentation)
     175            s += self._renderAttributes(dset, indentation)
    162176            if self.array_items_shown > 2:
    163                 value = self.formatArray(dset, indentation + '  ')
     177                value = self._renderArray(dset, indentation + '  ')
    164178                s += [ "%s  %s = %s" % (indentation, "__array", value) ]
    165179            else:
     
    167181        return s
    168182
    169     def getType(self, obj):
     183    def _renderDsType(self, obj):
    170184        ''' get the storage (data) type of the dataset '''
    171185        t = str(obj.dtype)
     
    177191        return t
    178192
    179     def getShape(self, obj):
     193    def _renderDsShape(self, obj):
    180194        ''' return the shape of the HDF5 dataset '''
    181195        s = obj.shape
     
    189203        return result
    190204
    191     def formatArray(self, obj, indentation = '  '):
     205    def _renderArray(self, obj, indentation = '  '):
    192206        ''' nicely format an array up to rank=5 '''
    193207        shape = obj.shape
    194208        r = ""
    195209        if len(shape) in (1, 2, 3, 4, 5):
    196             r = self.formatNdArray(obj, indentation + '  ')
     210            r = self._renderNdArray(obj, indentation + '  ')
    197211        if len(shape) > 5:
    198212            r = "### no arrays for rank > 5 ###"
    199213        return r
    200214
    201     def decideNumShown(self, n):
     215    def _decideNumShown(self, n):
    202216        ''' determine how many values to show '''
    203217        if self.array_items_shown != None:
     
    206220        return n
    207221
    208     def formatNdArray(self, obj, indentation = '  '):
     222    def _renderNdArray(self, obj, indentation = '  '):
    209223        ''' return a list of lower-dimension arrays, nicely formatted '''
    210224        shape = obj.shape
    211225        rank = len(shape)
    212226        if not rank in (1, 2, 3, 4, 5): return None
    213         n = self.decideNumShown( shape[0] )
     227        n = self._decideNumShown( shape[0] )
    214228        r = []
    215229        for i in range(n):
    216230            if rank == 1: item = obj[i]
    217231            # TODO: can this be combined?
    218             if rank == 2: item = self.formatNdArray(obj[i, :])
    219             if rank == 3: item = self.formatNdArray(obj[i, :, :],
    220                                                     indentation + '  ')
    221             if rank == 4: item = self.formatNdArray(obj[i, :, :, :],
    222                                                     indentation + '  ')
    223             if rank == 5: item = self.formatNdArray(obj[i, :, :, :, :],
     232            if rank == 2: item = self._renderNdArray(obj[i, :])
     233            if rank == 3: item = self._renderNdArray(obj[i, :, :],
     234                                                    indentation + '  ')
     235            if rank == 4: item = self._renderNdArray(obj[i, :, :, :],
     236                                                    indentation + '  ')
     237            if rank == 5: item = self._renderNdArray(obj[i, :, :, :, :],
    224238                                                    indentation + '  ')
    225239            r.append( item )
     
    230244            if rank == 1: item = obj[-1]
    231245            # TODO: can this be combined?
    232             if rank == 2: item = self.formatNdArray(obj[-1, :])
    233             if rank == 3: item = self.formatNdArray(obj[-1, :, :],
    234                                                     indentation + '  ')
    235             if rank == 4: item = self.formatNdArray(obj[-1, :, :, :],
    236                                                     indentation + '  ')
    237             if rank == 5: item = self.formatNdArray(obj[-1, :, :, :, :],
     246            if rank == 2: item = self._renderNdArray(obj[-1, :])
     247            if rank == 3: item = self._renderNdArray(obj[-1, :, :],
     248                                                    indentation + '  ')
     249            if rank == 4: item = self._renderNdArray(obj[-1, :, :, :],
     250                                                    indentation + '  ')
     251            if rank == 5: item = self._renderNdArray(obj[-1, :, :, :, :],
    238252                                                    indentation + '  ')
    239253            r.append( item )
     
    262276
    263277
    264 def do_test():
    265     limit = 0
     278def get_test_file_list():
    266279    path = os.path.dirname(os.path.abspath(__file__))
    267280    filelist = []
     
    280293        filelist.append(os.path.abspath(hdf5File))
    281294   
    282     do_filelist(filelist, limit=limit)
     295    return filelist
     296
     297
     298def do_test():
     299    limit = 0
     300    do_filelist('nonexistent file', limit=limit)   # should produce no output
     301    do_filelist(get_test_file_list(), limit=limit)   
    283302
    284303
Note: See TracChangeset for help on using the changeset viewer.